aboutsummaryrefslogtreecommitdiff
path: root/include/shared
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2021-10-26 00:10:06 -0600
committerJosh Rahm <joshuarahm@gmail.com>2021-10-26 00:10:06 -0600
commitf9b12f748b557994b958115c04fd1591b322248e (patch)
tree7d80680edadf5b0018944966af64f8773bfa8f1a /include/shared
parentdbbe83bd8882fe18e26f6305a1f425145bfea8db (diff)
parent90eb3a0b79bfef67c70dc545b49c48928eea05f4 (diff)
downloadstm32l4-f9b12f748b557994b958115c04fd1591b322248e.tar.gz
stm32l4-f9b12f748b557994b958115c04fd1591b322248e.tar.bz2
stm32l4-f9b12f748b557994b958115c04fd1591b322248e.zip
Merge branch 'christmas' into HEAD
Diffstat (limited to 'include/shared')
-rw-r--r--include/shared/array_list.h105
-rw-r--r--include/shared/avl_tree.h270
-rw-r--r--include/shared/avl_tree.h.gchbin0 -> 11451 bytes
-rw-r--r--include/shared/linked_list.h277
-rw-r--r--include/shared/map.h90
-rw-r--r--include/shared/math.h19
-rw-r--r--include/shared/stdmacro.h7
7 files changed, 664 insertions, 104 deletions
diff --git a/include/shared/array_list.h b/include/shared/array_list.h
new file mode 100644
index 0000000..8b942ad
--- /dev/null
+++ b/include/shared/array_list.h
@@ -0,0 +1,105 @@
+#ifndef SHARED_ARRAY_LIST_H_
+#define SHARED_ARRAY_LIST_H_
+
+#include "kern/common.h"
+#include "kern/mem.h"
+
+#define ALLOC kalloc
+#define FREE kfree
+
+#define array_list_t(type) array_list_##type##_t
+#define array_list_new(type) array_list_##type##_new
+#define array_list_length(type) array_list_##type##_length
+#define array_list_reserve(type) array_list_##type##_reserve
+#define array_list_add(type) array_list_##type##_add
+#define array_list_remove(type) array_list_##type##remove
+#define array_list_ref(type) array_list_##type##_get
+#define array_list_free(type) array_list_##type##_free
+
+#define array_list_foreach(ar, val) \
+ typeof((ar)->elements[0]) val; \
+ if ((ar)->size > 0) val = (ar)->elements[0]; \
+ for (size_t _idx_ = 0; _idx_ < (ar)->size; \
+ val = (++_idx_) >= (ar)->size ? val : (ar)->elements[_idx_])
+
+#define ARRAY_LIST_DECL(type) \
+ typedef struct { \
+ size_t reserved; \
+ size_t size; \
+ type* elements; \
+ } array_list_t(type); \
+ size_t array_list_length(type)(const array_list_t(type)*); \
+ array_list_t(type) * array_list_new(type)(); \
+ bool array_list_reserve(type)(array_list_t(type)*, size_t len); \
+ bool array_list_add(type)(array_list_t(type)*, type val); \
+ bool array_list_remove(type)(array_list_t(type)*, size_t idx, type * out); \
+ type* array_list_ref(type)(array_list_t(type)*, size_t idx); \
+ void array_list_free(type)(array_list_t(type)*);
+
+#define ARRAY_LIST_IMPL(type) \
+ array_list_t(type) * array_list_new(type)() \
+ { \
+ array_list_t(type)* ret = ALLOC(sizeof(array_list_t(type))); \
+ ret->size = 0; \
+ ret->reserved = 0; \
+ ret->elements = NULL; \
+ return ret; \
+ } \
+ size_t array_list_length(type)(const array_list_t(type) * lst) \
+ { \
+ return lst->size; \
+ } \
+ bool array_list_reserve(type)(array_list_t(type) * lst, size_t newlen) \
+ { \
+ if (lst->reserved < newlen) { \
+ type* new_arr = ALLOC(sizeof(type) * newlen); \
+ if (!new_arr) { \
+ return 0; \
+ } \
+ for (size_t i = 0; i < lst->size; ++i) { \
+ new_arr[i] = lst->elements[i]; \
+ } \
+ FREE(lst->elements); \
+ lst->elements = new_arr; \
+ lst->reserved = newlen; \
+ } \
+ return 1; \
+ } \
+ bool array_list_add(type)(array_list_t(type) * lst, type v) \
+ { \
+ if (lst->size == lst->reserved) { \
+ if (!array_list_reserve(type)( \
+ lst, lst->reserved == 0 ? 4 : lst->reserved * 2)) { \
+ return 0; \
+ } \
+ } \
+ lst->elements[lst->size++] = v; \
+ return 1; \
+ } \
+ bool array_list_remove(type)( \
+ array_list_t(type) * lst, size_t idx, type * out) \
+ { \
+ if (idx >= lst->size) { \
+ return 0; \
+ } \
+ if (out) *out = lst->elements[idx]; \
+ for (size_t i = idx; i < lst->size - 1; ++i) { \
+ lst->elements[i] = lst->elements[i + 1]; \
+ } \
+ lst->size--; \
+ return 1; \
+ } \
+ type* array_list_ref(type)(array_list_t(type) * lst, size_t idx) \
+ { \
+ if (idx >= lst->size) { \
+ return NULL; \
+ } \
+ return &lst->elements[idx]; \
+ } \
+ void array_list_free(type)(array_list_t(type) * lst) \
+ { \
+ FREE(lst->elements); \
+ FREE(lst); \
+ }
+
+#endif /* SHARED_ARRAY_LIST_H_ */
diff --git a/include/shared/avl_tree.h b/include/shared/avl_tree.h
new file mode 100644
index 0000000..2b174d3
--- /dev/null
+++ b/include/shared/avl_tree.h
@@ -0,0 +1,270 @@
+#ifndef _SHARED_AVL_TREE_H_
+#define _SHARED_AVL_TREE_H_
+
+#define ALLOC kalloc
+#define FREE kfree
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "kern/common.h"
+#include "kern/mem.h"
+#include "shared/stdmacro.h"
+
+#define get_height(n) ((n) == NULL ? 0 : (n)->height)
+#define max(a, b) ((a) < (b) ? (b) : (a))
+#define reset_height(node) \
+ (node)->height = \
+ (max(get_height((node)->right), get_height((node)->left)) + 1)
+
+#define avl_tree_t(T) CONCAT(avl_tree__, T)
+#define avl_tree_node_t(T) CONCAT(avl_tree_node__, T)
+
+#define avl_tree_new(T) CONCAT(avl_tree_new__, T)
+#define avl_tree_free(T) CONCAT(avl_tree_free__, T)
+#define avl_tree_size(T) CONCAT(avl_tree_size__, T)
+#define avl_tree_insert(T) CONCAT(avl_tree_insert__, T)
+#define avl_tree_find(T) CONCAT(avl_tree_find__, T)
+#define avl_tree_erase(T) CONCAT(avl_tree_erase__, T)
+#define avl_tree_height(T) CONCAT(avl_tree_height__, T)
+
+#define null_dtor(a)
+
+#define AVL_TREE_DECL(T) \
+ typedef struct CONCAT(AVL_TREE_NODE_, T) { \
+ T value; \
+ size_t height; \
+ struct CONCAT(AVL_TREE_NODE_, T) * left; \
+ struct CONCAT(AVL_TREE_NODE_, T) * right; \
+ } avl_tree_node_t(T); \
+ \
+ typedef struct { \
+ avl_tree_node_t(T) * root; \
+ } avl_tree_t(T); \
+ \
+ size_t avl_tree_height(T)(avl_tree_t(T) * tree); \
+ avl_tree_t(T) * avl_tree_new(T)(); \
+ void avl_tree_free(T)(avl_tree_t(T) * tree); \
+ size_t avl_tree_size(T)(const avl_tree_t(T) * avl_tree); \
+ T* avl_tree_insert(T)(avl_tree_t(T) * avl_tree, T value); \
+ T* avl_tree_find(T)(const avl_tree_t(T)*, T val); \
+ bool avl_tree_erase(T)(avl_tree_t(T) * tree, T val, T * out);
+
+#define AVL_TREE_IMPL(T, CMP, DTOR) \
+ avl_tree_t(T) * avl_tree_new(T)() \
+ { \
+ avl_tree_t(T)* ret = ALLOC(sizeof(avl_tree_t(T))); \
+ ret->root = NULL; \
+ return ret; \
+ } \
+ static void CONCAT(avl_loose_free__, T)(avl_tree_node_t(T) * node) \
+ { \
+ if (!node) return; \
+ CONCAT(avl_loose_free__, T)(node->right); \
+ CONCAT(avl_loose_free__, T)(node->left); \
+ DTOR(node->value); \
+ FREE(node); \
+ } \
+ void avl_tree_free(T)(avl_tree_t(T) * tree) \
+ { \
+ CONCAT(avl_loose_free__, T)(tree->root); \
+ FREE(tree); \
+ } \
+ static inline size_t CONCAT( \
+ loose_size__, T)(const avl_tree_node_t(T) * node) \
+ { \
+ if (!node) return 0; \
+ return 1 + CONCAT(loose_size__, T)(node->left) + \
+ CONCAT(loose_size__, T)(node->right); \
+ } \
+ size_t avl_tree_size(T)(const avl_tree_t(T) * tree) \
+ { \
+ return CONCAT(loose_size__, T)(tree->root); \
+ } \
+ static int CONCAT(balance_factor, T)(avl_tree_node_t(T) * node) \
+ { \
+ return get_height(node->left) - get_height(node->right); \
+ } \
+ static avl_tree_node_t(T) * CONCAT(ll_rotate, T)(avl_tree_node_t(T) * node) \
+ { \
+ avl_tree_node_t(T)* child = node->left; \
+ node->left = child->right; \
+ reset_height(node); \
+ child->right = node; \
+ reset_height(child); \
+ return child; \
+ } \
+ static avl_tree_node_t(T) * CONCAT(rr_rotate, T)(avl_tree_node_t(T) * node) \
+ { \
+ avl_tree_node_t(T)* child = node->right; \
+ node->right = child->left; \
+ reset_height(node); \
+ child->left = node; \
+ reset_height(child); \
+ return child; \
+ } \
+ static avl_tree_node_t(T) * CONCAT(rl_rotate, T)(avl_tree_node_t(T) * node) \
+ { \
+ avl_tree_node_t(T)* child = node->right; \
+ node->right = CONCAT(ll_rotate, T)(child); \
+ reset_height(node); \
+ return CONCAT(rr_rotate, T)(node); \
+ } \
+ static avl_tree_node_t(T) * CONCAT(lr_rotate, T)(avl_tree_node_t(T) * node) \
+ { \
+ avl_tree_node_t(T)* child = node->left; \
+ node->left = CONCAT(rr_rotate, T)(child); \
+ reset_height(node); \
+ return CONCAT(ll_rotate, T)(node); \
+ } \
+ static avl_tree_node_t(T) * \
+ CONCAT(avl_tree_balance_, T)(avl_tree_node_t(T) * node) \
+ { \
+ int d = CONCAT(balance_factor, T)(node); \
+ if (d > 1) { \
+ if (CONCAT(balance_factor, T)(node->left) > 0) { \
+ return CONCAT(ll_rotate, T)(node); \
+ } else { \
+ return CONCAT(lr_rotate, T)(node); \
+ } \
+ } else if (d < -1) { \
+ if (CONCAT(balance_factor, T)(node->right) > 0) { \
+ return CONCAT(rl_rotate, T)(node); \
+ } else { \
+ return CONCAT(rr_rotate, T)(node); \
+ } \
+ } \
+ \
+ return node; \
+ } \
+ static avl_tree_node_t(T) * \
+ CONCAT(avl_tree_loose_insert_, T)( \
+ avl_tree_node_t(T) * node, T value, T * *ptr_out) \
+ { \
+ if (!node) { \
+ node = ALLOC(sizeof(avl_tree_node_t(T))); \
+ assert(node); \
+ node->left = NULL; \
+ node->right = NULL; \
+ node->value = value; \
+ node->height = 1; \
+ *ptr_out = &node->value; \
+ } else { \
+ typeof(CMP(node->value, value)) cmp = CMP(node->value, value); \
+ if (cmp < 0) { \
+ node->left = \
+ CONCAT(avl_tree_loose_insert_, T)(node->left, value, ptr_out); \
+ reset_height(node); \
+ node = CONCAT(avl_tree_balance_, T)(node); \
+ } else if (cmp > 0) { \
+ node->right = \
+ CONCAT(avl_tree_loose_insert_, T)(node->right, value, ptr_out); \
+ reset_height(node); \
+ node = CONCAT(avl_tree_balance_, T)(node); \
+ } \
+ } \
+ return node; \
+ } \
+ T* avl_tree_insert(T)(avl_tree_t(T) * tree, T value) \
+ { \
+ T* ret; \
+ tree->root = CONCAT(avl_tree_loose_insert_, T)(tree->root, value, &ret); \
+ return ret; \
+ } \
+ size_t avl_tree_height(T)(avl_tree_t(T) * tree) \
+ { \
+ if (!tree) return 0; \
+ return get_height(tree->root); \
+ } \
+ static T* CONCAT(loose_avl_tree_find, T)(avl_tree_node_t(T) * node, T value) \
+ { \
+ if (!node) return NULL; \
+ \
+ typeof(CMP(node->value, value)) cmp = CMP(node->value, value); \
+ if (cmp > 0) { \
+ return CONCAT(loose_avl_tree_find, T)(node->right, value); \
+ } else if (cmp < 0) { \
+ return CONCAT(loose_avl_tree_find, T)(node->left, value); \
+ } \
+ return &node->value; \
+ } \
+ T* avl_tree_find(T)(const avl_tree_t(T) * tree, T val) \
+ { \
+ if (!tree) return NULL; \
+ return CONCAT(loose_avl_tree_find, T)(tree->root, val); \
+ } \
+ static avl_tree_node_t(T) * \
+ CONCAT(pluck_left, T)(avl_tree_node_t(T) * node, T * into) \
+ { \
+ if (node->left) { \
+ node->left = CONCAT(pluck_left, T)(node->left, into); \
+ reset_height(node); \
+ return CONCAT(avl_tree_balance_, T)(node); \
+ } else { \
+ *into = node->value; \
+ FREE(node); \
+ return node->right; \
+ } \
+ } \
+ static avl_tree_node_t(T) * \
+ CONCAT(pluck_right, T)(avl_tree_node_t(T) * node, T * into) \
+ { \
+ if (node->right) { \
+ node->right = CONCAT(pluck_right, T)(node->right, into); \
+ reset_height(node); \
+ return CONCAT(avl_tree_balance_, T)(node); \
+ } else { \
+ *into = node->value; \
+ FREE(node); \
+ return node->left; \
+ } \
+ } \
+ avl_tree_node_t(T) * \
+ CONCAT(loose_avl_tree_erase, T)( \
+ avl_tree_node_t(T) * node, T value, bool* out, T* erased) \
+ { \
+ if (!node) { \
+ *out = 0; \
+ return NULL; \
+ } \
+ typeof(CMP(node->value, value)) cmp = CMP(node->value, value); \
+ if (cmp == 0) { \
+ if (erased) *erased = node->value; \
+ *out = 1; \
+ if (!node->right && !node->left) { \
+ FREE(node); \
+ return NULL; \
+ } \
+ if (get_height(node->right) > get_height(node->left)) { \
+ node->right = CONCAT(pluck_left, T)(node->right, &node->value); \
+ reset_height(node); \
+ node = CONCAT(avl_tree_balance_, T)(node); \
+ return node; \
+ } \
+ node->left = CONCAT(pluck_right, T)(node->left, &node->value); \
+ reset_height(node); \
+ node = CONCAT(avl_tree_balance_, T)(node); \
+ return node; \
+ } else if (cmp < 0) { \
+ node->left = \
+ CONCAT(loose_avl_tree_erase, T)(node->left, value, out, erased); \
+ reset_height(node); \
+ node = CONCAT(avl_tree_balance_, T)(node); \
+ } else { \
+ node->right = \
+ CONCAT(loose_avl_tree_erase, T)(node->right, value, out, erased); \
+ reset_height(node); \
+ node = CONCAT(avl_tree_balance_, T)(node); \
+ } \
+ return node; \
+ } \
+ bool avl_tree_erase(T)(avl_tree_t(T) * tree, T val, T * erased) \
+ { \
+ if (!tree) return 0; \
+ bool out; \
+ tree->root = \
+ CONCAT(loose_avl_tree_erase, T)(tree->root, val, &out, erased); \
+ return out; \
+ }
+
+#endif /* _SHARED_AVL_TREE_H_ */
diff --git a/include/shared/avl_tree.h.gch b/include/shared/avl_tree.h.gch
new file mode 100644
index 0000000..78fc043
--- /dev/null
+++ b/include/shared/avl_tree.h.gch
Binary files differ
diff --git a/include/shared/linked_list.h b/include/shared/linked_list.h
index 3f8e075..ec72377 100644
--- a/include/shared/linked_list.h
+++ b/include/shared/linked_list.h
@@ -1,15 +1,21 @@
#ifndef SHARED_LINKED_LIST_H_
#define SHARED_LINKED_LIST_H_
-#define linked_list_t(type) linked_list_##type##_t
-#define linked_list_node_t(type) linked_list_node_##type##_t
-#define linked_list_push_back(type) linked_list_push_back_##type
-#define linked_list_push_front(type) linked_list_push_front_##type
-#define linked_list_pop_front(type) linked_list_pop_front_##type
-#define linked_list_pop_back(type) linked_list_pop_back_##type
-#define linked_list_front(type) linked_list_front_##type
-#define linked_list_back(type) linked_list_back_##type
-#define linked_list_length(type) linked_list_length_##type
+#include "kern/common.h"
+
+#define linked_list_t(T) linked_list___##T##___t
+#define linked_list_node_t(T) linked_list_node___##T##___t
+#define linked_list_itr_t(T) linked_list_node_itr___##T##___t
+#define linked_list_push_back(T) linked_list_push_back___##T
+#define linked_list_push_front(T) linked_list_push_front___##T
+#define linked_list_pop_front(T) linked_list_pop_front___##T
+#define linked_list_pop_back(T) linked_list_pop_back___##T
+#define linked_list_front(T) linked_list_front___##T
+#define linked_list_back(T) linked_list_back___##T
+#define linked_list_length(T) linked_list_length___##T
+#define linked_list_find_match(T) linked_list_find_match___##T
+#define linked_list_remove_first_match(T) linked_list_remove_first_match___##T
+#define linked_list_remove(T) linked_list_remove___##T
#define LINKED_LIST_INIT \
{ \
@@ -24,108 +30,171 @@
#define NO_ATTRIBUTE
-#define LINKED_LIST_DECL(type) LINKED_LIST_INTERNAL_DECL(type, NO_ATTRIBUTE)
+#define LINKED_LIST_DECL(T) LINKED_LIST_INTERNAL_DECL(T, NO_ATTRIBUTE)
-#define LINKED_LIST_STATIC_DECL(type) LINKED_LIST_INTERNAL_DECL(type, static)
+#define LINKED_LIST_STATIC_DECL(T) LINKED_LIST_INTERNAL_DECL(T, static inline)
-#define LINKED_LIST_INTERNAL_DECL(type, attr) \
- typedef struct LINKED_LIST_NODE_##type { \
- type value; \
- struct LINKED_LIST_NODE_##type* next; \
- } linked_list_node_t(type); \
+#define LINKED_LIST_INTERNAL_DECL(T, attr) \
+ typedef struct LINKED_LIST_NODE_##T { \
+ T value; \
+ struct LINKED_LIST_NODE_##T* next; \
+ } linked_list_node_t(T); \
+ \
+ typedef struct { \
+ linked_list_node_t(T) * prev; \
+ linked_list_node_t(T) * cur; \
+ } linked_list_itr_t(T); \
\
typedef struct { \
- linked_list_node_t(type) * head; \
- } linked_list_t(type); \
+ linked_list_node_t(T) * head; \
+ } linked_list_t(T); \
\
- attr void linked_list_push_back(type)(linked_list_t(type) * ll, type value); \
- attr void linked_list_push_front(type)( \
- linked_list_t(type) * ll, type value); \
- attr void linked_list_pop_back(type)(linked_list_t(type) * ll); \
- attr void linked_list_pop_front(type)(linked_list_t(type) * ll); \
- attr type* linked_list_front(type)(linked_list_t(type) * ll); \
- attr type* linked_list_back(type)(linked_list_t(type) * ll);
+ attr void linked_list_push_back(T)(linked_list_t(T) * ll, T value); \
+ attr void linked_list_push_front(T)(linked_list_t(T) * ll, T value); \
+ attr void linked_list_pop_back(T)(linked_list_t(T) * ll); \
+ attr void linked_list_pop_front(T)(linked_list_t(T) * ll); \
+ attr size_t linked_list_length(T)(const linked_list_t(T) * ll); \
+ attr T* linked_list_front(T)(const linked_list_t(T) * ll); \
+ attr bool linked_list_find_match(T)( \
+ const linked_list_t(T) * ll, \
+ linked_list_itr_t(T) * itr_out, \
+ bool (*match)(T, void*), \
+ void* closure); \
+ attr bool linked_list_remove_first_match(T)( \
+ linked_list_t(T) * ll, T * out, bool (*match)(T, void*), void* closure); \
+ attr T* linked_list_back(T)(const linked_list_t(T) * ll);
-#define LINKED_LIST_IMPL(type) LINKED_LIST_INTERNAL_IMPL(type, NO_ATTRIBUTE)
+#define LINKED_LIST_IMPL(T) LINKED_LIST_INTERNAL_IMPL(T, NO_ATTRIBUTE)
-#define LINKED_LIST_STATIC_IMPL(type) LINKED_LIST_INTERNAL_IMPL(type, static)
+#define LINKED_LIST_STATIC_IMPL(T) LINKED_LIST_INTERNAL_IMPL(T, static inline)
-#define LINKED_LIST_INTERNAL_IMPL(type, attr) \
- attr void linked_list_push_back(type)(linked_list_t(type) * ll, type value) \
- { \
- if (!ll->head) { \
- ll->head = kalloc(sizeof(linked_list_node_t(type))); \
- ll->head->value = value; \
- ll->head->next = NULL; \
- } else { \
- linked_list_node_t(type)* c = ll->head; \
- while (c->next) c = c->next; \
- c->next = kalloc(sizeof(linked_list_node_t(type))); \
- c->next->next = NULL; \
- c->next->value = value; \
- } \
- } \
- attr void linked_list_push_front(type)(linked_list_t(type) * ll, type value) \
- { \
- if (!ll->head) { \
- ll->head = kalloc(sizeof(linked_list_node_t(type))); \
- ll->head->value = value; \
- ll->head->next = NULL; \
- } else { \
- linked_list_node_t(type)* node = \
- kalloc(sizeof(linked_list_node_t(type))); \
- node->next = ll->head; \
- node->value = value; \
- ll->head = node; \
- } \
- } \
- attr void linked_list_pop_back(type)(linked_list_t(type) * ll) \
- { \
- if (!ll->head) { \
- return; \
- } \
- if (!ll->head->next) { \
- kfree(ll->head); \
- ll->head = NULL; \
- return; \
- } \
- linked_list_node_t(type)* c = ll->head; \
- while (c->next->next) c = c->next; \
- kfree(c->next); \
- c->next = NULL; \
- return; \
- } \
- attr void linked_list_pop_front(type)(linked_list_t(type) * ll) \
- { \
- if (!ll->head) { \
- return; \
- } \
- linked_list_node_t(type)* node = ll->head; \
- ll->head = node->next; \
- kfree(node); \
- } \
- attr type* linked_list_front(type)(linked_list_t(type) * ll) \
- { \
- if (!ll->head) { \
- return NULL; \
- } \
- return &ll->head->value; \
- } \
- attr type* linked_list_back(type)(linked_list_t(type) * ll) \
- { \
- if (!ll->head) { \
- return NULL; \
- } \
- linked_list_node_t(type)* cur = ll->head; \
- while (cur->next) cur = cur->next; \
- return &cur->value; \
- } \
- attr size_t linked_list_length(type)(linked_list_t(type) * ll) \
- { \
- linked_list_node_t(type) * cur; \
- size_t ret = 0; \
- for (cur = ll->head; cur; cur = cur->next) ++ret; \
- return ret; \
- }
+#define PRAGMA(x) _Pragma(#x)
+#define LINKED_LIST_INTERNAL_IMPL(T, attr) \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wunused-function\"") \
+ attr void linked_list_push_back(T)(linked_list_t(T) * ll, T value) \
+ { \
+ if (!ll->head) { \
+ ll->head = kalloc(sizeof(linked_list_node_t(T))); \
+ ll->head->value = value; \
+ ll->head->next = NULL; \
+ } else { \
+ linked_list_node_t(T)* c = ll->head; \
+ while (c->next) c = c->next; \
+ c->next = kalloc(sizeof(linked_list_node_t(T))); \
+ c->next->next = NULL; \
+ c->next->value = value; \
+ } \
+ } \
+ attr void linked_list_push_front(T)(linked_list_t(T) * ll, T value) \
+ { \
+ if (!ll->head) { \
+ ll->head = kalloc(sizeof(linked_list_node_t(T))); \
+ ll->head->value = value; \
+ ll->head->next = NULL; \
+ } else { \
+ linked_list_node_t(T)* node = kalloc(sizeof(linked_list_node_t(T))); \
+ node->next = ll->head; \
+ node->value = value; \
+ ll->head = node; \
+ } \
+ } \
+ attr void linked_list_pop_back(T)(linked_list_t(T) * ll) \
+ {