Nebula
Loading...
Searching...
No Matches
dictionary.h
Go to the documentation of this file.
1#pragma once
2//------------------------------------------------------------------------------
27#include "util/array.h"
28#include "util/keyvaluepair.h"
29#include <utility>
30
31//------------------------------------------------------------------------------
32namespace Util
33{
34template<class KEYTYPE, class VALUETYPE> class Dictionary
35{
36public:
44 Dictionary(const std::initializer_list<KeyValuePair<KEYTYPE, VALUETYPE>>&& pairs);
50 VALUETYPE& operator[](const KEYTYPE& key);
52 const VALUETYPE& operator[](const KEYTYPE& key) const;
54 SizeT Size() const;
56 void Clear();
58 bool IsEmpty() const;
60 void Reserve(SizeT numElements);
68 IndexT Add(const KEYTYPE& key, const VALUETYPE& value);
70 IndexT Add(KEYTYPE&& key, VALUETYPE&& value);
72 VALUETYPE& Emplace(const KEYTYPE& key);
74 void EndBulkAdd();
78 void Erase(const KEYTYPE& key);
80 void EraseAtIndex(IndexT index);
82 IndexT FindIndex(const KEYTYPE& key) const;
84 bool Contains(const KEYTYPE& key) const;
86 bool Contains(const KEYTYPE& key, IndexT& index) const;
88 const KEYTYPE& KeyAtIndex(IndexT index) const;
90 VALUETYPE& ValueAtIndex(IndexT index);
92 const VALUETYPE& ValueAtIndex(IndexT index) const;
102 template<class RETURNTYPE> RETURNTYPE KeysAs() const;
104 template<class RETURNTYPE> RETURNTYPE ValuesAs() const;
105
109 void clear();
110 void emplace(KEYTYPE&&key, VALUETYPE&&value);
111
112protected:
114 void SortIfDirty() const;
115
118};
119
120//------------------------------------------------------------------------------
123template<class KEYTYPE, class VALUETYPE>
125 inBulkInsert(false)
126{
127 // empty
128}
129
130//------------------------------------------------------------------------------
133template<class KEYTYPE, class VALUETYPE>
136 inBulkInsert(false)
137{
138 #if NEBULA_BOUNDSCHECKS
140 #endif
141}
142
143//------------------------------------------------------------------------------
146template<class KEYTYPE, class VALUETYPE>
148 keyValuePairs(std::move(rhs.keyValuePairs)),
149 inBulkInsert(false)
150{
151#if NEBULA_BOUNDSCHECKS
152 n_assert(!rhs.inBulkInsert);
153#endif
154}
155
156//------------------------------------------------------------------------------
159template<class KEYTYPE, class VALUETYPE> inline
161{
162 this->inBulkInsert = true;
163 this->keyValuePairs.Resize((SizeT)pairs.size());
164 IndexT i = 0;
165 for (const auto& pair : pairs)
166 {
167 this->keyValuePairs[i++] = pair;
168 }
169 this->keyValuePairs.Sort();
170 this->inBulkInsert = false;
171}
172
173//------------------------------------------------------------------------------
176template<class KEYTYPE, class VALUETYPE>
177inline void
179{
180 #if NEBULA_BOUNDSCHECKS
181 n_assert(!this->inBulkInsert);
183 #endif
184 this->keyValuePairs = rhs.keyValuePairs;
185}
186
187//------------------------------------------------------------------------------
190template<class KEYTYPE, class VALUETYPE>
191inline void
193{
194#if NEBULA_BOUNDSCHECKS
195 n_assert(!this->inBulkInsert);
196 n_assert(!rhs.inBulkInsert);
197#endif
198 this->keyValuePairs = std::move(rhs.keyValuePairs);
199}
200
201//------------------------------------------------------------------------------
204template<class KEYTYPE, class VALUETYPE>
205inline void
207{
208 #if NEBULA_BOUNDSCHECKS
209 n_assert(!this->inBulkInsert);
210 #endif
211 this->keyValuePairs.Clear();
212}
213
214//------------------------------------------------------------------------------
217template<class KEYTYPE, class VALUETYPE>
218inline SizeT
220{
221 return this->keyValuePairs.Size();
222}
223
224//------------------------------------------------------------------------------
227template<class KEYTYPE, class VALUETYPE>
228inline bool
230{
231 return (0 == this->keyValuePairs.Size());
232}
233
234//------------------------------------------------------------------------------
237template<class KEYTYPE, class VALUETYPE>
238inline void
240{
241 this->keyValuePairs.Reserve(numElements);
242}
243
244//------------------------------------------------------------------------------
247template<class KEYTYPE, class VALUETYPE>
248inline void
250{
251 #if NEBULA_BOUNDSCHECKS
252 n_assert(!this->inBulkInsert);
253 #endif
254 this->inBulkInsert = true;
255}
256
257//------------------------------------------------------------------------------
260template<class KEYTYPE, class VALUETYPE>
261inline void
263{
264 #if NEBULA_BOUNDSCHECKS
265 n_assert(this->inBulkInsert);
266 #endif
267 this->keyValuePairs.Sort();
268 this->inBulkInsert = false;
269}
270
271//------------------------------------------------------------------------------
274template<class KEYTYPE, class VALUETYPE>
275inline void
277{
278 if (&rhs == this) return;
279 this->BeginBulkAdd();
280 IndexT i;
281 for (i = 0; i < rhs.keyValuePairs.Size(); i++)
282 {
283 this->keyValuePairs.Append(rhs.keyValuePairs[i]);
284 }
285 this->EndBulkAdd();
286}
287
288
289//------------------------------------------------------------------------------
292template<class KEYTYPE, class VALUETYPE>
293inline IndexT
295{
296 if (this->inBulkInsert)
297 {
298 this->keyValuePairs.Append(kvp);
299 return this->keyValuePairs.Size() - 1;
300 }
301 else
302 {
303 return this->keyValuePairs.InsertSorted(kvp);
304 }
305}
306
307//------------------------------------------------------------------------------
310template<class KEYTYPE, class VALUETYPE>
311inline IndexT
313{
314 if (this->inBulkInsert)
315 {
316 this->keyValuePairs.Append(std::move(kvp));
317 return this->keyValuePairs.Size() - 1;
318 }
319 else
320 {
321 return this->keyValuePairs.InsertSorted(std::move(kvp));
322 }
323}
324
325//------------------------------------------------------------------------------
328template<class KEYTYPE, class VALUETYPE>
329inline IndexT
330Dictionary<KEYTYPE, VALUETYPE>::Add(const KEYTYPE& key, const VALUETYPE& value)
331{
332#if NEBULA_BOUNDSCHECKS
333 //n_assert(!this->Contains(key));
334#endif
335 KeyValuePair<KEYTYPE, VALUETYPE> kvp(key, value);
336 if (this->inBulkInsert)
337 {
338 this->keyValuePairs.Append(kvp);
339 return this->keyValuePairs.Size() - 1;
340 }
341 else
342 {
343 return this->keyValuePairs.InsertSorted(kvp);
344 }
345}
346
347//------------------------------------------------------------------------------
350template<class KEYTYPE, class VALUETYPE>
351inline IndexT
352Dictionary<KEYTYPE, VALUETYPE>::Add(KEYTYPE&& key, VALUETYPE&& value)
353{
354 return this->Add(KeyValuePair<KEYTYPE, VALUETYPE>(std::move(key), std::move(value)));
355}
356
357//------------------------------------------------------------------------------
360template<class KEYTYPE, class VALUETYPE>
361inline VALUETYPE&
363{
364 IndexT i = this->FindIndex(key);
365 if (i == InvalidIndex)
366 {
367 return this->ValueAtIndex(this->Add(key, VALUETYPE()));
368 }
369 else
370 {
371 return this->ValueAtIndex(i);
372 }
373}
374
375//------------------------------------------------------------------------------
378template<class KEYTYPE, class VALUETYPE>
379inline void
381{
382 #if NEBULA_BOUNDSCHECKS
383 n_assert(!this->inBulkInsert);
384 #endif
385 IndexT eraseIndex = this->keyValuePairs.template BinarySearchIndex<KEYTYPE>(key);
386 #if NEBULA_BOUNDSCHECKS
387 n_assert(InvalidIndex != eraseIndex);
388 #endif
389 this->keyValuePairs.EraseIndex(eraseIndex);
390}
391
392//------------------------------------------------------------------------------
395template<class KEYTYPE, class VALUETYPE>
396inline void
398{
399 #if NEBULA_BOUNDSCHECKS
400 n_assert(!this->inBulkInsert);
401 #endif
402 this->keyValuePairs.EraseIndex(index);
403}
404
405//------------------------------------------------------------------------------
408template<class KEYTYPE, class VALUETYPE>
409inline IndexT
411{
412 #if NEBULA_BOUNDSCHECKS
413 n_assert(!this->inBulkInsert);
414 #endif
415 return this->keyValuePairs.template BinarySearchIndex<KEYTYPE>(key);
416}
417
418//------------------------------------------------------------------------------
421template<class KEYTYPE, class VALUETYPE>
422inline bool
424{
425 #if NEBULA_BOUNDSCHECKS
426 n_assert(!this->inBulkInsert);
427 #endif
428 return (InvalidIndex != this->keyValuePairs.template BinarySearchIndex<KEYTYPE>(key));
429}
430
431//------------------------------------------------------------------------------
434template<class KEYTYPE, class VALUETYPE>
435inline bool
436Dictionary<KEYTYPE, VALUETYPE>::Contains(const KEYTYPE& key, IndexT& index) const
437{
438#if NEBULA_BOUNDSCHECKS
439 n_assert(!this->inBulkInsert);
440#endif
441 index = this->keyValuePairs.template BinarySearchIndex<KEYTYPE>(key);
442 return (InvalidIndex != index);
443}
444
445//------------------------------------------------------------------------------
448template<class KEYTYPE, class VALUETYPE>
449inline const KEYTYPE&
451{
452 #if NEBULA_BOUNDSCHECKS
453 n_assert(!this->inBulkInsert);
454 #endif
455 return this->keyValuePairs[index].Key();
456}
457
458//------------------------------------------------------------------------------
461template<class KEYTYPE, class VALUETYPE>
462inline VALUETYPE&
464{
465 #if NEBULA_BOUNDSCHECKS
466 n_assert(!this->inBulkInsert);
467 #endif
468 return this->keyValuePairs[index].Value();
469}
470
471//------------------------------------------------------------------------------
474template<class KEYTYPE, class VALUETYPE>
475inline const VALUETYPE&
477{
478 #if NEBULA_BOUNDSCHECKS
479 n_assert(!this->inBulkInsert);
480 #endif
481 return this->keyValuePairs[index].Value();
482}
483
484//------------------------------------------------------------------------------
487template<class KEYTYPE, class VALUETYPE>
490{
491 #if NEBULA_BOUNDSCHECKS
492 n_assert(!this->inBulkInsert);
493 #endif
494 return this->keyValuePairs[index];
495}
496
497//------------------------------------------------------------------------------
500template<class KEYTYPE, class VALUETYPE>
503{
504 #if NEBULA_BOUNDSCHECKS
505 n_assert(!this->inBulkInsert);
506 #endif
507 return this->keyValuePairs[index];
508}
509
510//------------------------------------------------------------------------------
513template<class KEYTYPE, class VALUETYPE>
514inline VALUETYPE&
516{
517 IndexT keyValuePairIndex = this->FindIndex(key);
518 #if NEBULA_BOUNDSCHECKS
519 n_assert(InvalidIndex != keyValuePairIndex);
520 #endif
521 return this->keyValuePairs[keyValuePairIndex].Value();
522}
523
524//------------------------------------------------------------------------------
527template<class KEYTYPE, class VALUETYPE>
528inline const VALUETYPE&
530{
531 IndexT keyValuePairIndex = this->FindIndex(key);
532 #if NEBULA_BOUNDSCHECKS
533 n_assert(InvalidIndex != keyValuePairIndex);
534 #endif
535 return this->keyValuePairs[keyValuePairIndex].Value();
536}
537
538//------------------------------------------------------------------------------
541template<class KEYTYPE, class VALUETYPE>
542template<class RETURNTYPE>
543RETURNTYPE
545{
546 #if NEBULA_BOUNDSCHECKS
547 n_assert(!this->inBulkInsert);
548 #endif
549 RETURNTYPE result(this->Size(),this->Size());
550 IndexT i;
551 for (i = 0; i < this->keyValuePairs.Size(); i++)
552 {
553 result.Append(this->keyValuePairs[i].Value());
554 }
555 return result;
556}
557
558//------------------------------------------------------------------------------
561template<class KEYTYPE, class VALUETYPE>
562inline Array<VALUETYPE>
567
568//------------------------------------------------------------------------------
571template<class KEYTYPE, class VALUETYPE>
572template<class RETURNTYPE>
573inline RETURNTYPE
575{
576 #if NEBULA_BOUNDSCHECKS
577 n_assert(!this->inBulkInsert);
578 #endif
579 RETURNTYPE result(this->Size(),this->Size());
580 IndexT i;
581 for (i = 0; i < this->keyValuePairs.Size(); i++)
582 {
583 result.Append(this->keyValuePairs[i].Key());
584 }
585 return result;
586}
587
588//------------------------------------------------------------------------------
591template<class KEYTYPE, class VALUETYPE>
592inline Array<KEYTYPE>
597
598//------------------------------------------------------------------------------
601template<class KEYTYPE, class VALUETYPE>
604{
605 return this->keyValuePairs.begin();
606}
607//------------------------------------------------------------------------------
610template<class KEYTYPE, class VALUETYPE>
613{
614 return this->keyValuePairs.end();
615}
616//------------------------------------------------------------------------------
619template<class KEYTYPE, class VALUETYPE>
620inline void
625//------------------------------------------------------------------------------
628template<class KEYTYPE, class VALUETYPE>
629inline void
630Dictionary<KEYTYPE, VALUETYPE>::emplace(KEYTYPE&&key, VALUETYPE&&value)
631{
632 this->Add(std::move(key), std::move(value));
633}
634} // namespace Util
635//------------------------------------------------------------------------------
Nebula's dynamic array class.
Definition array.h:61
void BeginBulkAdd()
begin a bulk insert (array will be sorted at End)
Definition dictionary.h:249
IndexT Add(KEYTYPE &&key, VALUETYPE &&value)
add a key and associated value, consuming rvalues
Definition dictionary.h:352
void operator=(Dictionary< KEYTYPE, VALUETYPE > &&rhs) noexcept
move operator
Definition dictionary.h:192
Dictionary(const Dictionary< KEYTYPE, VALUETYPE > &rhs)
copy constructor
Definition dictionary.h:134
void Reserve(SizeT numElements)
reserve space (useful if number of elements is known beforehand)
Definition dictionary.h:239
bool Contains(const KEYTYPE &key) const
return true if key exists in the array
Definition dictionary.h:423
void Clear()
clear the dictionary
Definition dictionary.h:206
SizeT Size() const
return number of key/value pairs in the dictionary
Definition dictionary.h:219
KeyValuePair< KEYTYPE, VALUETYPE > * end() const
Definition dictionary.h:612
const KEYTYPE & KeyAtIndex(IndexT index) const
get a key at given index
Definition dictionary.h:450
IndexT FindIndex(const KEYTYPE &key) const
find index of key/value pair (InvalidIndex if doesn't exist)
Definition dictionary.h:410
Array< KEYTYPE > KeysAsArray() const
get all keys as an Util::Array
Definition dictionary.h:593
Dictionary(Dictionary< KEYTYPE, VALUETYPE > &&rhs) noexcept
move constructor
Definition dictionary.h:147
const VALUETYPE & ValueAtIndex(IndexT index) const
get a value at given index
Definition dictionary.h:476
IndexT Add(const KeyValuePair< KEYTYPE, VALUETYPE > &kvp)
add a key/value pair
Definition dictionary.h:294
void clear()
Definition dictionary.h:621
void EraseAtIndex(IndexT index)
erase a key at index
Definition dictionary.h:397
const VALUETYPE & operator[](const KEYTYPE &key) const
read-only [] operator
Definition dictionary.h:529
RETURNTYPE ValuesAs() const
get all keys as (typically) an array
Definition dictionary.h:544
bool IsEmpty() const
return true if empty
Definition dictionary.h:229
VALUETYPE & ValueAtIndex(IndexT index)
access to value at given index
Definition dictionary.h:463
RETURNTYPE KeysAs() const
get all keys as (typically) an array
Definition dictionary.h:574
Array< VALUETYPE > ValuesAsArray() const
get all keys as an Util::Array
Definition dictionary.h:563
void emplace(KEYTYPE &&key, VALUETYPE &&value)
Definition dictionary.h:630
void Erase(const KEYTYPE &key)
erase a key and its associated value
Definition dictionary.h:380
VALUETYPE & operator[](const KEYTYPE &key)
read/write [] operator
Definition dictionary.h:515
bool Contains(const KEYTYPE &key, IndexT &index) const
return true if key exists in the array, and saves index
Definition dictionary.h:436
Dictionary(const std::initializer_list< KeyValuePair< KEYTYPE, VALUETYPE > > &&pairs)
initializer list constructor
Definition dictionary.h:160
void Merge(const Dictionary< KEYTYPE, VALUETYPE > &rhs)
merge two dictionaries
Definition dictionary.h:276
const KeyValuePair< KEYTYPE, VALUETYPE > & KeyValuePairAtIndex(IndexT index) const
get key/value pair at index
Definition dictionary.h:502
KeyValuePair< KEYTYPE, VALUETYPE > & KeyValuePairAtIndex(IndexT index)
get key/value pair at index
Definition dictionary.h:489
IndexT Add(const KEYTYPE &key, const VALUETYPE &value)
add a key and associated value
Definition dictionary.h:330
KeyValuePair< KEYTYPE, VALUETYPE > * begin() const
functions for stl like behaviour
Definition dictionary.h:603
void EndBulkAdd()
end a bulk insert (this will sort the internal array)
Definition dictionary.h:262
void operator=(const Dictionary< KEYTYPE, VALUETYPE > &rhs)
assignment operator
Definition dictionary.h:178
Array< KeyValuePair< Util::StringAtom, CoreGraphics::BufferId > > keyValuePairs
Definition dictionary.h:116
Dictionary()
default constructor
Definition dictionary.h:124
VALUETYPE & Emplace(const KEYTYPE &key)
creates a new entry of VALUETYPE if key does not exist, or returns the existing element
Definition dictionary.h:362
IndexT Add(KeyValuePair< KEYTYPE, VALUETYPE > &&kvp)
add a key/value pair, consuming rvalues
Definition dictionary.h:312
void SortIfDirty() const
make sure the key value pair array is sorted
Key/Value pair objects are used by most assiociative container classes, like Dictionary or HashTable.
Definition keyvaluepair.h:19
#define n_assert(exp)
Definition debug.h:58
A quad tree designed to return regions of free 2D space.
Definition Random.cs:4
int SizeT
Definition types.h:42
int IndexT
Definition types.h:41