diff --git a/ds/xor_list/Makefile b/ds/xor_list/Makefile new file mode 100644 index 0000000..09075df --- /dev/null +++ b/ds/xor_list/Makefile @@ -0,0 +1,5 @@ +all: + cc -o main main.c && ./main + +clean: + rm -f main \ No newline at end of file diff --git a/ds/xor_list/main.c b/ds/xor_list/main.c new file mode 100644 index 0000000..5a90a36 --- /dev/null +++ b/ds/xor_list/main.c @@ -0,0 +1,61 @@ +#include "xor_list.h" + +#include + +struct book { + int id; + char name[50]; + xor_list_node_t node; +}; + +int match_id(xor_list_node_t *n, void *arg) +{ + struct book *b = container_of(n, struct book, node); + return b->id == *(int *)arg; +} + +int main() { + xor_list_t list; + xor_list_init(&list); + + struct book a = { .id = 1, .name = "西游记" }; + struct book b = { .id = 2, .name = "红楼梦" }; + struct book c = { .id = 3, .name = "三国演义" }; + struct book d = { .id = 4, .name = "水浒传" }; + xor_list_append(&list, &a.node); + xor_list_append(&list, &b.node); + xor_list_append(&list, &c.node); + xor_list_append(&list, &d.node); + + xor_list_node_t *pos, *prev, *next; + printf("\n----for_each forward----\n"); + xor_list_for_each(pos, prev, &list) { + struct book *it = container_of(pos, struct book, node); + printf("[%d] 《%s》\n", it->id, it->name); + } + printf("\n----for_each reverse----\n"); + xor_list_for_each_reverse(pos, next, &list) { + struct book *it = container_of(pos, struct book, node); + printf("[%d] 《%s》\n", it->id, it->name); + } + + struct book e = { 5, "聊斋志异" }; + struct book f = { 6, "老子" }; + int key = 3; + pos = xor_list_find(&list, match_id, &key, &prev); + if (pos) { + xor_list_add_after(&list, pos, prev, &e.node); + xor_list_add_after(&list, pos, prev, &f.node); + } + printf("\n----add_before_(id=%d)_after----\n", key); + xor_list_for_each(pos, prev, &list) { + struct book *it = container_of(pos, struct book, node); + printf("[%d] 《%s》\n", it->id, it->name); + } + printf("\n----reverse add_before_(id=%d)_after----\n", key); + xor_list_for_each_reverse(pos, next, &list) { + struct book *it = container_of(pos, struct book, node); + printf("[%d] 《%s》\n", it->id, it->name); + } + return 0; +} \ No newline at end of file diff --git a/ds/xor_list/xor_list.h b/ds/xor_list/xor_list.h new file mode 100644 index 0000000..92e6b0c --- /dev/null +++ b/ds/xor_list/xor_list.h @@ -0,0 +1,145 @@ +#ifndef _XOR_LIST_H +#define _XOR_LIST_H + +#include +#include + +// XOR Linked List Implementation +// Inspired by Tsoding + +typedef struct xor_list_node { + uintptr_t npx; +} xor_list_node_t; + +typedef struct xor_list { + xor_list_node_t *head; + xor_list_node_t *tail; +} xor_list_t; + +static inline xor_list_node_t * +xor_node(xor_list_node_t *a, xor_list_node_t *b) +{ + return (xor_list_node_t *)((uintptr_t)a ^ (uintptr_t)b); +} + +static inline xor_list_node_t * +xor_list_next(xor_list_node_t *curr, xor_list_node_t *prev) +{ + return xor_node((xor_list_node_t *)curr->npx, prev); +} + +static inline void +xor_list_init(xor_list_t *l) +{ + l->head = NULL; + l->tail = NULL; +} + +static inline int +xor_list_empty(const xor_list_t *l) +{ + return l->head == NULL; +} + +static inline void +xor_list_node_init(xor_list_node_t *n) +{ + n->npx = 0; +} + +static inline void +xor_list_append(xor_list_t *l, xor_list_node_t *n) +{ + xor_list_node_init(n); + n->npx = (uintptr_t)l->tail; + if (l->tail) { + l->tail->npx ^= (uintptr_t)n; + } else { + l->head = n; + } + l->tail = n; +} + +static inline void +xor_list_prepend(xor_list_t *l, xor_list_node_t *n) +{ + xor_list_node_init(n); + n->npx = (uintptr_t)l->head; + if (l->head) { + l->head->npx ^= (uintptr_t)n; + } else { + l->tail = n; + } + l->head = n; +} + +static inline void +xor_list_add_before(xor_list_t *l, xor_list_node_t *pos, xor_list_node_t *prev, xor_list_node_t *n) +{ + xor_list_node_t *next; + next = xor_list_next(pos, prev); + xor_list_node_init(n); + n->npx = (uintptr_t)prev ^ (uintptr_t)pos; + prev->npx ^= (uintptr_t)pos ^ (uintptr_t)n; + pos->npx ^= (uintptr_t)prev ^ (uintptr_t)n; +} + +static inline void +xor_list_add_after(xor_list_t *l, xor_list_node_t *pos, xor_list_node_t *prev, xor_list_node_t *n) +{ + xor_list_node_t *next; + next = xor_list_next(pos, prev); + xor_list_node_init(n); + n->npx = (uintptr_t)pos ^ (uintptr_t)next; + pos->npx ^= (uintptr_t)next ^ (uintptr_t)n; + if (next) { + next->npx ^= (uintptr_t)pos ^ (uintptr_t)n; + } else { + l->tail = n; + } +} + +static inline xor_list_node_t * +xor_list_find(xor_list_t *l, int (*pred)(xor_list_node_t *n, void *arg), void *arg, xor_list_node_t **out_prev) +{ + xor_list_node_t *curr = l->head; + xor_list_node_t *prev = NULL; + while (curr) { + if (pred(curr, arg)) { + if (out_prev) + *out_prev = prev; + return curr; + } + xor_list_node_t *next = xor_list_next(curr, prev); + prev = curr; + curr = next; + } + return NULL; +} + +#define xor_list_for_each(pos, prev, list) \ + for ((prev) = NULL, (pos) = (list)->head; \ + (pos) != NULL; \ + ({ \ + xor_list_node_t *next = \ + xor_list_next((pos), (prev)); \ + (prev) = (pos); \ + (pos) = next; \ + })) + +#define xor_list_for_each_reverse(pos, next, list) \ + for ((next) = NULL, (pos) = (list)->tail; \ + (pos) != NULL; \ + ({ \ + xor_list_node_t *prev = \ + xor_list_next((pos), (next)); \ + (next) = (pos); \ + (pos) = prev; \ + })) + +#define container_of(ptr, type, member) ({ \ + const typeof(((type *)0)->member) *__mptr = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); \ +}) + +#endif /* _XOR_LIST_H */ \ No newline at end of file