diff --git a/src/guf_dbuf.h b/src/guf_dbuf.h index ae91ba6..7ac729b 100644 --- a/src/guf_dbuf.h +++ b/src/guf_dbuf.h @@ -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; - } else { - ptrdiff_t idx = it.ptr - begin.ptr; - GUF_ASSERT(idx >= 0 && idx <= dbuf->size); - return idx; + } + + bool is_reverse_it = it.base != NULL; + + if (is_reverse_it) { + return (ptrdiff_t)(it.base - dbuf->data) - 1; + } else { + 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; @@ -912,23 +942,36 @@ GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find)(GUF_CN } 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) -{ +{ 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)) { diff --git a/src/guf_test.c b/src/guf_test.c index 41dca98..aca8bad 100644 --- a/src/guf_test.c +++ b/src/guf_test.c @@ -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); }