src/kv_list.c

changeset 1350
189756516eaa
parent 1348
a1da355ed3b8
equal deleted inserted replaced
1349:b1696d0d598b 1350:189756516eaa
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29 #include "cx/kv_list.h" 29 #include "cx/kv_list.h"
30 #include "cx/hash_map.h"
31 #include "cx/linked_list.h"
32
33 typedef struct cx_kv_list_s cx_kv_list;
34
35 struct cx_kv_list_map_s {
36 struct cx_hash_map_s map_base;
37 /** Back-reference to the list. */
38 cx_kv_list *list;
39 };
40
41 /** The list aspect (must have the same layout as the normal linked list). */
42 struct cx_kv_list_list_s {
43 struct cx_list_s list_base;
44 void *begin;
45 void *end;
46 };
47
48 struct cx_kv_list_s {
49 struct cx_kv_list_list_s list;
50 /** The lookup map - stores pointers to the nodes. */
51 struct cx_kv_list_map_s *map;
52 const cx_list_class *list_methods;
53 const cx_map_class *map_methods;
54 };
55
56 static void cx_kvl_deallocate(struct cx_list_s *list) {
57 cx_kv_list *kv_list = (cx_kv_list*)list;
58 // free the map first
59 kv_list->map_methods->deallocate(&kv_list->map->map_base.base);
60 kv_list->list_methods->deallocate(list);
61 }
62
63 static void *cx_kvl_insert_element(
64 struct cx_list_s *list,
65 size_t index,
66 const void *data
67 ) {
68 cx_kv_list *kv_list = (cx_kv_list*)list;
69 // TODO: trick the base method by adding the required space for the key to the elem_size
70 return kv_list->list_methods->insert_element(list, index, data);
71 }
72
73 static size_t cx_kvl_insert_array(
74 struct cx_list_s *list,
75 size_t index,
76 const void *data,
77 size_t n
78 ) {
79 cx_kv_list *kv_list = (cx_kv_list*)list;
80 // TODO: trick the base method by adding the required space for the key to the elem_size
81 return kv_list->list_methods->insert_array(list, index, data, n);
82 }
83
84 static size_t cx_kvl_insert_sorted(
85 struct cx_list_s *list,
86 const void *sorted_data,
87 size_t n
88 ) {
89 cx_kv_list *kv_list = (cx_kv_list*)list;
90 // TODO: trick the base method by adding the required space for the key to the elem_size
91 return kv_list->list_methods->insert_sorted(list, sorted_data, n);
92 }
93
94 static int cx_kvl_insert_iter(
95 struct cx_iterator_s *iter,
96 const void *elem,
97 int prepend
98 ) {
99 cx_kv_list *kv_list = (cx_kv_list*)iter->src_handle.m;
100 // TODO: trick the base method by adding the required space for the key to the elem_size
101 return kv_list->list_methods->insert_iter(iter, elem, prepend);
102 }
103
104 static size_t cx_kvl_remove(
105 struct cx_list_s *list,
106 size_t index,
107 size_t num,
108 void *targetbuf
109 ) {
110 cx_kv_list *kv_list = (cx_kv_list*)list;
111 // TODO: always use the target buffer to get the element first,
112 // then obtain the key, remove it from the map,
113 // and finally call any destructors manually
114 return kv_list->list_methods->remove(list, index, num, targetbuf);
115 }
116
117 static void cx_kvl_clear(struct cx_list_s *list) {
118 cx_kv_list *kv_list = (cx_kv_list*)list;
119 kv_list->list_methods->clear(list);
120 // also clear all lookup entries
121 cxMapClear(&kv_list->map->map_base.base);
122 }
123
124 static int cx_kvl_swap(
125 struct cx_list_s *list,
126 size_t i,
127 size_t j
128 ) {
129 cx_kv_list *kv_list = (cx_kv_list*)list;
130 return kv_list->list_methods->swap(list, i, j);
131 }
132
133 static void *cx_kvl_at(
134 const struct cx_list_s *list,
135 size_t index
136 ) {
137 const cx_kv_list *kv_list = (const cx_kv_list*)list;
138 return kv_list->list_methods->at(list, index);
139 }
140
141 static size_t cx_kvl_find_remove(
142 struct cx_list_s *list,
143 const void *elem,
144 bool remove
145 ) {
146 cx_kv_list *kv_list = (cx_kv_list*)list;
147 // TODO: implement removal of the key in the map
148 return kv_list->list_methods->find_remove(list, elem, remove);
149 }
150
151 static void cx_kvl_sort(struct cx_list_s *list) {
152 cx_kv_list *kv_list = (cx_kv_list*)list;
153 kv_list->list_methods->sort(list);
154 }
155
156 static int cx_kvl_compare(
157 const struct cx_list_s *list,
158 const struct cx_list_s *other
159 ) {
160 // TODO: make it so that comparison with normal linked lists is also optimized
161 const cx_kv_list *kv_list = (const cx_kv_list*)list;
162 return kv_list->list_methods->compare(list, other);
163 }
164
165 static void cx_kvl_reverse(struct cx_list_s *list) {
166 cx_kv_list *kv_list = (cx_kv_list*)list;
167 kv_list->list_methods->reverse(list);
168 }
169
170 static struct cx_iterator_s cx_kvl_iterator(
171 const struct cx_list_s *list,
172 size_t index,
173 bool backward
174 ) {
175 const cx_kv_list *kv_list = (const cx_kv_list*)list;
176 // TODO: cannot really forward, because mutating iterators must be able to remove the element
177 return kv_list->list_methods->iterator(list, index, backward);
178 }
179
180 static cx_list_class cx_kv_list_class = {
181 cx_kvl_deallocate,
182 cx_kvl_insert_element,
183 cx_kvl_insert_array,
184 cx_kvl_insert_sorted,
185 cx_kvl_insert_iter,
186 cx_kvl_remove,
187 cx_kvl_clear,
188 cx_kvl_swap,
189 cx_kvl_at,
190 cx_kvl_find_remove,
191 cx_kvl_sort,
192 cx_kvl_compare,
193 cx_kvl_reverse,
194 cx_kvl_iterator,
195 };
30 196
31 CxList *cxKvListCreate( 197 CxList *cxKvListCreate(
32 const CxAllocator *allocator, 198 const CxAllocator *allocator,
33 cx_compare_func comparator, 199 cx_compare_func comparator,
34 size_t elem_size 200 size_t elem_size
35 ) { 201 ) {
36 return NULL; 202 if (allocator == NULL) {
203 allocator = cxDefaultAllocator;
204 }
205
206 // create a normal linked list and a normal hash map, first
207 CxList *list = cxLinkedListCreate(allocator, comparator, elem_size);
208 if (list == NULL) return NULL; // LCOV_EXCL_LINE
209 CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 0);
210 if (map == NULL) { // LCOV_EXCL_START
211 cxListFree(list);
212 return NULL;
213 } // LCOV_EXCL_STOP
214
215 // reallocate the map to add memory for the list back-reference
216 struct cx_kv_list_map_s *kv_map = cxRealloc(allocator, map, sizeof(struct cx_kv_list_map_s));
217
218 // reallocate the list to add memory for storing the metadata
219 cx_kv_list *kv_list = cxRealloc(allocator, list, sizeof(cx_kv_list));
220
221 // if any of the reallocations failed, we bail out
222 if (kv_map != NULL && kv_list != NULL) {
223 map = (CxMap*) kv_map;
224 list = (CxList*) kv_list;
225 } else { // LCOV_EXCL_START
226 cxListFree(list);
227 cxMapFree(map);
228 return NULL;
229 } // LCOV_EXCL_STOP
230
231 // combine the list and the map aspect
232 kv_list->map = kv_map;
233 kv_map->list = kv_list;
234
235 // remember the base methods and override them
236 kv_list->list_methods = list->cl;
237 kv_list->map_methods = map->cl;
238 list->cl = &cx_kv_list_class;
239 // TODO: override all map members
240 // and remember to set the sorted flag of the list to false in the put/emplace methods!
241
242 return list;
37 } 243 }
38 244
39 CxMap *cxKvListCreateAsMap( 245 CxMap *cxKvListCreateAsMap(
40 const CxAllocator *allocator, 246 const CxAllocator *allocator,
41 cx_compare_func comparator, 247 cx_compare_func comparator,
44 CxList *list = cxKvListCreate(allocator, comparator, elem_size); 250 CxList *list = cxKvListCreate(allocator, comparator, elem_size);
45 return list == NULL ? NULL : cxKvListAsMap(list); 251 return list == NULL ? NULL : cxKvListAsMap(list);
46 } 252 }
47 253
48 CxList *cxKvListAsList(CxMap *map) { 254 CxList *cxKvListAsList(CxMap *map) {
49 return NULL; 255 return &((struct cx_kv_list_map_s*)map)->list->list.list_base;
50 } 256 }
51 257
52 CxMap *cxKvListAsMap(CxList *list) { 258 CxMap *cxKvListAsMap(CxList *list) {
53 return NULL; 259 return &((cx_kv_list*)list)->map->map_base.base;
54 } 260 }
55 261
56 int cx_kv_list_set_key(CxList *list, size_t index, CxHashKey key) { 262 int cx_kv_list_set_key(CxList *list, size_t index, CxHashKey key) {
57 return -1; 263 return -1;
58 } 264 }

mercurial