Change iterator

This commit is contained in:
jun 2025-02-01 13:31:15 +01:00
parent df9d1c9c10
commit fd58daa8b5
2 changed files with 117 additions and 68 deletions

View File

@ -57,9 +57,18 @@ typedef struct GUF_CNT_NAME {
#endif
} GUF_CNT_NAME;
/*
- Regular iterator: base is always NULL
- Reverse iterator: base points the element after ptr
Examples:
- rbegin(): base points to end().ptr, and ptr to end().ptr - 1
- rend(): base points to begin().ptr and ptr to NULL
- reverse iterator for the first element of the container: base points to the second element, ptr points to the first element
*/
typedef struct GUF_CAT(GUF_CNT_NAME, _iter) {
GUF_T *ptr;
bool reverse;
GUF_T *base;
} GUF_CAT(GUF_CNT_NAME, _iter);
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _valid)(const GUF_CNT_NAME* dbuf);
@ -132,6 +141,8 @@ GUF_FN_KEYWORDS ptrdiff_t GUF_CAT(GUF_CNT_NAME, _iter_to_idx)(const GUF_CNT_NAME
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find)(GUF_CNT_NAME *dbuf, GUF_CAT(GUF_CNT_NAME, _iter) begin, GUF_CAT(GUF_CNT_NAME, _iter) end, const GUF_T *needle);
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find_val)(GUF_CNT_NAME *dbuf, GUF_CAT(GUF_CNT_NAME, _iter) begin, GUF_CAT(GUF_CNT_NAME, _iter) end, GUF_T needle_val);
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find_if)(GUF_CNT_NAME *dbuf, GUF_CAT(GUF_CNT_NAME, _iter) begin, GUF_CAT(GUF_CNT_NAME, _iter) end, bool (*predicate)(const GUF_T *));
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _contains)(GUF_CNT_NAME *dbuf, const GUF_T *needle);
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _contains_val)(GUF_CNT_NAME *dbuf, GUF_T needle);
#endif
#if defined(GUF_IMPL) || defined(GUF_IMPL_STATIC)
@ -761,12 +772,14 @@ GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _try_shrink_to_fit)(GUF_CNT_NAME *dbu
/* Iterator functions */
#define ITER_PTR(it) !it.reverse ? (it.iter.ptr) : (it.rev_iter.ptr - 1)
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _begin)(const GUF_CNT_NAME* dbuf)
{
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
return (GUF_CAT(GUF_CNT_NAME, _iter)) {
.ptr = dbuf->data,
.reverse = false
.base = NULL
};
}
@ -774,8 +787,8 @@ GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _end)(const G
{
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
return (GUF_CAT(GUF_CNT_NAME, _iter)) {
.ptr = dbuf->data ? dbuf->data + dbuf->size : NULL,
.reverse = false
.ptr = dbuf->data && dbuf->size ? dbuf->data + dbuf->size : NULL,
.base = NULL
};
}
@ -783,8 +796,8 @@ GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _rbegin)(cons
{
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
return (GUF_CAT(GUF_CNT_NAME, _iter)) {
.ptr = dbuf->data ? dbuf->data + (dbuf->size > 0 ? dbuf->size - 1 : 0) : NULL,
.reverse = true
.base = dbuf->data && dbuf->size ? dbuf->data + dbuf->size : NULL,
.ptr = dbuf->data && dbuf->size ? dbuf->data + (dbuf->size - 1) : NULL
};
}
@ -792,8 +805,8 @@ GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _rend)(const
{
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
return (GUF_CAT(GUF_CNT_NAME, _iter)) {
.ptr = dbuf->data ? dbuf->data + dbuf->size : NULL,
.reverse = true
.base = dbuf->data && dbuf->size ? dbuf->data : NULL,
.ptr = NULL
};
}
@ -802,39 +815,64 @@ GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _iter_at_idx
GUF_ASSERT(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
GUF_CAT(GUF_CNT_NAME, _iter) it;
it.reverse = false;
if (idx < 0 || idx >= dbuf->size || !dbuf->data) {
it.ptr = GUF_CAT(GUF_CNT_NAME, _end)(dbuf).ptr;
it.base = NULL;
if (!dbuf->data || !dbuf->size) {
it.ptr = NULL;
return it;
}
if (idx < 0) {
it.ptr = dbuf->data;
} else if (idx > dbuf->size) {
it.ptr = dbuf->data + dbuf->size;
} else {
it.ptr = dbuf->data + idx;
}
return it;
}
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _reverse_iter_at_idx)(const GUF_CNT_NAME* dbuf, ptrdiff_t idx)
{
GUF_CAT(GUF_CNT_NAME, _iter) it = GUF_CAT(GUF_CNT_NAME, _iter_at_idx)(dbuf, idx);
it.reverse = true;
if (!dbuf->data || !dbuf->size) {
it.base = NULL;
it.ptr = NULL;
return it;
}
if (idx < 0) {
it.base = dbuf->data;
it.ptr = NULL;
} else if (idx >= dbuf->size) {
it.base = dbuf->data + dbuf->size;
it.ptr = it.base - 1;
} else {
it.base = dbuf->data + idx + 1;
it.ptr = it.base - 1;
}
return it;
}
static const ptrdiff_t GUF_CAT(GUF_CNT_NAME, _npos) = -1;
static const ptrdiff_t GUF_CAT(GUF_CNT_NAME, _npos) = PTRDIFF_MIN;
GUF_FN_KEYWORDS ptrdiff_t GUF_CAT(GUF_CNT_NAME, _iter_to_idx)(const GUF_CNT_NAME* dbuf, GUF_CAT(GUF_CNT_NAME, _iter) it)
GUF_FN_KEYWORDS ptrdiff_t
GUF_CAT(GUF_CNT_NAME, _iter_to_idx)(const GUF_CNT_NAME* dbuf, GUF_CAT(GUF_CNT_NAME, _iter) it)
{
GUF_ASSERT(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
GUF_CAT(GUF_CNT_NAME, _iter) begin = GUF_CAT(GUF_CNT_NAME, _begin)(dbuf);
GUF_CAT(GUF_CNT_NAME, _iter) end = GUF_CAT(GUF_CNT_NAME, _end)(dbuf);
if (it.ptr == NULL || begin.ptr == NULL || end.ptr == NULL || it.ptr < begin.ptr || it.ptr > end.ptr || !dbuf->data) {
if ((!it.ptr && !it.base) || !dbuf->data || !dbuf->size) {
return GUF_CAT(GUF_CNT_NAME, _npos);
} else if (it.ptr == end.ptr) {
return it.reverse ? -1 : dbuf->size;
}
bool is_reverse_it = it.base != NULL;
if (is_reverse_it) {
return (ptrdiff_t)(it.base - dbuf->data) - 1;
} else {
ptrdiff_t idx = it.ptr - begin.ptr;
GUF_ASSERT(idx >= 0 && idx <= dbuf->size);
return idx;
return (ptrdiff_t)(it.ptr - dbuf->data);
}
}
@ -842,62 +880,54 @@ GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _iter_next)(c
{
GUF_ASSERT(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
GUF_T *end_ptr = dbuf->data ? dbuf->data + dbuf->size : NULL;
if (!dbuf->size || !dbuf->data || !it.ptr) {
it.ptr = end_ptr;
if (!dbuf->size || !dbuf->data || (!it.base && !it.ptr)) {
it.ptr = NULL;
it.base = NULL;
return it;
}
if (it.reverse) {
const bool is_reverse_it = it.base != NULL;
if (is_reverse_it) {
if (step < 0) {
GUF_ASSERT_RELEASE(step > PTRDIFF_MIN); // Catch overflow.
}
step = -step;
}
ptrdiff_t it_idx = 0;
if (it.ptr == end_ptr && it.reverse) { // Handle rend()
it_idx = step - 1;
} else if (it.ptr == end_ptr && !it.reverse) { // Handle end()
it_idx = dbuf->size + step;
if (is_reverse_it) {
ptrdiff_t idx = (ptrdiff_t)(it.base - dbuf->data) + step;
idx = GUF_CLAMP(idx, 0, dbuf->size);
it.base = dbuf->data + idx;
it.ptr = idx == 0 ? NULL : it.base - 1;
} else {
GUF_ASSERT_RELEASE(it.ptr >= dbuf->data && it.ptr < end_ptr)
it_idx = (ptrdiff_t)(it.ptr - dbuf->data) + step;
GUF_ASSERT(it.ptr);
ptrdiff_t idx = (ptrdiff_t)(it.ptr - dbuf->data) + step;
idx = GUF_CLAMP(idx, 0, dbuf->size);
it.ptr = dbuf->data + idx;
}
const ptrdiff_t len = (end_ptr && dbuf->data) ? end_ptr - dbuf->data : 0;
GUF_ASSERT_RELEASE(len >= 0);
if (len == 0 || it_idx >= len || it_idx < 0) {
it.ptr = end_ptr;
} else {
GUF_ASSERT(dbuf->data && it.ptr);
it.ptr = dbuf->data + it_idx;
}
return it;
}
#if defined(GUF_T_IS_INTEGRAL_TYPE) || defined(GUF_T_EQ)
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find)(GUF_CNT_NAME *dbuf, GUF_CAT(GUF_CNT_NAME, _iter) begin, GUF_CAT(GUF_CNT_NAME, _iter) end, const GUF_T *needle)
{
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
GUF_ASSERT_RELEASE(needle);
GUF_CAT(GUF_CNT_NAME, _iter) dbuf_end = GUF_CAT(GUF_CNT_NAME, _end)(dbuf);
dbuf_end.reverse = begin.reverse;
ptrdiff_t begin_idx = GUF_CAT(GUF_CNT_NAME, _iter_to_idx)(dbuf, begin);
ptrdiff_t end_idx = GUF_CAT(GUF_CNT_NAME, _iter_to_idx)(dbuf, end);
if (!begin.ptr || !end.ptr || !dbuf->data || begin.ptr == dbuf_end.ptr) {
return dbuf_end;
} else if (!begin.reverse && begin_idx >= end_idx) {
return dbuf_end;
} else if (begin.reverse && begin_idx <= end_idx) {
return dbuf_end;
const bool is_reverse_it = begin.base != NULL;
GUF_ASSERT_RELEASE(is_reverse_it == (end.base != NULL)); // begin and end must be the same iterator type.
const GUF_CAT(GUF_CNT_NAME, _iter) dbuf_end_it = is_reverse_it ? GUF_CAT(GUF_CNT_NAME, _rend)(dbuf) : GUF_CAT(GUF_CNT_NAME, _end)(dbuf);
if (!dbuf->data || !dbuf->size || (!begin.ptr && !begin.base) || (!end.ptr && !end.base)) {
return dbuf_end_it;
}
if ((begin.ptr == dbuf_end_it.ptr) || (!is_reverse_it && begin.ptr >= end.ptr) || (is_reverse_it && begin.base <= end.base)) {
return dbuf_end_it;
}
for (GUF_CAT(GUF_CNT_NAME, _iter) it = begin; it.ptr != end.ptr && it.ptr != dbuf_end.ptr; it = GUF_CAT(GUF_CNT_NAME, _iter_next)(dbuf, it, 1)) {
for (GUF_CAT(GUF_CNT_NAME, _iter) it = begin; it.ptr != end.ptr; it = GUF_CAT(GUF_CNT_NAME, _iter_next)(dbuf, it, 1)) {
#ifdef GUF_T_EQ
if (GUF_T_EQ(it.ptr, needle)) {
return it;
@ -916,19 +946,32 @@ GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find_val)(GU
return GUF_CAT(GUF_CNT_NAME, _find)(dbuf, begin, end, &needle_val);
}
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _contains)(GUF_CNT_NAME *dbuf, const GUF_T *needle)
{
GUF_CAT(GUF_CNT_NAME, _iter) beg = GUF_CAT(GUF_CNT_NAME, _begin)(dbuf);
GUF_CAT(GUF_CNT_NAME, _iter) end = GUF_CAT(GUF_CNT_NAME, _end)(dbuf);
return GUF_CAT(GUF_CNT_NAME, _find)(dbuf, beg, end, needle).ptr != end.ptr;
}
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _contains_val)(GUF_CNT_NAME *dbuf, GUF_T needle)
{
return GUF_CAT(GUF_CNT_NAME, _contains)(dbuf, &needle);
}
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find_if)(GUF_CNT_NAME *dbuf, GUF_CAT(GUF_CNT_NAME, _iter) begin, GUF_CAT(GUF_CNT_NAME, _iter) end, bool (*predicate)(const GUF_T *))
{
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
GUF_ASSERT_RELEASE(predicate);
GUF_CAT(GUF_CNT_NAME, _iter) dbuf_end = GUF_CAT(GUF_CNT_NAME, _end)(dbuf);
dbuf_end.reverse = begin.reverse;
if (!begin.ptr || !end.ptr || !dbuf->data) {
return dbuf_end;
} else if (!begin.reverse && begin.ptr >= end.ptr) {
return dbuf_end;
} else if (begin.reverse && begin.ptr <= end.ptr) {
return dbuf_end;
const bool is_reverse_it = begin.base != NULL;
GUF_ASSERT_RELEASE(is_reverse_it == (end.base != NULL)); // begin and end must be the same iterator type.
const GUF_CAT(GUF_CNT_NAME, _iter) dbuf_end_it = is_reverse_it ? GUF_CAT(GUF_CNT_NAME, _rend)(dbuf) : GUF_CAT(GUF_CNT_NAME, _end)(dbuf);
if (!dbuf->data || !dbuf->size || (!begin.ptr && !begin.base) || (!end.ptr && !end.base)) {
return dbuf_end_it;
}
if ((begin.ptr == dbuf_end_it.ptr) || (!is_reverse_it && begin.ptr >= end.ptr) || (is_reverse_it && begin.base <= end.base)) {
return dbuf_end_it;
}
for (GUF_CAT(GUF_CNT_NAME, _iter) it = begin; it.ptr != end.ptr; GUF_CAT(GUF_CNT_NAME, _iter_next)(dbuf, it, 1)) {

View File

@ -75,8 +75,8 @@ int main(void)
dbuf_heap_cstr_push_val_cpy(&strings, "Boz 4");
char *findme = "Baz 3";
dbuf_heap_cstr_iter beg = dbuf_heap_cstr_rbegin(&strings);
dbuf_heap_cstr_iter end = dbuf_heap_cstr_rend(&strings);
dbuf_heap_cstr_iter beg = dbuf_heap_cstr_begin(&strings);
dbuf_heap_cstr_iter end = dbuf_heap_cstr_end(&strings);
dbuf_heap_cstr_iter fnd_it = dbuf_heap_cstr_find(&strings, beg, end, &findme);
if (fnd_it.ptr != dbuf_heap_cstr_end(&strings).ptr) {
printf("%s found in range [%td, %td) at idx %td\n", findme, dbuf_heap_cstr_iter_to_idx(&strings, beg), dbuf_heap_cstr_iter_to_idx(&strings, end), dbuf_heap_cstr_iter_to_idx(&strings, fnd_it));
@ -84,6 +84,12 @@ int main(void)
printf("%s not found in range [%td, %td) at idx %td\n", findme, dbuf_heap_cstr_iter_to_idx(&strings, beg), dbuf_heap_cstr_iter_to_idx(&strings, end), dbuf_heap_cstr_iter_to_idx(&strings, fnd_it));
}
if (dbuf_heap_cstr_contains_val(&strings, "Baz 3")) {
printf("contains\n");
} else {
printf("does not contain\n");
}
GUF_CNT_FOREACH(&strings, dbuf_heap_cstr, it) {
printf("%s\n", *it.ptr);
}