diff --git a/Bin/Demangler/Main.c b/Bin/Demangler/Main.c index e9272a5..8583467 100644 --- a/Bin/Demangler/Main.c +++ b/Bin/Demangler/Main.c @@ -6,7 +6,7 @@ int main(void) { Strs lines = StrSplit(&file, "\n"); // Use the fixed VecForeachPtr macro - VecForeachPtr(&lines, line, { + VecForeachPtr(&lines, line) { if (StrStartsWithZstr(line, "[.") && StrEndsWithZstr(line, "]")) { Str rule_name = StrInit(); StrReadFmt(line->data, "[.{}]", rule_name); @@ -16,7 +16,7 @@ int main(void) { StrDeinit(&rule_name); } } - }); + } VecDeinit(&lines); VecDeinit(&file); diff --git a/Bin/ElfInfo.c b/Bin/ElfInfo.c index b77a009..a0b9541 100644 --- a/Bin/ElfInfo.c +++ b/Bin/ElfInfo.c @@ -411,5 +411,10 @@ int main(int argc, char** argv) { eh.string_table_index ); + Vec(int) vi = VecInit(); + VecForeachIdx(&vi, val, i) { + WriteFmtLn("{}", val); + } + return 0; } diff --git a/Bin/MisraDoc.c b/Bin/MisraDoc.c index d3f1843..8ef0e21 100644 --- a/Bin/MisraDoc.c +++ b/Bin/MisraDoc.c @@ -126,14 +126,14 @@ int main(int argc, char** argv) { VecMerge(&dir_paths, &project.test_directories); // recursively explore directories and get filenames - VecForeach(&dir_paths, dir_name, { + VecForeach(&dir_paths, dir_name) { // keep track of current path we're exploring Str current_path = StrInit(); StrMerge(¤t_path, &dir_name); SysDirContents dir_contents = SysGetDirContents(dir_name.data); Scope(&dir_contents, VecDeinit, { - VecForeach(&dir_contents, dir_entry, { + VecForeach(&dir_contents, dir_entry) { // if it's a directory then store it for exploration later on if (dir_entry.type == SYS_DIR_ENTRY_TYPE_DIRECTORY) { // create new directory path relative to current directory search path @@ -144,84 +144,80 @@ int main(int argc, char** argv) { // store the directory name, ownersip transferred VecPushBack(&dir_paths, path); - } else if (dir_entry.type == SYS_DIR_ENTRY_TYPE_REGULAR_FILE) { - // create complete relative file path - Str path = StrInit(); - StrMerge(&path, ¤t_path); - StrPushBack(&path, '/'); - StrMerge(&path, &dir_entry.name); - - // store discovered file name, ownersip transferred - VecPushBack(&file_paths, path); - } - // any other file type is not documented - }); - }); - }); - }); - - // go over each file and generate corresponding markdown - VecForeach(&file_paths, file_path, { - Str file_contents = StrInit(); - Scope(&file_contents, StrDeinit, { - if (!ReadCompleteFile( - file_path.data, - &file_contents.data, - &file_contents.length, - &file_contents.capacity - )) { - LOG_ERROR("Failed to read \"{}\" source file.", file_path.data); - continue; - } - - Str output_path = StrInit(); - Scope(&output_path, StrDeinit, { - StrMerge(&output_path, &file_path); - LOG_INFO("{}", output_path); - StrReplaceZstr(&output_path, "/", "-", -1); - LOG_INFO("{}", output_path); - - Str md_code = StrInit(); - Scope(&md_code, StrDeinit, { - // Create template strings for StrWriteFmt with escaped braces - const char* mdHeader = - "---\n" - "title: \"{}\"\n" - "meta_title: \"{}\"\n" - "description: \"Documentation for {}\"\n" - "date: 2025-05-12T05:00:00Z\n" - "# image: \"/images/image-placeholder.png\"\n" - "categories: [\"Vec\", \"Macro\", \"Generic\"]\n" - "author: \"Siddharth Mishra\"\n" - "tags: [\"vec\", \"macro\", \"generic\"]\n" - "draft: false\n" - "---\n" - "```c\n"; - - StrWriteFmt(&md_code, mdHeader, output_path.data, output_path.data, output_path.data); - StrMerge(&md_code, &file_contents); - StrWriteFmt(&md_code, "\n```"); - - // complete relative file path - StrPushFront(&output_path, '/'); - LOG_INFO("{}", output_path); - StrPushFrontCstr(&output_path, project.build_dir.data, project.build_dir.length); - LOG_INFO("{}", output_path); - StrReplaceZstr(&output_path, ".c", ".md", 1); - StrReplaceZstr(&output_path, ".h", ".md", 1); - LOG_INFO("{}\n\n", output_path); - - - // dump code to output path - FILE* f = fopen(output_path.data, "w"); - Scope(f, fclose, { fwrite(md_code.data, 1, md_code.length, f); }); - }); - }); - }); + } + else if (dir_entry.type == SYS_DIR_ENTRY_TYPE_REGULAR_FILE) { + // create complete relative file path + Str path = StrInit(); + StrMerge(&path, ¤t_path); + StrPushBack(&path, '/'); + StrMerge(&path, &dir_entry.name); + + // store discovered file name, ownersip transferred + VecPushBack(&file_paths, path); + } + // any other file type is not documented + } + }); + } +}); + +// go over each file and generate corresponding markdown +VecForeach(&file_paths, file_path) { + Str file_contents = StrInit(); + Scope(&file_contents, StrDeinit, { + if (!ReadCompleteFile(file_path.data, &file_contents.data, &file_contents.length, &file_contents.capacity)) { + LOG_ERROR("Failed to read \"{}\" source file.", file_path.data); + continue; + } + + Str output_path = StrInit(); + Scope(&output_path, StrDeinit, { + StrMerge(&output_path, &file_path); + LOG_INFO("{}", output_path); + StrReplaceZstr(&output_path, "/", "-", -1); + LOG_INFO("{}", output_path); + + Str md_code = StrInit(); + Scope(&md_code, StrDeinit, { + // Create template strings for StrWriteFmt with escaped braces + const char* mdHeader = + "---\n" + "title: \"{}\"\n" + "meta_title: \"{}\"\n" + "description: \"Documentation for {}\"\n" + "date: 2025-05-12T05:00:00Z\n" + "# image: \"/images/image-placeholder.png\"\n" + "categories: [\"Vec\", \"Macro\", \"Generic\"]\n" + "author: \"Siddharth Mishra\"\n" + "tags: [\"vec\", \"macro\", \"generic\"]\n" + "draft: false\n" + "---\n" + "```c\n"; + + StrWriteFmt(&md_code, mdHeader, output_path.data, output_path.data, output_path.data); + StrMerge(&md_code, &file_contents); + StrWriteFmt(&md_code, "\n```"); + + // complete relative file path + StrPushFront(&output_path, '/'); + LOG_INFO("{}", output_path); + StrPushFrontCstr(&output_path, project.build_dir.data, project.build_dir.length); + LOG_INFO("{}", output_path); + StrReplaceZstr(&output_path, ".c", ".md", 1); + StrReplaceZstr(&output_path, ".h", ".md", 1); + LOG_INFO("{}\n\n", output_path); + + + // dump code to output path + FILE* f = fopen(output_path.data, "w"); + Scope(f, fclose, { fwrite(md_code.data, 1, md_code.length, f); }); }); }); }); +}; +}); +}); - LogDeinit(); - return 0; +LogDeinit(); +return 0; } diff --git a/Bin/MisraEnum.c b/Bin/MisraEnum.c index 72fffa9..511301f 100644 --- a/Bin/MisraEnum.c +++ b/Bin/MisraEnum.c @@ -113,14 +113,14 @@ int main(int argc, char** argv) { } // Use VecForeach for iterating over entries - VecForeach(&entries, e, { + VecForeach(&entries, e) { if (last_value == e.value - 1) { StrWriteFmt(&code, " {},\n", e.name.data); } else { StrWriteFmt(&code, " {} = {},\n", e.name.data, e.value); } last_value = e.value; - }); + }; StrWriteFmt(&code, "}} {};\n", enum_name.data); @@ -150,12 +150,12 @@ int main(int argc, char** argv) { StrWriteFmt(&code, funcHeader, enum_name.data, enum_name.data, enum_name.data, invalidEnumName); // Use VecForeach for iterating over entries - VecForeach(&entries, e, { + VecForeach(&entries, e) { const char* compareTemplate = " if(ZstrCompareN(\"{}\", zstr, {}) == 0) {{return {};}}\n"; // Store the length in a variable to avoid taking address of rvalue unsigned long long strLength = (unsigned long long)e.str.length; StrWriteFmt(&code, compareTemplate, e.str.data, strLength, e.name.data); - }); + }; const char* returnTemplate = " return {};\n}}\n"; StrWriteFmt(&code, returnTemplate, invalidEnumName); @@ -175,10 +175,10 @@ int main(int argc, char** argv) { StrWriteFmt(&code, toZstrHeader, enum_name.data, enum_name.data, enum_name.data); // Use VecForeach for iterating over entries - VecForeach(&entries, e, { + VecForeach(&entries, e) { const char* caseTemplate = " case {} : {{return \"{}\";}}\n"; StrWriteFmt(&code, caseTemplate, e.name.data, e.str.data); - }); + }; const char* defaultTemplate = " default: break;\n" @@ -209,10 +209,10 @@ int main(int argc, char** argv) { StrDeinit(&enum_name); StrDeinit(&code); - VecForeach(&entries, e, { + VecForeach(&entries, e) { StrDeinit(&e.name); StrDeinit(&e.str); - }); + }; VecDeinit(&entries); LogDeinit(); diff --git a/Include/Misra/Parsers/JSON.h b/Include/Misra/Parsers/JSON.h index b63d23a..e25e734 100644 --- a/Include/Misra/Parsers/JSON.h +++ b/Include/Misra/Parsers/JSON.h @@ -56,7 +56,7 @@ WriteFmtLn("X : {}", obj.data.y); WriteFmtLn("N : {}", obj.data.n); WriteFmt("strs : ["); - VecForeach(&obj.strs, str, { WriteFmt("{}, ", str); }); + VecForeach(&obj.strs, str) { WriteFmt("{}, ", str); } WriteFmtLn("]"); StrClear(&json); @@ -730,14 +730,14 @@ StrIter JSkipValue(StrIter si); bool ___is_first___ = true; \ (void)___is_first___; \ StrPushBack(&(j), '['); \ - VecForeach(&(arr), item, { \ + VecForeach(&(arr), item) { \ if (___is_first___) { \ ___is_first___ = false; \ } else { \ StrPushBack(&(j), ','); \ } \ { writer } \ - }); \ + } \ StrPushBack(&(j), ']'); \ } while (0) diff --git a/Include/Misra/Std/Container/BitVec/Foreach.h b/Include/Misra/Std/Container/BitVec/Foreach.h index fa6a28f..4e136ba 100644 --- a/Include/Misra/Std/Container/BitVec/Foreach.h +++ b/Include/Misra/Std/Container/BitVec/Foreach.h @@ -8,7 +8,6 @@ #define MISRA_STD_CONTAINER_BITVEC_FOREACH_H #include "Type.h" -#include #include "Access.h" /// @@ -20,28 +19,12 @@ /// bv[in,out] : Bitvector to iterate over. /// var[in] : Name of variable to be used which'll contain bit value at iterated index `idx` /// idx[in] : Name of variable to be used for iterating over indices. -/// body : Body of this foreach loop -/// -/// SUCCESS : The `body` is executed for each bit of the bitvector `bv` from the -/// beginning to the end. -/// FAILURE : If the bitvector `bv` is NULL or its length is zero, the loop body will not -/// be executed. Any failures within the `BitVecForeachIdx` macro (like invalid -/// index access) will result in a fatal log message and program termination. -/// -#define BitVecForeachIdx(bv, var, idx, body) \ - do { \ - ValidateBitVec(bv); \ - u64 idx = 0; \ - if ((bv)->length > 0) { \ - for ((idx) = 0; (idx) < (bv)->length; ++(idx)) { \ - bool var = BitVecGet(bv, idx); \ - { body } \ - if ((idx) >= (bv)->length) { \ - LOG_FATAL("BitVec range overflow : Invalid index reached during Foreach iteration."); \ - } \ - } \ - } \ - } while (0) +/// +#define BitVecForeachIdx(bv, var, idx) \ + for (TYPE_OF(bv) UNPL(pbv) = (bv); UNPL(pbv); UNPL(pbv) = NULL) \ + if ((ValidateBitVec(UNPL(pbv)), 1) && UNPL(pbv)->length > 0) \ + for (u64 idx = 0, UNPL(d) = 1; UNPL(d); UNPL(d)--) \ + for (bool var = 0; idx < UNPL(pbv)->length && (var = BitVecGet(UNPL(pbv), idx), 1); idx++) /// /// Iterate over each bit `var` of given bitvector `bv` at each index `idx` into the bitvector. @@ -52,24 +35,13 @@ /// bv[in,out] : Bitvector to iterate over. /// var[in] : Name of variable to be used which'll contain bit value at iterated index `idx` /// idx[in] : Name of variable to be used for iterating over indices. -/// body : Body of this foreach loop -/// -#define BitVecForeachReverseIdx(bv, var, idx, body) \ - do { \ - ValidateBitVec(bv); \ - u64 idx = 0; \ - if ((bv)->length > 0) { \ - for (idx = (bv)->length - 1; (idx) < (bv)->length; --(idx)) { \ - bool var = BitVecGet(bv, idx); \ - { body } \ - if ((idx) >= (bv)->length) { \ - LOG_FATAL("BitVec range overflow : Invalid index reached during Foreach reverse iteration."); \ - } \ - if (idx == 0) \ - break; /* Stop after processing index 0 */ \ - } \ - } \ - } while (0) +/// +#define BitVecForeachReverseIdx(bv, var, idx) \ + for (TYPE_OF(bv) UNPL(pbv) = (bv); UNPL(pbv); UNPL(pbv) = NULL) \ + if ((ValidateBitVec(UNPL(pbv)), 1) && UNPL(pbv)->length > 0) \ + for (u64 idx = UNPL(pbv)->length; idx-- > 0 && idx < UNPL(pbv)->length;) \ + for (u8 UNPL(run_once) = 1; UNPL(run_once); UNPL(run_once) = 0) \ + for (bool var = BitVecGet(UNPL(pbv), idx); UNPL(run_once); UNPL(run_once) = 0) /// /// Iterate over each bit `var` of the given bitvector `bv`. @@ -79,15 +51,8 @@ /// bv[in,out] : Bitvector to iterate over. /// var[in] : Name of the variable to be used which will contain the value of the /// current bit during iteration. The type of `var` will be `bool`. -/// body : The block of code to be executed for each bit of the bitvector. -/// -/// SUCCESS : The `body` is executed for each bit of the bitvector `bv` from the -/// beginning to the end. -/// FAILURE : If the bitvector `bv` is NULL or its length is zero, the loop body will not -/// be executed. Any failures within the `BitVecForeachIdx` macro (like invalid -/// index access) will result in a fatal log message and program termination. /// -#define BitVecForeach(bv, var, body) BitVecForeachIdx((bv), var, ____iter___, {body}) +#define BitVecForeach(bv, var) BitVecForeachIdx((bv), (var), UNPL(iter)) /// /// Iterate over each bit `var` of the given bitvector `bv` in reverse order. @@ -97,15 +62,8 @@ /// bv[in,out] : Bitvector to iterate over. /// var[in] : Name of the variable to be used which will contain the value of the /// current bit during iteration. The type of `var` will be `bool`. -/// body : The block of code to be executed for each bit of the bitvector. /// -/// SUCCESS : The `body` is executed for each bit of the bitvector `bv` from the -/// end to the beginning. -/// FAILURE : If the bitvector `bv` is NULL or its length is zero, the loop body will not -/// be executed. Any failures within the `BitVecForeachReverseIdx` macro (like -/// invalid index access) will result in a fatal log message and program termination. -/// -#define BitVecForeachReverse(bv, var, body) BitVecForeachReverseIdx((bv), (var), (____iter___), {body}) +#define BitVecForeachReverse(bv, var) BitVecForeachReverseIdx((bv), (var), UNPL(iter)) /// /// Iterate over bits in a specific range of the given bitvector `bv` at each index `idx`. @@ -118,52 +76,15 @@ /// idx[in] : Name of variable to be used for iterating over indices. /// start[in] : Starting index (inclusive). /// end[in] : Ending index (exclusive). -/// body : Body of this foreach loop. -/// -/// SUCCESS : The `body` is executed for each bit of the bitvector `bv` from the -/// `start` index to the `end-1` index. -/// FAILURE : If the bitvector `bv` is NULL, its length is zero, or the range is invalid, -/// the loop body will not be executed. Any access to an invalid index will -/// result in a fatal log message and program termination. -/// -#define BitVecForeachInRangeIdx(bv, var, idx, start, end, body) \ - do { \ - ValidateBitVec(bv); \ - u64 idx = 0; \ - u64 _s = start; \ - u64 _e = end; \ - if ((bv)->length > 0) { \ - if ((_e) > (bv)->length) { \ - LOG_FATAL( \ - "BitVec range overflow: End index {} exceeds bitvector length {}. " \ - "If you intended to iterate over all bits, use BitVecForeach instead.", \ - _e, \ - (bv)->length \ - ); \ - } \ - if ((_s) >= (bv)->length) { \ - LOG_FATAL( \ - "BitVec range overflow: Start index {} exceeds or equals bitvector length {}.", \ - _s, \ - (bv)->length \ - ); \ - } \ - if ((_s) > (_e)) { \ - LOG_FATAL("Invalid range: Start index {} must be less than or equal to end index {}.", _s, _e); \ - } \ - for ((idx) = (_s); (idx) < (_e); ++(idx)) { \ - if ((idx) >= (bv)->length) { \ - LOG_FATAL( \ - "BitVec range overflow: Index {} exceeds bitvector length {} during iteration.", \ - idx, \ - (bv)->length \ - ); \ - } \ - bool var = BitVecGet(bv, idx); \ - { body } \ - } \ - } \ - } while (0) +/// +#define BitVecForeachInRangeIdx(bv, var, idx, start, end) \ + for (TYPE_OF(bv) UNPL(pbv) = (bv); UNPL(pbv); UNPL(pbv) = NULL) \ + if ((ValidateBitVec(UNPL(pbv)), 1) && UNPL(pbv)->length > 0) \ + for (u64 UNPL(s) = (start), UNPL(e) = (end), idx = UNPL(s), UNPL(d) = 1; \ + UNPL(s) <= idx && idx < UNPL(e) && idx < UNPL(pbv)->length && UNPL(s) <= UNPL(e); \ + ++idx, UNPL(d) = 1) \ + for (bool var = BitVecGet(UNPL(pbv), idx); UNPL(d); UNPL(d) = 0) + /// /// Iterate over bits in a specific range of the given bitvector `bv`. @@ -174,44 +95,7 @@ /// var[in] : Name of variable to be used which'll contain bit value of the current bit. /// start[in] : Starting index (inclusive). /// end[in] : Ending index (exclusive). -/// body : Body of this foreach loop. -/// -/// SUCCESS : The `body` is executed for each bit of the bitvector `bv` from the -/// `start` index to the `end-1` index. -/// FAILURE : If the bitvector `bv` is NULL, its length is zero, or the range is invalid, -/// the loop body will not be executed. Any failures within the `BitVecForeachInRangeIdx` -/// macro will result in a fatal log message and program termination. /// -#define BitVecForeachInRange(bv, var, start, end, body) \ - BitVecForeachInRangeIdx((bv), (var), (____iter___), (start), (end), {body}) - -#ifdef __cplusplus -extern "C" { -#endif - - /// - /// Analyze run lengths in a bitvector. - /// A run is a sequence of consecutive identical bits. - /// Results array must be pre-allocated with sufficient space. - /// - /// bv[in] : Bitvector to analyze - /// runs[out] : Array to store run lengths - /// values[out] : Array to store run values (true/false) - /// max_runs[in] : Maximum number of runs to store - /// - /// RETURNS: Number of runs found - /// - /// USAGE: - /// u64 run_lengths[50]; - /// bool run_values[50]; - /// u64 count = BitVecRunLengths(&flags, run_lengths, run_values, 50); - /// - /// TAGS: BitVec, RunLength, Analysis, Pattern - /// - u64 BitVecRunLengths(BitVec *bv, u64 *runs, bool *values, u64 max_runs); - -#ifdef __cplusplus -} -#endif +#define BitVecForeachInRange(bv, var, start, end) BitVecForeachInRangeIdx((bv), (var), UNPL(iter), (start), (end)) #endif // MISRA_STD_CONTAINER_BITVEC_FOREACH_H diff --git a/Include/Misra/Std/Container/BitVec/Math.h b/Include/Misra/Std/Container/BitVec/Math.h index e3d379c..5e909c0 100644 --- a/Include/Misra/Std/Container/BitVec/Math.h +++ b/Include/Misra/Std/Container/BitVec/Math.h @@ -159,8 +159,29 @@ extern "C" { /// u64 BitVecBestAlignment(BitVec *bv1, BitVec *bv2); + /// + /// Analyze run lengths in a bitvector. + /// A run is a sequence of consecutive identical bits. + /// Results array must be pre-allocated with sufficient space. + /// + /// bv[in] : Bitvector to analyze + /// runs[out] : Array to store run lengths + /// values[out] : Array to store run values (true/false) + /// max_runs[in] : Maximum number of runs to store + /// + /// RETURNS: Number of runs found + /// + /// USAGE: + /// u64 run_lengths[50]; + /// bool run_values[50]; + /// u64 count = BitVecRunLengths(&flags, run_lengths, run_values, 50); + /// + /// TAGS: BitVec, RunLength, Analysis, Pattern + /// + u64 BitVecRunLengths(BitVec *bv, u64 *runs, bool *values, u64 max_runs); + #ifdef __cplusplus } #endif -#endif // MISRA_STD_CONTAINER_BITVEC_MATH_H \ No newline at end of file +#endif // MISRA_STD_CONTAINER_BITVEC_MATH_H diff --git a/Include/Misra/Std/Container/List/Access.h b/Include/Misra/Std/Container/List/Access.h index b2785db..b5516de 100644 --- a/Include/Misra/Std/Container/List/Access.h +++ b/Include/Misra/Std/Container/List/Access.h @@ -140,4 +140,17 @@ /// #define ListNodePrev(item) ((TYPE_OF(item))((item) ? (item)->prev : NULL)) +/// +/// Get item relative to given node. +/// +/// item[in] : List node to get previous node of, in the list. +/// ridx[in] : Relative index +ve or -ve. +/// +/// If relative index exceeds the bounds of list, then NULL is returned. +/// +/// SUCCESS: Node relative to given `item` in list. +/// FAILURE: `NULL` or abort +/// +#define ListNodeRelative(base_node, ridx) get_relative_node_to_list_node(GENERIC_LIST_NODE(base_node), (i64)(ridx)) + #endif // MISRA_STD_CONTAINER_LIST_OPS_H diff --git a/Include/Misra/Std/Container/List/Foreach.h b/Include/Misra/Std/Container/List/Foreach.h index 2bebe30..067dea4 100644 --- a/Include/Misra/Std/Container/List/Foreach.h +++ b/Include/Misra/Std/Container/List/Foreach.h @@ -8,84 +8,382 @@ #ifndef MISRA_STD_CONTAINER_LIST_FOREACH_H #define MISRA_STD_CONTAINER_LIST_FOREACH_H -#define ListForeach(l, var, body) \ - do { \ - ValidateList(l); \ - LIST_NODE_TYPE(l) *_node_##__LINE__ = NULL; \ - LIST_DATA_TYPE(l) var = {0}; \ - for (_node_##__LINE__ = (l)->head; _node_##__LINE__; _node_##__LINE__ = (_node_##__LINE__)->next) { \ - if ((_node_##__LINE__)->next == _node_##__LINE__) { \ - LOG_FATAL("Node points to itself in 'next' field."); \ - } \ - if ((_node_##__LINE__)->prev == _node_##__LINE__) { \ - LOG_FATAL("Node points to itself in 'prev' field."); \ - } \ - if (!(_node_##__LINE__)->data) { \ - LOG_FATAL("Invalid data in node."); \ - } \ - var = *(_node_##__LINE__)->data; \ - {body}; \ - } \ - } while (0) +/// +/// Iterate over each element var of the given list l. +/// The variable var is declared and defined by this macro. +/// +/// Iteration happens in forward order, starting from the head of the list +/// and continuing through the next pointers until the end is reached. +/// The variable var will contain a copy of the value pointed to by each list node. +/// +/// l[in] : List to iterate over. +/// var[out] : Name of the variable to be used which will contain the value of the +/// current element during iteration. The type of var will be the +/// data type of the list elements (obtained via LIST_DATA_TYPE(l)). +/// +/// TAGS: Foreach, List, Iteration, Loop +/// +#define ListForeach(l, var) \ + for (TYPE_OF(l) UNPL(pl) = (l); UNPL(pl); UNPL(pl) = NULL) \ + if ((ValidateList(UNPL(pl)), 1) && (UNPL(pl)->head)) \ + for (LIST_NODE_TYPE(UNPL(pl)) * UNPL(node) = (TYPE_OF(UNPL(node)))ListNodeBegin(UNPL(pl)); UNPL(node); \ + UNPL(node) = ListNodeNext(UNPL(node))) \ + if (((void *)UNPL(node)->next != (void *)UNPL(node)) && \ + ((void *)UNPL(node)->prev != (void *)UNPL(node)) && (UNPL(node)->data)) \ + for (bool UNPL(_once) = true; UNPL(_once); UNPL(_once) = false) \ + for (LIST_DATA_TYPE(UNPL(pl)) var = *(UNPL(node)->data); UNPL(_once); UNPL(_once) = false) -#define ListForeachReverse(l, var, body) \ - do { \ - ValidateList(l); \ - LIST_NODE_TYPE(l) *_node_##__LINE__ = NULL; \ - LIST_DATA_TYPE(l) var = {0}; \ - for (_node_##__LINE__ = (l)->tail; _node_##__LINE__; _node_##__LINE__ = (_node_##__LINE__)->prev, ++idx) { \ - if ((_node_##__LINE__)->next == _node_##__LINE__) { \ - LOG_FATAL("Node points to itself in 'next' field."); \ - } \ - if ((_node_##__LINE__)->prev == _node_##__LINE__) { \ - LOG_FATAL("Node points to itself in 'prev' field."); \ - } \ - if (!(_node_##__LINE__)->data) { \ - LOG_FATAL("Invalid data in node."); \ - } \ - var = *(_node_##__LINE__)->data; \ - {body}; \ - } \ - } while (0) +/// +/// Iterate over each element var (as a pointer) of the given list l. +/// The variable var is declared and defined by this macro as a pointer to the list's data type. +/// +/// Iteration happens in forward order, starting from the head of the list +/// and continuing through the next pointers until the end is reached. +/// The variable var will point to the data associated with each list node. +/// +/// l[in,out] : List to iterate over. +/// var[out] : Name of the pointer variable to be used which will point to the +/// current element during iteration. The type of var will be a pointer +/// to the data type of the list elements (i.e., LIST_DATA_TYPE(l) *). +/// +/// TAGS: Foreach, List, Iteration, Loop, Pointer +/// +#define ListForeachPtr(l, var) \ + for (TYPE_OF(l) UNPL(pl) = (l); UNPL(pl); UNPL(pl) = NULL) \ + if ((ValidateList(UNPL(pl)), 1) && (UNPL(pl)->head)) \ + for (LIST_NODE_TYPE(UNPL(pl)) * UNPL(node) = (TYPE_OF(UNPL(node)))ListNodeBegin(UNPL(pl)); UNPL(node); \ + UNPL(node) = ListNodeNext(UNPL(node))) \ + if ((void *)(UNPL(node)->next != (void *)UNPL(node)) && \ + ((void *)UNPL(node)->prev != (void *)UNPL(node)) && (UNPL(node)->data)) \ + for (bool UNPL(_once) = true; UNPL(_once); UNPL(_once) = false) \ + for (LIST_DATA_TYPE(UNPL(pl)) *var = UNPL(node)->data; UNPL(_once); UNPL(_once) = false) -#define ListForeachPtr(l, var, body) \ - do { \ - ValidateList(l); \ - LIST_NODE_TYPE(l) *_node_##__LINE__ = NULL; \ - LIST_DATA_TYPE(l) *var = NULL; \ - for (_node_##__LINE__ = (l)->head; _node_##__LINE__; _node_##__LINE__ = (_node_##__LINE__)->next, ++idx) { \ - if ((_node_##__LINE__)->next == _node_##__LINE__) { \ - LOG_FATAL("Node points to itself in 'next' field."); \ - } \ - if ((_node_##__LINE__)->prev == _node_##__LINE__) { \ - LOG_FATAL("Node points to itself in 'prev' field."); \ - } \ - if (!(_node_##__LINE__)->data) { \ - LOG_FATAL("Invalid data in node."); \ - } \ - var = (_node_##__LINE__)->data; \ - {body}; \ - } \ - } while (0) +/// +/// Iterate over each element var of the given list l in reverse order. +/// The variable var is declared and defined by this macro. +/// +/// Iteration happens in reverse, starting from the tail of the list +/// and continuing through the prev pointers until the head is reached. +/// The variable var will contain a copy of the value pointed to by each list node. +/// +/// l[in] : List to iterate over. +/// var[out] : Name of the variable to be used which will contain the value of the +/// current element during iteration. The type of var will be the +/// data type of the list elements (obtained via LIST_DATA_TYPE(l)). +/// +/// TAGS: Foreach, List, Iteration, Loop, Reverse +/// +#define ListForeachReverse(l, var) \ + for (TYPE_OF(l) UNPL(pl) = (l); UNPL(pl); UNPL(pl) = NULL) \ + if ((ValidateList(UNPL(pl)), 1) && (UNPL(pl)->tail)) \ + for (LIST_NODE_TYPE(UNPL(pl)) * UNPL(node) = (TYPE_OF(UNPL(node)))ListNodeEnd(UNPL(pl)); UNPL(node); \ + UNPL(node) = ListNodePrev(UNPL(node))) \ + if ((void *)(UNPL(node)->next != (void *)UNPL(node)) && \ + ((void *)UNPL(node)->prev != (void *)UNPL(node)) && (UNPL(node)->data)) \ + for (bool UNPL(_once) = true; UNPL(_once); UNPL(_once) = false) \ + for (LIST_DATA_TYPE(UNPL(pl)) var = *(UNPL(node)->data); UNPL(_once); UNPL(_once) = false) -#define ListForeachPtrReverse(l, var, body) \ - do { \ - ValidateList(l); \ - LIST_NODE_TYPE(l) *_node_##__LINE__ = NULL; \ - LIST_DATA_TYPE(l) *var = NULL; \ - for (_node_##__LINE__ = (l)->tail; _node_##__LINE__; _node_##__LINE__ = (_node_##__LINE__)->prev, ++idx) { \ - if ((_node_##__LINE__)->next == _node_##__LINE__) { \ - LOG_FATAL("Node points to itself in 'next' field."); \ - } \ - if ((_node_##__LINE__)->prev == _node_##__LINE__) { \ - LOG_FATAL("Node points to itself in 'prev' field."); \ - } \ - if (!(_node_##__LINE__)->data) { \ - LOG_FATAL("Invalid data in node."); \ - } \ - var = (_node_##__LINE__)->data; \ - {body}; \ - } \ - } while (0) +/// +/// Iterate over each element var (as a pointer) of the given list l in reverse order. +/// The variable var is declared and defined by this macro as a pointer to the list's data type. +/// +/// Iteration happens in reverse, starting from the tail of the list +/// and continuing through the prev pointers until the head is reached. +/// The variable var will point to the data associated with each list node. +/// +/// l[in,out] : List to iterate over. +/// var[out] : Name of the pointer variable to be used which will point to the +/// current element during iteration. The type of var will be a pointer +/// to the data type of the list elements (i.e., LIST_DATA_TYPE(l) *). +/// +/// TAGS: Foreach, List, Iteration, Loop, Reverse, Pointer +/// +#define ListForeachPtrReverse(l, var) \ + for (TYPE_OF(l) UNPL(pl) = (l); UNPL(pl); UNPL(pl) = NULL) \ + if ((ValidateList(UNPL(pl)), 1) && (UNPL(pl)->tail)) \ + for (LIST_NODE_TYPE(UNPL(pl)) * UNPL(node) = (TYPE_OF(UNPL(node)))ListNodeEnd(UNPL(pl)); UNPL(node); \ + UNPL(node) = ListNodePrev(UNPL(node))) \ + if ((void *)(UNPL(node)->next != (void *)UNPL(node)) && \ + ((void *)UNPL(node)->prev != (void *)UNPL(node)) && (UNPL(node)->data)) \ + for (bool UNPL(_once) = true; UNPL(_once); UNPL(_once) = false) \ + for (LIST_DATA_TYPE(UNPL(pl)) *var = UNPL(node)->data; UNPL(_once); UNPL(_once) = false) + +/// +/// Iterate over each element var of the given list l in the index range [start, end). +/// The variable var is declared and defined by this macro. +/// +/// This macro performs forward traversal, starting at index start (inclusive) +/// and continuing until index end (exclusive), assuming zero-based indexing. +/// +/// Since linked lists are not indexable, the traversal walks node-by-node and skips +/// nodes before start, then continues while tracking the current index. +/// +/// l[in] : List to iterate over. +/// var[out] : Name of the variable to be used which will contain the value +/// of the current element during iteration. +/// start[in] : Starting index (inclusive). +/// end[in] : Ending index (exclusive). +/// +/// TAGS: Foreach, List, Iteration, Loop, Range +/// +#define ListForeachInRange(l, var, start, end) \ + for (TYPE_OF(l) UNPL(pl) = (l); UNPL(pl); UNPL(pl) = NULL) \ + if ((ValidateList(UNPL(pl)), 1) && UNPL(pl)->head) \ + for (LIST_NODE_TYPE(UNPL(pl)) * UNPL(node) = (TYPE_OF(UNPL(node)))ListNodeBegin(UNPL(pl)); UNPL(node); \ + UNPL(node) = ListNodeNext(UNPL(node))) \ + for (u64 UNPL(i) = 0; UNPL(node) && UNPL(i) < (end); UNPL(node) = ListNodeNext(UNPL(node)), ++UNPL(i)) \ + if (UNPL(i) >= (start) && (UNPL(node)->data)) \ + for (bool UNPL(_once) = true; UNPL(_once); UNPL(_once) = false) \ + for (LIST_DATA_TYPE(UNPL(pl)) var = *(UNPL(node)->data); UNPL(_once); UNPL(_once) = false) + +/// +/// This macro performs forward traversal, starting at index start (inclusive) +/// and continuing until index end (exclusive), assuming zero-based indexing. +/// +/// Since linked lists are not indexable, the traversal walks node-by-node and skips +/// nodes before start, then continues while tracking the current index. +/// +/// l[in,out] : List to iterate over. +/// var[in,out] : Name of the pointer variable to be used which will point to the +/// current element during iteration. +/// start[in] : Starting index (inclusive). +/// end[in] : Ending index (exclusive). +/// +/// TAGS: Foreach, List, Iteration, Loop, Range, Pointer +/// +#define ListForeachPtrInRange(l, var, start, end) \ + for (TYPE_OF(l) UNPL(pl) = (l); UNPL(pl); UNPL(pl) = NULL) \ + if ((ValidateList(UNPL(pl)), 1) && UNPL(pl)->head) \ + for (LIST_NODE_TYPE(UNPL(pl)) * UNPL(node) = (TYPE_OF(UNPL(node)))ListNodeBegin(UNPL(pl)); UNPL(node); \ + UNPL(node) = ListNodeNext(UNPL(node))) \ + for (u64 UNPL(i) = 0; UNPL(node) && UNPL(i) < (end); UNPL(node) = ListNodeNext(UNPL(node)), ++UNPL(i)) \ + if (UNPL(i) >= (start) && (UNPL(node)->data)) \ + for (bool UNPL(_once) = true; UNPL(_once); UNPL(_once) = false) \ + for (LIST_DATA_TYPE(UNPL(pl)) *var = UNPL(node)->data; UNPL(_once); UNPL(_once) = false) + +/// +/// Iterate over each element var of the given list l in reverse, limited to index range [start, end) +/// relative to the tail of the list. Index 0 corresponds to the tail, 1 to the previous node, and so on. +/// +/// The variable var is declared and defined by this macro. +/// +/// Since linked lists do not support indexing, this macro counts nodes from the tail +/// and includes only those where the relative reverse index lies in [start, end). +/// +/// l[in] : List to iterate over. +/// var[in,out] : Name of the variable to be used which will contain the value +/// of the current element during iteration. +/// start[in] : Starting index from tail (inclusive). +/// end[in] : Ending index from tail (exclusive). +/// +/// TAGS: Foreach, List, Iteration, Loop, Reverse, Range +/// +#define ListForeachReverseInRange(l, var, start, end) \ + for (TYPE_OF(l) UNPL(pl) = (l); UNPL(pl); UNPL(pl) = NULL) \ + if ((ValidateList(UNPL(pl)), 1) && UNPL(pl)->tail) \ + for (LIST_NODE_TYPE(UNPL(pl)) * UNPL(node) = (TYPE_OF(UNPL(node)))ListNodeEnd(UNPL(pl)); UNPL(node); \ + UNPL(node) = ListNodePrev(UNPL(node))) \ + for (u64 UNPL(i) = 0; UNPL(node) && UNPL(i) < (end); UNPL(node) = ListNodePrev(UNPL(node)), ++UNPL(i)) \ + if (UNPL(i) >= (start) && (UNPL(node)->data)) \ + for (bool UNPL(_once) = true; UNPL(_once); UNPL(_once) = false) \ + for (LIST_DATA_TYPE(UNPL(pl)) var = *(UNPL(node)->data); UNPL(_once); UNPL(_once) = false) + +/// +/// Iterate over each element var (as a pointer) of the given list l in reverse, +/// limited to index range [start, end) relative to the tail of the list. +/// Index 0 corresponds to the tail, 1 to the previous node, and so on. +/// +/// The variable var is declared and defined by this macro as a pointer to the list's data type. +/// +/// Since linked lists do not support indexing, this macro counts nodes from the tail +/// and includes only those where the relative reverse index lies in [start, end). +/// +/// l[in,out] : List to iterate over. +/// var[out] : Name of the pointer variable to be used which will point to the +/// current element during iteration. +/// start[in] : Starting index from tail (inclusive). +/// end[in] : Ending index from tail (exclusive). +/// +/// TAGS: Foreach, List, Iteration, Loop, Reverse, Range, Pointer +/// +#define ListForeachPtrReverseInRange(l, var, start, end) \ + for (TYPE_OF(l) UNPL(pl) = (l); UNPL(pl); UNPL(pl) = NULL) \ + if ((ValidateList(UNPL(pl)), 1) && UNPL(pl)->tail) \ + for (LIST_NODE_TYPE(UNPL(pl)) * UNPL(node) = (TYPE_OF(UNPL(node)))ListNodeEnd(UNPL(pl)); UNPL(node); \ + UNPL(node) = ListNodePrev(UNPL(node))) \ + for (u64 UNPL(i) = 0; UNPL(node) && UNPL(i) < (end); UNPL(node) = ListNodePrev(UNPL(node)), ++UNPL(i)) \ + if (UNPL(i) >= (start) && (UNPL(node)->data)) \ + for (bool UNPL(_once) = true; UNPL(_once); UNPL(_once) = false) \ + for (LIST_DATA_TYPE(UNPL(pl)) *var = UNPL(node)->data; UNPL(_once); UNPL(_once) = false) + +/// +/// Iterate over each element `var` of the given list `l`, with index `idx`. +/// The variable `var` is declared and defined by this macro. +/// +/// Iteration happens in forward order, starting from the head of the list. +/// This macro also tracks the index (`idx`) of each element during iteration. +/// +/// `var` will contain a copy of the value pointed to by each list node, +/// and `idx` will be the zero-based index of the current element. +/// +/// INFO: The macro supports iteration using relative traversal if random access is required. +/// This means user code can change `idx` to any value in list boundaries and the macro +/// will adjust node automatically for the new index. +/// +/// l[in] : List to iterate over. +/// var[out] : Name of the variable that will hold the current value during iteration. +/// idx[out] : Name of the variable that will hold the current index during iteration. +/// +/// TAGS: Foreach, List, Iteration, Loop, Index +/// +#define ListForeachIdx(l, var, idx) \ + for (TYPE_OF(l) UNPL(pl) = (l); UNPL(pl); UNPL(pl) = NULL) \ + if ((ValidateList(UNPL(pl)), 1) && UNPL(pl)->head) \ + for (u64 idx = 0, UNPL(pidx) = 0; idx < UNPL(pl)->length;) \ + for (LIST_NODE_TYPE(UNPL(pl)) * UNPL(node) = (TYPE_OF(UNPL(node)))ListNodeBegin(UNPL(pl)), \ + *UNPL(next) = NULL; \ + UNPL(node) && \ + (UNPL(next) = \ + (UNPL(pidx) ? get_node_random_access( \ + GENERIC_LIST(UNPL(pl)), \ + GENERIC_LIST_NODE(UNPL(node)), \ + UNPL(pidx), \ + (i64)(idx) - (i64)UNPL(pidx) \ + ) : \ + UNPL(pl)->head)) && \ + UNPL(next) && UNPL(next)->data; \ + UNPL(pidx) = ++idx, UNPL(node) = UNPL(next)) \ + for (bool UNPL(_once) = true; UNPL(_once); UNPL(_once) = false) \ + for (LIST_DATA_TYPE(UNPL(pl)) var = *(UNPL(next)->data); UNPL(_once); UNPL(_once) = false) + +/// +/// Iterate over each element `var` (as a pointer) of the given list `l`, with index `idx`. +/// The variable `var` is declared and defined by this macro as a pointer to the data. +/// +/// Iteration happens in forward order, starting from the head of the list. +/// This macro also tracks the index (`idx`) of each element during iteration. +/// +/// `var` will point to the data associated with the current list node, +/// and `idx` will be the zero-based index of the current element. +/// +/// INFO: The macro supports iteration using relative traversal if random access is required. +/// This means user code can change `idx` to any value in list boundaries and the macro +/// will adjust node automatically for the new index. +/// +/// l[in] : List to iterate over. +/// var[out] : Pointer variable that will point to the current element. +/// idx[out] : Name of the variable that will hold the current index during iteration. +/// +/// TAGS: Foreach, List, Iteration, Loop, Index, Pointer +/// +#define ListForeachPtrIdx(l, var, idx) \ + for (TYPE_OF(l) UNPL(pl) = (l); UNPL(pl); UNPL(pl) = NULL) \ + if ((ValidateList(UNPL(pl)), 1) && UNPL(pl)->head) \ + for (u64 idx = 0, UNPL(pidx) = 0; idx < UNPL(pl)->length;) \ + for (LIST_NODE_TYPE(UNPL(pl)) * UNPL(node) = (TYPE_OF(UNPL(node)))ListNodeBegin(UNPL(pl)), \ + *UNPL(next) = NULL; \ + UNPL(node) && \ + (UNPL(next) = \ + (UNPL(pidx) ? get_node_random_access( \ + GENERIC_LIST(UNPL(pl)), \ + GENERIC_LIST_NODE(UNPL(node)), \ + UNPL(pidx), \ + (i64)(idx) - (i64)UNPL(pidx) \ + ) : \ + UNPL(pl)->head)) && \ + UNPL(next) && UNPL(next)->data; \ + UNPL(pidx) = ++idx, UNPL(node) = UNPL(next)) \ + for (bool UNPL(_once) = true; UNPL(_once); UNPL(_once) = false) \ + for (LIST_DATA_TYPE(UNPL(pl)) *var = UNPL(next)->data; UNPL(_once); UNPL(_once) = false) + +/// +/// Iterate over each element `var` of the given list `l` in reverse order, with index `idx`. +/// The variable `var` is declared and defined by this macro. +/// +/// Iteration starts from the tail and moves backward using the `prev` pointers. +/// The variable `idx` will contain the zero-based index from the head: +/// index length-1 corresponds to the tail, length-2 to the previous node, and so on down to 0 (head). +/// +/// INFO: The macro supports iteration using relative traversal if random access is required. +/// This means user code can change `idx` to any value in list boundaries and the macro +/// will adjust node automatically for the new index. +/// +/// l[in] : List to iterate over. +/// var[out] : Name of the variable to hold the value during iteration. +/// idx[out] : Variable that will track the index from the head. +/// +/// TAGS: Foreach, List, Iteration, Loop, Index, Reverse +/// +#define ListForeachReverseIdx(l, var, idx) \ + for (TYPE_OF(l) UNPL(pl) = (l); UNPL(pl); UNPL(pl) = NULL) \ + if ((ValidateList(UNPL(pl)), 1) && UNPL(pl)->tail && UNPL(pl)->length > 0) \ + for (u64 idx = UNPL(pl)->length - 1, UNPL(pidx) = UNPL(pl)->length - 1, UNPL(first) = 1; \ + idx < UNPL(pl)->length;) \ + for (LIST_NODE_TYPE(UNPL(pl)) * UNPL(node) = (UNPL(first) ? UNPL(pl)->tail : UNPL(node)), \ + *UNPL(next) = NULL; \ + UNPL(node) && idx < UNPL(pl)->length && (UNPL(first) = 0) && \ + (UNPL(next) = \ + (UNPL(pidx) != idx ? get_node_random_access( \ + GENERIC_LIST(UNPL(pl)), \ + GENERIC_LIST_NODE(UNPL(node)), \ + UNPL(pidx), \ + (i64)(idx) - (i64)UNPL(pidx) \ + ) : \ + UNPL(node))) && \ + UNPL(next) && UNPL(next)->data; \ + UNPL(node) = UNPL(next), UNPL(pidx) = idx) \ + for (bool UNPL(_once) = true; UNPL(_once); UNPL(_once) = false) \ + for (LIST_DATA_TYPE(UNPL(pl)) var = *(UNPL(next)->data); UNPL(_once); UNPL(_once) = false) \ + for (bool UNPL(_update) = true; UNPL(_update); \ + UNPL(_update) = false, \ + UNPL(user_idx) = idx, \ + idx = \ + (UNPL(user_idx) != UNPL(pidx) ? UNPL(user_idx) : \ + (idx > 0 ? idx - 1 : UNPL(pl)->length))) + +/// +/// Iterate over each element `var` of the given list `l` in reverse order, with index `idx`. +/// The variable `var` is declared and defined by this macro. +/// +/// Iteration starts from the tail and moves backward using the `prev` pointers. +/// The variable `idx` will contain the zero-based index from the head: +/// index length-1 corresponds to the tail, length-2 to the previous node, and so on down to 0 (head). +/// +/// INFO: The macro supports iteration using relative traversal if random access is required. +/// This means user code can change `idx` to any value in list boundaries and the macro +/// will adjust node automatically for the new index. +/// +/// l[in] : List to iterate over. +/// var[out] : Name of the variable to hold the pointer to the value during iteration. +/// idx[out] : Variable that will track the index from the head. +/// +/// TAGS: Foreach, List, Iteration, Loop, Index, Reverse +/// +#define ListForeachPtrReverseIdx(l, var, idx) \ + for (TYPE_OF(l) UNPL(pl) = (l); UNPL(pl); UNPL(pl) = NULL) \ + if ((ValidateList(UNPL(pl)), 1) && UNPL(pl)->tail && UNPL(pl)->length > 0) \ + for (u64 idx = UNPL(pl)->length - 1, UNPL(pidx) = UNPL(pl)->length - 1, UNPL(first) = 1; \ + idx < UNPL(pl)->length;) \ + for (LIST_NODE_TYPE(UNPL(pl)) * UNPL(node) = (UNPL(first) ? UNPL(pl)->tail : UNPL(node)), \ + *UNPL(next) = NULL; \ + UNPL(node) && idx < UNPL(pl)->length && (UNPL(first) = 0) && \ + (UNPL(next) = \ + (UNPL(pidx) != idx ? get_node_random_access( \ + GENERIC_LIST(UNPL(pl)), \ + GENERIC_LIST_NODE(UNPL(node)), \ + UNPL(pidx), \ + (i64)(idx) - (i64)(UNPL(pidx)) \ + ) : \ + UNPL(node))) && \ + UNPL(next) && UNPL(next)->data; \ + UNPL(node) = UNPL(next), UNPL(pidx) = idx) \ + for (bool UNPL(_once) = true; UNPL(_once); UNPL(_once) = false) \ + for (LIST_DATA_TYPE(UNPL(pl)) *var = UNPL(next)->data; UNPL(_once); UNPL(_once) = false) \ + for (bool UNPL(_update) = true; UNPL(_update); \ + UNPL(_update) = false, \ + UNPL(user_idx) = idx, \ + idx = \ + (UNPL(user_idx) != UNPL(pidx) ? UNPL(user_idx) : \ + (idx > 0 ? idx - 1 : UNPL(pl)->length))) #endif // MISRA_STD_CONTAINER_LIST_FOREACH_H diff --git a/Include/Misra/Std/Container/List/Private.h b/Include/Misra/Std/Container/List/Private.h index 8631d94..d4c6451 100644 --- a/Include/Misra/Std/Container/List/Private.h +++ b/Include/Misra/Std/Container/List/Private.h @@ -22,5 +22,7 @@ void clear_list(GenericList *list, u64 item_size); GenericListNode *node_at_list(GenericList *list, u64 item_size, u64 idx); void *item_ptr_at_list(GenericList *list, u64 item_size, u64 idx); void validate_list(const GenericList *list); +GenericListNode *get_node_relative_to_list_node(GenericListNode *node, i64 ridx); +GenericListNode *get_node_random_access(GenericList *list, GenericListNode *node, u64 nidx, i64 ridx); #endif // MISRA_STD_CONTAINER_LIST_PRIVATE_H diff --git a/Include/Misra/Std/Container/Str/Foreach.h b/Include/Misra/Std/Container/Str/Foreach.h index dbfeb67..1f2d215 100644 --- a/Include/Misra/Std/Container/Str/Foreach.h +++ b/Include/Misra/Std/Container/Str/Foreach.h @@ -23,9 +23,8 @@ extern "C" { /// at the iterated index `idx`. The type of `chr` will likely be /// the character type used by the `Str` implementation (e.g., `char`). /// idx[in] : Name of the variable to be used for iterating over indices (i64). -/// body : Body of this foreach loop. /// -#define StrForeachIdx(str, chr, idx, body) VecForeachIdx((str), (chr), idx, {body}) +#define StrForeachIdx(str, chr, idx) VecForeachIdx((str), (chr), idx) /// /// Iterate over each character `chr` of the given Str `str` in reverse order at each index `idx`. @@ -37,9 +36,8 @@ extern "C" { /// at the iterated index `idx`. The type of `chr` will likely be /// the character type used by the `Str` implementation (e.g., `char`). /// idx[in] : Name of the variable to be used for iterating over indices (i64). -/// body : Body of this foreach loop. /// -#define StrForeachReverseIdx(str, chr, idx, body) VecForeachReverseIdx((str), (chr), idx, {body}) +#define StrForeachReverseIdx(str, chr, idx) VecForeachReverseIdx((str), (chr), idx) /// /// Iterate over each character pointer `chrptr` of the given Str `str` at each index `idx`. @@ -52,9 +50,8 @@ extern "C" { /// likely be a pointer to the character type used by the `Str` /// implementation (e.g., `char*`). /// idx[in] : Name of the variable to be used for iterating over indices (i64). -/// body : Body of this foreach loop. /// -#define StrForeachPtrIdx(str, chrptr, idx, body) VecForeachPtrIdx((str), (chrptr), idx, {body}) +#define StrForeachPtrIdx(str, chrptr, idx) VecForeachPtrIdx((str), (chrptr), idx) /// /// Iterate over each character pointer `chrptr` of the given Str `str` in reverse order at each index `idx`. @@ -67,9 +64,8 @@ extern "C" { /// likely be a pointer to the character type used by the `Str` /// implementation (e.g., `char*`). /// idx[in] : Name of the variable to be used for iterating over indices (i64). -/// body : Body of this foreach loop. /// -#define StrForeachReversePtrIdx(str, chrptr, idx, body) VecForeachPtrReverseIdx((str), (chrptr), idx, {body}) +#define StrForeachReversePtrIdx(str, chrptr, idx) VecForeachPtrReverseIdx((str), (chrptr), idx) /// /// Iterate over each character `chr` of the given Str `str`. @@ -80,9 +76,8 @@ extern "C" { /// chr[in] : Name of the variable to be used which will contain the character of the /// current element during iteration. The type of `chr` will likely be /// the character type used by the `Str` implementation (e.g., `char`). -/// body : The block of code to be executed for each character of the Str. /// -#define StrForeach(str, chr, body) VecForeach((str), (chr), {body}) +#define StrForeach(str, chr) VecForeach((str), (chr)) /// /// Iterate over each character `chr` of the given Str `str` in reverse order. @@ -93,9 +88,8 @@ extern "C" { /// chr[in] : Name of the variable to be used which will contain the character of the /// current element during iteration. The type of `chr` will likely be /// the character type used by the `Str` implementation (e.g., `char`). -/// body : The block of code to be executed for each character of the Str. /// -#define StrForeachReverse(str, chr, body) VecForeachReverse((str), (chr), {body}) +#define StrForeachReverse(str, chr) VecForeachReverse((str), (chr)) /// /// Iterate over each character pointer `chrptr` of the given Str `str`. @@ -108,9 +102,8 @@ extern "C" { /// current character during iteration. The type of `chrptr` will /// likely be a pointer to the character type used by the `Str` /// implementation (e.g., `char*`). -/// body : The block of code to be executed for each character of the Str. /// -#define StrForeachPtr(str, chrptr, body) VecForeachPtr((str), (chrptr), {body}) +#define StrForeachPtr(str, chrptr) VecForeachPtr((str), (chrptr)) /// /// Iterate over each character pointer `chrptr` of the given Str `str` in reverse order. @@ -123,9 +116,8 @@ extern "C" { /// current character during iteration. The type of `chrptr` will /// likely be a pointer to the character type used by the `Str` /// implementation (e.g., `char*`). -/// body : The block of code to be executed for each character of the Str. /// -#define StrForeachPtrReverse(str, chrptr, body) VecForeachPtrReverse((str), (chrptr), {body}) +#define StrForeachPtrReverse(str, chrptr) VecForeachPtrReverse((str), (chrptr)) /// /// Iterate over characters in a specific range of the given Str `str` at each index `idx`. @@ -137,16 +129,8 @@ extern "C" { /// idx[in] : Name of variable to be used for iterating over indices. /// start[in] : Starting index (inclusive). /// end[in] : Ending index (exclusive). -/// body : Body of this foreach loop. /// -/// SUCCESS : The `body` is executed for each character of the Str `str` from the -/// `start` index to the `end-1` index. -/// FAILURE : If the Str `str` is NULL, its length is zero, or the range is invalid, -/// the loop body will not be executed. Any access to an invalid index will -/// result in a fatal log message and program termination. -/// -#define StrForeachInRangeIdx(str, chr, idx, start, end, body) \ - VecForeachInRangeIdx((str), (chr), idx, (start), (end), {body}) +#define StrForeachInRangeIdx(str, chr, idx, start, end) VecForeachInRangeIdx((str), (chr), idx, (start), (end)) /// /// Iterate over characters in a specific range of the given Str `str`. @@ -157,15 +141,8 @@ extern "C" { /// chr[in] : Name of variable to be used which'll contain character of the current element. /// start[in] : Starting index (inclusive). /// end[in] : Ending index (exclusive). -/// body : Body of this foreach loop. -/// -/// SUCCESS : The `body` is executed for each character of the Str `str` from the -/// `start` index to the `end-1` index. -/// FAILURE : If the Str `str` is NULL, its length is zero, or the range is invalid, -/// the loop body will not be executed. Any failures within the `VecForeachInRangeIdx` -/// macro will result in a fatal log message and program termination. /// -#define StrForeachInRange(str, chr, start, end, body) VecForeachInRange((str), (chr), (start), (end), {body}) +#define StrForeachInRange(str, chr, start, end) VecForeachInRange((str), (chr), (start), (end)) /// /// Iterate over characters in a specific range of the given Str `str` at each index `idx` (as pointers). @@ -177,16 +154,9 @@ extern "C" { /// idx[in] : Name of variable to be used for iterating over indices. /// start[in] : Starting index (inclusive). /// end[in] : Ending index (exclusive). -/// body : Body of this foreach loop. /// -/// SUCCESS : The `body` is executed for each character of the Str `str` from the -/// `start` index to the `end-1` index, with `chrptr` pointing to each character. -/// FAILURE : If the Str `str` is NULL, its length is zero, or the range is invalid, -/// the loop body will not be executed. Any access to an invalid index will -/// result in a fatal log message and program termination. -/// -#define StrForeachPtrInRangeIdx(str, chrptr, idx, start, end, body) \ - VecForeachPtrInRangeIdx((str), (chrptr), idx, (start), (end), {body}) +#define StrForeachPtrInRangeIdx(str, chrptr, idx, start, end) \ + VecForeachPtrInRangeIdx((str), (chrptr), idx, (start), (end)) /// /// Iterate over characters in a specific range of the given Str `str` (as pointers). @@ -198,16 +168,8 @@ extern "C" { /// chrptr[in] : Name of pointer variable to be used which'll point to the current character. /// start[in] : Starting index (inclusive). /// end[in] : Ending index (exclusive). -/// body : Body of this foreach loop. -/// -/// SUCCESS : The `body` is executed for each character of the Str `str` from the -/// `start` index to the `end-1` index, with `chrptr` pointing to each character. -/// FAILURE : If the Str `str` is NULL, its length is zero, or the range is invalid, -/// the loop body will not be executed. Any failures within the `VecForeachPtrInRangeIdx` -/// macro will result in a fatal log message and program termination. /// -#define StrForeachPtrInRange(str, chrptr, start, end, body) \ - VecForeachPtrInRange((str), (chrptr), (start), (end), {body}) +#define StrForeachPtrInRange(str, chrptr, start, end) VecForeachPtrInRange((str), (chrptr), (start), (end)) #ifdef __cplusplus } diff --git a/Include/Misra/Std/Container/Vec/Foreach.h b/Include/Misra/Std/Container/Vec/Foreach.h index b3674a1..caf4cd5 100644 --- a/Include/Misra/Std/Container/Vec/Foreach.h +++ b/Include/Misra/Std/Container/Vec/Foreach.h @@ -16,29 +16,14 @@ /// v[in,out] : Vector to iterate over. /// var[in] : Name of variable to be used which'll contain value at iterated index `idx` /// idx[in] : Name of variable to be used for iterating over indices. -/// body : Body of this foreach loop -/// -/// SUCCESS : The `body` is executed for each element of the vector `v` from the -/// beginning to the end. -/// FAILURE : If the vector `v` is NULL or its length is zero, the loop body will not -/// be executed. Any failures within the `VecForeachIdx` macro (like invalid -/// index access) will result in a fatal log message and program termination. -/// -#define VecForeachIdx(v, var, idx, body) \ - do { \ - ValidateVec(v); \ - size idx = 0; \ - VEC_DATATYPE(v) var = {0}; \ - if ((v)->length > 0) { \ - for ((idx) = 0; (idx) < (v)->length; ++(idx)) { \ - var = VecAt(v, idx); \ - { body } \ - if ((idx) >= (v)->length) { \ - LOG_FATAL("Vector range overflow : Invalid index reached during Foreach iteration."); \ - } \ - } \ - } \ - } while (0) +/// +/// TAGS: Foreach, Vec, Iteration, Loop +/// +#define VecForeachIdx(v, var, idx) \ + for (TYPE_OF(v) UNPL(pv) = (v); UNPL(pv); UNPL(pv) = NULL) \ + if ((ValidateVec(UNPL(pv)), 1) && UNPL(pv)->length > 0) \ + for (u64 idx = 0, UNPL(d) = 1; UNPL(d); UNPL(d)--) \ + for (VEC_DATATYPE(UNPL(pv)) var = {}; idx < UNPL(pv)->length && (var = VecAt(UNPL(pv), idx), 1); idx++) /// /// Iterate over each element `var` of given vector `v` at each index `idx` into the vector. @@ -49,25 +34,15 @@ /// v[in,out] : Vector to iterate over. /// var[in] : Name of variable to be used which'll contain value at iterated index `idx` /// idx[in] : Name of variable to be used for iterating over indices. -/// body : Body of this foreach loop -/// -#define VecForeachReverseIdx(v, var, idx, body) \ - do { \ - ValidateVec(v); \ - size idx = 0; \ - VEC_DATATYPE(v) var = {0}; \ - if ((v)->length > 0) { \ - for ((idx) = (v)->length - 1; (idx) < (v)->length; --(idx)) { \ - var = VecAt(v, idx); \ - { body } \ - if ((idx) >= (v)->length) { \ - LOG_FATAL("Vector range overflow : Invalid index reached during Foreach reverse iteration."); \ - } \ - if (idx == 0) \ - break; /* Stop after processing index 0 */ \ - } \ - } \ - } while (0) +/// +/// TAGS: Foreach, Vec, Iteration, Loop, Reverse +/// +#define VecForeachReverseIdx(v, var, idx) \ + for (TYPE_OF(v) UNPL(pv) = (v); UNPL(pv); UNPL(pv) = NULL) \ + if ((ValidateVec(UNPL(pv)), 1) && UNPL(pv)->length > 0) \ + for (u64 idx = UNPL(pv)->length; idx-- > 0 && idx < UNPL(pv)->length;) \ + for (u8 UNPL(run_once) = 1; UNPL(run_once); UNPL(run_once) = 0) \ + for (VEC_DATATYPE(UNPL(pv)) var = VecAt(UNPL(pv), idx); UNPL(run_once); UNPL(run_once) = 0) /// /// Iterate over each element `var` of given vector `v` at each index `idx` into the vector. @@ -76,24 +51,17 @@ /// `idx` will start from 0 and will go till v->length - 1 /// /// v[in,out] : Vector to iterate over. -/// var[in] : Name of variable to be used which'll contain value at iterated index `idx` +/// var[in] : Name of variable to be used which'll contain pointer to value at iterated index `idx` /// idx[in] : Name of variable to be used for iterating over indices. -/// body : Body of this foreach loop -/// -#define VecForeachPtrIdx(v, var, idx, body) \ - do { \ - ValidateVec(v); \ - size idx = 0; \ - VEC_DATATYPE(v) *var = NULL; \ - if ((v)->length > 0) { \ - for ((idx) = 0; (idx) < (v)->length; ++(idx)) { \ - var = VecPtrAt(v, idx); \ - body if ((idx) >= (v)->length) { \ - LOG_FATAL("Vector range overflow : Invalid index reached during Foreach iteration."); \ - } \ - } \ - } \ - } while (0) +/// +/// TAGS: Foreach, Vec, Iteration, Loop, Pointer +/// +#define VecForeachPtrIdx(v, var, idx) \ + for (TYPE_OF(v) UNPL(pv) = (v); UNPL(pv); UNPL(pv) = NULL) \ + if ((ValidateVec(UNPL(pv)), 1) && UNPL(pv)->length > 0) \ + for (u64 idx = 0, UNPL(d) = 1; UNPL(d); UNPL(d)--) \ + for (VEC_DATATYPE(UNPL(pv)) *var = NULL; idx < UNPL(pv)->length && (var = VecPtrAt(UNPL(pv), idx), 1); \ + idx++) /// /// Iterate over each element `var` of given vector `v` at each index `idx` into the vector. @@ -102,27 +70,17 @@ /// `idx` will start from v->length - 1 and will go till 0 /// /// v[in,out] : Vector to iterate over. -/// var[in] : Name of variable to be used which'll contain value at iterated index `idx` +/// var[in] : Name of variable to be used which'll contain pointer to value at iterated index `idx` /// idx[in] : Name of variable to be used for iterating over indices. -/// body : Body of this foreach loop -/// -#define VecForeachPtrReverseIdx(v, var, idx, body) \ - do { \ - ValidateVec(v); \ - size idx = 0; \ - VEC_DATATYPE(v) *var = {0}; \ - if ((v)->length > 0) { \ - for ((idx) = (v)->length - 1; (idx) < (v)->length; --(idx)) { \ - var = VecPtrAt(v, idx); \ - { body } \ - if ((idx) >= (v)->length) { \ - LOG_FATAL("Vector range overflow : Invalid index reached during Foreach reverse iteration."); \ - } \ - if (idx == 0) \ - break; /* Stop after processing index 0 */ \ - } \ - } \ - } while (0) +/// +/// TAGS: Foreach, Vec, Iteration, Loop, Reverse, Pointer +/// +#define VecForeachPtrReverseIdx(v, var, idx) \ + for (TYPE_OF(v) UNPL(pv) = (v); UNPL(pv); UNPL(pv) = NULL) \ + if ((ValidateVec(UNPL(pv)), 1) && UNPL(pv)->length > 0) \ + for (u64 idx = UNPL(pv)->length; idx-- > 0 && idx < UNPL(pv)->length;) \ + for (u8 UNPL(run_once) = 1; UNPL(run_once); UNPL(run_once) = 0) \ + for (VEC_DATATYPE(UNPL(pv)) *var = VecPtrAt(UNPL(pv), idx); UNPL(run_once); UNPL(run_once) = 0) /// /// Iterate over each element `var` of the given vector `v`. @@ -133,15 +91,10 @@ /// var[in] : Name of the variable to be used which will contain the value of the /// current element during iteration. The type of `var` will be the /// data type of the vector elements (obtained via `VEC_DATATYPE(v)`). -/// body : The block of code to be executed for each element of the vector. /// -/// SUCCESS : The `body` is executed for each element of the vector `v` from the -/// beginning to the end. -/// FAILURE : If the vector `v` is NULL or its length is zero, the loop body will not -/// be executed. Any failures within the `VecForeachIdx` macro (like invalid -/// index access) will result in a fatal log message and program termination. +/// TAGS: Foreach, Vec, Iteration, Loop /// -#define VecForeach(v, var, body) VecForeachIdx((v), (var), (____iter___), {body}) +#define VecForeach(v, var) VecForeachIdx((v), (var), UNPL(iter)) /// /// Iterate over each element `var` of the given vector `v` in reverse order. @@ -152,15 +105,10 @@ /// var[in] : Name of the variable to be used which will contain the value of the /// current element during iteration. The type of `var` will be the /// data type of the vector elements (obtained via `VEC_DATATYPE(v)`). -/// body : The block of code to be executed for each element of the vector. /// -/// SUCCESS : The `body` is executed for each element of the vector `v` from the -/// end to the beginning. -/// FAILURE : If the vector `v` is NULL or its length is zero, the loop body will not -/// be executed. Any failures within the `VecForeachReverseIdx` macro (like -/// invalid index access) will result in a fatal log message and program termination. +/// TAGS: Foreach, Vec, Iteration, Loop, Reverse /// -#define VecForeachReverse(v, var, body) VecForeachReverseIdx((v), (var), (____iter___), {body}) +#define VecForeachReverse(v, var) VecForeachReverseIdx((v), (var), UNPL(iter)) /// /// Iterate over each element `var` of the given vector `v` (as a pointer). @@ -173,15 +121,10 @@ /// current element during iteration. The type of `var` will be a pointer /// to the data type of the vector elements (obtained via /// `VEC_DATATYPE(v) *`). -/// body : The block of code to be executed for each element of the vector. /// -/// SUCCESS : The `body` is executed for each element of the vector `v` (with `var` -/// pointing to the current element) from the beginning to the end. -/// FAILURE : If the vector `v` is NULL or its length is zero, the loop body will not -/// be executed. Any failures within the `VecForeachPtrIdx` macro (like invalid -/// index access) will result in a fatal log message and program termination. +/// TAGS: Foreach, Vec, Iteration, Loop, Pointer /// -#define VecForeachPtr(v, var, body) VecForeachPtrIdx((v), (var), (____iter___), {body}) +#define VecForeachPtr(v, var) VecForeachPtrIdx((v), (var), UNPL(iter)) /// /// Iterate over each element `var` (as a pointer) of the given vector `v` in reverse order. @@ -194,15 +137,10 @@ /// current element during iteration. The type of `var` will be a pointer /// to the data type of the vector elements (obtained via /// `VEC_DATATYPE(v) *`). -/// body : The block of code to be executed for each element of the vector. /// -/// SUCCESS : The `body` is executed for each element of the vector `v` (with `var` -/// pointing to the current element) from the end to the beginning. -/// FAILURE : If the vector `v` is NULL or its length is zero, the loop body will not -/// be executed. Any failures within the `VecForeachPtrReverseIdx` macro (like -/// invalid index access) will result in a fatal log message and program termination. +/// TAGS: Foreach, Vec, Iteration, Loop, Reverse, Pointer /// -#define VecForeachPtrReverse(v, var, body) VecForeachPtrReverseIdx((v), (var), (____iter___), {body}) +#define VecForeachPtrReverse(v, var) VecForeachPtrReverseIdx((v), (var), (____iter___)) /// /// Iterate over elements in a specific range of the given vector `v` at each index `idx`. @@ -215,53 +153,16 @@ /// idx[in] : Name of variable to be used for iterating over indices. /// start[in] : Starting index (inclusive). /// end[in] : Ending index (exclusive). -/// body : Body of this foreach loop. -/// -/// SUCCESS : The `body` is executed for each element of the vector `v` from the -/// `start` index to the `end-1` index. -/// FAILURE : If the vector `v` is NULL, its length is zero, or the range is invalid, -/// the loop body will not be executed. Any access to an invalid index will -/// result in a fatal log message and program termination. -/// -#define VecForeachInRangeIdx(v, var, idx, start, end, body) \ - do { \ - ValidateVec(v); \ - size idx = 0; \ - VEC_DATATYPE(v) var = {0}; \ - u64 _s = start; \ - u64 _e = end; \ - if ((v)->length > 0) { \ - if ((_e) > (v)->length) { \ - LOG_FATAL( \ - "Vector range overflow: End index %zu exceeds vector length %zu. " \ - "If you intended to iterate over all items, use VecForeach instead.", \ - _e, \ - (v)->length \ - ); \ - } \ - if ((_s) >= (v)->length) { \ - LOG_FATAL( \ - "Vector range overflow: Start index %zu exceeds or equals vector length %zu.", \ - _s, \ - (v)->length \ - ); \ - } \ - if ((_s) > (_e)) { \ - LOG_FATAL("Invalid range: Start index %zu must be less than or equal to end index %zu.", _s, _e); \ - } \ - for ((idx) = (_s); (idx) < (_e); ++(idx)) { \ - if ((idx) >= (v)->length) { \ - LOG_FATAL( \ - "Vector range overflow: Index %zu exceeds vector length %zu during iteration.", \ - idx, \ - (v)->length \ - ); \ - } \ - var = VecAt(v, idx); \ - { body } \ - } \ - } \ - } while (0) +/// +/// TAGS: Foreach, Vec, Iteration, Loop, Range +/// +#define VecForeachInRangeIdx(v, var, idx, start, end) \ + for (TYPE_OF(v) UNPL(pv) = (v); UNPL(pv); UNPL(pv) = NULL) \ + if ((ValidateVec(UNPL(pv)), 1) && UNPL(pv)->length > 0) \ + for (u64 UNPL(s) = (start), UNPL(e) = (end), idx = UNPL(s), UNPL(d) = 1; \ + UNPL(s) <= idx && idx < UNPL(e) && idx < UNPL(pv)->length && UNPL(s) <= UNPL(e); \ + ++idx, UNPL(d) = 1) \ + for (VEC_DATATYPE(UNPL(pv)) var = VecAt(UNPL(pv), idx); UNPL(d); UNPL(d) = 0) /// /// Iterate over elements in a specific range of the given vector `v`. @@ -272,16 +173,10 @@ /// var[in] : Name of variable to be used which'll contain value of the current element. /// start[in] : Starting index (inclusive). /// end[in] : Ending index (exclusive). -/// body : Body of this foreach loop. /// -/// SUCCESS : The `body` is executed for each element of the vector `v` from the -/// `start` index to the `end-1` index. -/// FAILURE : If the vector `v` is NULL, its length is zero, or the range is invalid, -/// the loop body will not be executed. Any failures within the `VecForeachInRangeIdx` -/// macro will result in a fatal log message and program termination. +/// TAGS: Foreach, Vec, Iteration, Loop, Range /// -#define VecForeachInRange(v, var, start, end, body) \ - VecForeachInRangeIdx((v), (var), (____iter___), (start), (end), {body}) +#define VecForeachInRange(v, var, start, end) VecForeachInRangeIdx((v), (var), (____iter___), (start), (end)) /// /// Iterate over elements in a specific range of the given vector `v` at each index `idx` (as pointers). @@ -294,53 +189,16 @@ /// idx[in] : Name of variable to be used for iterating over indices. /// start[in] : Starting index (inclusive). /// end[in] : Ending index (exclusive). -/// body : Body of this foreach loop. -/// -/// SUCCESS : The `body` is executed for each element of the vector `v` from the -/// `start` index to the `end-1` index, with `var` pointing to each element. -/// FAILURE : If the vector `v` is NULL, its length is zero, or the range is invalid, -/// the loop body will not be executed. Any access to an invalid index will -/// result in a fatal log message and program termination. -/// -#define VecForeachPtrInRangeIdx(v, var, idx, start, end, body) \ - do { \ - ValidateVec(v); \ - size idx = 0; \ - VEC_DATATYPE(v) *var = NULL; \ - u64 _s = start; \ - u64 _e = end; \ - if ((v)->length > 0) { \ - if ((_e) > (v)->length) { \ - LOG_FATAL( \ - "Vector range overflow: End index {} exceeds vector length {}. " \ - "If you intended to iterate over all items, use VecForeach instead.", \ - _e, \ - (v)->length \ - ); \ - } \ - if ((_s) >= (v)->length) { \ - LOG_FATAL( \ - "Vector range overflow: Start index {} exceeds or equals vector length {}.", \ - _e, \ - (v)->length \ - ); \ - } \ - if ((_s) > (_e)) { \ - LOG_FATAL("Invalid range: Start index {} must be less than or equal to end index {}.", _s, _e); \ - } \ - for ((idx) = (_s); (idx) < (_e); ++(idx)) { \ - if ((idx) >= (v)->length) { \ - LOG_FATAL( \ - "Vector range overflow: Index {} exceeds vector length {} during iteration.", \ - idx, \ - (v)->length \ - ); \ - } \ - var = VecPtrAt(v, idx); \ - { body } \ - } \ - } \ - } while (0) +/// +/// TAGS: Foreach, Vec, Iteration, Loop, Range, Pointer +/// +#define VecForeachPtrInRangeIdx(v, var, idx, start, end) \ + for (TYPE_OF(v) UNPL(pv) = (v); UNPL(pv); UNPL(pv) = NULL) \ + if ((ValidateVec(UNPL(pv)), 1) && UNPL(pv)->length > 0) \ + for (u64 UNPL(s) = (start), UNPL(e) = (end), idx = UNPL(s), UNPL(d) = 1; \ + idx >= UNPL(s) && idx < UNPL(e) && idx < UNPL(pv)->length && UNPL(s) <= UNPL(e); \ + ++idx, UNPL(d) = 1) \ + for (VEC_DATATYPE(UNPL(pv)) *var = VecPtrAt(UNPL(pv), idx); UNPL(d); UNPL(d) = 0) /// /// Iterate over elements in a specific range of the given vector `v` (as pointers). @@ -352,15 +210,9 @@ /// var[in] : Name of pointer variable to be used which'll point to the current element. /// start[in] : Starting index (inclusive). /// end[in] : Ending index (exclusive). -/// body : Body of this foreach loop. /// -/// SUCCESS : The `body` is executed for each element of the vector `v` from the -/// `start` index to the `end-1` index, with `var` pointing to each element. -/// FAILURE : If the vector `v` is NULL, its length is zero, or the range is invalid, -/// the loop body will not be executed. Any failures within the `VecForeachPtrInRangeIdx` -/// macro will result in a fatal log message and program termination. +/// TAGS: Foreach, Vec, Iteration, Loop, Range, Pointer /// -#define VecForeachPtrInRange(v, var, start, end, body) \ - VecForeachPtrInRangeIdx((v), (var), (____iter___), (start), (end), {body}) +#define VecForeachPtrInRange(v, var, start, end) VecForeachPtrInRangeIdx((v), (var), (____iter___), (start), (end)) #endif // MISRA_STD_CONTAINER_VEC_FOREACH_H diff --git a/Include/Misra/Types.h b/Include/Misra/Types.h index 24fa842..188ab61 100644 --- a/Include/Misra/Types.h +++ b/Include/Misra/Types.h @@ -644,4 +644,16 @@ typedef i8 bool; /// #define APPLY_MACRO_FOREACH_AGAIN() APPLY_MACRO_FOREACH_HELPER + +/// +/// Macro helper to generate unique names +/// +#define CONCAT_(a, b) a##b +#define CONCAT(a, b) CONCAT_(a, b) +#define UNIQUE_NAME(base) CONCAT(base, __COUNTER__) + +/// Unique name per line +#define UNPL(base) CONCAT(base, __LINE__) + + #endif // MISRA_TYPES_H diff --git a/Source/Misra/Std/Container/BitVec.c b/Source/Misra/Std/Container/BitVec.c index f54c339..48d76a0 100644 --- a/Source/Misra/Std/Container/BitVec.c +++ b/Source/Misra/Std/Container/BitVec.c @@ -1611,11 +1611,11 @@ u64 BitVecPrefixMatch(BitVec *bv, BitVecs *patterns) { LOG_FATAL("invalid BitVecs object provided"); } - VecForeachPtrIdx(patterns, pattern, i, { + VecForeachPtrIdx(patterns, pattern, i) { if (BitVecStartsWith(bv, pattern)) { return i; } - }); + } return SIZE_MAX; } @@ -1626,11 +1626,11 @@ u64 BitVecSuffixMatch(BitVec *bv, BitVecs *patterns) { LOG_FATAL("invalid arguments"); } - VecForeachPtrIdx(patterns, pattern, i, { + VecForeachPtrIdx(patterns, pattern, i) { if (BitVecEndsWith(bv, pattern)) { return i; } - }); + } return SIZE_MAX; } diff --git a/Source/Misra/Std/Container/List.c b/Source/Misra/Std/Container/List.c index 105b994..b087cb7 100644 --- a/Source/Misra/Std/Container/List.c +++ b/Source/Misra/Std/Container/List.c @@ -103,7 +103,7 @@ void remove_range_list(GenericList *list, void *removed_data, u64 item_size, u64 if (removed_data) { GenericListNode *node = node_at_list(list, item_size, start); for (u64 c = 0; (c < count) && node; c++) { - memcpy(removed_data + c * item_size, node->data, item_size); + memcpy((u8 *)removed_data + c * item_size, node->data, item_size); memset(node->data, 0, item_size); free(node->data); @@ -158,8 +158,8 @@ void qsort_list(GenericList *list, u64 item_size, GenericCompare comp) { ValidateList(list); - void *data = malloc(item_size * list->length); - u64 item_count = list->length; + void *data = malloc(item_size * list->length); + u64 item_count = list->length; remove_range_list(list, data, item_size, 0, list->length); qsort(data, item_count, item_size, comp); push_arr_list(list, item_size, data, item_count); @@ -236,7 +236,7 @@ void push_arr_list(GenericList *list, u64 item_size, void *arr, u64 count) { memcpy(new_tail->data, arr, item_size); } - arr += item_size; + arr = (u8 *)arr + item_size; } } @@ -318,3 +318,80 @@ void validate_list(const GenericList *l) { } } } + +GenericListNode *get_node_relative_to_list_node(GenericListNode *node, i64 ridx) { + if (!node) { + LOG_FATAL("Invalid arguments"); + } + + if (ridx > 0) { + while (node->next && ridx) { + node = node->next; + ridx--; + } + if (!node->next && ridx) { + return NULL; + } + } else if (ridx < 0) { + while (node->prev && ridx < 0) { + node = node->prev; + ridx++; + } + if (!node->prev && ridx < 0) { + return NULL; + } + } + + return node; +} + +GenericListNode *get_node_random_access(GenericList *list, GenericListNode *node, u64 nidx, i64 ridx) { + if (!list || !node) { + LOG_FATAL("Invalid arguments"); + } + + if (nidx >= list->length) { + LOG_FATAL("Node index exceeds list bounds"); + } + + if ((ridx < 0 && (u64)(-ridx) > nidx) || (ridx > 0 && nidx + (u64)ridx >= list->length)) { + LOG_FATAL("Relative node index outside of list bounds"); + } + + ValidateList(list); + + u64 abs_target_idx = nidx + ridx; + u64 dist_from_node = (nidx > abs_target_idx) ? nidx - abs_target_idx : abs_target_idx - nidx; + u64 dist_from_head = abs_target_idx; + u64 dist_from_tail = list->length - 1 - abs_target_idx; + + GenericListNode *cur = NULL; + if (dist_from_node <= dist_from_head && dist_from_node <= dist_from_tail) { + // Traverse from current node + cur = node; + i64 steps = ridx; + while (steps > 0 && cur) { + cur = cur->next; + steps--; + } + while (steps < 0 && cur) { + cur = cur->prev; + steps++; + } + return cur; + } else if (dist_from_head <= dist_from_tail) { + // Traverse from head + cur = list->head; + for (u64 i = 0; i < abs_target_idx && cur; i++) { + cur = cur->next; + } + return cur; + } else { + // Traverse from tail + cur = list->tail; + for (u64 i = list->length - 1; i > abs_target_idx && cur; i--) { + cur = cur->prev; + } + return cur; + } +} diff --git a/Source/Misra/Std/Container/Str.c b/Source/Misra/Std/Container/Str.c index 7f275b7..fbd533d 100644 --- a/Source/Misra/Std/Container/Str.c +++ b/Source/Misra/Std/Container/Str.c @@ -861,7 +861,9 @@ void ValidateStr(const Str* s) { void ValidateStrs(const Strs* vs) { ValidateVec(vs); - VecForeachPtr(vs, sp, { ValidateStr(sp); }); + VecForeachPtr(vs, sp) { + ValidateStr(sp); + } } // ====================================== diff --git a/Source/Misra/Std/Io.c b/Source/Misra/Std/Io.c index 3c0bf02..e1d3df7 100644 --- a/Source/Misra/Std/Io.c +++ b/Source/Misra/Std/Io.c @@ -847,7 +847,7 @@ void _write_Str(Str* o, FmtInfo* fmt_info, Str* s) { if (fmt_info->flags & FMT_FLAG_HEX) { // Format each character as hex StrIntFormat config = {.base = 16, .uppercase = (fmt_info->flags & FMT_FLAG_CAPS) != 0}; - StrForeachIdx(s, c, i, { + StrForeachIdx(s, c, i) { if (i > 0) { StrPushBack(o, ' '); } @@ -861,7 +861,7 @@ void _write_Str(Str* o, FmtInfo* fmt_info, Str* s) { StrPushBackZstr(o, "0x"); StrMerge(o, &hex); StrDeinit(&hex); - }); + } } else { // If precision is specified, use it as max length size len = s->length; @@ -878,7 +878,7 @@ void _write_Str(Str* o, FmtInfo* fmt_info, Str* s) { if (fmt_info->flags & FMT_FLAG_CHAR) { write_char_internal(o, fmt_info->flags, (const char*)s->data, len); } else { - StrForeachInRange(s, c, 0, len, { + StrForeachInRange(s, c, 0, len) { if (IS_PRINTABLE(c)) { StrPushBack(o, c); } else { @@ -887,7 +887,7 @@ void _write_Str(Str* o, FmtInfo* fmt_info, Str* s) { StrPushBack(o, digits[(c >> 4) & 0xf]); StrPushBack(o, digits[c & 0xf]); } - }); + } } } } diff --git a/Tests/Json/Read.Nested.c b/Tests/Json/Read.Nested.c index 037bb14..49647a9 100644 --- a/Tests/Json/Read.Nested.c +++ b/Tests/Json/Read.Nested.c @@ -79,7 +79,9 @@ void ModelInfoDeinit(ModelInfo* info) { void SearchResultDeinit(SearchResult* result) { StrDeinit(&result->binary_name); StrDeinit(&result->sha256); - VecForeach(&result->tags, tag, { StrDeinit(&tag); }); + VecForeach(&result->tags, tag) { + StrDeinit(&tag); + } VecDeinit(&result->tags); StrDeinit(&result->created_at); StrDeinit(&result->model_name); diff --git a/Tests/Json/Write.Nested.c b/Tests/Json/Write.Nested.c index 28ffd2c..93befd2 100644 --- a/Tests/Json/Write.Nested.c +++ b/Tests/Json/Write.Nested.c @@ -405,37 +405,37 @@ bool test_dynamic_object_keys_writing(void) { JW_OBJ(json, { JW_OBJ_KV(json, "functions", { - VecForeach(&symbols, symbol, { + VecForeach(&symbols, symbol) { Str source_key = StrInit(); StrWriteFmt(&source_key, "{}", symbol.source_function_id); JW_OBJ_KV(json, source_key.data, { - Str target_key = StrInit(); - StrWriteFmt(&target_key, "{}", symbol.target_function_id); + Str target_key = StrInit(); + StrWriteFmt(&target_key, "{}", symbol.target_function_id); - JW_OBJ_KV(json, target_key.data, { - JW_FLT_KV(json, "distance", symbol.distance); - JW_STR_KV(json, "name", symbol.function_name); - }); + JW_OBJ_KV(json, target_key.data, { + JW_FLT_KV(json, "distance", symbol.distance); + JW_STR_KV(json, "name", symbol.function_name); + }); - StrDeinit(&target_key); + StrDeinit(&target_key); }); StrDeinit(&source_key); - }); - }); - }); - - const char* expected = - "{\"functions\":{\"111\":{\"222\":{\"distance\":0.900000,\"name\":\"func1\"}},\"333\":{\"444\":{\"distance\":0." - "800000,\"name\":\"func2\"}}}}"; - if (!compare_json_output(&json, expected)) { - success = false; - } + } +}); +}); + +const char* expected = + "{\"functions\":{\"111\":{\"222\":{\"distance\":0.900000,\"name\":\"func1\"}},\"333\":{\"444\":{\"distance\":0." + "800000,\"name\":\"func2\"}}}}"; +if (!compare_json_output(&json, expected)) { + success = false; +} - StrDeinit(&json); - VecDeinit(&symbols); - return success; +StrDeinit(&json); +VecDeinit(&symbols); +return success; } // Test 7: Deeply nested structure writing diff --git a/Tests/Std/BitVec.Foreach.Deadend.c b/Tests/Std/BitVec.Foreach.Deadend.c index b40aae9..5b6b630 100644 --- a/Tests/Std/BitVec.Foreach.Deadend.c +++ b/Tests/Std/BitVec.Foreach.Deadend.c @@ -79,14 +79,16 @@ bool test_bitvec_foreach_invalid_usage(void) { WriteFmt("Testing BitVec foreach with invalid bitvec\n"); // Test foreach with invalid bitvec (length > 0 but data is NULL) - BitVec bv = {.length = 5, .capacity = 10, .data = NULL, .byte_size = 0}; + BitVec bv = BitVecInit(); + bv.length = 5; + bv.capacity = 10; // This should abort due to ValidateBitVec check int count = 0; - BitVecForeach(&bv, bit, { + BitVecForeach(&bv, bit) { (void)bit; count++; - }); + } // Should not reach here (void)count; // Silence unused variable warning @@ -108,6 +110,12 @@ int main(void) { int total_deadend_tests = sizeof(deadend_tests) / sizeof(deadend_tests[0]); + typedef List(int) LI; + LI li = ListInit(); + ListForeach(&li, i) { + (void)i; + } + // Run all deadend tests using the centralized test driver return run_test_suite(NULL, 0, deadend_tests, total_deadend_tests, "BitVec.Foreach.Deadend"); } diff --git a/Tests/Std/BitVec.Foreach.Simple.c b/Tests/Std/BitVec.Foreach.Simple.c index 60b4bd3..1f2ae04 100644 --- a/Tests/Std/BitVec.Foreach.Simple.c +++ b/Tests/Std/BitVec.Foreach.Simple.c @@ -47,14 +47,14 @@ bool test_bitvec_foreach_idx(void) { u64 count = 0; bool pattern_correct = true; - BitVecForeachIdx(&bv, bit, idx, { + BitVecForeachIdx(&bv, bit, idx) { if (idx == 0 || idx == 2) { pattern_correct = pattern_correct && (bit == true); } else { pattern_correct = pattern_correct && (bit == false); } count++; - }); + } bool result = (count == 4) && pattern_correct; @@ -79,13 +79,13 @@ bool test_bitvec_foreach(void) { u64 true_count = 0; u64 false_count = 0; - BitVecForeach(&bv, bit, { + BitVecForeach(&bv, bit) { if (bit) { true_count++; } else { false_count++; } - }); + } bool result = (true_count == 2) && (false_count == 1); @@ -111,12 +111,12 @@ bool test_bitvec_foreach_reverse_idx(void) { u64 count = 0; bool first_bit_is_false = false; // Should be last bit when iterating in reverse - BitVecForeachReverseIdx(&bv, bit, idx, { + BitVecForeachReverseIdx(&bv, bit, idx) { if (count == 0) { first_bit_is_false = (bit == false) && (idx == 3); } count++; - }); + } bool result = (count == 4) && first_bit_is_false; @@ -141,12 +141,12 @@ bool test_bitvec_foreach_reverse(void) { u64 count = 0; bool first_is_true = false; // Should be the last bit (true) - BitVecForeachReverse(&bv, bit, { + BitVecForeachReverse(&bv, bit) { if (count == 0) { first_is_true = (bit == true); } count++; - }); + } bool result = (count == 3) && first_is_true; @@ -173,7 +173,7 @@ bool test_bitvec_foreach_in_range_idx(void) { u64 count = 0; bool range_correct = true; - BitVecForeachInRangeIdx(&bv, bit, idx, 1, 4, { + BitVecForeachInRangeIdx(&bv, bit, idx, 1, 4) { // Should iterate over indices 1, 2, 3 // Values: false, true, false if (idx == 1 || idx == 3) { @@ -182,7 +182,7 @@ bool test_bitvec_foreach_in_range_idx(void) { range_correct = range_correct && (bit == true); } count++; - }); + } bool result = (count == 3) && range_correct; @@ -209,7 +209,7 @@ bool test_bitvec_foreach_in_range(void) { u64 true_count = 0; u64 false_count = 0; - BitVecForeachInRange(&bv, bit, 1, 3, { + BitVecForeachInRange(&bv, bit, 1, 3) { // Should iterate over indices 1, 2 // Values: true, true if (bit) { @@ -217,7 +217,7 @@ bool test_bitvec_foreach_in_range(void) { } else { false_count++; } - }); + } bool result = (true_count == 2) && (false_count == 0); @@ -236,19 +236,19 @@ bool test_bitvec_foreach_edge_cases(void) { int count = 0; // Test foreach on empty bitvec - BitVecForeach(&bv, bit, { + BitVecForeach(&bv, bit) { (void)bit; count++; // Should not execute - }); + } result = result && (count == 0); // Test foreach on single element BitVecPush(&bv, true); count = 0; - BitVecForeach(&bv, bit, { + BitVecForeach(&bv, bit) { count++; result = result && (bit == true); - }); + } result = result && (count == 1); // Test foreach on large data @@ -258,10 +258,10 @@ bool test_bitvec_foreach_edge_cases(void) { } count = 0; - BitVecForeach(&bv, bit, { + BitVecForeach(&bv, bit) { (void)bit; count++; - }); + } result = result && (count == 1000); BitVecDeinit(&bv); @@ -276,18 +276,18 @@ bool test_bitvec_foreach_idx_edge_cases(void) { u64 last_idx = SIZE_MAX; // Test foreach idx on empty bitvec - BitVecForeachIdx(&bv, bit, idx, { + BitVecForeachIdx(&bv, bit, idx) { (void)bit; result = false; // Should not execute - }); + } // Test foreach idx on single element BitVecPush(&bv, false); - BitVecForeachIdx(&bv, bit, idx, { + BitVecForeachIdx(&bv, bit, idx) { result = result && (idx == 0); result = result && (bit == false); last_idx = idx; - }); + } result = result && (last_idx == 0); // Test foreach idx ordering @@ -297,11 +297,11 @@ bool test_bitvec_foreach_idx_edge_cases(void) { } u64 expected_idx = 0; - BitVecForeachIdx(&bv, bit, idx, { + BitVecForeachIdx(&bv, bit, idx) { (void)bit; result = result && (idx == expected_idx); expected_idx++; - }); + } BitVecDeinit(&bv); return result; @@ -314,18 +314,18 @@ bool test_bitvec_foreach_reverse_edge_cases(void) { bool result = true; // Test reverse foreach on empty bitvec - BitVecForeachReverse(&bv, bit, { + BitVecForeachReverse(&bv, bit) { (void)bit; result = false; // Should not execute - }); + } // Test reverse foreach on single element BitVecPush(&bv, true); int count = 0; - BitVecForeachReverse(&bv, bit, { + BitVecForeachReverse(&bv, bit) { count++; result = result && (bit == true); - }); + } result = result && (count == 1); // Test reverse ordering @@ -336,10 +336,10 @@ bool test_bitvec_foreach_reverse_edge_cases(void) { bool expected_sequence[] = {true, false, true}; // Reverse order int seq_idx = 0; - BitVecForeachReverse(&bv, bit, { + BitVecForeachReverse(&bv, bit) { result = result && (bit == expected_sequence[seq_idx]); seq_idx++; - }); + } BitVecDeinit(&bv); return result; @@ -358,34 +358,34 @@ bool test_bitvec_foreach_range_edge_cases(void) { // Test range with start == end (should not execute) int count = 0; - BitVecForeachInRange(&bv, bit, 5, 5, { + BitVecForeachInRange(&bv, bit, 5, 5) { (void)bit; count++; // Should not execute - }); + } result = result && (count == 0); // Test range with single element count = 0; - BitVecForeachInRange(&bv, bit, 3, 4, { + BitVecForeachInRange(&bv, bit, 3, 4) { count++; result = result && (bit == false); // 3 % 2 != 0 - }); + } result = result && (count == 1); // Test range at boundaries count = 0; - BitVecForeachInRange(&bv, bit, 0, 2, { + BitVecForeachInRange(&bv, bit, 0, 2) { (void)bit; count++; - }); + } result = result && (count == 2); // Test range at the end of bitvector count = 0; - BitVecForeachInRange(&bv, bit, 8, 10, { + BitVecForeachInRange(&bv, bit, 8, 10) { (void)bit; count++; - }); + } result = result && (count == 2); // Should iterate over indices 8,9 BitVecDeinit(&bv); @@ -408,22 +408,22 @@ bool test_bitvec_foreach_stress_test(void) { // Test all foreach variants int count1 = 0, count2 = 0, count3 = 0, count4 = 0; - BitVecForeach(&bv, bitval, { + BitVecForeach(&bv, bitval) { (void)bitval; count1++; - }); - BitVecForeachIdx(&bv, bitval, i, { + } + BitVecForeachIdx(&bv, bitval, i) { (void)bitval; count2++; - }); - BitVecForeachReverse(&bv, bitval, { + } + BitVecForeachReverse(&bv, bitval) { (void)bitval; count3++; - }); - BitVecForeachReverseIdx(&bv, bitval, i, { + } + BitVecForeachReverseIdx(&bv, bitval, i) { (void)bitval; count4++; - }); + } result = result && (count1 == sz); result = result && (count2 == sz); diff --git a/Tests/Std/BitVec.Foreach.c b/Tests/Std/BitVec.Foreach.c index d9e3349..f1a7df5 100644 --- a/Tests/Std/BitVec.Foreach.c +++ b/Tests/Std/BitVec.Foreach.c @@ -47,14 +47,14 @@ bool test_bitvec_foreach_idx(void) { u64 count = 0; bool pattern_correct = true; - BitVecForeachIdx(&bv, bit, idx, { + BitVecForeachIdx(&bv, bit, idx) { if (idx == 0 || idx == 2) { pattern_correct = pattern_correct && (bit == true); } else { pattern_correct = pattern_correct && (bit == false); } count++; - }); + } bool result = (count == 4) && pattern_correct; @@ -79,13 +79,13 @@ bool test_bitvec_foreach(void) { u64 true_count = 0; u64 false_count = 0; - BitVecForeach(&bv, bit, { + BitVecForeach(&bv, bit) { if (bit) { true_count++; } else { false_count++; } - }); + } bool result = (true_count == 2) && (false_count == 1); @@ -111,12 +111,12 @@ bool test_bitvec_foreach_reverse_idx(void) { u64 count = 0; bool first_bit_is_false = false; // Should be last bit when iterating in reverse - BitVecForeachReverseIdx(&bv, bit, idx, { + BitVecForeachReverseIdx(&bv, bit, idx) { if (count == 0) { first_bit_is_false = (bit == false) && (idx == 3); } count++; - }); + } bool result = (count == 4) && first_bit_is_false; @@ -141,12 +141,12 @@ bool test_bitvec_foreach_reverse(void) { u64 count = 0; bool first_is_true = false; // Should be the last bit (true) - BitVecForeachReverse(&bv, bit, { + BitVecForeachReverse(&bv, bit) { if (count == 0) { first_is_true = (bit == true); } count++; - }); + } bool result = (count == 3) && first_is_true; @@ -173,7 +173,7 @@ bool test_bitvec_foreach_in_range_idx(void) { u64 count = 0; bool range_correct = true; - BitVecForeachInRangeIdx(&bv, bit, idx, 1, 4, { + BitVecForeachInRangeIdx(&bv, bit, idx, 1, 4) { // Should iterate over indices 1, 2, 3 // Values: false, true, false if (idx == 1 || idx == 3) { @@ -182,7 +182,7 @@ bool test_bitvec_foreach_in_range_idx(void) { range_correct = range_correct && (bit == true); } count++; - }); + } bool result = (count == 3) && range_correct; @@ -209,7 +209,7 @@ bool test_bitvec_foreach_in_range(void) { u64 true_count = 0; u64 false_count = 0; - BitVecForeachInRange(&bv, bit, 1, 3, { + BitVecForeachInRange(&bv, bit, 1, 3) { // Should iterate over indices 1, 2 // Values: true, true if (bit) { @@ -217,7 +217,7 @@ bool test_bitvec_foreach_in_range(void) { } else { false_count++; } - }); + } bool result = (true_count == 2) && (false_count == 0); @@ -236,19 +236,19 @@ bool test_bitvec_foreach_edge_cases(void) { int count = 0; // Test foreach on empty bitvec - BitVecForeach(&bv, bit, { + BitVecForeach(&bv, bit) { (void)bit; count++; // Should not execute - }); + } result = result && (count == 0); // Test foreach on single element BitVecPush(&bv, true); count = 0; - BitVecForeach(&bv, bit, { + BitVecForeach(&bv, bit) { count++; result = result && (bit == true); - }); + } result = result && (count == 1); // Test foreach on large data @@ -258,10 +258,10 @@ bool test_bitvec_foreach_edge_cases(void) { } count = 0; - BitVecForeach(&bv, bit, { + BitVecForeach(&bv, bit) { (void)bit; count++; - }); + } result = result && (count == 1000); BitVecDeinit(&bv); @@ -276,18 +276,18 @@ bool test_bitvec_foreach_idx_edge_cases(void) { u64 last_idx = SIZE_MAX; // Test foreach idx on empty bitvec - BitVecForeachIdx(&bv, bit, idx, { + BitVecForeachIdx(&bv, bit, idx) { (void)bit; result = false; // Should not execute - }); + } // Test foreach idx on single element BitVecPush(&bv, false); - BitVecForeachIdx(&bv, bit, idx, { + BitVecForeachIdx(&bv, bit, idx) { result = result && (idx == 0); result = result && (bit == false); last_idx = idx; - }); + } result = result && (last_idx == 0); // Test foreach idx ordering @@ -297,11 +297,11 @@ bool test_bitvec_foreach_idx_edge_cases(void) { } u64 expected_idx = 0; - BitVecForeachIdx(&bv, bit, idx, { + BitVecForeachIdx(&bv, bit, idx) { (void)bit; result = result && (idx == expected_idx); expected_idx++; - }); + } BitVecDeinit(&bv); return result; @@ -314,18 +314,18 @@ bool test_bitvec_foreach_reverse_edge_cases(void) { bool result = true; // Test reverse foreach on empty bitvec - BitVecForeachReverse(&bv, bit, { + BitVecForeachReverse(&bv, bit) { (void)bit; result = false; // Should not execute - }); + } // Test reverse foreach on single element BitVecPush(&bv, true); int count = 0; - BitVecForeachReverse(&bv, bit, { + BitVecForeachReverse(&bv, bit) { count++; result = result && (bit == true); - }); + } result = result && (count == 1); // Test reverse ordering @@ -336,10 +336,10 @@ bool test_bitvec_foreach_reverse_edge_cases(void) { bool expected_sequence[] = {true, false, true}; // Reverse order int seq_idx = 0; - BitVecForeachReverse(&bv, bit, { + BitVecForeachReverse(&bv, bit) { result = result && (bit == expected_sequence[seq_idx]); seq_idx++; - }); + } BitVecDeinit(&bv); return result; @@ -358,34 +358,34 @@ bool test_bitvec_foreach_range_edge_cases(void) { // Test range with start == end (should not execute) int count = 0; - BitVecForeachInRange(&bv, bit, 5, 5, { + BitVecForeachInRange(&bv, bit, 5, 5) { (void)bit; count++; // Should not execute - }); + } result = result && (count == 0); // Test range with single element count = 0; - BitVecForeachInRange(&bv, bit, 3, 4, { + BitVecForeachInRange(&bv, bit, 3, 4) { count++; result = result && (bit == false); // 3 % 2 != 0 - }); + } result = result && (count == 1); // Test range at boundaries count = 0; - BitVecForeachInRange(&bv, bit, 0, 2, { + BitVecForeachInRange(&bv, bit, 0, 2) { (void)bit; count++; - }); + } result = result && (count == 2); // Test range at the end of bitvector count = 0; - BitVecForeachInRange(&bv, bit, 8, 10, { + BitVecForeachInRange(&bv, bit, 8, 10) { (void)bit; count++; - }); + } result = result && (count == 2); // Should iterate over indices 8,9 BitVecDeinit(&bv); @@ -408,22 +408,22 @@ bool test_bitvec_foreach_stress_test(void) { // Test all foreach variants int count1 = 0, count2 = 0, count3 = 0, count4 = 0; - BitVecForeach(&bv, bitval, { + BitVecForeach(&bv, bitval) { (void)bitval; count1++; - }); - BitVecForeachIdx(&bv, bitval, i, { + } + BitVecForeachIdx(&bv, bitval, i) { (void)bitval; count2++; - }); - BitVecForeachReverse(&bv, bitval, { + } + BitVecForeachReverse(&bv, bitval) { (void)bitval; count3++; - }); - BitVecForeachReverseIdx(&bv, bitval, i, { + } + BitVecForeachReverseIdx(&bv, bitval, i) { (void)bitval; count4++; - }); + } result = result && (count1 == sz); result = result && (count2 == sz); @@ -700,10 +700,10 @@ bool test_bitvec_foreach_invalid_usage(void) { // This should abort due to ValidateBitVec check int count = 0; - BitVecForeach(&bv, bit, { + BitVecForeach(&bv, bit) { (void)bit; count++; - }); + } // Should not reach here (void)count; // Silence unused variable warning diff --git a/Tests/Std/Str.Foreach.Deadend.c b/Tests/Std/Str.Foreach.Deadend.c deleted file mode 100644 index 28b0302..0000000 --- a/Tests/Std/Str.Foreach.Deadend.c +++ /dev/null @@ -1,237 +0,0 @@ -#include -#include -#include -#include // For LVAL macro - -// Include test utilities -#include "../Util/TestRunner.h" - -// Deadend test prototypes (tests that should crash due to out-of-bounds access) -bool test_str_foreach_out_of_bounds_access(void); -bool test_str_foreach_idx_out_of_bounds_access(void); -bool test_str_foreach_idx_basic_out_of_bounds_access(void); -bool test_str_foreach_reverse_idx_out_of_bounds_access(void); -bool test_str_foreach_ptr_idx_out_of_bounds_access(void); -bool test_str_foreach_reverse_ptr_idx_out_of_bounds_access(void); -bool test_str_foreach_ptr_in_range_idx_out_of_bounds_access(void); - -// Deadend test: Make idx go out of bounds in StrForeachInRangeIdx by shrinking string during iteration -bool test_str_foreach_out_of_bounds_access(void) { - WriteFmt("Testing StrForeachInRangeIdx where idx goes out of bounds (should crash)\n"); - - Str s = StrInitFromZstr("Hello World!"); // 12 characters - - // Use StrForeachInRangeIdx which captures the 'end' parameter at the start - // Even if we shrink the string, the loop will continue until idx reaches the fixed end - size original_length = s.length; // Capture this as 12 - StrForeachInRangeIdx(&s, chr, idx, 0, original_length, { - WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, s.length, chr); - - // When we reach idx=4, drastically shrink the string to length 3 - // But StrForeachInRangeIdx will continue until idx reaches original_length (12) - if (idx == 4) { - StrResize(&s, 3); // Shrink to only 3 characters - WriteFmt( - "String resized to length {}, but range iteration will continue to idx {}...\n", - s.length, - original_length - ); - } - - // When idx >= 3 (after resize), StrForeachInRangeIdx will detect: - // if ((idx) >= (v)->length) LOG_FATAL(...) - // This should cause a fatal error when idx >= s.length - }); - - // Should never reach here if idx goes out of bounds - StrDeinit(&s); - return false; -} - -// Deadend test: Make idx go out of bounds in StrForeachInRangeIdx by deleting characters -bool test_str_foreach_idx_out_of_bounds_access(void) { - WriteFmt("Testing StrForeachInRangeIdx with character deletion where idx goes out of bounds (should crash)\n"); - - Str s = StrInitFromZstr("Programming"); // 11 characters - - // Use StrForeachInRangeIdx with a fixed range that will become invalid - // when we delete characters during iteration - size original_length = s.length; // Capture this as 11 - StrForeachInRangeIdx(&s, chr, idx, 0, original_length, { - WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, s.length, chr); - - // When we reach idx=3, delete several characters from the beginning - // This will make the higher indices invalid - if (idx == 3) { - StrDeleteRange(&s, 0, 6); // Remove first 6 characters - WriteFmt( - "Deleted first 6 characters, new length={}, but range iteration will continue to idx {}...\n", - s.length, - original_length - ); - } - - // When idx >= 5 (after deletion), StrForeachInRangeIdx will detect: - // if ((idx) >= (v)->length) LOG_FATAL(...) - // This should cause a fatal error when idx >= s.length - }); - - // Should never reach here if bounds checking triggers - StrDeinit(&s); - return false; -} - -// Deadend test: Make idx go out of bounds in StrForeachReverseIdx by modifying string during iteration -bool test_str_foreach_reverse_idx_out_of_bounds_access(void) { - WriteFmt("Testing StrForeachReverseIdx where idx goes out of bounds (should crash)\n"); - - Str s = StrInitFromZstr("Beautiful Weather"); // 17 characters - - // StrForeachReverseIdx (VecForeachReverseIdx) has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) - StrForeachReverseIdx(&s, chr, idx, { - WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, s.length, chr); - - // When we reach idx=10, drastically shrink the string - // This will make subsequent iterations invalid since idx will still decrement - // but the string length is now smaller - if (idx == 10) { - StrResize(&s, 4); // Shrink to only 4 characters - WriteFmt("String resized to length {} during reverse iteration...\n", s.length); - } - - // When idx >= s.length, the bounds check will trigger: - // if ((idx) >= (v)->length) LOG_FATAL(...) - }); - - // Should never reach here if bounds checking triggers - StrDeinit(&s); - return false; -} - -// Deadend test: Make idx go out of bounds in StrForeachPtrIdx by modifying string during iteration -bool test_str_foreach_ptr_idx_out_of_bounds_access(void) { - WriteFmt("Testing StrForeachPtrIdx where idx goes out of bounds (should crash)\n"); - - Str s = StrInitFromZstr("Programming Test"); // 16 characters - - // StrForeachPtrIdx (VecForeachPtrIdx) has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) - StrForeachPtrIdx(&s, chr_ptr, idx, { - WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, s.length, *chr_ptr); - - // When we reach idx=4, delete most characters from the string - // This will make the current idx invalid after the body executes - if (idx == 4) { - StrResize(&s, 4); // Shrink to only 4 characters (valid indices: 0,1,2,3) - WriteFmt("String resized to length {}, current idx={} is now out of bounds...\n", s.length, idx); - } - - // When idx >= s.length, the bounds check will trigger: - // if ((idx) >= (v)->length) LOG_FATAL(...) - }); - - // Should never reach here if bounds checking triggers - StrDeinit(&s); - return false; -} - -// Deadend test: Make idx go out of bounds in StrForeachReversePtrIdx by modifying string during iteration -bool test_str_foreach_reverse_ptr_idx_out_of_bounds_access(void) { - WriteFmt("Testing StrForeachReversePtrIdx where idx goes out of bounds (should crash)\n"); - - Str s = StrInitFromZstr("Excellent Example"); // 17 characters - - // StrForeachReversePtrIdx (VecForeachPtrReverseIdx) has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) - StrForeachReversePtrIdx(&s, chr_ptr, idx, { - WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, s.length, *chr_ptr); - - // When we reach idx=12, shrink the string significantly - if (idx == 12) { - StrResize(&s, 5); // Shrink to only 5 characters - WriteFmt("String resized to length {} during reverse ptr iteration...\n", s.length); - } - - // When idx >= s.length, the bounds check will trigger: - // if ((idx) >= (v)->length) LOG_FATAL(...) - }); - - // Should never reach here if bounds checking triggers - StrDeinit(&s); - return false; -} - -// Deadend test: Make idx go out of bounds in StrForeachPtrInRangeIdx by modifying string during iteration -bool test_str_foreach_ptr_in_range_idx_out_of_bounds_access(void) { - WriteFmt("Testing StrForeachPtrInRangeIdx where idx goes out of bounds (should crash)\n"); - - Str s = StrInitFromZstr("Comprehensive Testing Framework"); // 32 characters - - // Use StrForeachPtrInRangeIdx with a fixed range that becomes invalid when we modify the string - size original_length = s.length; // Capture this as 32 - StrForeachPtrInRangeIdx(&s, chr_ptr, idx, 0, original_length, { - WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, s.length, *chr_ptr); - - // When we reach idx=8, delete several characters - if (idx == 8) { - StrDeleteRange(&s, 0, 20); // Remove first 20 characters - WriteFmt( - "Deleted first 20 characters, new length={}, but range ptr iteration continues to idx {}...\n", - s.length, - original_length - ); - } - - // When idx >= s.length, the bounds check will trigger: - // if ((idx) >= (v)->length) LOG_FATAL(...) - }); - - // Should never reach here if bounds checking triggers - StrDeinit(&s); - return false; -} - -// Deadend test: Make idx go out of bounds in basic StrForeachIdx by modifying string during iteration -bool test_str_foreach_idx_basic_out_of_bounds_access(void) { - WriteFmt("Testing basic StrForeachIdx where idx goes out of bounds (should crash)\n"); - - Str s = StrInitFromZstr("Testing Basic"); // 13 characters - - // Basic StrForeachIdx (VecForeachIdx) now has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) - StrForeachIdx(&s, chr, idx, { - WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, s.length, chr); - - // When we reach idx=3, drastically shrink the string - // This will make subsequent iterations invalid - if (idx == 3) { - StrResize(&s, 2); // Shrink to only 2 characters - WriteFmt("String resized to length {}, but basic foreach iteration continues...\n", s.length); - } - - // When idx >= s.length, the bounds check will trigger: - // if ((idx) >= (v)->length) LOG_FATAL(...) - }); - - // Should never reach here if bounds checking triggers - StrDeinit(&s); - return false; -} - -// Main function that runs all deadend tests -int main(void) { - WriteFmt("[INFO] Starting Str.Foreach.Deadend tests\n\n"); - - // Array of deadend test functions (tests that should crash) - TestFunction deadend_tests[] = { - test_str_foreach_out_of_bounds_access, - test_str_foreach_idx_out_of_bounds_access, - test_str_foreach_idx_basic_out_of_bounds_access, - test_str_foreach_reverse_idx_out_of_bounds_access, - test_str_foreach_ptr_idx_out_of_bounds_access, - test_str_foreach_reverse_ptr_idx_out_of_bounds_access, - test_str_foreach_ptr_in_range_idx_out_of_bounds_access - }; - - int deadend_count = sizeof(deadend_tests) / sizeof(deadend_tests[0]); - - // Run all deadend tests using the centralized test driver - return run_test_suite(NULL, 0, deadend_tests, deadend_count, "Str.Foreach.Deadend"); -} diff --git a/Tests/Std/Str.Foreach.Simple.c b/Tests/Std/Str.Foreach.c similarity index 51% rename from Tests/Std/Str.Foreach.Simple.c rename to Tests/Std/Str.Foreach.c index 1860d54..8208c6e 100644 --- a/Tests/Std/Str.Foreach.Simple.c +++ b/Tests/Std/Str.Foreach.c @@ -21,6 +21,14 @@ bool test_str_foreach_in_range(void); bool test_str_foreach_ptr_in_range_idx(void); bool test_str_foreach_ptr_in_range(void); +bool test_str_foreach_out_of_bounds_access(void); +bool test_str_foreach_idx_out_of_bounds_access(void); +bool test_str_foreach_idx_basic_out_of_bounds_access(void); +bool test_str_foreach_reverse_idx_out_of_bounds_access(void); +bool test_str_foreach_ptr_idx_out_of_bounds_access(void); +bool test_str_foreach_reverse_ptr_idx_out_of_bounds_access(void); +bool test_str_foreach_ptr_in_range_idx_out_of_bounds_access(void); + // Test StrForeachIdx macro bool test_str_foreach_idx(void) { WriteFmt("Testing StrForeachIdx\n"); @@ -29,7 +37,9 @@ bool test_str_foreach_idx(void) { // Build a new string by iterating through each character with its index Str result = StrInit(); - StrForeachIdx(&s, chr, idx, { StrWriteFmt(&result, "{c}{}", chr, idx); }); + StrForeachIdx(&s, chr, idx) { + StrWriteFmt(&result, "{c}{}", chr, idx); + } // The result should be "H0e1l2l3o4" bool success = (ZstrCompare(result.data, "H0e1l2l3o4") == 0); @@ -46,30 +56,16 @@ bool test_str_foreach_reverse_idx(void) { Str s = StrInitFromZstr("Hello"); // Build a new string by iterating through each character in reverse with its index - Str result = StrInit(); - bool saw_index_zero = false; - - StrForeachReverseIdx(&s, chr, idx, { - // Check if we see index 0 - if (idx == 0) { - saw_index_zero = true; - } + Str result = StrInit(); + StrForeachReverseIdx(&s, chr, idx) { // Append the character and its index to the result string StrWriteFmt(&result, "{c}{}", chr, idx); - }); - - // The expected result depends on whether index 0 is processed - bool success = false; - if (saw_index_zero) { - // The test output shows index 0 is processed, but the order is different than expected - success = (ZstrCompare(result.data, "o4l3l2e1H0") == 0); - WriteFmt(" (Index 0 was processed)\n"); - } else { - success = (ZstrCompare(result.data, "o4l3l2e1") == 0); - WriteFmt(" (Index 0 was NOT processed - bug in macro)\n"); } + bool success = (ZstrCompare(result.data, "o4l3l2e1H0") == 0); + WriteFmt(" (Index 0 was processed)\n"); + StrDeinit(&s); StrDeinit(&result); return success; @@ -83,7 +79,7 @@ bool test_str_foreach_ptr_idx(void) { // Build a new string by iterating through each character pointer with its index Str result = StrInit(); - StrForeachPtrIdx(&s, chrptr, idx, { + StrForeachPtrIdx(&s, chrptr, idx) { // Append the character (via pointer) and its index to the result string StrWriteFmt(&result, "{c}{}", *chrptr, idx); @@ -91,7 +87,7 @@ bool test_str_foreach_ptr_idx(void) { if (*chrptr >= 'a' && *chrptr <= 'z') { *chrptr = *chrptr - 'a' + 'A'; } - }); + } // The result should be "H0e1l2l3o4" bool success = (ZstrCompare(result.data, "H0e1l2l3o4") == 0); @@ -111,15 +107,9 @@ bool test_str_foreach_reverse_ptr_idx(void) { Str s = StrInitFromZstr("Hello"); // Build a new string by iterating through each character pointer in reverse with its index - Str result = StrInit(); - bool saw_index_zero = false; - - StrForeachReversePtrIdx(&s, chrptr, idx, { - // Check if we see index 0 - if (idx == 0) { - saw_index_zero = true; - } + Str result = StrInit(); + StrForeachReversePtrIdx(&s, chrptr, idx) { // Append the character (via pointer) and its index to the result string StrWriteFmt(&result, "{c}{}", *chrptr, idx); @@ -127,20 +117,12 @@ bool test_str_foreach_reverse_ptr_idx(void) { if (*chrptr >= 'a' && *chrptr <= 'z') { *chrptr = *chrptr - 'a' + 'A'; } - }); + } - // The expected result depends on whether index 0 is processed bool success = false; - if (saw_index_zero) { - // The test output shows index 0 is processed, but the order is different than expected - success = (ZstrCompare(result.data, "o4l3l2e1H0") == 0); - success = success && (ZstrCompare(s.data, "HELLO") == 0); // All uppercase - WriteFmt(" (Index 0 was processed)\n"); - } else { - success = (ZstrCompare(result.data, "o4l3l2e1") == 0); - success = success && (ZstrCompare(s.data, "HELLo") == 0); // All uppercase except first char - WriteFmt(" (Index 0 was NOT processed - bug in macro)\n"); - } + success = (ZstrCompare(result.data, "o4l3l2e1H0") == 0); + success = success && (ZstrCompare(s.data, "HELLO") == 0); // All uppercase + WriteFmt(" (Index 0 was processed)\n"); StrDeinit(&s); StrDeinit(&result); @@ -155,10 +137,10 @@ bool test_str_foreach(void) { // Build a new string by iterating through each character Str result = StrInit(); - StrForeach(&s, chr, { + StrForeach(&s, chr) { // Append the character to the result string StrPushBack(&result, chr); - }); + } // The result should be "Hello" bool success = (ZstrCompare(result.data, "Hello") == 0); @@ -178,11 +160,11 @@ bool test_str_foreach_reverse(void) { Str result = StrInit(); size char_count = 0; - StrForeachReverse(&s, chr, { + StrForeachReverse(&s, chr) { // Append the character to the result string StrPushBack(&result, chr); char_count++; - }); + } // The expected result depends on whether all characters are processed bool success = false; @@ -207,7 +189,7 @@ bool test_str_foreach_ptr(void) { // Build a new string by iterating through each character pointer Str result = StrInit(); - StrForeachPtr(&s, chrptr, { + StrForeachPtr(&s, chrptr) { // Append the character (via pointer) to the result string StrPushBack(&result, *chrptr); @@ -215,7 +197,7 @@ bool test_str_foreach_ptr(void) { if (*chrptr >= 'a' && *chrptr <= 'z') { *chrptr = *chrptr - 'a' + 'A'; } - }); + } // The result should be "Hello" (original values before modification) bool success = (ZstrCompare(result.data, "Hello") == 0); @@ -238,7 +220,7 @@ bool test_str_foreach_ptr_reverse(void) { Str result = StrInit(); size char_count = 0; - StrForeachPtrReverse(&s, chrptr, { + StrForeachPtrReverse(&s, chrptr) { // Append the character (via pointer) to the result string StrPushBack(&result, *chrptr); @@ -248,7 +230,7 @@ bool test_str_foreach_ptr_reverse(void) { } char_count++; - }); + } // The expected result depends on whether all characters are processed bool success = false; @@ -275,20 +257,20 @@ bool test_str_foreach_in_range_idx(void) { // Build a new string by iterating through a range of characters with indices Str result = StrInit(); - StrForeachInRangeIdx(&s, chr, idx, 6, 11, { + StrForeachInRangeIdx(&s, chr, idx, 6, 11) { // Append the character and its index to the result string StrWriteFmt(&result, "{c}{}", chr, idx); - }); + } // The result should be "W6o7r8l9d10" (characters from index 6-10 with their indices) bool success = (ZstrCompare(result.data, "W6o7r8l9d10") == 0); // Test with empty range Str empty_result = StrInit(); - StrForeachInRangeIdx(&s, chr, idx, 3, 3, { + StrForeachInRangeIdx(&s, chr, idx, 3, 3) { // This block should not execute StrPushBack(&empty_result, chr); - }); + } // The empty_result should remain empty success = success && (empty_result.length == 0); @@ -307,20 +289,20 @@ bool test_str_foreach_in_range(void) { // Build a new string by iterating through a range of characters Str result = StrInit(); - StrForeachInRange(&s, chr, 0, 5, { + StrForeachInRange(&s, chr, 0, 5) { // Append the character to the result string StrPushBack(&result, chr); - }); + } // The result should be "Hello" (first 5 characters) bool success = (ZstrCompare(result.data, "Hello") == 0); // Test with range at the end of the string Str end_result = StrInit(); - StrForeachInRange(&s, chr, 6, 11, { + StrForeachInRange(&s, chr, 6, 11) { // Append the character to the result string StrPushBack(&end_result, chr); - }); + } // The end_result should be "World" (last 5 characters) success = success && (ZstrCompare(end_result.data, "World") == 0); @@ -339,7 +321,7 @@ bool test_str_foreach_ptr_in_range_idx(void) { // Build a new string by iterating through a range of character pointers with indices Str result = StrInit(); - StrForeachPtrInRangeIdx(&s, chrptr, idx, 6, 11, { + StrForeachPtrInRangeIdx(&s, chrptr, idx, 6, 11) { // Append the character and its index to the result string StrWriteFmt(&result, "{c}{}", *chrptr, idx); @@ -347,7 +329,7 @@ bool test_str_foreach_ptr_in_range_idx(void) { if (*chrptr >= 'a' && *chrptr <= 'z') { *chrptr = *chrptr - 'a' + 'A'; } - }); + } // The result should be "W6o7r8l9d10" (characters from index 6-10 with their indices) bool success = (ZstrCompare(result.data, "W6o7r8l9d10") == 0); @@ -368,7 +350,7 @@ bool test_str_foreach_ptr_in_range(void) { // Build a new string by iterating through a range of character pointers Str result = StrInit(); - StrForeachPtrInRange(&s, chrptr, 0, 5, { + StrForeachPtrInRange(&s, chrptr, 0, 5) { // Append the character to the result string StrPushBack(&result, *chrptr); @@ -376,7 +358,7 @@ bool test_str_foreach_ptr_in_range(void) { if (*chrptr >= 'a' && *chrptr <= 'z') { *chrptr = *chrptr - 'a' + 'A'; } - }); + } // The result should be "Hello" (first 5 characters) bool success = (ZstrCompare(result.data, "Hello") == 0); @@ -389,6 +371,226 @@ bool test_str_foreach_ptr_in_range(void) { return success; } +// Make idx go out of bounds in StrForeachInRangeIdx by shrinking string during iteration +bool test_str_foreach_out_of_bounds_access(void) { + WriteFmt("Testing StrForeachInRangeIdx where idx goes out of bounds\n"); + + Str s = StrInitFromZstr("Hello World!"); // 12 characters + + // Use StrForeachInRangeIdx which captures the 'end' parameter at the start + // Even if we shrink the string, the loop will continue until idx reaches the fixed end + size original_length = s.length; // Capture this as 12 + StrForeachInRangeIdx(&s, chr, idx, 0, original_length) { + WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, s.length, chr); + + // When we reach idx=4, drastically shrink the string to length 3 + // But StrForeachInRangeIdx will continue until idx reaches original_length (12) + if (idx == 4) { + StrResize(&s, 3); // Shrink to only 3 characters + WriteFmt("String resized to length {}, idx={}...\n", s.length, idx); + } + + // When idx >= 3 (after resize), StrForeachInRangeIdx will detect: + // loop will automatically terminate + + if (idx > 4) { + LOG_ERROR("Should've terminated"); + StrDeinit(&s); + return false; + } + } + + StrDeinit(&s); + return true; +} + +// Make idx go out of bounds in StrForeachInRangeIdx by deleting characters +bool test_str_foreach_idx_out_of_bounds_access(void) { + WriteFmt("Testing StrForeachInRangeIdx with character deletion where idx goes out of bounds\n"); + + Str s = StrInitFromZstr("Programming"); // 11 characters + + // Use StrForeachInRangeIdx with a fixed range that will become invalid + // when we delete characters during iteration + size original_length = s.length; // Capture this as 11 + StrForeachInRangeIdx(&s, chr, idx, 0, original_length) { + WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, s.length, chr); + + // When we reach idx=3, delete several characters from the beginning + // This will make the higher indices invalid + if (idx == 3) { + StrDeleteRange(&s, 0, 6); // Remove first 6 characters + WriteFmt("Deleted first 6 characters, new length={}, idx={}...\n", s.length, idx); + } + + // When idx >= 5 (after deletion), StrForeachInRangeIdx will detect: + // loop will automatically terminate + + if (idx >= 5) { + LOG_ERROR("Should've terminated"); + StrDeinit(&s); + return false; + } + } + + StrDeinit(&s); + return true; +} + +// Make idx go out of bounds in StrForeachReverseIdx by modifying string during iteration +bool test_str_foreach_reverse_idx_out_of_bounds_access(void) { + WriteFmt("Testing StrForeachReverseIdx where idx goes out of bounds\n"); + + Str s = StrInitFromZstr("Beautiful Weather"); // 17 characters + + // StrForeachReverseIdx (VecForeachReverseIdx) has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) + StrForeachReverseIdx(&s, chr, idx) { + WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, s.length, chr); + + // When we reach idx=10, drastically shrink the string + // This will make subsequent iterations invalid since idx will still decrement + // but the string length is now smaller + if (idx == 10) { + StrResize(&s, 4); // Shrink to only 4 characters + WriteFmt("String resized to length {} during reverse iteration... idx = {}\n", s.length, idx); + } + + // When idx < 10, the bounds check will trigger: + // loop will automatically terminate + if (idx < 10) { + LOG_ERROR("Should've terminated"); + StrDeinit(&s); + return false; + } + } + + StrDeinit(&s); + return true; +} + +// Make idx go out of bounds in StrForeachPtrIdx by modifying string during iteration +bool test_str_foreach_ptr_idx_out_of_bounds_access(void) { + WriteFmt("Testing StrForeachPtrIdx where idx goes out of bounds\n"); + + Str s = StrInitFromZstr("Programming Test"); // 16 characters + + // StrForeachPtrIdx (VecForeachPtrIdx) has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) + StrForeachPtrIdx(&s, chr_ptr, idx) { + WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, s.length, *chr_ptr); + + // When we reach idx=4, delete most characters from the string + // This will make the current idx invalid after the body executes + if (idx == 4) { + StrResize(&s, 4); // Shrink to only 4 characters (valid indices: 0,1,2,3) + WriteFmt("String resized to length {}, current idx={} is now out of bounds...\n", s.length, idx); + } + + // When idx >= s.length, the bounds check will trigger: + // loop will automatically terminate + + if (idx > 4) { + LOG_ERROR("Should've terminated"); + StrDeinit(&s); + return false; + } + } + + StrDeinit(&s); + return true; +} + +// Make idx go out of bounds in StrForeachReversePtrIdx by modifying string during iteration +bool test_str_foreach_reverse_ptr_idx_out_of_bounds_access(void) { + WriteFmt("Testing StrForeachReversePtrIdx where idx goes out of bounds\n"); + + Str s = StrInitFromZstr("Excellent Example"); // 17 characters + + // StrForeachReversePtrIdx (VecForeachPtrReverseIdx) has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) + StrForeachReversePtrIdx(&s, chr_ptr, idx) { + WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, s.length, *chr_ptr); + + // When we reach idx=12, shrink the string significantly + if (idx == 12) { + StrResize(&s, 5); // Shrink to only 5 characters + WriteFmt("String resized to length {} during reverse ptr iteration... idx = {}\n", s.length, idx); + } + + // When idx < 12, the bounds check will trigger: + // loop will terminate automatically + + if (idx < 12) { + LOG_ERROR("Should've terminated"); + StrDeinit(&s); + return false; + } + } + + StrDeinit(&s); + return true; +} + +// Make idx go out of bounds in StrForeachPtrInRangeIdx by modifying string during iteration +bool test_str_foreach_ptr_in_range_idx_out_of_bounds_access(void) { + WriteFmt("Testing StrForeachPtrInRangeIdx where idx goes out of bounds\n"); + + Str s = StrInitFromZstr("Comprehensive Testing Framework"); // 31 characters + + // Use StrForeachPtrInRangeIdx with a fixed range that becomes invalid when we modify the string + size original_length = s.length; // Capture this as 32 + StrForeachPtrInRangeIdx(&s, chr_ptr, idx, 0, original_length) { + WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, s.length, *chr_ptr); + + // When we reach idx=8, delete several characters + if (idx == 8) { + StrDeleteRange(&s, 0, 20); // Remove first 20 characters + WriteFmt("Deleted first 20 characters, new length={}, idx = {}...\n", s.length, idx); + } + + // When idx >= s.length, the bounds check will trigger: + // loop will terminate automatically + + if (idx >= s.length) { + LOG_ERROR("Should've terminated"); + StrDeinit(&s); + return false; + } + } + + StrDeinit(&s); + return true; +} + +// Make idx go out of bounds in basic StrForeachIdx by modifying string during iteration +bool test_str_foreach_idx_basic_out_of_bounds_access(void) { + WriteFmt("Testing basic StrForeachIdx where idx goes out of bounds\n"); + + Str s = StrInitFromZstr("Testing Basic"); // 13 characters + + // Basic StrForeachIdx (VecForeachIdx) now has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) + StrForeachIdx(&s, chr, idx) { + WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, s.length, chr); + + // When we reach idx=3, drastically shrink the string + // This will make subsequent iterations invalid + if (idx == 3) { + StrResize(&s, 2); // Shrink to only 2 characters + WriteFmt("String resized to length {}, but basic foreach iteration continues... idx = {}\n", s.length, idx); + } + + // When idx >= s.length, the bounds check will trigger: + // loop will terminate automatically + + if (idx > 3) { + LOG_ERROR("Should've terminated"); + StrDeinit(&s); + return false; + } + } + + StrDeinit(&s); + return true; +} + // Main function that runs all tests int main(void) { WriteFmt("[INFO] Starting Str.Foreach.Simple tests\n\n"); @@ -406,7 +608,15 @@ int main(void) { test_str_foreach_in_range_idx, test_str_foreach_in_range, test_str_foreach_ptr_in_range_idx, - test_str_foreach_ptr_in_range + test_str_foreach_ptr_in_range, + + test_str_foreach_out_of_bounds_access, + test_str_foreach_idx_out_of_bounds_access, + test_str_foreach_idx_basic_out_of_bounds_access, + test_str_foreach_reverse_idx_out_of_bounds_access, + test_str_foreach_ptr_idx_out_of_bounds_access, + test_str_foreach_reverse_ptr_idx_out_of_bounds_access, + test_str_foreach_ptr_in_range_idx_out_of_bounds_access }; int total_tests = sizeof(tests) / sizeof(tests[0]); diff --git a/Tests/Std/Vec.Foreach.Deadend.c b/Tests/Std/Vec.Foreach.Deadend.c deleted file mode 100644 index 3ff1da6..0000000 --- a/Tests/Std/Vec.Foreach.Deadend.c +++ /dev/null @@ -1,266 +0,0 @@ -#include -#include - -#include -#include // For LVAL macro - -// Include test utilities -#include "../Util/TestRunner.h" - -// Deadend test prototypes (tests that should crash due to out-of-bounds access) -bool test_vec_foreach_out_of_bounds_access(void); -bool test_vec_foreach_idx_out_of_bounds_access(void); -bool test_vec_foreach_idx_basic_out_of_bounds_access(void); -bool test_vec_foreach_reverse_idx_out_of_bounds_access(void); -bool test_vec_foreach_ptr_idx_out_of_bounds_access(void); -bool test_vec_foreach_ptr_reverse_idx_out_of_bounds_access(void); -bool test_vec_foreach_ptr_in_range_idx_out_of_bounds_access(void); - -// Deadend test: Make idx go out of bounds during VecForeach by modifying vector during iteration -bool test_vec_foreach_out_of_bounds_access(void) { - WriteFmt("Testing VecForeach where modification causes out of bounds access (should crash)\n"); - - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add some elements - for (int i = 0; i < 5; i++) { - VecPushBackR(&vec, i * 10); - } - - // VecForeach doesn't use an explicit index but we can still cause issues - int iteration_count = 0; - VecForeach(&vec, val, { - WriteFmt("Iteration {} (vec.length={}): {}\n", iteration_count, vec.length, val); - - // After 2nd iteration, shrink the vector dramatically - if (iteration_count == 2) { - VecResize(&vec, 2); // Shrink to only 2 elements - WriteFmt("Vector resized to length {} during foreach iteration...\n", vec.length); - } - iteration_count++; - - // This will eventually cause bounds checking to trigger - }); - - // Should never reach here if bounds checking triggers - VecDeinit(&vec); - return false; -} - -// Deadend test: Make idx go out of bounds in VecForeachIdx by modifying vector during iteration -bool test_vec_foreach_idx_out_of_bounds_access(void) { - WriteFmt("Testing VecForeachIdx where idx goes out of bounds (should crash)\n"); - - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add some elements - for (int i = 0; i < 6; i++) { - VecPushBackR(&vec, i * 20); - } - - // VecForeachIdx has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) - VecForeachIdx(&vec, val, idx, { - WriteFmt("Accessing idx {} (vec.length={}): {}\n", idx, vec.length, val); - - // When we reach idx=2, drastically shrink the vector to make the current idx invalid - // The bounds check happens after the body, so it will check if idx=2 >= new_length - if (idx == 2) { - VecResize(&vec, 2); // Shrink so that idx=2 becomes out of bounds (valid indices: 0,1) - WriteFmt("Vector resized to length {}, current idx={} is now out of bounds...\n", vec.length, idx); - } - - // When idx >= vec.length, the bounds check will trigger: - // if ((idx) >= (v)->length) LOG_FATAL(...) - }); - - // Should never reach here if bounds checking triggers - VecDeinit(&vec); - return false; -} - -// Deadend test: Make idx go out of bounds in VecForeachReverseIdx by modifying vector during iteration -bool test_vec_foreach_reverse_idx_out_of_bounds_access(void) { - WriteFmt("Testing VecForeachReverseIdx where idx goes out of bounds (should crash)\n"); - - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add several elements - for (int i = 0; i < 6; i++) { - VecPushBackR(&vec, i * 15); - } - - // VecForeachReverseIdx has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) - VecForeachReverseIdx(&vec, val, idx, { - WriteFmt("Accessing idx {} (vec.length={}): {}\n", idx, vec.length, val); - - // When we reach idx=3, drastically shrink the vector - // This will make subsequent iterations invalid since idx will still decrement - // but the vector length is now smaller - if (idx == 3) { - VecResize(&vec, 2); // Shrink to only 2 elements - WriteFmt("Vector resized to length {} during reverse iteration...\n", vec.length); - } - - // When idx >= vec.length, the bounds check will trigger: - // if ((idx) >= (v)->length) LOG_FATAL(...) - }); - - // Should never reach here if bounds checking triggers - VecDeinit(&vec); - return false; -} - -// Deadend test: Make idx go out of bounds in VecForeachPtrIdx by modifying vector during iteration -bool test_vec_foreach_ptr_idx_out_of_bounds_access(void) { - WriteFmt("Testing VecForeachPtrIdx where idx goes out of bounds (should crash)\n"); - - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add several elements - for (int i = 0; i < 7; i++) { - VecPushBackR(&vec, i * 25); - } - - // VecForeachPtrIdx has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) - VecForeachPtrIdx(&vec, val_ptr, idx, { - WriteFmt("Accessing idx {} (vec.length={}): {}\n", idx, vec.length, *val_ptr); - - // When we reach idx=3, shrink the vector to make the CURRENT idx invalid - // The bounds check happens after the body, so it will check if idx=3 >= new_length - if (idx == 3) { - VecResize(&vec, 3); // Shrink so that idx=3 becomes out of bounds (valid indices: 0,1,2) - WriteFmt("Vector resized to length {}, current idx={} is now out of bounds...\n", vec.length, idx); - } - - // When idx >= vec.length, the bounds check will trigger: - // if ((idx) >= (v)->length) LOG_FATAL(...) - }); - - // Should never reach here if bounds checking triggers - VecDeinit(&vec); - return false; -} - -// Deadend test: Make idx go out of bounds in VecForeachPtrReverseIdx by modifying vector during iteration -bool test_vec_foreach_ptr_reverse_idx_out_of_bounds_access(void) { - WriteFmt("Testing VecForeachPtrReverseIdx where idx goes out of bounds (should crash)\n"); - - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add several elements - for (int i = 0; i < 8; i++) { - VecPushBackR(&vec, i * 35); - } - - // VecForeachPtrReverseIdx has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) - VecForeachPtrReverseIdx(&vec, val_ptr, idx, { - WriteFmt("Accessing idx {} (vec.length={}): {}\n", idx, vec.length, *val_ptr); - - // When we reach idx=5, shrink the vector significantly - if (idx == 5) { - VecResize(&vec, 3); // Shrink to only 3 elements - WriteFmt("Vector resized to length {} during reverse ptr iteration...\n", vec.length); - } - - // When idx >= vec.length, the bounds check will trigger: - // if ((idx) >= (v)->length) LOG_FATAL(...) - }); - - // Should never reach here if bounds checking triggers - VecDeinit(&vec); - return false; -} - -// Deadend test: Make idx go out of bounds in VecForeachPtrInRangeIdx by modifying vector during iteration -bool test_vec_foreach_ptr_in_range_idx_out_of_bounds_access(void) { - WriteFmt("Testing VecForeachPtrInRangeIdx where idx goes out of bounds (should crash)\n"); - - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add several elements - for (int i = 0; i < 9; i++) { - VecPushBackR(&vec, i * 45); - } - - // Use VecForeachPtrInRangeIdx with a fixed range that becomes invalid when we modify the vector - size original_length = vec.length; // Capture this as 9 - VecForeachPtrInRangeIdx(&vec, val_ptr, idx, 0, original_length, { - WriteFmt("Accessing idx {} (vec.length={}): {}\n", idx, vec.length, *val_ptr); - - // When we reach idx=3, delete several elements - if (idx == 3) { - VecDeleteRange(&vec, 0, 6); // Remove first 6 elements - WriteFmt( - "Deleted first 6 elements, new length={}, but range ptr iteration continues to idx {}...\n", - vec.length, - original_length - ); - } - - // When idx >= vec.length, the bounds check will trigger: - // if ((idx) >= (v)->length) LOG_FATAL(...) - }); - - // Should never reach here if bounds checking triggers - VecDeinit(&vec); - return false; -} - -// Deadend test: Make idx go out of bounds in basic VecForeachIdx by modifying vector during iteration -bool test_vec_foreach_idx_basic_out_of_bounds_access(void) { - WriteFmt("Testing basic VecForeachIdx where idx goes out of bounds (should crash)\n"); - - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add several elements - for (int i = 0; i < 5; i++) { - VecPushBackR(&vec, i * 30); - } - - // Basic VecForeachIdx now has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) - VecForeachIdx(&vec, val, idx, { - WriteFmt("Accessing idx {} (vec.length={}): {}\n", idx, vec.length, val); - - // When we reach idx=2, drastically shrink the vector - // This will make subsequent iterations invalid - if (idx == 2) { - VecResize(&vec, 1); // Shrink to only 1 element - WriteFmt("Vector resized to length {}, but basic foreach iteration continues...\n", vec.length); - } - - // When idx >= vec.length, the bounds check will trigger: - // if ((idx) >= (v)->length) LOG_FATAL(...) - }); - - // Should never reach here if bounds checking triggers - VecDeinit(&vec); - return false; -} - -// Main function that runs all deadend tests -int main(void) { - WriteFmt("[INFO] Starting Vec.Foreach.Deadend tests\n\n"); - - // Array of deadend test functions (tests that should crash) - TestFunction deadend_tests[] = { - test_vec_foreach_out_of_bounds_access, - test_vec_foreach_idx_out_of_bounds_access, - test_vec_foreach_idx_basic_out_of_bounds_access, - test_vec_foreach_reverse_idx_out_of_bounds_access, - test_vec_foreach_ptr_idx_out_of_bounds_access, - test_vec_foreach_ptr_reverse_idx_out_of_bounds_access, - test_vec_foreach_ptr_in_range_idx_out_of_bounds_access - }; - - int deadend_count = sizeof(deadend_tests) / sizeof(deadend_tests[0]); - - // Run all deadend tests using the centralized test driver - return run_test_suite(NULL, 0, deadend_tests, deadend_count, "Vec.Foreach.Deadend"); -} diff --git a/Tests/Std/Vec.Foreach.Simple.c b/Tests/Std/Vec.Foreach.Simple.c deleted file mode 100644 index fd25d93..0000000 --- a/Tests/Std/Vec.Foreach.Simple.c +++ /dev/null @@ -1,296 +0,0 @@ -#include -#include - -#include -#include // For LVAL macro - -// Include test utilities -#include "../Util/TestRunner.h" - -// Function prototypes -bool test_vec_foreach(void); -bool test_vec_foreach_idx(void); -bool test_vec_foreach_ptr(void); -bool test_vec_foreach_ptr_idx(void); -bool test_vec_foreach_reverse(void); -bool test_vec_foreach_reverse_idx(void); -bool test_vec_foreach_ptr_reverse(void); -bool test_vec_foreach_ptr_reverse_idx(void); - -// Test VecForeach macro -bool test_vec_foreach(void) { - WriteFmt("Testing VecForeach\n"); - - // Create a vector of integers - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add some data - int values[] = {10, 20, 30, 40, 50}; - for (int i = 0; i < 5; i++) { - VecPushBackR(&vec, values[i]); - } - - // Use VecForeach to sum the values - int sum = 0; - VecForeach(&vec, item, { sum += item; }); - - // Check the sum - bool result = (sum == 150); // 10 + 20 + 30 + 40 + 50 = 150 - - // Use VecForeach to double each value - VecForeach(&vec, item, { item *= 2; }); - - // Check that the values in the vector are unchanged (foreach uses value, not reference) - for (size i = 0; i < vec.length; i++) { - result = result && (VecAt(&vec, i) == values[i]); - } - - // Clean up - VecDeinit(&vec); - - return result; -} - -// Test VecForeachIdx macro -bool test_vec_foreach_idx(void) { - WriteFmt("Testing VecForeachIdx\n"); - - // Create a vector of integers - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add some data - int values[] = {10, 20, 30, 40, 50}; - for (int i = 0; i < 5; i++) { - VecPushBackR(&vec, values[i]); - } - - // Use VecForeachIdx to verify indices and values - bool result = true; - VecForeachIdx(&vec, item, idx, { result = result && (item == values[idx]); }); - - // Use VecForeachIdx to calculate weighted sum (value * index) - int weighted_sum = 0; - VecForeachIdx(&vec, item, idx, { weighted_sum += item * idx; }); - - // Check the weighted sum - // 10*0 + 20*1 + 30*2 + 40*3 + 50*4 = 0 + 20 + 60 + 120 + 200 = 400 - result = result && (weighted_sum == 400); - - // Clean up - VecDeinit(&vec); - - return result; -} - -// Test VecForeachPtr macro -bool test_vec_foreach_ptr(void) { - WriteFmt("Testing VecForeachPtr\n"); - - // Create a vector of integers - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add some data - int values[] = {10, 20, 30, 40, 50}; - for (int i = 0; i < 5; i++) { - VecPushBackR(&vec, values[i]); - } - - // Use VecForeachPtr to modify the values in the vector - VecForeachPtr(&vec, item_ptr, { *item_ptr *= 2; }); - - // Check that the values in the vector are doubled - bool result = true; - for (size i = 0; i < vec.length; i++) { - result = result && (VecAt(&vec, i) == values[i] * 2); - } - - // Use VecForeachPtr to calculate sum - int sum = 0; - VecForeachPtr(&vec, item_ptr, { sum += *item_ptr; }); - - // Check the sum (should be doubled values) - // 20 + 40 + 60 + 80 + 100 = 300 - result = result && (sum == 300); - - // Clean up - VecDeinit(&vec); - - return result; -} - -// Test VecForeachPtrIdx macro -bool test_vec_foreach_ptr_idx(void) { - WriteFmt("Testing VecForeachPtrIdx\n"); - - // Create a vector of integers - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add some data - int values[] = {10, 20, 30, 40, 50}; - for (int i = 0; i < 5; i++) { - VecPushBackR(&vec, values[i]); - } - - // Use VecForeachPtrIdx to set each value to its index - VecForeachPtrIdx(&vec, item_ptr, idx, { *item_ptr = idx; }); - - // Check that the values in the vector are set to their indices - bool result = true; - for (size i = 0; i < vec.length; i++) { - result = result && (VecAt(&vec, i) == i); - } - - // Clean up - VecDeinit(&vec); - - return result; -} - -// Test VecForeachReverse macro -bool test_vec_foreach_reverse(void) { - WriteFmt("Testing VecForeachReverse\n"); - - // Create a vector of integers - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add some data - int values[] = {10, 20, 30, 40, 50}; - for (int i = 0; i < 5; i++) { - VecPushBackR(&vec, values[i]); - } - - // Use VecForeachReverse to build a reversed array - int reversed[5] = {0}; - int idx = 0; - VecForeachReverse(&vec, item, { reversed[idx++] = item; }); - - // Check that the reversed array is correct - bool result = true; - for (int i = 0; i < 5; i++) { - result = result && (reversed[i] == values[4 - i]); - } - - // Clean up - VecDeinit(&vec); - - return result; -} - -// Test VecForeachReverseIdx macro -bool test_vec_foreach_reverse_idx(void) { - WriteFmt("Testing VecForeachReverseIdx\n"); - - // Create a vector of integers - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add some data - int values[] = {10, 20, 30, 40, 50}; - for (int i = 0; i < 5; i++) { - VecPushBackR(&vec, values[i]); - } - - // Use VecForeachReverseIdx to verify indices are correct in reverse - bool result = true; - VecForeachReverseIdx(&vec, item, idx, { - result = result && (item == values[idx]); - result = result && (VecAt(&vec, idx) == item); - }); - - // Clean up - VecDeinit(&vec); - - return result; -} - -// Test VecForeachPtrReverse macro -bool test_vec_foreach_ptr_reverse(void) { - WriteFmt("Testing VecForeachPtrReverse\n"); - - // Create a vector of integers - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add some data - int values[] = {10, 20, 30, 40, 50}; - for (int i = 0; i < 5; i++) { - VecPushBackR(&vec, values[i]); - } - - // Use VecForeachPtrReverse to increment values in reverse order - int increment = 1; - VecForeachPtrReverse(&vec, item_ptr, { *item_ptr += increment++; }); - - // Values should now be: [15, 24, 33, 42, 51] - // (50+1, 40+2, 30+3, 20+4, 10+5) - int expected[] = {15, 24, 33, 42, 51}; - bool result = true; - for (size i = 0; i < vec.length; i++) { - result = result && (VecAt(&vec, i) == expected[i]); - } - - // Clean up - VecDeinit(&vec); - - return result; -} - -// Test VecForeachPtrReverseIdx macro -bool test_vec_foreach_ptr_reverse_idx(void) { - WriteFmt("Testing VecForeachPtrReverseIdx\n"); - - // Create a vector of integers - typedef Vec(int) IntVec; - IntVec vec = VecInit(); - - // Add some data - int values[] = {10, 20, 30, 40, 50}; - for (int i = 0; i < 5; i++) { - VecPushBackR(&vec, values[i]); - } - - // Use VecForeachPtrReverseIdx to set each value to its index + 100 - VecForeachPtrReverseIdx(&vec, item_ptr, idx, { *item_ptr = idx + 100; }); - - // Check that the values are set correctly - // Even though we iterate in reverse, idx represents the actual vector index - // So: vec[4] = 104, vec[3] = 103, vec[2] = 102, vec[1] = 101, vec[0] = 100 - // Final vector: [100, 101, 102, 103, 104] - int expected[] = {100, 101, 102, 103, 104}; - bool result = true; - for (size i = 0; i < vec.length; i++) { - result = result && (VecAt(&vec, i) == expected[i]); - } - - // Clean up - VecDeinit(&vec); - - return result; -} - -// Main function that runs all tests -int main(void) { - WriteFmt("[INFO] Starting Vec.Foreach.Simple tests\n\n"); - - // Array of normal test functions - TestFunction tests[] = { - test_vec_foreach, - test_vec_foreach_idx, - test_vec_foreach_ptr, - test_vec_foreach_ptr_idx, - test_vec_foreach_reverse, - test_vec_foreach_reverse_idx, - test_vec_foreach_ptr_reverse, - test_vec_foreach_ptr_reverse_idx - }; - - int total_tests = sizeof(tests) / sizeof(tests[0]); - - // Run all tests using the centralized test driver - return run_test_suite(tests, total_tests, NULL, 0, "Vec.Foreach.Simple"); -} diff --git a/Tests/Std/Vec.Foreach.c b/Tests/Std/Vec.Foreach.c new file mode 100644 index 0000000..6e6b9d8 --- /dev/null +++ b/Tests/Std/Vec.Foreach.c @@ -0,0 +1,599 @@ +#include +#include + +#include +#include // For LVAL macro + +// Include test utilities +#include "../Util/TestRunner.h" + +// Function prototypes +bool test_vec_foreach(void); +bool test_vec_foreach_idx(void); +bool test_vec_foreach_ptr(void); +bool test_vec_foreach_ptr_idx(void); +bool test_vec_foreach_reverse(void); +bool test_vec_foreach_reverse_idx(void); +bool test_vec_foreach_ptr_reverse(void); +bool test_vec_foreach_ptr_reverse_idx(void); + +bool test_vec_foreach_out_of_bounds_access(void); +bool test_vec_foreach_idx_out_of_bounds_access(void); +bool test_vec_foreach_idx_basic_out_of_bounds_access(void); +bool test_vec_foreach_reverse_idx_out_of_bounds_access(void); +bool test_vec_foreach_ptr_idx_out_of_bounds_access(void); +bool test_vec_foreach_ptr_reverse_idx_out_of_bounds_access(void); +bool test_vec_foreach_ptr_in_range_idx_out_of_bounds_access(void); + +// Test VecForeach macro +bool test_vec_foreach(void) { + WriteFmt("Testing VecForeach\n"); + + // Create a vector of integers + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add some data + int values[] = {10, 20, 30, 40, 50}; + for (int i = 0; i < 5; i++) { + VecPushBackR(&vec, values[i]); + } + + // Use VecForeach to sum the values + int sum = 0; + VecForeach(&vec, item) { + sum += item; + } + + // Check the sum + bool result = (sum == 150); // 10 + 20 + 30 + 40 + 50 = 150 + + // Use VecForeach to double each value + VecForeach(&vec, item) { + item *= 2; + } + + // Check that the values in the vector are unchanged (foreach uses value, not reference) + for (u64 i = 0; i < vec.length; i++) { + result = result && (VecAt(&vec, i) == values[i]); + } + + // Clean up + VecDeinit(&vec); + + return result; +} + +// Test VecForeachIdx macro +bool test_vec_foreach_idx(void) { + WriteFmt("Testing VecForeachIdx\n"); + + // Create a vector of integers + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add some data + int values[] = {10, 20, 30, 40, 50}; + for (int i = 0; i < 5; i++) { + VecPushBackR(&vec, values[i]); + } + + // Use VecForeachIdx to verify indices and values + bool result = true; + VecForeachIdx(&vec, item, idx) { + result = result && (item == values[idx]); + }; + + // Use VecForeachIdx to calculate weighted sum (value * index) + int weighted_sum = 0; + VecForeachIdx(&vec, item, idx) { + weighted_sum += item * idx; + } + + // Check the weighted sum + // 10*0 + 20*1 + 30*2 + 40*3 + 50*4 = 0 + 20 + 60 + 120 + 200 = 400 + result = result && (weighted_sum == 400); + + // Clean up + VecDeinit(&vec); + + return result; +} + +// Test VecForeachPtr macro +bool test_vec_foreach_ptr(void) { + WriteFmt("Testing VecForeachPtr\n"); + + // Create a vector of integers + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add some data + int values[] = {10, 20, 30, 40, 50}; + for (int i = 0; i < 5; i++) { + VecPushBackR(&vec, values[i]); + } + + // Use VecForeachPtr to modify the values in the vector + VecForeachPtr(&vec, item_ptr) { + *item_ptr *= 2; + } + + // Check that the values in the vector are doubled + bool result = true; + for (u64 i = 0; i < vec.length; i++) { + result = result && (VecAt(&vec, i) == values[i] * 2); + } + + // Use VecForeachPtr to calculate sum + int sum = 0; + VecForeachPtr(&vec, item_ptr) { + sum += *item_ptr; + } + + // Check the sum (should be doubled values) + // 20 + 40 + 60 + 80 + 100 = 300 + result = result && (sum == 300); + + // Clean up + VecDeinit(&vec); + + return result; +} + +// Test VecForeachPtrIdx macro +bool test_vec_foreach_ptr_idx(void) { + WriteFmt("Testing VecForeachPtrIdx\n"); + + // Create a vector of integers + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add some data + int values[] = {10, 20, 30, 40, 50}; + for (int i = 0; i < 5; i++) { + VecPushBackR(&vec, values[i]); + } + + // Use VecForeachPtrIdx to set each value to its index + VecForeachPtrIdx(&vec, item_ptr, idx) { + *item_ptr = idx; + } + + // Check that the values in the vector are set to their indices + bool result = true; + for (u64 i = 0; i < vec.length; i++) { + result = result && (VecAt(&vec, i) == i); + } + + // Clean up + VecDeinit(&vec); + + return result; +} + +// Test VecForeachReverse macro +bool test_vec_foreach_reverse(void) { + WriteFmt("Testing VecForeachReverse\n"); + + // Create a vector of integers + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add some data + int values[] = {10, 20, 30, 40, 50}; + for (int i = 0; i < 5; i++) { + VecPushBackR(&vec, values[i]); + } + + // Use VecForeachReverse to build a reversed array + int reversed[5] = {0}; + int idx = 0; + VecForeachReverse(&vec, item) { + reversed[idx++] = item; + } + + // Check that the reversed array is correct + bool result = true; + for (int i = 0; i < 5; i++) { + result = result && (reversed[i] == values[4 - i]); + } + + // Clean up + VecDeinit(&vec); + + return result; +} + +// Test VecForeachReverseIdx macro +bool test_vec_foreach_reverse_idx(void) { + WriteFmt("Testing VecForeachReverseIdx\n"); + + // Create a vector of integers + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add some data + int values[] = {10, 20, 30, 40, 50}; + for (int i = 0; i < 5; i++) { + VecPushBackR(&vec, values[i]); + } + + // Use VecForeachReverseIdx to verify indices are correct in reverse + bool result = true; + VecForeachReverseIdx(&vec, item, idx) { + result = result && (item == values[idx]); + result = result && (VecAt(&vec, idx) == item); + } + + // Clean up + VecDeinit(&vec); + + return result; +} + +// Test VecForeachPtrReverse macro +bool test_vec_foreach_ptr_reverse(void) { + WriteFmt("Testing VecForeachPtrReverse\n"); + + // Create a vector of integers + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add some data + int values[] = {10, 20, 30, 40, 50}; + for (int i = 0; i < 5; i++) { + VecPushBackR(&vec, values[i]); + } + + // Use VecForeachPtrReverse to increment values in reverse order + int increment = 1; + VecForeachPtrReverse(&vec, item_ptr) { + *item_ptr += increment++; + } + + // Values should now be: [15, 24, 33, 42, 51] + // (50+1, 40+2, 30+3, 20+4, 10+5) + int expected[] = {15, 24, 33, 42, 51}; + bool result = true; + for (size i = 0; i < vec.length; i++) { + result = result && (VecAt(&vec, i) == expected[i]); + } + + // Clean up + VecDeinit(&vec); + + return result; +} + +// Test VecForeachPtrReverseIdx macro +bool test_vec_foreach_ptr_reverse_idx(void) { + WriteFmt("Testing VecForeachPtrReverseIdx\n"); + + // Create a vector of integers + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add some data + int values[] = {10, 20, 30, 40, 50}; + for (int i = 0; i < 5; i++) { + VecPushBackR(&vec, values[i]); + } + + // Use VecForeachPtrReverseIdx to set each value to its index + 100 + VecForeachPtrReverseIdx(&vec, item_ptr, idx) { + *item_ptr = idx + 100; + } + + // Check that the values are set correctly + // Even though we iterate in reverse, idx represents the actual vector index + // So: vec[4] = 104, vec[3] = 103, vec[2] = 102, vec[1] = 101, vec[0] = 100 + // Final vector: [100, 101, 102, 103, 104] + int expected[] = {100, 101, 102, 103, 104}; + bool result = true; + for (size i = 0; i < vec.length; i++) { + result = result && (VecAt(&vec, i) == expected[i]); + } + + // Clean up + VecDeinit(&vec); + + return result; +} + +// Make idx go out of bounds during VecForeach by modifying vector during iteration +bool test_vec_foreach_out_of_bounds_access(void) { + WriteFmt("Testing VecForeach where modification causes out of bounds access (should crash)\n"); + + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add some elements + for (int i = 0; i < 5; i++) { + VecPushBackR(&vec, i * 10); + } + + // VecForeach doesn't use an explicit index but we can still cause issues + int iteration_count = 0; + VecForeach(&vec, val) { + WriteFmt("Iteration {} (vec.length={}): {}\n", iteration_count, vec.length, val); + + // After 2nd iteration, shrink the vector dramatically + if (iteration_count == 2) { + VecResize(&vec, 2); // Shrink to only 2 elements + WriteFmt("Vector resized to length {} during foreach iteration...\n", vec.length); + } + + // This will eventually cause bounds checking to trigger + // loop will automatically terminate + + if (iteration_count > 2) { + LOG_ERROR("Should've terminated"); + VecDeinit(&vec); + return false; + } + + iteration_count++; + } + + // Should never reach here if bounds checking triggers + VecDeinit(&vec); + return true; +} + +// Make idx go out of bounds in VecForeachIdx by modifying vector during iteration +bool test_vec_foreach_idx_out_of_bounds_access(void) { + WriteFmt("Testing VecForeachIdx where idx goes out of bounds (should crash)\n"); + + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add some elements + for (int i = 0; i < 6; i++) { + VecPushBackR(&vec, i * 20); + } + + // VecForeachIdx has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) + VecForeachIdx(&vec, val, idx) { + WriteFmt("Accessing idx {} (vec.length={}): {}\n", idx, vec.length, val); + + // When we reach idx=2, drastically shrink the vector to make the current idx invalid + // The bounds check happens after the body, so it will check if idx=2 >= new_length + if (idx == 2) { + VecResize(&vec, 2); // Shrink so that idx=2 becomes out of bounds (valid indices: 0,1) + WriteFmt("Vector resized to length {}, current idx={} is now out of bounds...\n", vec.length, idx); + } + + // When idx >= vec.length, the bounds check will trigger: + // loop will automatically terminate + + if (idx > 2) { + LOG_ERROR("Should've terminated"); + VecDeinit(&vec); + return false; + } + } + + // Should never reach here if bounds checking triggers + VecDeinit(&vec); + return true; +} + +// Make idx go out of bounds in VecForeachReverseIdx by modifying vector during iteration +bool test_vec_foreach_reverse_idx_out_of_bounds_access(void) { + WriteFmt("Testing VecForeachReverseIdx where idx goes out of bounds (should crash)\n"); + + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add several elements + for (int i = 0; i < 6; i++) { + VecPushBackR(&vec, i * 15); + } + + // VecForeachReverseIdx has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) + VecForeachReverseIdx(&vec, val, idx) { + WriteFmt("Accessing idx {} (vec.length={}): {}\n", idx, vec.length, val); + + // When we reach idx=4, drastically shrink the vector + // This will make subsequent iterations invalid since idx will still decrement + // but the vector length is now smaller + if (idx == 4) { + VecResize(&vec, 2); // Shrink to only 2 elements + WriteFmt("Vector resized to length {} during reverse iteration...\n", vec.length); + } + + // When idx == 4 (> vec.length = 2), the bounds check will trigger: + // loop will automatically terminate + + if (idx < 4) { + LOG_ERROR("Should've terminated"); + VecDeinit(&vec); + return false; + } + } + + // Should never reach here if bounds checking triggers + VecDeinit(&vec); + return true; +} + +// Make idx go out of bounds in VecForeachPtrIdx by modifying vector during iteration +bool test_vec_foreach_ptr_idx_out_of_bounds_access(void) { + WriteFmt("Testing VecForeachPtrIdx where idx goes out of bounds (should crash)\n"); + + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add several elements + for (int i = 0; i < 7; i++) { + VecPushBackR(&vec, i * 25); + } + + // VecForeachPtrIdx has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) + VecForeachPtrIdx(&vec, val_ptr, idx) { + WriteFmt("Accessing idx {} (vec.length={}): {}\n", idx, vec.length, *val_ptr); + + // When we reach idx=3, shrink the vector to make the CURRENT idx invalid + // The bounds check happens after the body, so it will check if idx=3 >= new_length + if (idx == 3) { + VecResize(&vec, 3); // Shrink so that idx=3 becomes out of bounds (valid indices: 0,1,2) + WriteFmt("Vector resized to length {}, current idx={} is now out of bounds...\n", vec.length, idx); + } + + // When idx >= vec.length, the bounds check will trigger: + // loop will automatically terminate + + if (idx > 3) { + LOG_ERROR("Should've terminated"); + VecDeinit(&vec); + return false; + } + } + + // Should never reach here if bounds checking triggers + VecDeinit(&vec); + return true; +} + +// Make idx go out of bounds in VecForeachPtrReverseIdx by modifying vector during iteration +bool test_vec_foreach_ptr_reverse_idx_out_of_bounds_access(void) { + WriteFmt("Testing VecForeachPtrReverseIdx where idx goes out of bounds (should crash)\n"); + + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add several elements + for (int i = 0; i < 8; i++) { + VecPushBackR(&vec, i * 35); + } + + // VecForeachPtrReverseIdx has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) + VecForeachPtrReverseIdx(&vec, val_ptr, idx) { + WriteFmt("Accessing idx {} (vec.length={}): {}\n", idx, vec.length, *val_ptr); + + // When we reach idx=5, shrink the vector significantly + if (idx == 5) { + VecResize(&vec, 3); // Shrink to only 3 elements + WriteFmt("Vector resized to length {} during reverse ptr iteration...\n", vec.length); + } + + // When idx == 5 (> vec.length), the bounds check will trigger: + // loop will automatically terminate + + if (idx < 5) { + LOG_ERROR("Should've terminated"); + VecDeinit(&vec); + return false; + } + } + + // Should never reach here if bounds checking triggers + VecDeinit(&vec); + return true; +} + +// Make idx go out of bounds in VecForeachPtrInRangeIdx by modifying vector during iteration +bool test_vec_foreach_ptr_in_range_idx_out_of_bounds_access(void) { + WriteFmt("Testing VecForeachPtrInRangeIdx where idx goes out of bounds (should crash)\n"); + + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add several elements + for (int i = 0; i < 9; i++) { + VecPushBackR(&vec, i * 45); + } + + // Use VecForeachPtrInRangeIdx with a fixed range that becomes invalid when we modify the vector + size original_length = vec.length; // Capture this as 9 + VecForeachPtrInRangeIdx(&vec, val_ptr, idx, 0, original_length) { + WriteFmt("Accessing idx {} (vec.length={}): {}\n", idx, vec.length, *val_ptr); + + // When we reach idx=3, delete several elements + if (idx == 3) { + VecDeleteRange(&vec, 0, 6); // Remove first 6 elements + WriteFmt("Deleted first 6 elements, new length={}, idx = {}\n", vec.length, original_length, idx); + } + + // When idx >= vec.length, the bounds check will trigger: + // loop will automatically terminate + + if (idx > vec.length) { + LOG_ERROR("Should've terminated"); + VecDeinit(&vec); + return false; + } + } + + // Should never reach here if bounds checking triggers + VecDeinit(&vec); + return true; +} + +// Make idx go out of bounds in basic VecForeachIdx by modifying vector during iteration +bool test_vec_foreach_idx_basic_out_of_bounds_access(void) { + WriteFmt("Testing basic VecForeachIdx where idx goes out of bounds (should crash)\n"); + + typedef Vec(int) IntVec; + IntVec vec = VecInit(); + + // Add several elements + for (int i = 0; i < 5; i++) { + VecPushBackR(&vec, i * 30); + } + + // Basic VecForeachIdx now has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...) + VecForeachIdx(&vec, val, idx) { + WriteFmt("Accessing idx {} (vec.length={}): {}\n", idx, vec.length, val); + + // When we reach idx=2, drastically shrink the vector + // This will make subsequent iterations invalid + if (idx == 2) { + VecResize(&vec, 1); // Shrink to only 1 element + WriteFmt("Vector resized to length {}, current index={}\n", vec.length, idx); + } + + // When idx >= vec.length, the bounds check will trigger: + // loop will automatically terminate + + if (idx > 2) { + LOG_ERROR("Should've terminated"); + VecDeinit(&vec); + return false; + } + } + + // Should never reach here if bounds checking triggers + VecDeinit(&vec); + return true; +} + +// Main function that runs all tests +int main(void) { + WriteFmt("[INFO] Starting Vec.Foreach.Simple tests\n\n"); + + // Array of normal test functions + TestFunction tests[] = { + test_vec_foreach, + test_vec_foreach_idx, + test_vec_foreach_ptr, + test_vec_foreach_ptr_idx, + test_vec_foreach_reverse, + test_vec_foreach_reverse_idx, + test_vec_foreach_ptr_reverse, + test_vec_foreach_ptr_reverse_idx, + test_vec_foreach_out_of_bounds_access, + test_vec_foreach_idx_out_of_bounds_access, + test_vec_foreach_idx_basic_out_of_bounds_access, + test_vec_foreach_reverse_idx_out_of_bounds_access, + test_vec_foreach_ptr_idx_out_of_bounds_access, + test_vec_foreach_ptr_reverse_idx_out_of_bounds_access, + test_vec_foreach_ptr_in_range_idx_out_of_bounds_access + }; + + int total_tests = sizeof(tests) / sizeof(tests[0]); + + // Run all tests using the centralized test driver + return run_test_suite(tests, total_tests, NULL, 0, "Vec.Foreach.Simple"); +} diff --git a/Tests/meson.build b/Tests/meson.build index c5c3cda..14b762d 100644 --- a/Tests/meson.build +++ b/Tests/meson.build @@ -27,14 +27,10 @@ str_tests = [ ['Str.Access', 'Std/Str.Access.c'], ['Str.Memory', 'Std/Str.Memory.c'], ['Str.Convert', 'Std/Str.Convert.c'], - ['Str.Foreach.Simple', 'Std/Str.Foreach.Simple.c'], + ['Str.Foreach', 'Std/Str.Foreach.c'], ['Str.Ops', 'Std/Str.Ops.c'], ] -str_deadend_tests = [ - ['Str.Foreach.Deadend', 'Std/Str.Foreach.Deadend.c'], -] - vec_tests = [ ['Vec.Type', 'Std/Vec.Type.c'], ['Vec.Init', 'Std/Vec.Init.c'], @@ -42,15 +38,11 @@ vec_tests = [ ['Vec.Memory', 'Std/Vec.Memory.c'], ['Vec.Insert', 'Std/Vec.Insert.c'], ['Vec.Remove', 'Std/Vec.Remove.c'], - ['Vec.Foreach.Simple', 'Std/Vec.Foreach.Simple.c'], + ['Vec.Foreach', 'Std/Vec.Foreach.c'], ['Vec.Ops', 'Std/Vec.Ops.c'], ['Vec.Complex', 'Std/Vec.Complex.c'], ] -vec_deadend_tests = [ - ['Vec.Foreach.Deadend', 'Std/Vec.Foreach.Deadend.c'], -] - bitvec_tests = [ ['BitVec.Type', 'Std/BitVec.Type.c'], ['BitVec.Init', 'Std/BitVec.Init.c'], @@ -187,40 +179,3 @@ foreach test_info : bitvec_deadend_tests test(test_name, test_exe) endforeach - -# Build and register deadend tests WITHOUT sanitizers to avoid memory leak reports -foreach test_info : str_deadend_tests - test_name = test_info[0] - test_src = test_info[1] - - test_exe = executable( - test_name, - files(test_src), - link_with: [misra_std_no_sanitizers], # Use the non-sanitized library - dependencies: [test_util_dep_no_sanitizers], # Use non-sanitized test utils - c_args: test_args, - include_directories: inc_misra, - install: false, - override_options: ['b_sanitize=none'] # Disable all sanitizers for deadend tests - ) - - test(test_name, test_exe) -endforeach - -foreach test_info : vec_deadend_tests - test_name = test_info[0] - test_src = test_info[1] - - test_exe = executable( - test_name, - files(test_src), - link_with: [misra_std_no_sanitizers], # Use the non-sanitized library - dependencies: [test_util_dep_no_sanitizers], # Use non-sanitized test utils - c_args: test_args, - include_directories: inc_misra, - install: false, - override_options: ['b_sanitize=none'] # Disable all sanitizers for deadend tests - ) - - test(test_name, test_exe) -endforeach diff --git a/meson.build b/meson.build index 1ad0712..c5bb0a5 100644 --- a/meson.build +++ b/meson.build @@ -22,6 +22,7 @@ misra_std_sources = files( 'Source/Misra/Std/Memory.c', 'Source/Misra/Std/Container/Vec.c', 'Source/Misra/Std/Container/Str.c', + 'Source/Misra/Std/Container/List.c', 'Source/Misra/Std/Container/BitVec.c', 'Source/Misra/Std/Utility/Iter.c', 'Source/Misra/Parsers/JSON.c'