xref: /php-src/ext/dom/lexbor/lexbor/core/bst_map.c (revision bffab33a)
1 /*
2  * Copyright (C) 2018 Alexander Borisov
3  *
4  * Author: Alexander Borisov <borisov@lexbor.com>
5  */
6 
7 #include "lexbor/core/bst_map.h"
8 #include "lexbor/core/utils.h"
9 
10 
11 lexbor_bst_map_t *
lexbor_bst_map_create(void)12 lexbor_bst_map_create(void)
13 {
14     return lexbor_calloc(1, sizeof(lexbor_bst_map_t));
15 }
16 
17 lxb_status_t
lexbor_bst_map_init(lexbor_bst_map_t * bst_map,size_t size)18 lexbor_bst_map_init(lexbor_bst_map_t *bst_map, size_t size)
19 {
20     lxb_status_t status;
21 
22     if (bst_map == NULL) {
23         return LXB_STATUS_ERROR_OBJECT_IS_NULL;
24     }
25 
26     if (size == 0) {
27         return LXB_STATUS_ERROR_WRONG_ARGS;
28     }
29 
30     /* bst */
31     bst_map->bst = lexbor_bst_create();
32     status = lexbor_bst_init(bst_map->bst, size);
33     if (status) {
34         return status;
35     }
36 
37     /* dobject */
38     bst_map->entries = lexbor_dobject_create();
39     status = lexbor_dobject_init(bst_map->entries, size,
40                                  sizeof(lexbor_bst_map_entry_t));
41     if (status) {
42         return status;
43     }
44 
45     /* mraw */
46     bst_map->mraw = lexbor_mraw_create();
47     status = lexbor_mraw_init(bst_map->mraw, (size * 6));
48     if (status) {
49         return status;
50     }
51 
52     return LXB_STATUS_OK;
53 }
54 
55 void
lexbor_bst_map_clean(lexbor_bst_map_t * bst_map)56 lexbor_bst_map_clean(lexbor_bst_map_t *bst_map)
57 {
58     lexbor_bst_clean(bst_map->bst);
59     lexbor_mraw_clean(bst_map->mraw);
60     lexbor_dobject_clean(bst_map->entries);
61 }
62 
63 lexbor_bst_map_t *
lexbor_bst_map_destroy(lexbor_bst_map_t * bst_map,bool self_destroy)64 lexbor_bst_map_destroy(lexbor_bst_map_t *bst_map, bool self_destroy)
65 {
66     if (bst_map == NULL) {
67         return NULL;
68     }
69 
70     bst_map->bst = lexbor_bst_destroy(bst_map->bst, true);
71     bst_map->mraw = lexbor_mraw_destroy(bst_map->mraw, true);
72     bst_map->entries = lexbor_dobject_destroy(bst_map->entries, true);
73 
74     if (self_destroy) {
75         return lexbor_free(bst_map);
76     }
77 
78     return bst_map;
79 }
80 
81 lexbor_bst_map_entry_t *
lexbor_bst_map_search(lexbor_bst_map_t * bst_map,lexbor_bst_entry_t * scope,const lxb_char_t * key,size_t key_len)82 lexbor_bst_map_search(lexbor_bst_map_t *bst_map, lexbor_bst_entry_t *scope,
83                       const lxb_char_t *key, size_t key_len)
84 {
85     lexbor_bst_map_entry_t *entry;
86     lexbor_bst_entry_t *bst_entry;
87 
88     size_t hash_id = lexbor_utils_hash_hash(key, key_len);
89 
90     bst_entry = lexbor_bst_search(bst_map->bst, scope, hash_id);
91     if (bst_entry == NULL) {
92         return NULL;
93     }
94 
95     do {
96         entry = bst_entry->value;
97 
98         if (entry->str.length == key_len &&
99             lexbor_str_data_cmp(entry->str.data, key))
100         {
101             return entry;
102         }
103 
104         bst_entry = bst_entry->next;
105     }
106     while (bst_entry != NULL);
107 
108     return NULL;
109 }
110 
111 lexbor_bst_map_entry_t *
lexbor_bst_map_insert(lexbor_bst_map_t * bst_map,lexbor_bst_entry_t ** scope,const lxb_char_t * key,size_t key_len,void * value)112 lexbor_bst_map_insert(lexbor_bst_map_t *bst_map,
113                       lexbor_bst_entry_t **scope,
114                       const lxb_char_t *key, size_t key_len, void *value)
115 {
116     lexbor_bst_map_entry_t *entry;
117 
118     entry = lexbor_bst_map_insert_not_exists(bst_map, scope, key, key_len);
119     if (entry == NULL) {
120         return NULL;
121     }
122 
123     entry->value = value;
124 
125     return entry;
126 }
127 
128 lexbor_bst_map_entry_t *
lexbor_bst_map_insert_not_exists(lexbor_bst_map_t * bst_map,lexbor_bst_entry_t ** scope,const lxb_char_t * key,size_t key_len)129 lexbor_bst_map_insert_not_exists(lexbor_bst_map_t *bst_map,
130                                  lexbor_bst_entry_t **scope,
131                                  const lxb_char_t *key, size_t key_len)
132 {
133     lexbor_bst_map_entry_t *entry;
134     lexbor_bst_entry_t *bst_entry;
135 
136     size_t hash_id = lexbor_utils_hash_hash(key, key_len);
137 
138     bst_entry = lexbor_bst_insert_not_exists(bst_map->bst, scope, hash_id);
139     if (bst_entry == NULL) {
140         return NULL;
141     }
142 
143     if (bst_entry->value == NULL) {
144         goto new_entry;
145     }
146 
147     do {
148         entry = bst_entry->value;
149 
150         if (entry->str.length == key_len &&
151             lexbor_str_data_cmp(entry->str.data, key))
152         {
153             return entry;
154         }
155 
156         if (bst_entry->next == NULL) {
157             bst_entry->next = lexbor_bst_entry_make(bst_map->bst, hash_id);
158             bst_entry = bst_entry->next;
159 
160             if (bst_entry == NULL) {
161                 return NULL;
162             }
163 
164             goto new_entry;
165         }
166 
167         bst_entry = bst_entry->next;
168     }
169     while (1);
170 
171     return NULL;
172 
173 new_entry:
174 
175     entry = lexbor_dobject_calloc(bst_map->entries);
176     if (entry == NULL) {
177         return NULL;
178     }
179 
180     lexbor_str_init(&entry->str, bst_map->mraw, key_len);
181     if (entry->str.data == NULL) {
182         lexbor_dobject_free(bst_map->entries, entry);
183 
184         return NULL;
185     }
186 
187     lexbor_str_append(&entry->str, bst_map->mraw, key, key_len);
188 
189     bst_entry->value = entry;
190 
191     return entry;
192 }
193 
194 void *
lexbor_bst_map_remove(lexbor_bst_map_t * bst_map,lexbor_bst_entry_t ** scope,const lxb_char_t * key,size_t key_len)195 lexbor_bst_map_remove(lexbor_bst_map_t *bst_map, lexbor_bst_entry_t **scope,
196                       const lxb_char_t *key, size_t key_len)
197 {
198     lexbor_bst_map_entry_t *entry;
199     lexbor_bst_entry_t *bst_entry;
200 
201     size_t hash_id = lexbor_utils_hash_hash(key, key_len);
202 
203     bst_entry = lexbor_bst_search(bst_map->bst, *scope, hash_id);
204     if (bst_entry == NULL) {
205         return NULL;
206     }
207 
208     do {
209         entry = bst_entry->value;
210 
211         if (entry->str.length == key_len &&
212             lexbor_str_data_cmp(entry->str.data, key))
213         {
214             void *value = entry->value;
215 
216             lexbor_bst_remove_by_pointer(bst_map->bst, bst_entry, scope);
217 
218             lexbor_str_destroy(&entry->str, bst_map->mraw, false);
219             lexbor_dobject_free(bst_map->entries, entry);
220 
221             return value;
222         }
223 
224         bst_entry = bst_entry->next;
225     }
226     while (bst_entry != NULL);
227 
228     return NULL;
229 }
230 
231 /*
232  * No inline functions.
233  */
234 lexbor_mraw_t *
lexbor_bst_map_mraw_noi(lexbor_bst_map_t * bst_map)235 lexbor_bst_map_mraw_noi(lexbor_bst_map_t *bst_map)
236 {
237     return lexbor_bst_map_mraw(bst_map);
238 }
239