From b7264e20f26e31c6fcd0dd356e671d8f5438720c Mon Sep 17 00:00:00 2001 From: Abdelrahman Said Date: Sat, 1 Mar 2025 22:34:17 +0000 Subject: [PATCH] Add example for doubly linked list --- codegen/__main__.py | 3 +- codegen/codegen.py | 195 +++++++++++++++++++++++++++++++ codegen/snippets/list_empty | 8 ++ codegen/snippets/list_get | 13 +++ codegen/snippets/list_insert | 29 +++++ codegen/snippets/list_pop_back | 21 ++++ codegen/snippets/list_pop_front | 21 ++++ codegen/snippets/list_push_back | 21 ++++ codegen/snippets/list_push_front | 21 ++++ codegen/snippets/list_remove | 28 +++++ codegen/snippets/node_to_list | 15 +++ 11 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 codegen/snippets/list_empty create mode 100644 codegen/snippets/list_get create mode 100644 codegen/snippets/list_insert create mode 100644 codegen/snippets/list_pop_back create mode 100644 codegen/snippets/list_pop_front create mode 100644 codegen/snippets/list_push_back create mode 100644 codegen/snippets/list_push_front create mode 100644 codegen/snippets/list_remove create mode 100644 codegen/snippets/node_to_list diff --git a/codegen/__main__.py b/codegen/__main__.py index 7d6135a..fae93c7 100644 --- a/codegen/__main__.py +++ b/codegen/__main__.py @@ -1,5 +1,6 @@ -from .codegen import test_str8, test_typed_array +from .codegen import test_str8, test_doubly_linked_list, test_typed_array if __name__ == "__main__": test_str8() test_typed_array() + test_doubly_linked_list() diff --git a/codegen/codegen.py b/codegen/codegen.py index 5b0a23f..87a29fd 100644 --- a/codegen/codegen.py +++ b/codegen/codegen.py @@ -1,5 +1,6 @@ from pathlib import Path from .datatypes import ( + CDataType, CStruct, CEnum, CEnumVal, @@ -13,6 +14,7 @@ from .datatypes import ( CQualifier, CInclude, CUserType, + get_datatype_string, ) @@ -149,3 +151,196 @@ def test_typed_array(): header.save(Path(".")) source.save(Path(".")) + + +def test_doubly_linked_list(): + datatypes: dict[CDataType, list[CInclude]] = {"Str8": [CInclude(header="str8.h", local=True)]} + snippets_dir = Path("snippets") + + for _type, includes in datatypes.items(): + type_string = get_datatype_string(_type) + + node = CStruct( + name=f"{type_string}Node", + cargs=[ + CArg(name="string", _type=type_string, pointer=CPointer(_type=CPointerType.SINGLE)), + CArg(name="prev", _type=f"{type_string}Node", pointer=CPointer(_type=CPointerType.SINGLE)), + CArg(name="next", _type=f"{type_string}Node", pointer=CPointer(_type=CPointerType.SINGLE)), + ], + ) + + dl_list = CStruct( + name=f"{type_string}List", + cargs=[ + CArg(name="first", _type=node, pointer=CPointer(_type=CPointerType.SINGLE)), + CArg(name="last", _type=node, pointer=CPointer(_type=CPointerType.SINGLE)), + CArg(name="total_size", _type=CType.U64), + CArg(name="node_count", _type=CType.U64), + ], + ) + + get_func = CFunc( + name=f"wapp_{type_string.lower()}_list_get", + ret_type=node, + args=[ + CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE), qualifier=CQualifier.CONST), + CArg(name="index", _type=CType.U64), + ], + body=load_func_body_from_file(Path(__file__).parent / snippets_dir / "list_get").format( + T=type_string, + Tupper=type_string.upper(), + Tlower=type_string.lower() + ), + pointer=CPointer(CPointerType.SINGLE), + ) + + push_front_func = CFunc( + name=f"wapp_{type_string.lower()}_list_push_front", + ret_type=CType.VOID, + args=[ + CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE)), + CArg(name="node", _type=node, pointer=CPointer(CPointerType.SINGLE)), + ], + body=load_func_body_from_file(Path(__file__).parent / snippets_dir / "list_push_front").format( + T=type_string, + Tupper=type_string.upper(), + Tlower=type_string.lower() + ), + ) + + push_back_func = CFunc( + name=f"wapp_{type_string.lower()}_list_push_back", + ret_type=CType.VOID, + args=[ + CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE)), + CArg(name="node", _type=node, pointer=CPointer(CPointerType.SINGLE)), + ], + body=load_func_body_from_file(Path(__file__).parent / snippets_dir / "list_push_back").format( + T=type_string, + Tupper=type_string.upper(), + Tlower=type_string.lower() + ), + ) + + insert_func = CFunc( + name=f"wapp_{type_string.lower()}_list_insert", + ret_type=CType.VOID, + args=[ + CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE)), + CArg(name="node", _type=node, pointer=CPointer(CPointerType.SINGLE)), + CArg(name="index", _type=CType.U64), + ], + body=load_func_body_from_file(Path(__file__).parent / snippets_dir / "list_insert").format( + T=type_string, + Tupper=type_string.upper(), + Tlower=type_string.lower() + ), + ) + + pop_front_func = CFunc( + name=f"wapp_{type_string.lower()}_list_pop_front", + ret_type=node, + args=[ + CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE)), + ], + body=load_func_body_from_file(Path(__file__).parent / snippets_dir / "list_pop_front").format( + T=type_string, + Tupper=type_string.upper(), + Tlower=type_string.lower() + ), + pointer=CPointer(CPointerType.SINGLE), + ) + + pop_back_func = CFunc( + name=f"wapp_{type_string.lower()}_list_pop_back", + ret_type=node, + args=[ + CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE)), + ], + body=load_func_body_from_file(Path(__file__).parent / snippets_dir / "list_pop_back").format( + T=type_string, + Tupper=type_string.upper(), + Tlower=type_string.lower() + ), + pointer=CPointer(CPointerType.SINGLE), + ) + + remove_func = CFunc( + name=f"wapp_{type_string.lower()}_list_remove", + ret_type=node, + args=[ + CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE)), + CArg(name="index", _type=CType.U64), + ], + body=load_func_body_from_file(Path(__file__).parent / snippets_dir / "list_remove").format( + T=type_string, + Tupper=type_string.upper(), + Tlower=type_string.lower() + ), + pointer=CPointer(CPointerType.SINGLE), + ) + + empty_func = CFunc( + name=f"wapp_{type_string.lower()}_list_empty", + ret_type=CType.VOID, + args=[ + CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE)), + ], + body=load_func_body_from_file(Path(__file__).parent / snippets_dir / "list_empty").format( + T=type_string, + Tupper=type_string.upper(), + Tlower=type_string.lower() + ), + ) + + node_to_list_func = CFunc( + name=f"{type_string.lower()}_node_to_list", + ret_type=dl_list, + args=[ + CArg(name="node", _type=node, pointer=CPointer(CPointerType.SINGLE)), + ], + body=load_func_body_from_file(Path(__file__).parent / snippets_dir / "node_to_list").format( + T=type_string, + Tupper=type_string.upper(), + Tlower=type_string.lower(), + ), + qualifiers=[CQualifier.INTERNAL], + ) + + header = CHeader( + name=f"{type_string.lower()}_list", + includes=[CInclude(header="aliases.h", local=True)], + types=[node, dl_list], + funcs=[ + get_func, + push_front_func, + push_back_func, + insert_func, + pop_front_func, + pop_back_func, + remove_func, + empty_func, + ] + ) + + source = CSource( + name=header.name, + includes=[CInclude(header="aliases.h", local=True), CInclude(header, local=True), CInclude(header="stddef.h")], + internal_funcs=[node_to_list_func], + funcs=header.funcs + ) + + if len(includes) > 0: + header.includes.extend(includes) + source.includes.extend(includes) + + header.includes = sorted(header.includes, key=lambda inc: inc.local, reverse=True) + source.includes = sorted(source.includes, key=lambda inc: inc.local, reverse=True) + + header.save(Path(".")) + source.save(Path(".")) + + +def load_func_body_from_file(filename: Path) -> str: + with open(filename, "r") as infile: + return infile.read() diff --git a/codegen/snippets/list_empty b/codegen/snippets/list_empty new file mode 100644 index 0000000..c14804f --- /dev/null +++ b/codegen/snippets/list_empty @@ -0,0 +1,8 @@ + if (!list) {{ + return; + }} + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) {{ + wapp_str8_list_pop_back(list); + }} diff --git a/codegen/snippets/list_get b/codegen/snippets/list_get new file mode 100644 index 0000000..c65985e --- /dev/null +++ b/codegen/snippets/list_get @@ -0,0 +1,13 @@ + if (index >= list->node_count) {{ + return NULL; + }} + + {T}Node *output = NULL; + {T}Node *current = list->first; + for (u64 i = 1; i <= index; ++i) {{ + current = current->next; + }} + + output = current; + + return output; diff --git a/codegen/snippets/list_insert b/codegen/snippets/list_insert new file mode 100644 index 0000000..0b6aa52 --- /dev/null +++ b/codegen/snippets/list_insert @@ -0,0 +1,29 @@ + if (!list || !node || !(node->string)) {{ + return; + }} + + if (index == 0) {{ + wapp_str8_list_push_front(list, node); + return; + }} else if (index == list->node_count) {{ + wapp_str8_list_push_back(list, node); + return; + }} + + {T}Node *dst_node = wapp_str8_list_get(list, index); + if (!dst_node) {{ + return; + }} + + {T}List node_list = {Tlower}_node_to_list(node); + + list->total_size += node_list.total_size; + list->node_count += node_list.node_count; + + {T}Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; diff --git a/codegen/snippets/list_pop_back b/codegen/snippets/list_pop_back new file mode 100644 index 0000000..3ee8a15 --- /dev/null +++ b/codegen/snippets/list_pop_back @@ -0,0 +1,21 @@ + {T}Node *output = NULL; + + if (!list || list->node_count == 0) {{ + goto RETURN_{Tupper}_LIST_POP_BACK; + }} + + output = list->last; + + if (list->node_count == 1) {{ + *list = ({T}List){{0}}; + goto RETURN_{Tupper}_LIST_POP_BACK; + }} + + --(list->node_count); + list->total_size -= output->string->size; + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_{Tupper}_LIST_POP_BACK: + return output; diff --git a/codegen/snippets/list_pop_front b/codegen/snippets/list_pop_front new file mode 100644 index 0000000..caba8c9 --- /dev/null +++ b/codegen/snippets/list_pop_front @@ -0,0 +1,21 @@ + {T}Node *output = NULL; + + if (!list || list->node_count == 0) {{ + goto RETURN_{Tupper}_LIST_POP_FRONT; + }} + + output = list->first; + + if (list->node_count == 1) {{ + *list = ({T}List){{0}}; + goto RETURN_{Tupper}_LIST_POP_FRONT; + }} + + --(list->node_count); + list->total_size -= output->string->size; + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_{Tupper}_LIST_POP_FRONT: + return output; diff --git a/codegen/snippets/list_push_back b/codegen/snippets/list_push_back new file mode 100644 index 0000000..cc51dac --- /dev/null +++ b/codegen/snippets/list_push_back @@ -0,0 +1,21 @@ + if (!list || !node || !(node->string)) {{ + return; + }} + + {T}List node_list = {Tlower}_node_to_list(node); + + if (list->node_count == 0) {{ + *list = node_list; + return; + }} + + list->total_size += node_list.total_size; + list->node_count += node_list.node_count; + + {T}Node *last = list->last; + if (last) {{ + last->next = node_list.first; + }} + + list->last = node_list.last; + node_list.first->prev = last; diff --git a/codegen/snippets/list_push_front b/codegen/snippets/list_push_front new file mode 100644 index 0000000..8989beb --- /dev/null +++ b/codegen/snippets/list_push_front @@ -0,0 +1,21 @@ + if (!list || !node || !(node->string)) {{ + return; + }} + + {T}List node_list = {Tlower}_node_to_list(node); + + if (list->node_count == 0) {{ + *list = node_list; + return; + }} + + list->total_size += node_list.total_size; + list->node_count += node_list.node_count; + + {T}Node *first = list->first; + if (first) {{ + first->prev = node_list.last; + }} + + list->first = node_list.first; + node_list.last->next = first; diff --git a/codegen/snippets/list_remove b/codegen/snippets/list_remove new file mode 100644 index 0000000..cc213c4 --- /dev/null +++ b/codegen/snippets/list_remove @@ -0,0 +1,28 @@ + {T}Node *output = NULL; + if (!list) {{ + goto RETURN_{Tupper}_LIST_REMOVE; + }} + + if (index == 0) {{ + output = wapp_str8_list_pop_front(list); + goto RETURN_{Tupper}_LIST_REMOVE; + }} else if (index == list->node_count) {{ + output = wapp_str8_list_pop_back(list); + goto RETURN_{Tupper}_LIST_REMOVE; + }} + + output = wapp_str8_list_get(list, index); + if (!output) {{ + goto RETURN_{Tupper}_LIST_REMOVE; + }} + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + list->total_size -= output->string->size; + + output->prev = output->next = NULL; + +RETURN_{Tupper}_LIST_REMOVE: + return output; diff --git a/codegen/snippets/node_to_list b/codegen/snippets/node_to_list new file mode 100644 index 0000000..2c52609 --- /dev/null +++ b/codegen/snippets/node_to_list @@ -0,0 +1,15 @@ + {T}List output = {{.first = node, .last = node, .total_size = node->string->size, .node_count = 1}}; + + while (output.first->prev != NULL) {{ + output.total_size += output.first->prev->string->size; + output.first = output.first->prev; + ++(output.node_count); + }} + + while (output.last->next != NULL) {{ + output.total_size += output.last->next->string->size; + output.last = output.last->next; + ++(output.node_count); + }} + + return output;