Line | Branch | Exec | Source |
---|---|---|---|
1 | /* GATE PROJECT LICENSE: | ||
2 | +----------------------------------------------------------------------------+ | ||
3 | | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> | | ||
4 | | All rights reserved. | | ||
5 | | | | ||
6 | | Redistribution and use in source and binary forms, with or without | | ||
7 | | modification, are permitted provided that the following conditions are met:| | ||
8 | | | | ||
9 | | 1. Redistributions of source code must retain the above copyright notice, | | ||
10 | | this list of conditions and the following disclaimer. | | ||
11 | | 2. Redistributions in binary form must reproduce the above copyright | | ||
12 | | notice, this list of conditions and the following disclaimer in the | | ||
13 | | documentation and/or other materials provided with the distribution. | | ||
14 | | | | ||
15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| | ||
16 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | ||
17 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ||
18 | | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | | ||
19 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | ||
20 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | ||
21 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | ||
22 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | ||
23 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | ||
24 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | ||
25 | | THE POSSIBILITY OF SUCH DAMAGE. | | ||
26 | +----------------------------------------------------------------------------+ | ||
27 | */ | ||
28 | |||
29 | /** @file | ||
30 | * @brief Associative fields to map and resolve key entries to values | ||
31 | * @ingroup gatecore_cpp | ||
32 | */ | ||
33 | |||
34 | #ifndef GATE_MAPS_HPP_INCLUDED | ||
35 | #define GATE_MAPS_HPP_INCLUDED | ||
36 | |||
37 | #include "gate/maps.h" | ||
38 | #include "gate/comparers.hpp" | ||
39 | #include "gate/memalloc.hpp" | ||
40 | #include "gate/results.hpp" | ||
41 | #include "gate/exceptions.hpp" | ||
42 | #include "gate/debugging.h" | ||
43 | #include "gate/enumerators.hpp" | ||
44 | #include "gate/hashes.hpp" | ||
45 | |||
46 | namespace gate | ||
47 | { | ||
48 | |||
49 | template<class KEY, class VALUE> | ||
50 | class Mapping | ||
51 | { | ||
52 | public: | ||
53 | typedef KEY key_t; | ||
54 | typedef VALUE value_t; | ||
55 | typedef Mapping<KEY, VALUE> self_t; | ||
56 | private: | ||
57 | #if defined(GATE_DEBUG_MODE) | ||
58 | union | ||
59 | { | ||
60 | gate_mapping_t impl; | ||
61 | struct | ||
62 | { | ||
63 | key_t const* key_shadow; | ||
64 | value_t const* value_shadow; | ||
65 | }; | ||
66 | }; | ||
67 | #else | ||
68 | gate_mapping_t impl; | ||
69 | #endif | ||
70 | |||
71 | protected: | ||
72 | 753186 | void loadMapping(gate_mapping_t const& mapping) noexcept | |
73 | { | ||
74 | #if defined(GATE_DEBUG_MODE) | ||
75 | 753186 | this->key_shadow = NULL; | |
76 | 753186 | this->value_shadow = NULL; | |
77 | #endif | ||
78 | 753186 | this->impl = mapping; | |
79 | 753186 | } | |
80 | |||
81 | public: | ||
82 | 3010 | Mapping() noexcept | |
83 | { | ||
84 | 3010 | Mem::clear(this->impl); | |
85 | 3010 | } | |
86 | |||
87 | 88 | Mapping(gate_mapping_t const& mapping) noexcept | |
88 | { | ||
89 | 88 | this->loadMapping(mapping); | |
90 | 88 | } | |
91 | |||
92 | 88 | Mapping(self_t const& src) noexcept | |
93 | { | ||
94 | 88 | this->loadMapping(src.impl); | |
95 | 88 | } | |
96 | |||
97 | self_t& operator=(self_t const& src) noexcept | ||
98 | { | ||
99 | this->loadMapping(src.impl); | ||
100 | return *this; | ||
101 | } | ||
102 | 3098 | ~Mapping() noexcept | |
103 | { | ||
104 | 3098 | } | |
105 | |||
106 | 498090 | key_t const& key() const noexcept | |
107 | { | ||
108 | 498090 | return *static_cast<key_t const*>(this->impl.key); | |
109 | } | ||
110 | |||
111 | 90 | value_t const& value() const noexcept | |
112 | { | ||
113 | 90 | return *static_cast<value_t const*>(this->impl.value); | |
114 | } | ||
115 | |||
116 | gate_mapping_t const* c_impl() const noexcept | ||
117 | { | ||
118 | return &this->impl; | ||
119 | } | ||
120 | }; | ||
121 | |||
122 | |||
123 | template<class KEY, class VALUE, class COMPARER = DefaultComparer<KEY> > | ||
124 | class Map | ||
125 | { | ||
126 | public: | ||
127 | typedef KEY key_t; | ||
128 | typedef VALUE value_t; | ||
129 | typedef Map<KEY, VALUE, COMPARER> self_t; | ||
130 | typedef Mapping<KEY, VALUE> mapping_t; | ||
131 | |||
132 | private: | ||
133 | gate_map_t impl; | ||
134 | |||
135 | public: | ||
136 | |||
137 | class const_iterator : public mapping_t | ||
138 | { | ||
139 | protected: | ||
140 | gate_map_iterator_t iter; | ||
141 | |||
142 | 753010 | void loadIterator(gate_map_iterator_t mapiter) noexcept | |
143 | { | ||
144 | 753010 | this->iter = mapiter; | |
145 |
2/2✓ Branch 1 taken 750005 times.
✓ Branch 2 taken 3005 times.
|
753010 | if (gate_map_iterator_valid(mapiter)) |
146 | { | ||
147 | 750005 | this->loadMapping(this->iter->mapping); | |
148 | } | ||
149 | else | ||
150 | { | ||
151 | static gate_mapping_t const empty_mapping = GATE_INIT_EMPTY; | ||
152 | 3005 | this->loadMapping(empty_mapping); | |
153 | } | ||
154 | 753010 | } | |
155 | |||
156 | public: | ||
157 | 2010 | const_iterator(gate_map_iterator_t mapiter) noexcept | |
158 | 2010 | : iter(NULL) | |
159 | { | ||
160 | 2010 | this->loadIterator(mapiter); | |
161 | 2010 | } | |
162 | 1000 | const_iterator(const_iterator const& src) noexcept | |
163 | 1000 | : iter(NULL) | |
164 | { | ||
165 | 1000 | this->loadIterator(src.iter); | |
166 | 1000 | } | |
167 | 500000 | const_iterator& operator=(const_iterator const& src) noexcept | |
168 | { | ||
169 | 500000 | this->loadIterator(src.iter); | |
170 | 500000 | return *this; | |
171 | } | ||
172 | |||
173 | 4 | bool_t operator==(const_iterator const& that) const noexcept | |
174 | { | ||
175 | 4 | return gate_map_iterator_equals(this->iter, that.iter); | |
176 | } | ||
177 | 501001 | bool_t operator!=(const_iterator const& that) const noexcept | |
178 | { | ||
179 | 501001 | return !gate_map_iterator_equals(this->iter, that.iter); | |
180 | } | ||
181 | |||
182 | 250000 | const_iterator& operator++() noexcept { this->loadIterator(gate_map_iterator_next(this->iter)); return *this; } | |
183 | ✗ | const_iterator operator++(int) noexcept { const_iterator ret(*this); ++(*this); return ret; } | |
184 | |||
185 | ✗ | const_iterator& operator--() noexcept { this->loadIterator(gate_map_iterator_prev(this->iter)); return *this; } | |
186 | ✗ | const_iterator operator--(int) noexcept { const_iterator ret(*this); --(*this); return ret; } | |
187 | |||
188 | ✗ | mapping_t const& operator*() const noexcept { return *this; } | |
189 | }; | ||
190 | |||
191 | class iterator : public const_iterator | ||
192 | { | ||
193 | public: | ||
194 | 2 | iterator(gate_map_iterator_t mapiter) noexcept : const_iterator(mapiter) {} | |
195 | ✗ | iterator(iterator const& src) noexcept : const_iterator(src) {} | |
196 | ✗ | iterator& operator=(iterator const& src) noexcept | |
197 | { | ||
198 | ✗ | const_iterator::operator=(static_cast<const_iterator const&>(src)); | |
199 | ✗ | return *this; | |
200 | } | ||
201 | |||
202 | 1 | value_t& value() noexcept { return *static_cast<value_t*>(gate_map_iterator_value(this->iter)); } | |
203 | |||
204 | ✗ | iterator& operator++() noexcept { this->loadIterator(gate_map_iterator_next(this->iter)); return *this; } | |
205 | ✗ | iterator operator++(int) noexcept { iterator ret(*this); ++(*this); return ret; } | |
206 | |||
207 | ✗ | iterator& operator--() noexcept { this->loadIterator(gate_map_iterator_prev(this->iter)); return *this; } | |
208 | ✗ | iterator operator--(int) noexcept { iterator ret(*this); --(*this); return ret; } | |
209 | }; | ||
210 | |||
211 | 17 | Map() noexcept | |
212 | { | ||
213 | 17 | gate_map_create(&this->impl, &COMPARER::c_compare, | |
214 | sizeof(key_t), &TypeFunctions<key_t>::copyConstruct, &TypeFunctions<key_t>::destruct, | ||
215 | sizeof(value_t), &TypeFunctions<value_t>::copyConstruct, &TypeFunctions<value_t>::destruct | ||
216 | ); | ||
217 | 17 | } | |
218 | |||
219 | ✗ | Map(self_t const& src) | |
220 | { | ||
221 | ✗ | if (NULL == gate_map_copy(&this->impl, &src.impl)) | |
222 | { | ||
223 | ✗ | GATEXX_RAISE_ERROR(results::OutOfMemory); | |
224 | } | ||
225 | ✗ | } | |
226 | |||
227 | 8 | void swap(self_t& that) noexcept | |
228 | { | ||
229 | 8 | gate::swapRefsNoExcept(this->impl, that.impl); | |
230 | 8 | } | |
231 | |||
232 | ✗ | self_t& operator=(self_t const& src) | |
233 | { | ||
234 | ✗ | self_t that(src); | |
235 | ✗ | this->swap(that); | |
236 | ✗ | return *this; | |
237 | } | ||
238 | |||
239 | 17 | ~Map() noexcept | |
240 | { | ||
241 | 17 | gate_map_destroy(&this->impl); | |
242 | 17 | } | |
243 | |||
244 | #if defined(GATE_COMPILER_SUPPORTS_CPP_MOVEREFS) | ||
245 | ✗ | Map(self_t&& that) noexcept | |
246 | ✗ | : impl(that.impl) | |
247 | { | ||
248 | ✗ | Mem::clear(that.impl); | |
249 | ✗ | } | |
250 | |||
251 | 4 | self_t& operator=(self_t&& that) noexcept | |
252 | { | ||
253 | 4 | self_t tmp; | |
254 | 4 | that.swap(tmp); | |
255 | 4 | this->swap(tmp); | |
256 | 4 | return *this; | |
257 | } | ||
258 | #endif | ||
259 | |||
260 | ✗ | gate_map_t const* c_impl() const | |
261 | { | ||
262 | ✗ | return &this->impl; | |
263 | } | ||
264 | |||
265 | 636 | void add(key_t const& key, value_t const& value) | |
266 | { | ||
267 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 636 times.
|
636 | if (NULL == gate_map_add(&this->impl, &key, &value)) |
268 | { | ||
269 | ✗ | GATEXX_RAISE_ERROR(results::OutOfMemory); | |
270 | } | ||
271 | 636 | } | |
272 | 500 | bool_t remove(key_t const& key) noexcept | |
273 | { | ||
274 | 500 | return gate_map_remove(&this->impl, &key); | |
275 | } | ||
276 | |||
277 | ✗ | iterator get(key_t const& key) noexcept | |
278 | { | ||
279 | ✗ | return iterator(gate_map_get(&this->impl, &key)); | |
280 | } | ||
281 | 4 | const_iterator get(key_t const& key) const noexcept | |
282 | { | ||
283 | 4 | return const_iterator(gate_map_get(&this->impl, &key)); | |
284 | } | ||
285 | |||
286 | ✗ | const_iterator find(key_t const& key) const noexcept | |
287 | { | ||
288 | ✗ | return this->get(key); | |
289 | } | ||
290 | |||
291 | 2 | value_t getValue(key_t const& key, value_t const& altvalue) const | |
292 | { | ||
293 | 4 | const_iterator it = this->get(key); | |
294 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
|
2 | if (it == this->cend()) |
295 | { | ||
296 | ✗ | return altvalue; | |
297 | } | ||
298 | else | ||
299 | { | ||
300 | 2 | return it.value(); | |
301 | } | ||
302 | } | ||
303 | |||
304 | ✗ | void clear() noexcept | |
305 | { | ||
306 | ✗ | gate_map_clear(&this->impl); | |
307 | ✗ | } | |
308 | |||
309 | 1004 | size_t count() const noexcept | |
310 | { | ||
311 | 1004 | return gate_map_count(&this->impl); | |
312 | } | ||
313 | |||
314 | 3 | bool_t empty() const noexcept | |
315 | { | ||
316 | 3 | return this->count() == 0; | |
317 | } | ||
318 | |||
319 | 1000 | const_iterator cbegin() const noexcept | |
320 | { | ||
321 | 1000 | return const_iterator(gate_map_first(&this->impl)); | |
322 | } | ||
323 | 1004 | const_iterator cend() const noexcept | |
324 | { | ||
325 | 1004 | return const_iterator(NULL); | |
326 | } | ||
327 | 1 | iterator begin() noexcept | |
328 | { | ||
329 | 1 | return iterator(gate_map_first(&this->impl)); | |
330 | } | ||
331 | 1 | iterator end() noexcept | |
332 | { | ||
333 | 1 | return iterator(NULL); | |
334 | } | ||
335 | 1000 | const_iterator begin() const noexcept | |
336 | { | ||
337 | 1000 | return this->cbegin(); | |
338 | } | ||
339 | 1002 | const_iterator end() const noexcept | |
340 | { | ||
341 | 1002 | return this->cend(); | |
342 | } | ||
343 | |||
344 | 2 | bool_t contains(key_t const& key, value_t const** ptrValue = NULL) const noexcept | |
345 | { | ||
346 | 4 | const_iterator iter = this->get(key); | |
347 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
|
2 | if (iter == this->end()) |
348 | { | ||
349 | ✗ | return false; | |
350 | } | ||
351 | else | ||
352 | { | ||
353 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ptrValue != NULL) |
354 | { | ||
355 | ✗ | *ptrValue = &iter.value(); | |
356 | } | ||
357 | 2 | return true; | |
358 | } | ||
359 | } | ||
360 | |||
361 | typedef Enumerator<mapping_t> enumerator_t; | ||
362 | |||
363 | 89 | static gate_bool_t enumerator_is_valid(gate_enumerator_t const* enumerator) noexcept | |
364 | { | ||
365 | 89 | return gate_map_iterator_valid(static_cast<gate_map_iterator_t>(enumerator->current_position)); | |
366 | } | ||
367 | 88 | static gate_bool_t enumerator_next(gate_enumerator_t* enumerator) noexcept | |
368 | { | ||
369 | 88 | gate_map_iterator_t iter = static_cast<gate_map_iterator_t>(enumerator->current_position); | |
370 | 88 | gate_map_iterator_t next_iter = gate_map_iterator_next(iter); | |
371 | 88 | enumerator->current_position = static_cast<void*>(next_iter); | |
372 | 88 | gate_bool_t ret = gate_map_iterator_valid(next_iter); | |
373 |
2/2✓ Branch 0 taken 87 times.
✓ Branch 1 taken 1 times.
|
88 | if (ret) |
374 | { | ||
375 | 174 | mapping_t mapping(next_iter->mapping); | |
376 | 87 | TypeFunctions<mapping_t>::copyConstruct(&enumerator->handles[0], &mapping); | |
377 | } | ||
378 | 88 | return ret; | |
379 | |||
380 | } | ||
381 | 176 | static void const* enumerator_get(gate_enumerator_t const* enumerator) noexcept | |
382 | { | ||
383 | 176 | mapping_t const* ptr_mapping = reinterpret_cast<mapping_t const*>(&enumerator->handles[0]); | |
384 | 176 | return ptr_mapping; | |
385 | } | ||
386 | ✗ | static void const* enumerator_get_key(gate_enumerator_t const* enumerator) noexcept | |
387 | { | ||
388 | ✗ | mapping_t const* ptr_mapping = reinterpret_cast<mapping_t const*>(&enumerator->handles[0]); | |
389 | ✗ | return &ptr_mapping->key(); | |
390 | } | ||
391 | ✗ | static void const* enumerator_get_value(gate_enumerator_t const* enumerator) noexcept | |
392 | { | ||
393 | ✗ | mapping_t const* ptr_mapping = reinterpret_cast<mapping_t const*>(&enumerator->handles[0]); | |
394 | ✗ | return &ptr_mapping->value(); | |
395 | } | ||
396 | |||
397 | 1 | enumerator_t enumerate() const noexcept | |
398 | { | ||
399 | 1 | gate_map_iterator_t iter_begin = gate_map_first(&this->impl); | |
400 | gate_enumerator_t enumerator; | ||
401 | 1 | Mem::clear(enumerator); | |
402 | 1 | enumerator.is_valid = &self_t::enumerator_is_valid; | |
403 | 1 | enumerator.next = &self_t::enumerator_next; | |
404 | 1 | enumerator.get = &self_t::enumerator_get; | |
405 | 1 | enumerator.ptr_origin = &this->impl; | |
406 | 1 | enumerator.current_position = static_cast<void*>(iter_begin); | |
407 | 1 | gate_bool_t valid = gate_map_iterator_valid(iter_begin); | |
408 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (valid) |
409 | { | ||
410 | 2 | mapping_t mapping(iter_begin->mapping); | |
411 | 1 | TypeFunctions<mapping_t>::copyConstruct(&enumerator.handles[0], &mapping); | |
412 | } | ||
413 | 1 | return enumerator_t(enumerator); | |
414 | } | ||
415 | |||
416 | ✗ | Enumerator<key_t const> enumerateKeys() const noexcept | |
417 | { | ||
418 | ✗ | gate_map_iterator_t iter_begin = gate_map_first(&this->impl); | |
419 | gate_enumerator_t enumerator; | ||
420 | ✗ | Mem::clear(enumerator); | |
421 | ✗ | enumerator.is_valid = &self_t::enumerator_is_valid; | |
422 | ✗ | enumerator.next = &self_t::enumerator_next; | |
423 | ✗ | enumerator.get = &self_t::enumerator_get_key; | |
424 | ✗ | enumerator.ptr_origin = &this->impl; | |
425 | ✗ | enumerator.current_position = static_cast<void*>(iter_begin); | |
426 | ✗ | gate_bool_t valid = gate_map_iterator_valid(iter_begin); | |
427 | ✗ | if (valid) | |
428 | { | ||
429 | ✗ | mapping_t mapping(iter_begin->mapping); | |
430 | ✗ | TypeFunctions<mapping_t>::copyConstruct(&enumerator.handles[0], &mapping); | |
431 | } | ||
432 | ✗ | return Enumerator<key_t const>(enumerator); | |
433 | } | ||
434 | |||
435 | ✗ | Enumerator<value_t> enumerateValues() const noexcept | |
436 | { | ||
437 | ✗ | gate_map_iterator_t iter_begin = gate_map_first(&this->impl); | |
438 | gate_enumerator_t enumerator; | ||
439 | ✗ | Mem::clear(enumerator); | |
440 | ✗ | enumerator.is_valid = &self_t::enumerator_is_valid; | |
441 | ✗ | enumerator.next = &self_t::enumerator_next; | |
442 | ✗ | enumerator.get = &self_t::enumerator_get_value; | |
443 | ✗ | enumerator.ptr_origin = &this->impl; | |
444 | ✗ | enumerator.current_position = static_cast<void*>(iter_begin); | |
445 | ✗ | gate_bool_t valid = gate_map_iterator_valid(iter_begin); | |
446 | ✗ | if (valid) | |
447 | { | ||
448 | ✗ | mapping_t mapping(iter_begin->mapping); | |
449 | ✗ | TypeFunctions<mapping_t>::copyConstruct(&enumerator.handles[0], &mapping); | |
450 | } | ||
451 | ✗ | return Enumerator<value_t>(enumerator); | |
452 | } | ||
453 | }; | ||
454 | |||
455 | #define gate_map_for_each(iterator_var, map_type, map_instance) \ | ||
456 | for(map_type ::const_iterator iterator_var = map_instance.begin(); iterator_var != map_instance.end(); ++iterator_var) | ||
457 | |||
458 | |||
459 | |||
460 | |||
461 | |||
462 | |||
463 | template<class KEY, class COMPARER = DefaultComparer<KEY> > | ||
464 | class Set : public Map<KEY, bool_t, COMPARER> | ||
465 | { | ||
466 | public: | ||
467 | typedef KEY key_t; | ||
468 | typedef Map<KEY, bool_t, COMPARER> base_t; | ||
469 | typedef Set<KEY, COMPARER> self_t; | ||
470 | typedef typename base_t::const_iterator const_iterator; | ||
471 | typedef typename base_t::const_iterator iterator; | ||
472 | |||
473 | typedef Enumerator<key_t const> enumerator_t; | ||
474 | |||
475 | public: | ||
476 | ✗ | Set() noexcept | |
477 | ✗ | : base_t() | |
478 | { | ||
479 | ✗ | } | |
480 | |||
481 | ✗ | Set(self_t const& src) | |
482 | ✗ | : base_t(src) | |
483 | { | ||
484 | ✗ | } | |
485 | |||
486 | ✗ | Set(enumerator_t enumerator) | |
487 | ✗ | : base_t() | |
488 | { | ||
489 | ✗ | for (; enumerator.valid(); enumerator.next()) | |
490 | { | ||
491 | ✗ | this->add(*enumerator); | |
492 | } | ||
493 | ✗ | } | |
494 | |||
495 | ✗ | void swap(self_t& that) noexcept | |
496 | { | ||
497 | ✗ | base_t::swap(that); | |
498 | ✗ | } | |
499 | |||
500 | ✗ | self_t& operator=(self_t const& src) | |
501 | { | ||
502 | ✗ | base_t::operator=(src); | |
503 | ✗ | return *this; | |
504 | } | ||
505 | |||
506 | ✗ | ~Set() noexcept | |
507 | { | ||
508 | ✗ | } | |
509 | |||
510 | #if defined(GATE_COMPILER_SUPPORTS_CPP_MOVEREFS) | ||
511 | ✗ | Set(self_t&& that) noexcept | |
512 | ✗ | : base_t(static_cast<base_t&&>(that)) | |
513 | { | ||
514 | ✗ | } | |
515 | |||
516 | ✗ | self_t& operator=(self_t&& that) noexcept | |
517 | { | ||
518 | ✗ | self_t tmp; | |
519 | ✗ | that.swap(tmp); | |
520 | ✗ | this->swap(tmp); | |
521 | ✗ | return *this; | |
522 | } | ||
523 | #endif | ||
524 | |||
525 | ✗ | void add(key_t const& key) | |
526 | { | ||
527 | static bool_t value = false; | ||
528 | ✗ | base_t::add(key, value); | |
529 | ✗ | } | |
530 | |||
531 | ✗ | bool_t contains(key_t const& key) const noexcept | |
532 | { | ||
533 | ✗ | return base_t::contains(key); | |
534 | } | ||
535 | |||
536 | ✗ | enumerator_t enumerate() const noexcept | |
537 | { | ||
538 | ✗ | return base_t::enumerateKeys(); | |
539 | } | ||
540 | }; | ||
541 | |||
542 | |||
543 | |||
544 | |||
545 | |||
546 | |||
547 | |||
548 | template<class KEY, class VALUE, class COMPARER = DefaultComparer<KEY> > | ||
549 | class FlatMap | ||
550 | { | ||
551 | public: | ||
552 | typedef KEY key_t; | ||
553 | typedef VALUE value_t; | ||
554 | typedef FlatMap<KEY, VALUE, COMPARER> self_t, seqmap_t; | ||
555 | |||
556 | private: | ||
557 | gate_flatmap_t impl; | ||
558 | |||
559 | public: | ||
560 | typedef gate_mapping_t const* const* gate_flatmap_iterator_t; | ||
561 | |||
562 | class const_iterator | ||
563 | { | ||
564 | protected: | ||
565 | #if defined(GATE_DEBUG_MODE) | ||
566 | struct typed_mapping | ||
567 | { | ||
568 | key_t const* key_ptr; | ||
569 | value_t const* value_ptr; | ||
570 | }; | ||
571 | union | ||
572 | { | ||
573 | gate_flatmap_iterator_t iter; | ||
574 | typed_mapping const* const* mapping; | ||
575 | }; | ||
576 | #else | ||
577 | gate_flatmap_iterator_t iter; | ||
578 | #endif | ||
579 | gate_flatmap_t const* source; | ||
580 | |||
581 | 10 | void loadIterator(gate_flatmap_t const* mapptr, gate_flatmap_iterator_t mapiter) noexcept | |
582 | { | ||
583 | 10 | this->iter = mapiter; | |
584 | 10 | this->source = mapptr; | |
585 | 10 | } | |
586 | |||
587 | public: | ||
588 | 5 | const_iterator(gate_flatmap_t const* mapptr = NULL, gate_flatmap_iterator_t mapiter = NULL) noexcept | |
589 | { | ||
590 | 5 | this->loadIterator(mapptr, mapiter); | |
591 | 5 | } | |
592 | 5 | const_iterator(const_iterator const& src) noexcept | |
593 | { | ||
594 | 5 | this->loadIterator(src.source, src.iter); | |
595 | 5 | } | |
596 | const_iterator& operator=(const_iterator const& src) noexcept | ||
597 | { | ||
598 | this->loadIterator(src.source, src.iter); | ||
599 | return *this; | ||
600 | } | ||
601 | |||
602 | 4 | key_t const& key() const noexcept { return *static_cast<key_t const*>(gate_flatmap_iterator_key(this->iter)); } | |
603 | 4 | value_t const& value() const noexcept { return *static_cast<value_t const*>(gate_flatmap_iterator_value(this->iter)); } | |
604 | |||
605 | bool_t operator==(const_iterator const& that) const noexcept { return this->iter == that.iter; } | ||
606 | bool_t operator!=(const_iterator const& that) const noexcept { return this->iter != that.iter; } | ||
607 | |||
608 | const_iterator& operator++() noexcept { this->loadIterator(this->source, gate_flatmap_iterator_next(this->iter)); return *this; } | ||
609 | const_iterator operator++(int) noexcept { const_iterator ret(*this); ++(*this); return ret; } | ||
610 | |||
611 | const_iterator& operator--() noexcept { this->loadIterator(this->source, gate_flatmap_iterator_prev(this->iter)); return *this; } | ||
612 | const_iterator operator--(int) noexcept { const_iterator ret(*this); --(*this); return ret; } | ||
613 | }; | ||
614 | |||
615 | class iterator : public const_iterator | ||
616 | { | ||
617 | public: | ||
618 | iterator(gate_flatmap_t const* mapptr = NULL, gate_flatmap_iterator_t mapiter = NULL) noexcept : const_iterator(mapptr, mapiter) {} | ||
619 | iterator(iterator const& src) noexcept : const_iterator(src) {} | ||
620 | iterator& operator=(iterator const& src) noexcept | ||
621 | { | ||
622 | const_iterator::operator=(static_cast<const_iterator const&>(src)); | ||
623 | return *this; | ||
624 | } | ||
625 | |||
626 | value_t& value() noexcept { return *static_cast<value_t*>(gate_flatmap_iterator_value(this->iter)); } | ||
627 | |||
628 | iterator& operator++() noexcept { this->loadIterator(this->source, gate_flatmap_iterator_next(this->iter)); return *this; } | ||
629 | iterator operator++(int) noexcept { iterator ret(*this); ++(*this); return ret; } | ||
630 | |||
631 | iterator& operator--() noexcept { this->loadIterator(this->source, gate_flatmap_iterator_prev(this->iter)); return *this; } | ||
632 | iterator operator--(int) noexcept { iterator ret(*this); --(*this); return ret; } | ||
633 | }; | ||
634 | |||
635 | 2 | FlatMap() | |
636 | { | ||
637 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (NULL == gate_flatmap_create(&this->impl, &COMPARER::c_compare, |
638 | sizeof(key_t), &TypeFunctions<key_t>::copyConstruct, &TypeFunctions<key_t>::destruct, | ||
639 | sizeof(value_t), &TypeFunctions<value_t>::copyConstruct, &TypeFunctions<value_t>::destruct | ||
640 | )) | ||
641 | { | ||
642 | ✗ | GATEXX_RAISE_ERROR(results::OutOfMemory); | |
643 | } | ||
644 | 2 | } | |
645 | |||
646 | FlatMap(self_t const& src) | ||
647 | { | ||
648 | if (NULL == gate_flatmap_copy(&this->impl, &src.impl)) | ||
649 | { | ||
650 | GATEXX_RAISE_ERROR(results::OutOfMemory); | ||
651 | } | ||
652 | } | ||
653 | |||
654 | void swap(self_t& that) noexcept | ||
655 | { | ||
656 | gate::swapRefsNoExcept(this->impl, that.impl); | ||
657 | } | ||
658 | |||
659 | self_t& operator=(self_t const& src) | ||
660 | { | ||
661 | self_t that(src); | ||
662 | this->swap(that); | ||
663 | return *this; | ||
664 | } | ||
665 | |||
666 | 2 | ~FlatMap() noexcept | |
667 | { | ||
668 | 2 | gate_flatmap_destroy(&this->impl); | |
669 | 2 | } | |
670 | |||
671 | gate_flatmap_t const* c_impl() const noexcept | ||
672 | { | ||
673 | return &this->impl; | ||
674 | } | ||
675 | gate_flatmap_t* c_impl() noexcept | ||
676 | { | ||
677 | return &this->impl; | ||
678 | } | ||
679 | |||
680 | 8 | void add(key_t const& key, value_t const& value) | |
681 | { | ||
682 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
|
8 | if (NULL == gate_flatmap_add(&this->impl, &key, &value)) |
683 | { | ||
684 | ✗ | GATEXX_RAISE_ERROR(results::OutOfMemory); | |
685 | } | ||
686 | 8 | } | |
687 | bool_t remove(key_t const& key) noexcept | ||
688 | { | ||
689 | return gate_flatmap_remove(&this->impl, &key); | ||
690 | } | ||
691 | |||
692 | iterator get(key_t const& key) noexcept | ||
693 | { | ||
694 | return iterator(&this->impl, gate_flatmap_get(&this->impl, &key)); | ||
695 | } | ||
696 | const_iterator get(key_t const& key) const noexcept | ||
697 | { | ||
698 | return const_iterator(&this->impl, gate_flatmap_get(&this->impl, &key)); | ||
699 | } | ||
700 | |||
701 | value_t getValue(key_t const& key, value_t const& altvalue) const | ||
702 | { | ||
703 | const_iterator it = this->get(key); | ||
704 | if (it == this->cend()) | ||
705 | { | ||
706 | return altvalue; | ||
707 | } | ||
708 | else | ||
709 | { | ||
710 | return it.value(); | ||
711 | } | ||
712 | } | ||
713 | |||
714 | const_iterator find(key_t const& key) const noexcept | ||
715 | { | ||
716 | return this->get(key); | ||
717 | } | ||
718 | |||
719 | void clear() | ||
720 | { | ||
721 | gate_flatmap_clear(&this->impl); | ||
722 | } | ||
723 | |||
724 | size_t count() const noexcept | ||
725 | { | ||
726 | return gate_flatmap_count(&this->impl); | ||
727 | } | ||
728 | |||
729 | const_iterator cbegin() const noexcept | ||
730 | { | ||
731 | return const_iterator(&this->impl, gate_flatmap_first(&this->impl)); | ||
732 | } | ||
733 | const_iterator cend() const noexcept | ||
734 | { | ||
735 | return const_iterator(&this->impl, gate_flatmap_end(&this->impl)); | ||
736 | } | ||
737 | iterator begin() noexcept | ||
738 | { | ||
739 | return iterator(&this->impl, gate_flatmap_first(&this->impl)); | ||
740 | } | ||
741 | iterator end() noexcept | ||
742 | { | ||
743 | return iterator(&this->impl, gate_flatmap_end(&this->impl)); | ||
744 | } | ||
745 | const_iterator begin() const noexcept | ||
746 | { | ||
747 | return this->cbegin(); | ||
748 | } | ||
749 | const_iterator end() const noexcept | ||
750 | { | ||
751 | return this->cend(); | ||
752 | } | ||
753 | |||
754 | bool_t contains(key_t const& key, value_t const** ptrValue = NULL) const | ||
755 | { | ||
756 | const_iterator iter = this->get(key); | ||
757 | if (iter == this->end()) | ||
758 | { | ||
759 | return false; | ||
760 | } | ||
761 | else | ||
762 | { | ||
763 | if (ptrValue != NULL) | ||
764 | { | ||
765 | *ptrValue = &iter.value(); | ||
766 | } | ||
767 | return true; | ||
768 | } | ||
769 | } | ||
770 | |||
771 | typedef Enumerator<const_iterator> enumerator_t; | ||
772 | |||
773 | 4 | static gate_bool_t enumerator_next(gate_enumerator_t* enumerator) | |
774 | { | ||
775 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (enumerator->current_position) |
776 | { | ||
777 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | enumerator->current_position = (void*)gate_flatmap_iterator_next((gate_flatmap_iterator_t)enumerator->current_position); |
778 | 4 | const_iterator iter((gate_flatmap_t const*)enumerator->ptr_origin, (gate_flatmap_iterator_t)enumerator->current_position); | |
779 | 4 | TypeFunctions<const_iterator>::copyConstruct(&enumerator->handles[0], &iter); | |
780 | 4 | return true; | |
781 | } | ||
782 | else | ||
783 | { | ||
784 | ✗ | return false; | |
785 | } | ||
786 | } | ||
787 | 8 | static void const* enumerator_get(gate_enumerator_t const* enumerator) noexcept | |
788 | { | ||
789 | 8 | return &enumerator->handles[0]; | |
790 | } | ||
791 | 5 | static gate_bool_t enumerator_is_valid(gate_enumerator_t const* enumerator) noexcept | |
792 | { | ||
793 | 5 | return gate_flatmap_iterator_valid((gate_flatmap_t const*)enumerator->ptr_origin, (gate_flatmap_iterator_t)enumerator->current_position); | |
794 | } | ||
795 | |||
796 | 1 | enumerator_t enumerate() const | |
797 | { | ||
798 | gate_enumerator_t enumerator; | ||
799 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | gate_flatmap_enumerate(&this->impl, &enumerator); |
800 | 1 | enumerator.next = &self_t::enumerator_next; | |
801 | 1 | enumerator.get = &self_t::enumerator_get; | |
802 | 1 | enumerator.is_valid = &self_t::enumerator_is_valid; | |
803 | 1 | const_iterator iter(&this->impl, (gate_flatmap_iterator_t)enumerator.current_position); | |
804 | 1 | TypeFunctions<const_iterator>::copyConstruct(&enumerator.handles[0], &iter); | |
805 | 2 | return enumerator_t(enumerator); | |
806 | } | ||
807 | }; | ||
808 | |||
809 | |||
810 | |||
811 | |||
812 | |||
813 | |||
814 | template<class KEY, class VALUE, class COMPARER = DefaultComparer<KEY>, class HASHGEN = TypeHash<KEY> > | ||
815 | class HashMap | ||
816 | { | ||
817 | public: | ||
818 | typedef KEY key_t; | ||
819 | typedef VALUE value_t; | ||
820 | typedef HashMap<KEY, VALUE, COMPARER, HASHGEN> self_t; | ||
821 | typedef COMPARER key_comparer_t; | ||
822 | typedef HASHGEN hash_gen_t; | ||
823 | typedef Mapping<KEY, VALUE> mapping_t; | ||
824 | |||
825 | private: | ||
826 | gate_hashmap_t impl; | ||
827 | |||
828 | public: | ||
829 | class const_iterator : public mapping_t | ||
830 | { | ||
831 | protected: | ||
832 | gate_hashmap_iterator_t iter; | ||
833 | |||
834 | void loadIterator(gate_hashmap_iterator_t mapiter) | ||
835 | { | ||
836 | this->iter = mapiter; | ||
837 | if (gate_hashmap_iterator_valid(this->iter)) | ||
838 | { | ||
839 | this->loadMapping(*this->iter.hashmap->buckets[this->iter.bucket_index]->entries[this->iter.entry_index]); | ||
840 | } | ||
841 | else | ||
842 | { | ||
843 | static gate_mapping_t empty_mapping = { NULL, NULL }; | ||
844 | this->loadMapping(empty_mapping); | ||
845 | } | ||
846 | } | ||
847 | |||
848 | public: | ||
849 | const_iterator(gate_hashmap_iterator_t mapiter) { this->loadIterator(mapiter); } | ||
850 | const_iterator(const_iterator const& src) { this->loadIterator(src.iter); } | ||
851 | const_iterator& operator=(const_iterator const& src) | ||
852 | { | ||
853 | this->loadIterator(src.iter); | ||
854 | return *this; | ||
855 | } | ||
856 | |||
857 | bool_t operator==(const_iterator const& that) const { return gate_hashmap_iterator_equals(this->iter, that.iter); } | ||
858 | bool_t operator!=(const_iterator const& that) const { return !gate_hashmap_iterator_equals(this->iter, that.iter); } | ||
859 | |||
860 | const_iterator& operator++() { this->loadIterator(gate_hashmap_iterator_next(this->iter)); return *this; } | ||
861 | const_iterator operator++(int) { const_iterator ret(*this); ++(*this); return ret; } | ||
862 | |||
863 | const_iterator& operator--() { this->loadIterator(gate_hashmap_iterator_prev(this->iter)); return *this; } | ||
864 | const_iterator operator--(int) { const_iterator ret(*this); --(*this); return ret; } | ||
865 | }; | ||
866 | |||
867 | class iterator : public const_iterator | ||
868 | { | ||
869 | public: | ||
870 | iterator(gate_hashmap_iterator_t mapiter) : const_iterator(mapiter) {} | ||
871 | iterator(iterator const& src) : const_iterator(src) {} | ||
872 | iterator& operator=(iterator const& src) | ||
873 | { | ||
874 | const_iterator::operator=(static_cast<const_iterator const&>(src)); | ||
875 | return *this; | ||
876 | } | ||
877 | |||
878 | value_t& value() { return *static_cast<value_t*>(gate_hashmap_iterator_value(this->iter)); } | ||
879 | |||
880 | iterator& operator++() { this->loadIterator(gate_hashmap_iterator_next(this->iter)); return *this; } | ||
881 | iterator operator++(int) { iterator ret(*this); ++(*this); return ret; } | ||
882 | |||
883 | iterator& operator--() { this->loadIterator(gate_hashmap_iterator_prev(this->iter)); return *this; } | ||
884 | iterator operator--(int) { iterator ret(*this); --(*this); return ret; } | ||
885 | }; | ||
886 | |||
887 | |||
888 | public: | ||
889 | HashMap() | ||
890 | { | ||
891 | gate_type_hash_generator_t gen = hash_gen_t::c_generator(); | ||
892 | if (NULL == gen) | ||
893 | { | ||
894 | GATEXX_RAISE_ERROR(results::NotImplemented); | ||
895 | } | ||
896 | gate_hashmap_t* hashmap = gate_hashmap_create( | ||
897 | &this->impl, &key_comparer_t::c_compare, gen, | ||
898 | sizeof(key_t), &TypeFunctions<key_t>::copyConstruct, &TypeFunctions<key_t>::destruct, | ||
899 | sizeof(value_t), &TypeFunctions<value_t>::copyConstruct, &TypeFunctions<value_t>::destruct | ||
900 | ); | ||
901 | if (NULL == hashmap) | ||
902 | { | ||
903 | GATEXX_RAISE_ERROR(results::OutOfMemory); | ||
904 | } | ||
905 | } | ||
906 | |||
907 | HashMap(self_t const& src) | ||
908 | { | ||
909 | if (NULL == gate_hashmap_copy(&this->impl, &src.impl)) | ||
910 | { | ||
911 | GATEXX_RAISE_ERROR(results::OutOfMemory); | ||
912 | } | ||
913 | } | ||
914 | |||
915 | void swap(self_t& that) noexcept | ||
916 | { | ||
917 | gate::swapRefsNoExcept(this->impl, that.impl); | ||
918 | } | ||
919 | |||
920 | self_t& operator=(self_t const& src) | ||
921 | { | ||
922 | self_t that(src); | ||
923 | this->swap(that); | ||
924 | return *this; | ||
925 | } | ||
926 | |||
927 | ~HashMap() noexcept | ||
928 | { | ||
929 | gate_hashmap_destroy(&this->impl); | ||
930 | } | ||
931 | |||
932 | #if defined(GATE_COMPILER_SUPPORTS_CPP_MOVEREFS) | ||
933 | HashMap(self_t&& that) | ||
934 | : impl(that.impl) | ||
935 | { | ||
936 | Mem::clear(that.impl); | ||
937 | } | ||
938 | |||
939 | self_t& operator=(self_t&& that) | ||
940 | { | ||
941 | self_t tmp; | ||
942 | that.swap(tmp); | ||
943 | this->swap(tmp); | ||
944 | return *this; | ||
945 | } | ||
946 | #endif | ||
947 | |||
948 | void add(key_t const& key, value_t const& value) | ||
949 | { | ||
950 | gate_hashmap_iterator_t iter = gate_hashmap_add(&this->impl, &key, &value); | ||
951 | if (!gate_hashmap_iterator_valid(iter)) | ||
952 | { | ||
953 | GATEXX_RAISE_ERROR(results::OutOfMemory); | ||
954 | } | ||
955 | } | ||
956 | bool_t remove(key_t const& key) noexcept | ||
957 | { | ||
958 | return gate_hashmap_remove(&this->impl, &key); | ||
959 | } | ||
960 | |||
961 | iterator get(key_t const& key) noexcept | ||
962 | { | ||
963 | return iterator(gate_hashmap_get(&this->impl, &key)); | ||
964 | } | ||
965 | const_iterator get(key_t const& key) const noexcept | ||
966 | { | ||
967 | return const_iterator(gate_hashmap_get(&this->impl, &key)); | ||
968 | } | ||
969 | value_t getValue(key_t const& key, value_t const& altvalue) const | ||
970 | { | ||
971 | const_iterator it = this->get(key); | ||
972 | if (it == this->cend()) | ||
973 | { | ||
974 | return altvalue; | ||
975 | } | ||
976 | else | ||
977 | { | ||
978 | return it.value(); | ||
979 | } | ||
980 | } | ||
981 | const_iterator find(key_t const& key) const noexcept | ||
982 | { | ||
983 | return this->get(key); | ||
984 | } | ||
985 | |||
986 | void clear() noexcept | ||
987 | { | ||
988 | gate_hashmap_clear(&this->impl); | ||
989 | } | ||
990 | |||
991 | size_t count() const noexcept | ||
992 | { | ||
993 | return gate_hashmap_count(&this->impl); | ||
994 | } | ||
995 | |||
996 | const_iterator cbegin() const noexcept | ||
997 | { | ||
998 | return const_iterator(gate_hashmap_first(&this->impl)); | ||
999 | } | ||
1000 | const_iterator cend() const noexcept | ||
1001 | { | ||
1002 | return const_iterator(gate_hashmap_end(&this->impl)); | ||
1003 | } | ||
1004 | iterator begin() noexcept | ||
1005 | { | ||
1006 | return iterator(gate_hashmap_first(&this->impl)); | ||
1007 | } | ||
1008 | iterator end() noexcept | ||
1009 | { | ||
1010 | return iterator(gate_hashmap_end(&this->impl)); | ||
1011 | } | ||
1012 | const_iterator begin() const noexcept | ||
1013 | { | ||
1014 | return this->cbegin(); | ||
1015 | } | ||
1016 | const_iterator end() const noexcept | ||
1017 | { | ||
1018 | return this->cend(); | ||
1019 | } | ||
1020 | |||
1021 | bool_t contains(key_t const& key, value_t const** ptrValue = NULL) const noexcept | ||
1022 | { | ||
1023 | const_iterator iter = this->get(key); | ||
1024 | if (iter == this->end()) | ||
1025 | { | ||
1026 | return false; | ||
1027 | } | ||
1028 | else | ||
1029 | { | ||
1030 | if (ptrValue != NULL) | ||
1031 | { | ||
1032 | *ptrValue = &iter.value(); | ||
1033 | } | ||
1034 | return true; | ||
1035 | } | ||
1036 | } | ||
1037 | |||
1038 | typedef Enumerator<const_iterator> enumerator_t; | ||
1039 | |||
1040 | enumerator_t enumerate() const | ||
1041 | { | ||
1042 | gate_enumerator_t enumerator; | ||
1043 | if (NULL == gate_hashmap_enumerate(&this->impl, &enumerator)) | ||
1044 | { | ||
1045 | GATEXX_RAISE_ERROR(results::OutOfMemory); | ||
1046 | } | ||
1047 | return enumerator_t(enumerator); | ||
1048 | } | ||
1049 | }; | ||
1050 | |||
1051 | |||
1052 | |||
1053 | } // end of namespace gate | ||
1054 | |||
1055 | #endif | ||
1056 |