#include "test_dbuf.hpp" extern "C" { #include "guf_alloc_libc.h" #include "impls/dbuf_impl.h" } /* DbufIntTest */ void DbufIntTest::run() { if (done) { return; } // allocator_ctx.tracker.log = fopen("alloc_log.txt", "w"); // allocator_ctx.tracker.err_log = fopen("alloc_err_log.txt", "w"); dbuf_int dbuf {}; dbuf_int_init(&dbuf, 0, &allocator); push_check_name("test_push"); test_push(&dbuf, 256); test_push(&dbuf, 128); test_push(&dbuf, 17); TEST_CHECK(dbuf.size == (256 + 128 + 17)); dbuf_int_free(&dbuf, NULL); TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 0 && dbuf.data == NULL); dbuf_int_init(&dbuf, 24, &allocator); TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 24 && dbuf.data); test_push(&dbuf, 365); test_push(&dbuf, 4); test_push(&dbuf, 25); test_push(&dbuf, 64); TEST_CHECK(dbuf.size == (365 + 4 + 25 + 64)); dbuf_int_free(&dbuf, NULL); TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 0 && dbuf.data == NULL); pop_check_name(); push_check_name("insert_remove"); for (int n = 0; n <= 128; ++n) { test_insert_remove(n); } test_insert_remove(400); test_insert_remove(401); test_insert_remove(512); test_insert_remove(513); test_insert_remove(601); test_insert_remove(2048); test_insert_remove(2049); pop_check_name(); TEST_CHECK(!guf_alloc_tracker_found_leak(&allocator_ctx.tracker)); // guf_alloc_tracker_print(&allocator_ctx.tracker, stdout); // puts(""); // fclose(allocator_ctx.tracker.log); // fclose(allocator_ctx.tracker.err_log); } std::vector DbufIntTest::dbuf_to_vec(dbuf_int *dbuf) { std::vector vec; GUF_CNT_FOREACH(dbuf, dbuf_int, it) { vec.push_back(*it.ptr); } return vec; } void DbufIntTest::test_push(dbuf_int *dbuf, int n) { std::vector vec = dbuf_to_vec(dbuf); TEST_CHECK(std::ssize(vec) == dbuf->size); for (int i = 0; i < n; ++i) { dbuf_int_push_val(dbuf, i); vec.push_back(i); TEST_CHECK(*dbuf_int_back(dbuf) == vec.back()); } ptrdiff_t i = 0; GUF_CNT_FOREACH(dbuf, dbuf_int, it) { TEST_CHECK(*it.ptr == vec.at(i++)); } TEST_CHECK(i == dbuf->size); i = dbuf->size - 1; GUF_CNT_FOREACH_REVERSE(dbuf, dbuf_int, rit) { TEST_CHECK(*rit.ptr == vec.at(i--)); } TEST_CHECK(i == -1); } void DbufIntTest::test_insert_remove(int n) { dbuf_int dbuf = {}; dbuf_int_init(&dbuf, 0, &allocator); std::vector vec = dbuf_to_vec(&dbuf); guf_err err = GUF_ERR_NONE; dbuf_int_try_erase(&dbuf, 0, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); err = GUF_ERR_NONE; dbuf_int_try_erase(&dbuf, 12, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); err = GUF_ERR_NONE; dbuf_int_try_front(&dbuf, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); err = GUF_ERR_NONE; dbuf_int_try_back(&dbuf, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); err = GUF_ERR_NONE; dbuf_int_try_at(&dbuf, 0, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); for (int i = 0; i < n; ++i) { dbuf_int_insert_val(&dbuf, i, i); dbuf_int_insert_val(&dbuf, i * 2, 0); dbuf_int_insert_val(&dbuf, i * 4, dbuf.size); vec.insert(vec.begin() + i, i); vec.insert(vec.begin(), i * 2); vec.insert(vec.end(), i * 4); } TEST_CHECK(std::ssize(vec) == dbuf.size); // Iterate dbuf_int_iter it_dbuf = dbuf_int_begin(&dbuf); std::vector::const_iterator it_vec = vec.begin(); while (!dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec != vec.end()) { TEST_CHECK(*it_dbuf.ptr == *it_vec); it_dbuf = dbuf_int_iter_next(&dbuf, it_dbuf, 1); std::advance(it_vec, 1); } TEST_CHECK(dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec == vec.end()); // Step iterate. it_dbuf = dbuf_int_begin(&dbuf); it_vec = vec.begin(); while (!dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec != vec.end()) { TEST_CHECK(*it_dbuf.ptr == *it_vec); it_dbuf = dbuf_int_iter_next(&dbuf, it_dbuf, 7); if (dbuf_int_iter_is_end(&dbuf, it_dbuf)) { it_vec = vec.end(); } else { std::advance(it_vec, 7); } } TEST_CHECK(dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec == vec.end()); // Reverse iterate. dbuf_int_iter rit_dbuf = dbuf_int_rbegin(&dbuf); std::vector::const_reverse_iterator rit_vec = vec.crbegin(); while (!dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec != vec.crend()) { TEST_CHECK(*rit_dbuf.ptr == *rit_vec); rit_dbuf = dbuf_int_iter_next(&dbuf, rit_dbuf, 1); std::advance(rit_vec, 1); } TEST_CHECK(dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec == vec.rend()); // Reverse iterate step. rit_dbuf = dbuf_int_rbegin(&dbuf); rit_vec = vec.crbegin(); while (!dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec != vec.crend()) { TEST_CHECK(*rit_dbuf.ptr == *rit_vec); rit_dbuf = dbuf_int_iter_next(&dbuf, rit_dbuf, 4); if (dbuf_int_iter_is_end(&dbuf, rit_dbuf)) { rit_vec = vec.rend(); } else { std::advance(rit_vec, 4); } } TEST_CHECK(dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec == vec.rend()); TEST_CHECK(dbuf.size == std::ssize(vec)); for (ptrdiff_t i = 0; i < dbuf.size; i += 8) { dbuf_int_erase(&dbuf, i); dbuf_int_erase(&dbuf, 0); dbuf_int_pop(&dbuf); vec.erase(vec.begin() + i); vec.erase(vec.begin() + 0); vec.pop_back(); } TEST_CHECK(dbuf.size == std::ssize(vec)); for (ptrdiff_t i = 0; i < dbuf.size; i += 8) { TEST_CHECK(*dbuf_int_at(&dbuf, i) == vec.at(i)); } const ptrdiff_t size = dbuf.size; for (ptrdiff_t i = 0; i < size; ++i) { int a = dbuf_int_pop_move(&dbuf); int b = vec.back(); TEST_CHECK(a == b); vec.pop_back(); } TEST_CHECK(dbuf.size == 0 && vec.size() == 0); dbuf_int_free(&dbuf, NULL); TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 0 && !dbuf.data); } /* DbufCstringTest */ void DbufCstringTest::run() { if (done) { return; } // allocator_ctx.tracker.log = fopen("alloc_log.txt", "w"); // allocator_ctx.tracker.err_log = fopen("alloc_err_log.txt", "w"); push_check_name("push_insert_erase"); for (int i = 1; i <= 32; ++i) { test_push_insert_erase(i); test_push_insert_erase(i, i - 1); test_push_insert_erase(i, i + 1); test_push_insert_erase(i, i); test_push_insert_erase(i, i / 2); } test_push_insert_erase(2048); test_push_insert_erase(2048, 11); dbuf_heap_cstr str_dbuf = {}; dbuf_heap_cstr_init(&str_dbuf, 0, &allocator); std::vector str_vec {}; for (int i = 0; i < 512; ++i) { char buf[128]; memset(buf, '\0', GUF_ARR_SIZE(buf)); snprintf(buf, GUF_ARR_SIZE(buf), "This is a pretty guf string (number %d)", i); guf_cstr_heap str = buf; dbuf_heap_cstr_push(&str_dbuf, &str, GUF_CPY_DEEP); str_vec.push_back(std::string{buf}); } for (int i = 0; i < str_dbuf.size + 16; ++i) { test_iter(str_vec, &str_dbuf, i); } dbuf_heap_cstr_free(&str_dbuf, NULL); TEST_CHECK(str_dbuf.size == 0 && str_dbuf.capacity == 0 && !str_dbuf.data); pop_check_name(); push_check_name("find"); test_find(); test_find(3); test_find(42); test_find(129); pop_check_name(); TEST_CHECK(!guf_alloc_tracker_found_leak(&allocator_ctx.tracker)); // guf_alloc_tracker_print(&allocator_ctx.tracker, stdout); // puts(""); // fclose(allocator_ctx.tracker.log); // fclose(allocator_ctx.tracker.err_log); } void DbufCstringTest::test_iter(std::vector& str_vec, dbuf_heap_cstr *str_dbuf, int step) { GUF_ASSERT_RELEASE(str_dbuf); if (step <= 0) { step = 1; } ptrdiff_t i = 0; GUF_CNT_FOREACH(str_dbuf, dbuf_heap_cstr, it) { char *str = *it.ptr; TEST_CHECK(str_vec.at(i) == str); ++i; } TEST_CHECK(i == str_dbuf->size); i = str_dbuf->size - 1; GUF_CNT_FOREACH_REVERSE(str_dbuf, dbuf_heap_cstr, rit) { char *str = *rit.ptr; TEST_CHECK(str_vec.at(i) == str); --i; } TEST_CHECK(i == -1); dbuf_heap_cstr_iter it_dbuf = dbuf_heap_cstr_begin(str_dbuf); std::vector::iterator it_vec = str_vec.begin(); while (!dbuf_heap_cstr_iter_is_end(str_dbuf, it_dbuf)) { TEST_CHECK(it_vec != str_vec.end()); TEST_CHECK(*it_vec == *it_dbuf.ptr); it_dbuf = dbuf_heap_cstr_iter_next(str_dbuf, it_dbuf, step); if (!dbuf_heap_cstr_iter_is_end(str_dbuf, it_dbuf)) { std::advance(it_vec, step); } else { it_vec = str_vec.end(); } } TEST_CHECK(dbuf_heap_cstr_iter_is_end(str_dbuf, it_dbuf) && it_vec == str_vec.end()); dbuf_heap_cstr_iter rit_dbuf = dbuf_heap_cstr_rbegin(str_dbuf); std::vector::reverse_iterator rit_vec = str_vec.rbegin(); while (!dbuf_heap_cstr_iter_is_end(str_dbuf, rit_dbuf)) { TEST_CHECK(rit_vec != str_vec.rend()); TEST_CHECK(*rit_vec == *rit_dbuf.ptr); rit_dbuf = dbuf_heap_cstr_iter_next(str_dbuf, rit_dbuf, step); if (!dbuf_heap_cstr_iter_is_end(str_dbuf, rit_dbuf)) { std::advance(rit_vec, step); } else { rit_vec = str_vec.rend(); } } TEST_CHECK(dbuf_heap_cstr_iter_is_end(str_dbuf, rit_dbuf) && rit_vec == str_vec.rend()); for (i = 0; i < str_dbuf->size; ++i) { char *str = *dbuf_heap_cstr_at(str_dbuf, i); TEST_CHECK(str_vec.at(i) == str); } } void DbufCstringTest::test_push_insert_erase(int n, ptrdiff_t start_cap) { std::vector str_vec; dbuf_heap_cstr str_dbuf {}; dbuf_heap_cstr_init(&str_dbuf, start_cap, &allocator); for (int i = 0; i < n; ++i) { constexpr int BUF_SZ = 128; char buf[BUF_SZ]; memset(buf, '\0', BUF_SZ); snprintf(buf, BUF_SZ, "This is string number %d", i); guf_cstr_heap str = buf; dbuf_heap_cstr_push(&str_dbuf, &str, GUF_CPY_DEEP); dbuf_heap_cstr_push_val_cpy(&str_dbuf, str); char *heap_buf = strdup("Move me plz"); dbuf_heap_cstr_push(&str_dbuf, &heap_buf, GUF_CPY_MOVE); TEST_CHECK(heap_buf == NULL); TEST_CHECK(strncmp(*dbuf_heap_cstr_back(&str_dbuf), "Move me plz", BUF_SZ) == 0); TEST_CHECK(strncmp(*dbuf_heap_cstr_at(&str_dbuf, str_dbuf.size - 2), buf, BUF_SZ) == 0); TEST_CHECK(strncmp(*dbuf_heap_cstr_at(&str_dbuf, str_dbuf.size - 3), buf, BUF_SZ) == 0); str_vec.push_back(std::string{buf}); str_vec.push_back(std::string{buf}); str_vec.emplace_back("Move me plz"); } TEST_CHECK(str_dbuf.size == std::ssize(str_vec)); TEST_CHECK(str_dbuf.size == 3 * n); for (int i = 1; i <= 8; ++i) { test_iter(str_vec, &str_dbuf, i); } test_iter(str_vec, &str_dbuf, (int)str_dbuf.size); test_iter(str_vec, &str_dbuf, (int)str_dbuf.size - 1); test_iter(str_vec, &str_dbuf, (int)str_dbuf.size + 1); for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) { TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i)); } // Insert front. for (ptrdiff_t i = 0; i < 16; ++i) { char str[] = "front"; dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, 0); str_vec.insert(str_vec.begin(), std::string{str}); } TEST_CHECK(std::ssize(str_vec) == str_dbuf.size); for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) { TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i)); } // Insert back. for (ptrdiff_t i = 0; i < 16; ++i) { char str[] = "front"; dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, str_dbuf.size); str_vec.insert(str_vec.end(), std::string{str}); } TEST_CHECK(std::ssize(str_vec) == str_dbuf.size); for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) { TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i)); } // Insert at i. char str[] = "guf"; dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, str_dbuf.size / 2); str_vec.insert(str_vec.begin() + str_vec.size() / 2, str); dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, str_dbuf.size / 4); str_vec.insert(str_vec.begin() + str_vec.size() / 4, str); dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, 1); str_vec.insert(str_vec.begin() + 1, str); dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, str_dbuf.size - 1); str_vec.insert(str_vec.begin() + (str_vec.size() - 1), str); for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) { TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i)); } guf_err err = GUF_ERR_NONE; dbuf_heap_cstr_try_insert_val_cpy(&str_dbuf, str, str_dbuf.size + 1, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); err = GUF_ERR_NONE; dbuf_heap_cstr_try_insert_val_cpy(&str_dbuf, str, -1, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); err = GUF_ERR_NONE; dbuf_heap_cstr_try_insert_val_cpy(&str_dbuf, str, str_dbuf.size + 2, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); TEST_CHECK(std::ssize(str_vec) == str_dbuf.size); for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) { TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i)); } if (str_dbuf.size) { dbuf_heap_cstr_erase(&str_dbuf, str_dbuf.size - 1); str_vec.erase(str_vec.end() - 1); } ptrdiff_t to_rem = 8; while (str_dbuf.size && to_rem--) { dbuf_heap_cstr_erase(&str_dbuf, 0); str_vec.erase(str_vec.begin()); TEST_CHECK(std::ssize(str_vec) == str_dbuf.size); if (str_dbuf.size) { dbuf_heap_cstr_pop(&str_dbuf); str_vec.pop_back(); TEST_CHECK(std::ssize(str_vec) == str_dbuf.size); } if (str_dbuf.size) { dbuf_heap_cstr_erase(&str_dbuf, str_dbuf.size / 2); str_vec.erase(str_vec.begin() + (str_vec.size() / 2)); TEST_CHECK(std::ssize(str_vec) == str_dbuf.size); } } dbuf_heap_cstr_free(&str_dbuf, NULL); TEST_CHECK(str_dbuf.size == 0 && str_dbuf.capacity == 0 && !str_dbuf.data); } void DbufCstringTest::test_find(int n) { if (n < 2) { n = 2; } std::vector str_vec {}; dbuf_heap_cstr str_dbuf = {}; dbuf_heap_cstr_init(&str_dbuf, 0, &allocator); for (int i = 0; i < n; ++i) { constexpr int BUF_SZ = 128; char buf[BUF_SZ]; memset(buf, '\0', BUF_SZ); snprintf(buf, BUF_SZ, "String number %d", i); dbuf_heap_cstr_push_val_cpy(&str_dbuf, buf); str_vec.push_back(buf); } char *move_me = strdup("Moved string"); dbuf_heap_cstr_push(&str_dbuf, &move_me, GUF_CPY_MOVE); GUF_ASSERT_RELEASE(move_me == NULL); str_vec.emplace_back("Moved string"); TEST_CHECK(std::ssize(str_vec) == str_dbuf.size); for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) { char *needle = *dbuf_heap_cstr_at(&str_dbuf, i); TEST_CHECK(str_vec.at(i) == needle); TEST_CHECK(dbuf_heap_cstr_contains_val(&str_dbuf, needle)); dbuf_heap_cstr_iter fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), dbuf_heap_cstr_end(&str_dbuf), needle); TEST_CHECK(!dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.cbegin(), str_vec.cend(), needle) != str_vec.end()); dbuf_heap_cstr_iter begin = dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), i); dbuf_heap_cstr_iter end = dbuf_heap_cstr_end(&str_dbuf); fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, begin, end, needle); TEST_CHECK(!dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.cbegin() + i, str_vec.cend(), needle) != str_vec.end()); begin = dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), i + 1); end = dbuf_heap_cstr_end(&str_dbuf); fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, begin, end, needle); TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.cbegin() + i + 1, str_vec.cend(), needle) == str_vec.end()); // Reverse. fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_rbegin(&str_dbuf), dbuf_heap_cstr_rend(&str_dbuf), needle); TEST_CHECK(!dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.crbegin(), str_vec.crend(), needle) != str_vec.rend()); } char needle[] = "Definitely not inside"; dbuf_heap_cstr_iter fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), dbuf_heap_cstr_end(&str_dbuf), needle); TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.cbegin(), str_vec.cend(), needle) == str_vec.end()); fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_rbegin(&str_dbuf), dbuf_heap_cstr_rend(&str_dbuf), needle); TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.crbegin(), str_vec.crend(), needle) == str_vec.rend()); char *needle2 = *dbuf_heap_cstr_at(&str_dbuf, 0); fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), 1), dbuf_heap_cstr_end(&str_dbuf), needle2); TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.cbegin() + 1, str_vec.cend(), needle2) == str_vec.end()); needle2 = *dbuf_heap_cstr_back(&str_dbuf); fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), 1), dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_end(&str_dbuf), -1), needle2); TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.begin(), str_vec.end() - 1, needle2) == (str_vec.end() - 1)); needle2 = *dbuf_heap_cstr_at(&str_dbuf, 0); fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), dbuf_heap_cstr_begin(&str_dbuf), needle2); TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.cbegin(), str_vec.cbegin(), needle2) == str_vec.cbegin()); dbuf_heap_cstr_free(&str_dbuf, NULL); } /* DbufStrTest: */ void DbufStrTest::run() { test_push_insert_erase(16); test_push_insert_erase(16, 1); test_push_insert_erase(16, 15); test_push_insert_erase(16, 16); test_push_insert_erase(16, 97); test_push_insert_erase(16, 256); test_push_insert_erase(500); test_push_insert_erase(500, 1); test_push_insert_erase(500, 499); test_push_insert_erase(500, 500); test_push_insert_erase(500, 97); test_push_insert_erase(500, 256); } void DbufStrTest::test_push_insert_erase(size_t n, ptrdiff_t start_cap) { dbuf_str strings = start_cap < 0 ? dbuf_str_new(&allocator) : dbuf_str_new_with_capacity(start_cap, &allocator); std::vector strings_cpp {}; guf_libc_alloc_ctx str_allocator_ctx = { .tracker = guf_alloc_tracker_new(42, "test_push_insert_erase: local str allocator", NULL, NULL), .zero_init = false }; guf_allocator str_allocator = guf_libc_allocator_new(&str_allocator_ctx); for (size_t i = 0; i < n; ++i) { std::string str; for (size_t c = 0; c < 512 + GUF_STR_SSO_BUF_CAP; ++c) { str += (char)(c % 10 + '0'); } const guf_str_view sv_long = guf_str_view{.str = str.data(), .len = (ptrdiff_t)str.size()}; const guf_str_view sv_short = guf_str_view{.str = str.data(), .len = (ptrdiff_t)GUF_STR_SSO_BUF_CAP - 1}; guf_str long_str = GUF_STR_UNINITIALISED_CPP, short_str = GUF_STR_UNINITIALISED_CPP; guf_str_init(&long_str, sv_long, &str_allocator); guf_str_init(&short_str, sv_short, &str_allocator); TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 1 + (i*3)); // Move guf_err err; dbuf_str_try_push(&strings, &long_str, GUF_CPY_MOVE, &err); TEST_CHECK(err == GUF_ERR_NONE); dbuf_str_try_push(&strings, &short_str, GUF_CPY_MOVE, &err); TEST_CHECK(err == GUF_ERR_NONE); strings_cpp.push_back(str.substr(0, str.size())); strings_cpp.push_back(str.substr(0, GUF_STR_SSO_BUF_CAP - 1)); TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 1 + (i*3)); TEST_CHECK(guf_str_is_uninit(&long_str)); TEST_CHECK(guf_str_is_uninit(&short_str)); // Deep-copy guf_str_init(&long_str, sv_long, &str_allocator); guf_str_init(&short_str, sv_short, &str_allocator); TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 2 + (i*3)); dbuf_str_try_push(&strings, &long_str, GUF_CPY_DEEP, &err); TEST_CHECK(err == GUF_ERR_NONE); dbuf_str_try_push(&strings, &short_str, GUF_CPY_DEEP, &err); TEST_CHECK(err == GUF_ERR_NONE); strings_cpp.push_back(str.substr(0, str.size())); strings_cpp.push_back(str.substr(0, GUF_STR_SSO_BUF_CAP - 1)); TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 3 + (i*3)); TEST_CHECK(guf_str_is_valid(&long_str) && guf_str_is_valid(&short_str)); TEST_CHECK(guf_str_view_equal_val_arg(guf_str_view_from_str(&long_str), sv_long)); TEST_CHECK(guf_str_view_equal_val_arg(guf_str_view_from_str(&short_str), sv_short)); guf_str_free(&long_str, NULL); guf_str_free(&short_str, NULL); TEST_CHECK(str_allocator_ctx.tracker.free_count == 1 + (i*1)); TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 3 + (i*3)); } TEST_CHECK(str_allocator_ctx.tracker.free_count == n); TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 3 * n); TEST_CHECK(strings.size == 4 * (ptrdiff_t)n); TEST_CHECK(strings.size == std::ssize(strings_cpp)); std::string str; for (size_t c = 0; c < 512 + GUF_STR_SSO_BUF_CAP; ++c) { str += (char)(c % 10 + '0'); } const guf_str_view sv_long = guf_str_view{.str = str.data(), .len = (ptrdiff_t)str.size()}; const guf_str_view sv_short = guf_str_view{.str = str.data(), .len = (ptrdiff_t)GUF_STR_SSO_BUF_CAP - 1}; size_t i = 0; GUF_CNT_FOREACH(&strings, dbuf_str, it) { if (TEST_CHECK(it.ptr)) { const guf_str *s = it.ptr; TEST_CHECK(guf_str_view_equal_val_arg(guf_str_view_from_str(s), i % 2 == 0 ? sv_long : sv_short)); const guf_str_view sv_cpp = guf_str_view {.str = strings_cpp.at(i).data(), .len = (ptrdiff_t)strings_cpp.at(i).size()}; TEST_CHECK(guf_str_view_equal_val_arg(guf_str_view_from_str(s), sv_cpp)); } ++i; } GUF_CNT_FOREACH(&strings, dbuf_str, it) { if (TEST_CHECK(it.ptr)) { guf_str *s = it.ptr; TEST_CHECK(guf_str_append(s, GUF_CSTR_LIT_TO_VIEW_CPP(""))); } } std::vector delims = {guf_str_view{.str = "", .len = 5}}; i = 0; GUF_CNT_FOREACH(&strings, dbuf_str, it) { if (TEST_CHECK(it.ptr)) { const guf_str *s = it.ptr; guf_str_tok_state tk_state = guf_str_tok_state_new(guf_str_view_from_str(s), delims.data(), std::ssize(delims), GUF_STR_TOK_DELIM_OPT_MATCH_LONGEST); size_t tok_n = 0; while (guf_str_tok_next(&tk_state, true)) { TEST_CHECK(guf_str_view_equal_val_arg(tk_state.cur_tok , i % 2 == 0 ? sv_long : sv_short)); TEST_CHECK(guf_str_view_equal_val_arg(tk_state.cur_delim, guf_str_view{.str = "", .len = 5})); ++tok_n; } TEST_CHECK(tok_n == 1); } ++i; } dbuf_str_free(&strings, NULL); TEST_CHECK(!guf_alloc_tracker_found_leak(&str_allocator_ctx.tracker)); }