From acce76aa4c87017f3b668a07011ff55fbca411f3 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 27 Mar 2026 11:13:10 -0700 Subject: [PATCH] string list sub range helper --- src/base/base_strings.c | 36 +++++++++++++++++++ src/base/base_strings.h | 1 + src/torture/torture.h | 30 ++++++++-------- src/torture/torture_base.c | 73 ++++++++++++++++++++++++++++++++++++++ src/torture/torture_main.c | 1 + 5 files changed, 126 insertions(+), 15 deletions(-) create mode 100644 src/torture/torture_base.c diff --git a/src/base/base_strings.c b/src/base/base_strings.c index 9d489476..57c908fd 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -1143,6 +1143,42 @@ str8_list_copy(Arena *arena, String8List *list) return result; } +internal String8List +str8_list_substr(Arena *arena, String8List list, Rng1U64 range) +{ + String8List result = {0}; + + String8Node *n = list.first; + + U64 front_min = 0; + { + U64 cursor = 0; + for (; n != 0; cursor += n->string.size, n = n->next) { + if (cursor + n->string.size > range.min) { + front_min = range.min - cursor; + break; + } + } + } + + if (front_min > 0) { + U64 front_max = front_min + Min(dim_1u64(range), n->string.size); + str8_list_push(arena, &result, str8_substr(n->string, r1u64(front_max, front_max))); + n = n->next; + } + + for (; n != 0; n = n->next) { + if (result.total_size >= dim_1u64(range)) { + break; + } + U64 copy_max = dim_1u64(range) - result.total_size; + U64 copy_size = Min(copy_max, n->string.size); + str8_list_push(arena, &result, str8_substr(n->string, r1u64(0, copy_size))); + } + + return result; +} + //////////////////////////////// //~ rjf: String Splitting & Joining diff --git a/src/base/base_strings.h b/src/base/base_strings.h index 635bc9ee..e86c4dee 100644 --- a/src/base/base_strings.h +++ b/src/base/base_strings.h @@ -269,6 +269,7 @@ internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...); internal String8Node* str8_list_pop_front(String8List *list); internal String8List str8_list_copy(Arena *arena, String8List *list); +internal String8List str8_list_substr(Arena *arena, String8List list, Rng1U64 range); #define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero()) //////////////////////////////// diff --git a/src/torture/torture.h b/src/torture/torture.h index a2e90725..7a1638f6 100644 --- a/src/torture/torture.h +++ b/src/torture/torture.h @@ -39,10 +39,10 @@ typedef struct extern U64 g_torture_test_count; extern T_Test g_torture_tests[0xffffff]; -#define T_AddTest(name, l, ...) \ -T_RunResult t_##name(void); \ -__VA_ARGS__ void t_add_test_##name(void) \ -{ \ +#define T_AddTest(name, l, ...) \ +T_RunResult t_##name(void); \ +__VA_ARGS__ void t_add_test_##name(void) \ +{ \ g_torture_tests[g_torture_test_count].group = T_Group; \ g_torture_tests[g_torture_test_count].label = Stringify(name); \ g_torture_tests[g_torture_test_count].r = &t_##name; \ @@ -52,7 +52,7 @@ g_torture_test_count += 1; \ #if COMPILER_MSVC #pragma section(".CRT$XCU", read) -# define T_BeginTest_(name) \ +# define T_BeginTest_(name) \ T_AddTest(name, __LINE__) \ __declspec(allocate(".CRT$XCU")) void(*r_##name)(void) = t_add_test_##name; \ __pragma(comment(linker, "/include:" Stringify(r_##name))) @@ -61,20 +61,20 @@ __pragma(comment(linker, "/include:" Stringify(r_##name))) T_AddTest(name, __LINE__, __attribute__((constructor))) #endif -#define T_BeginTest(name) \ -T_BeginTest_(name) \ -T_RunResult t_##name(void) { \ +#define T_BeginTest(name) \ +T_BeginTest_(name) \ +T_RunResult t_##name(void) { \ Temp scratch = scratch_begin(0,0); \ -T_RunResult result = { .status = T_RunStatus_Fail }; +T_RunResult result_ = { .status = T_RunStatus_Fail }; -#define T_EndTest \ -result.status = T_RunStatus_Pass; \ -exit__:; \ -scratch_end(scratch); \ -return result; \ +#define T_EndTest \ +result_.status = T_RunStatus_Pass; \ +exit__:; \ +scratch_end(scratch); \ +return result_; \ } -#define T_Ok(c) do { if (!(c)) { result.fail_file = __FILE__; result.fail_line = __LINE__; result.fail_cond = Stringify(c); goto exit__; } } while(0) +#define T_Ok(c) do { if (!(c)) { result_.fail_file = __FILE__; result_.fail_line = __LINE__; result_.fail_cond = Stringify(c); goto exit__; } } while(0) #define T_MatchLinef(out, ...) T_Ok(t_match_linef(out, __VA_ARGS__)) //////////////////////////////// diff --git a/src/torture/torture_base.c b/src/torture/torture_base.c new file mode 100644 index 00000000..724820ed --- /dev/null +++ b/src/torture/torture_base.c @@ -0,0 +1,73 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#define T_Group "Base" + +T_BeginTest(str8_list_substr) +{ + String8List zero_list = {0}; + + { + String8List list = {0}; + str8_list_pushf(scratch.arena, &list, "a"); + str8_list_pushf(scratch.arena, &list, "b"); + str8_list_pushf(scratch.arena, &list, "c"); + String8List sub = str8_list_substr(scratch.arena, list, r1u64(0, 3)); + String8 result = str8_list_join(scratch.arena, &list, 0); + T_Ok(str8_match(result, str8_lit("abc"), 0)); + } + + { + String8List list = {0}; + str8_list_pushf(scratch.arena, &list, "a"); + str8_list_pushf(scratch.arena, &list, "b"); + str8_list_pushf(scratch.arena, &list, "c"); + String8List sub = str8_list_substr(scratch.arena, list, r1u64(0, max_U64)); + String8 result = str8_list_join(scratch.arena, &list, 0); + T_Ok(str8_match(result, str8_lit("abc"), 0)); + } + + { + + String8List list = {0}; + str8_list_pushf(scratch.arena, &list, "a"); + str8_list_pushf(scratch.arena, &list, "bcd"); + String8List sub = str8_list_substr(scratch.arena, list, r1u64(2, 3)); + String8 result = str8_list_join(scratch.arena, &sub, 0); + T_Ok(str8_match(result, str8_lit("c"), 0)); + } + + { + + String8List list = {0}; + str8_list_pushf(scratch.arena, &list, "a"); + str8_list_pushf(scratch.arena, &list, "bcd"); + String8List sub = str8_list_substr(scratch.arena, list, r1u64(1, 2)); + String8 result = str8_list_join(scratch.arena, &sub, 0); + T_Ok(str8_match(result, str8_lit("b"), 0)); + } + + { + String8List list = {0}; + str8_list_pushf(scratch.arena, &list, "ab"); + str8_list_pushf(scratch.arena, &list, "cd"); + str8_list_pushf(scratch.arena, &list, "ef"); + String8List sub = str8_list_substr(scratch.arena, list, r1u64(1, 5)); + String8 result = str8_list_join(scratch.arena, &sub, 0); + T_Ok(str8_match(result, str8_lit("bcde"), 0)); + } + + { + String8List list = {0}; + str8_list_pushf(scratch.arena, &list, "abc"); + + String8List zero = str8_list_substr(scratch.arena, list, r1u64(0, 0)); + T_Ok(MemoryMatchStruct(&zero, &zero_list)); + + String8List out_of_bounds_range = str8_list_substr(scratch.arena, list, r1u64(max_U64/2, max_U64)); + T_Ok(MemoryMatchStruct(&out_of_bounds_range, &zero_list)); + } +} +T_EndTest; + +#undef T_Group diff --git a/src/torture/torture_main.c b/src/torture/torture_main.c index fec9f504..3fab8992 100644 --- a/src/torture/torture_main.c +++ b/src/torture/torture_main.c @@ -72,6 +72,7 @@ #include "linker/thread_pool/thread_pool.c" #include "linker/codeview_ext/codeview.c" #include "torture.c" +#include "torture_base.c" #include "torture_radlink.c" #include "torture_dwarf.c" #include "torture_d2r.c"