From 549812812d2265709e4be00caf1d2041b4d588f5 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Sat, 3 May 2025 09:04:41 -0400 Subject: str: Add remove_at() and replace() + tests - Bring wstr_remove_at() in line with str. - Add a test for correct snprintf usage with str. Signed-off-by: Andrew Opalach --- include/al/str.h | 17 +++++++++++++++++ include/al/wstr.h | 9 +++------ tests/str.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/include/al/str.h b/include/al/str.h index 4ff936b..e9ac8f2 100644 --- a/include/al/str.h +++ b/include/al/str.h @@ -103,6 +103,23 @@ static inline void al_str_prepend(str *s, str *c) al_str_insert(s, 0, c); } +static inline void al_str_remove_at(str *s, u32 i) +{ + al_assert(i < s->length); + if (i != --s->length) { + al_memmove(s->data + i, s->data + i + 1, s->length - i); + } +} + +static inline void al_str_replace(str *s, char c, char n) +{ + for (u32 i = 0; i < s->length; i++) { + if (al_str_at(s, i) == c) { + al_str_at(s, i) = n; + } + } +} + static inline s32 al_str_cmp(str *s, str *c, u32 start, u32 length) { if (length > c->length) return 1; diff --git a/include/al/wstr.h b/include/al/wstr.h index efecbfe..f700037 100644 --- a/include/al/wstr.h +++ b/include/al/wstr.h @@ -147,13 +147,10 @@ static inline void al_wstr_insert(wstr *w, u32 i, wstr *c) static inline void al_wstr_remove_at(wstr *w, u32 i) { - if (i >= w->length) { - return; - } else if (i != w->length - 1) { - wchar_t *data = w->data + i; - al_memmove(data, data + 1, (w->length - i - 1) * sizeof(wchar_t)); + al_assert(i < w->length); + if (i != --w->length) { + al_memmove(w->data + i, w->data + i + 1, (w->length - i) * sizeof(wchar_t)); } - w->length--; w->data[w->length] = L'\0'; } diff --git a/tests/str.c b/tests/str.c index 2f7f686..de5f576 100644 --- a/tests/str.c +++ b/tests/str.c @@ -129,6 +129,28 @@ static bool str_test_substr(void) AL_TEST_END(); } +static bool str_test_replace_and_remove(void) +{ + AL_TEST_START("str_replace_and_remove"); + + str string0 = al_str_c("beanie weenies"); + str s; + al_str_clone(&s, &string0); + + str result0 = al_str_c("beeneeweee"); + + al_str_replace(&s, 'a', 'e'); + al_str_replace(&s, 'i', 'e'); + s.length -= 3; + al_str_atr(&s, 1) = 'e'; + + al_str_remove_at(&s, 6); + + AL_TEST_TRUE(al_str_eq(&s, &result0)); + + AL_TEST_END(); +} + static bool str_test_get_line(void) { AL_TEST_START("str_get_line"); @@ -352,6 +374,34 @@ static bool str_test_error_prone_str_c(void) AL_TEST_END(); } +static bool str_test_snprintf_truncate(void) +{ + AL_TEST_START("str_snprintf_truncate"); + + str s; + al_str_sized(&s, 12); + + u32 num = 1232; + const char *st = "wuddup"; + s32 expected_length = 12; + // If the string is truncated, the return value is how many bytes would have been written. + // Meaning if ret = size, the output was truncated by 1 character but will still have a null terminator. + // This test is to show we should always expect snprintf to add a null terminator. Meaning there's no + // trick we can do for str's in terms of truncating, we just have to make space for an extra null byte. + AL_IGNORE_WARNING("-Wformat-truncation") + s32 ret = al_snprintf(s.data, expected_length, "%05u_%s", num, st); + AL_IGNORE_WARNING_END + AL_TEST_EQ(ret, expected_length, s32); + s.length = expected_length - 1; + + AL_TEST_TRUE(al_str_eq(&s, &al_str_c("01232_wuddu"))); + AL_TEST_FALSE(al_str_eq(&s, &al_str_c("01232_wuddup"))); + + al_str_free(&s); + + AL_TEST_END(); +} + bool str_tests_run(u32 skip_mask) { AL_TEST_START_GROUP("str"); @@ -361,12 +411,14 @@ bool str_tests_run(u32 skip_mask) AL_TEST_RUN(str_test_insert); AL_TEST_RUN(str_test_find_rfind); AL_TEST_RUN(str_test_substr); + AL_TEST_RUN(str_test_replace_and_remove); AL_TEST_RUN(str_test_get_line); AL_TEST_RUN(str_test_to_long); if (skip_mask & AL_TESTS_RUN_LIMITS) { AL_TEST_RUN(str_test_limits); } AL_TEST_RUN(str_test_error_prone_str_c); + AL_TEST_RUN(str_test_snprintf_truncate); AL_TEST_END_GROUP(); } -- cgit v1.2.3-101-g0448