GFXprim
2D bitmap graphics library with emphasis on speed and correctness
Loading...
Searching...
No Matches
gp_trie.h
Go to the documentation of this file.
1//SPDX-License-Identifier: GPL-2.1-or-later
2
3/*
4
5 Copyright (C) 2022 Cyril Hrubis <metan@ucw.cz>
6
7 */
8
16#ifndef UTILS_GP_TRIE_H
17#define UTILS_GP_TRIE_H
18
19#include <stdlib.h>
20#include <string.h>
21#include <stdint.h>
22#include <core/gp_common.h>
23#include <core/gp_compiler.h>
24#include <utils/gp_avl_tree.h>
25#include <utils/gp_utf.h>
26
28typedef struct gp_trie_node {
29 void *payload;
30 struct gp_trie_node *parent;
31
32 /* A node key */
33 uint32_t key;
34
35 /* embedded pointers */
36 gp_avl_node avl_next;
37
38 /* children */
39 gp_avl_node *nodes;
41
42static inline void *gp_trie_payload(gp_trie_node *self)
43{
44 return self->payload;
45}
46
47static inline gp_trie_node *gp_trie_node_new(void)
48{
49 struct gp_trie_node *node = malloc(sizeof(gp_trie_node));
50
51 if (!node)
52 return NULL;
53
54 memset(node, 0, sizeof(*node));
55
56 return node;
57}
58
59static inline void gp_trie_free(gp_trie_node *root, void (*payload_free)(void *payload))
60{
61 gp_avl_node *avl_root, *min;
62 gp_trie_node *node;
63
64 if (!root)
65 return;
66
67 avl_root = root->nodes;
68
69 if (avl_root) {
70 do {
71 avl_root = gp_avl_tree_del_min(avl_root, &min);
72 node = GP_CONTAINER_OF(min, gp_trie_node, avl_next);
73 gp_trie_free(node, payload_free);
74 } while (avl_root);
75 }
76
77 if (payload_free)
78 payload_free(root->payload);
79
80 free(root);
81}
82
83static inline int gp_trie_cmp(gp_avl_node *a, gp_avl_node *b)
84{
85 gp_trie_node *ta = GP_CONTAINER_OF(a, gp_trie_node, avl_next);
86 gp_trie_node *tb = GP_CONTAINER_OF(b, gp_trie_node, avl_next);
87
88 return ta->key - tb->key;
89}
90
91static inline int gp_trie_key_cmp(gp_avl_node *a, const void *key)
92{
93 gp_trie_node *ta = GP_CONTAINER_OF(a, gp_trie_node, avl_next);
94 uint32_t kval = *(const uint32_t*)key;
95
96 return ta->key - kval;
97}
98
99GP_WUR static inline gp_trie_node *gp_trie_ins(gp_trie_node *root, const char *str_key, void *payload)
100{
101 uint32_t key = gp_utf8_next(&str_key);
102 gp_trie_node *node = NULL;
103 gp_avl_node *avl_node;
104
105 if (!root) {
106 root = gp_trie_node_new();
107 if (!root)
108 return NULL;
109 }
110
111 if (!key) {
112 root->payload = payload;
113 return root;
114 }
115
116 avl_node = gp_avl_tree_lookup(root->nodes, &key, gp_trie_key_cmp);
117 if (avl_node)
118 node = GP_CONTAINER_OF(avl_node, gp_trie_node, avl_next);
119
120 node = gp_trie_ins(node, str_key, payload);
121
122 if (!node)
123 return root;
124
125 if (!avl_node) {
126 node->key = key;
127 root->nodes = gp_avl_tree_ins(root->nodes, &node->avl_next, gp_trie_cmp);
128 }
129
130 node->parent = root;
131 return root;
132}
133
134static inline gp_trie_node *gp_trie_lookup(gp_trie_node *root, const char *str_key)
135{
136 uint32_t key = gp_utf8_next(&str_key);
137 gp_avl_node *avl_node;
138
139 if (!key)
140 return root;
141
142 if (!root)
143 return NULL;
144
145 avl_node = gp_avl_tree_lookup(root->nodes, &key, gp_trie_key_cmp);
146 if (!avl_node)
147 return NULL;
148
149 return gp_trie_lookup(GP_CONTAINER_OF(avl_node, gp_trie_node, avl_next), str_key);
150}
151
152GP_WUR static inline gp_trie_node *gp_trie_del_(gp_trie_node *root, const char *str_key, void **payload)
153{
154 uint32_t key = gp_utf8_next(&str_key);
155 gp_trie_node *node = NULL;
156 gp_avl_node *avl_node;
157
158 if (!root)
159 return NULL;
160
161 if (!key) {
162 if (payload)
163 *payload = root->payload;
164
165 if (root->nodes) {
166 root->payload = NULL;
167 return NULL;
168 }
169
170 return root;
171 }
172
173 avl_node = gp_avl_tree_lookup(root->nodes, &key, gp_trie_key_cmp);
174 if (avl_node)
175 node = GP_CONTAINER_OF(avl_node, gp_trie_node, avl_next);
176
177 node = gp_trie_del_(node, str_key, payload);
178 if (node) {
179 root->nodes = gp_avl_tree_del(root->nodes, &key, NULL, gp_trie_key_cmp);
180 free(node);
181 }
182
183 if (root->payload)
184 return NULL;
185
186 if (root->nodes)
187 return NULL;
188
189 return root;
190}
191
192GP_WUR static inline gp_trie_node *gp_trie_del(gp_trie_node *root, const char *str_key, void **payload)
193{
194 gp_trie_node *node = gp_trie_del_(root, str_key, payload);
195
196 if (node) {
197 free(root);
198 return NULL;
199 }
200
201 return root;
202}
203
204#endif /* UTILS_GP_TRIE_H */
Common macros.
#define GP_CONTAINER_OF(ptr, structure, member)
Converts from a pointer to a struct field to a pointer to the struct itself.
Definition gp_common.h:156
AVL tree implementation.
static gp_avl_node * gp_avl_tree_del_min(gp_avl_node *root, gp_avl_node **min)
Removes a minimal node from an AVL tree.
static gp_avl_node * gp_avl_tree_ins(gp_avl_node *root, gp_avl_node *node, int(*cmp)(gp_avl_node *a, gp_avl_node *b))
Inserts a node into an AVL tree.
static gp_avl_node * gp_avl_tree_lookup(gp_avl_node *root, const void *key, int(*cmp)(gp_avl_node *a, const void *key))
Looks up a node by a key.
static gp_avl_node * gp_avl_tree_del(gp_avl_node *root, const void *key, gp_avl_node **del, int(*cmp)(gp_avl_node *a, const void *key))
Removes a node by a key from an AVL tree.
A compiler dependent macros.
#define GP_WUR
Expands to warn_unused_result attribute when supported by the compiler.
Definition gp_compiler.h:26
Unicode helper macros and functions.
static uint32_t gp_utf8_next(const char **str)
Parses next unicode character in UTF-8 string.
Definition gp_utf.h:35
AVL tree node.
Definition gp_avl_tree.h:24
Trie node stores pointers.
Definition gp_trie.h:28