-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcontainers.hpp
794 lines (645 loc) · 30.9 KB
/
containers.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "printing.hpp"
#endif
#pragma region Containers
template<class TType> struct RemoveConst { typedef TType Type; };
template<class TType> struct RemoveConst<const TType> { typedef TType Type; };
template<class TType> struct RemoveConst<const TType[]> { typedef TType Type[]; };
template<class TType, usize Size> struct RemoveConst<const TType[Size]> { typedef TType Type[Size]; };
template<class TType> using TRemoveConst = typename RemoveConst<TType>::Type;
template <class TType> struct RemovePtr { typedef TType Type; };
template <class TType> struct RemovePtr<TType*> { typedef TType Type; };
template <class TType> using TRemovePtr = typename RemovePtr<TType>::Type;
#pragma region Array
#define Array(Type) Array<Type>
// #define array_init(Type, ...) array_init <Type>(__VA_ARGS__)
// #define array_init_reserve(Type, ...) array_init_reserve<Type>(__VA_ARGS__)
struct ArrayHeader;
#if GEN_COMPILER_CPP
template<class Type> struct Array;
# define get_array_underlying_type(array) typename TRemovePtr<typeof(array)>:: DataType
#endif
usize array_grow_formula(ssize value);
template<class Type> Array<Type> array_init (AllocatorInfo allocator);
template<class Type> Array<Type> array_init_reserve (AllocatorInfo allocator, ssize capacity);
template<class Type> bool array_append_array (Array<Type>* array, Array<Type> other);
template<class Type> bool array_append (Array<Type>* array, Type value);
template<class Type> bool array_append_items (Array<Type>* array, Type* items, usize item_num);
template<class Type> bool array_append_at (Array<Type>* array, Type item, usize idx);
template<class Type> bool array_append_items_at(Array<Type>* array, Type* items, usize item_num, usize idx);
template<class Type> Type* array_back (Array<Type> array);
template<class Type> void array_clear (Array<Type> array);
template<class Type> bool array_fill (Array<Type> array, usize begin, usize end, Type value);
template<class Type> void array_free (Array<Type>* array);
template<class Type> bool arary_grow (Array<Type>* array, usize min_capacity);
template<class Type> usize array_num (Array<Type> array);
template<class Type> void arary_pop (Array<Type> array);
template<class Type> void arary_remove_at (Array<Type> array, usize idx);
template<class Type> bool arary_reserve (Array<Type>* array, usize new_capacity);
template<class Type> bool arary_resize (Array<Type>* array, usize num);
template<class Type> bool arary_set_capacity (Array<Type>* array, usize new_capacity);
template<class Type> ArrayHeader* arary_get_header (Array<Type> array);
struct ArrayHeader {
AllocatorInfo Allocator;
usize Capacity;
usize Num;
};
#if GEN_COMPILER_CPP
template<class Type>
struct Array
{
Type* Data;
#pragma region Member Mapping
forceinline static Array init(AllocatorInfo allocator) { return array_init<Type>(allocator); }
forceinline static Array init_reserve(AllocatorInfo allocator, ssize capacity) { return array_init_reserve<Type>(allocator, capacity); }
forceinline static usize grow_formula(ssize value) { return array_grow_formula<Type>(value); }
forceinline bool append(Array other) { return array_append_array<Type>(this, other); }
forceinline bool append(Type value) { return array_append<Type>(this, value); }
forceinline bool append(Type* items, usize item_num) { return array_append_items<Type>(this, items, item_num); }
forceinline bool append_at(Type item, usize idx) { return array_append_at<Type>(this, item, idx); }
forceinline bool append_at(Type* items, usize item_num, usize idx) { return array_append_items_at<Type>(this, items, item_num, idx); }
forceinline Type* back() { return array_back<Type>(* this); }
forceinline void clear() { array_clear<Type>(* this); }
forceinline bool fill(usize begin, usize end, Type value) { return array_fill<Type>(* this, begin, end, value); }
forceinline void free() { array_free<Type>(this); }
forceinline ArrayHeader* get_header() { return array_get_header<Type>(* this); }
forceinline bool grow(usize min_capacity) { return array_grow<Type>(this, min_capacity); }
forceinline usize num() { return array_num<Type>(*this); }
forceinline void pop() { array_pop<Type>(* this); }
forceinline void remove_at(usize idx) { array_remove_at<Type>(* this, idx); }
forceinline bool reserve(usize new_capacity) { return array_reserve<Type>(this, new_capacity); }
forceinline bool resize(usize num) { return array_resize<Type>(this, num); }
forceinline bool set_capacity(usize new_capacity) { return array_set_capacity<Type>(this, new_capacity); }
#pragma endregion Member Mapping
forceinline operator Type*() { return Data; }
forceinline operator Type const*() const { return Data; }
forceinline Type* begin() { return Data; }
forceinline Type* end() { return Data + get_header()->Num; }
forceinline Type& operator[](ssize index) { return Data[index]; }
forceinline Type const& operator[](ssize index) const { return Data[index]; }
using DataType = Type;
};
#endif
#if GEN_COMPILER_CPP && 0
template<class Type> bool append(Array<Type>& array, Array<Type> other) { return append( & array, other ); }
template<class Type> bool append(Array<Type>& array, Type value) { return append( & array, value ); }
template<class Type> bool append(Array<Type>& array, Type* items, usize item_num) { return append( & array, items, item_num ); }
template<class Type> bool append_at(Array<Type>& array, Type item, usize idx) { return append_at( & array, item, idx ); }
template<class Type> bool append_at(Array<Type>& array, Type* items, usize item_num, usize idx) { return append_at( & array, items, item_num, idx ); }
template<class Type> void free(Array<Type>& array) { return free( & array ); }
template<class Type> bool grow(Array<Type>& array, usize min_capacity) { return grow( & array, min_capacity); }
template<class Type> bool reserve(Array<Type>& array, usize new_capacity) { return reserve( & array, new_capacity); }
template<class Type> bool resize(Array<Type>& array, usize num) { return resize( & array, num); }
template<class Type> bool set_capacity(Array<Type>& array, usize new_capacity) { return set_capacity( & array, new_capacity); }
template<class Type> forceinline Type* begin(Array<Type>& array) { return array; }
template<class Type> forceinline Type* end(Array<Type>& array) { return array + array_get_header(array)->Num; }
template<class Type> forceinline Type* next(Array<Type>& array, Type* entry) { return entry + 1; }
#endif
template<class Type> forceinline Type* array_begin(Array<Type> array) { return array; }
template<class Type> forceinline Type* array_end(Array<Type> array) { return array + array_get_header(array)->Num; }
template<class Type> forceinline Type* array_next(Array<Type> array, Type* entry) { return ++ entry; }
template<class Type> inline
Array<Type> array_init(AllocatorInfo allocator) {
return array_init_reserve<Type>(allocator, array_grow_formula(0));
}
template<class Type> inline
Array<Type> array_init_reserve(AllocatorInfo allocator, ssize capacity)
{
GEN_ASSERT(capacity > 0);
ArrayHeader* header = rcast(ArrayHeader*, alloc(allocator, sizeof(ArrayHeader) + sizeof(Type) * capacity));
if (header == nullptr)
return {nullptr};
header->Allocator = allocator;
header->Capacity = capacity;
header->Num = 0;
return {rcast(Type*, header + 1)};
}
forceinline
usize array_grow_formula(ssize value) {
return 2 * value + 8;
}
template<class Type> inline
bool array_append_array(Array<Type>* array, Array<Type> other) {
return array_append_items(array, (Type*)other, array_num(other));
}
template<class Type> inline
bool array_append(Array<Type>* array, Type value)
{
GEN_ASSERT( array != nullptr);
GEN_ASSERT(* array != nullptr);
ArrayHeader* header = array_get_header(* array);
if (header->Num == header->Capacity)
{
if ( ! array_grow(array, header->Capacity))
return false;
header = array_get_header(* array);
}
(*array)[ header->Num] = value;
header->Num++;
return true;
}
template<class Type> inline
bool array_append_items(Array<Type>* array, Type* items, usize item_num)
{
GEN_ASSERT( array != nullptr);
GEN_ASSERT(* array != nullptr);
GEN_ASSERT(items != nullptr);
GEN_ASSERT(item_num > 0);
ArrayHeader* header = array_get_header(* array);
if (header->Num + item_num > header->Capacity)
{
if ( ! array_grow(array, header->Capacity + item_num))
return false;
header = array_get_header(* array);
}
mem_copy((Type*)array + header->Num, items, item_num * sizeof(Type));
header->Num += item_num;
return true;
}
template<class Type> inline
bool array_append_at(Array<Type>* array, Type item, usize idx)
{
GEN_ASSERT( array != nullptr);
GEN_ASSERT(* array != nullptr);
ArrayHeader* header = array_get_header(* array);
ssize slot = idx;
if (slot >= (ssize)(header->Num))
slot = header->Num - 1;
if (slot < 0)
slot = 0;
if (header->Capacity < header->Num + 1)
{
if ( ! array_grow(array, header->Capacity + 1))
return false;
header = array_get_header(* array);
}
Type* target = &(*array)[slot];
mem_move(target + 1, target, (header->Num - slot) * sizeof(Type));
header->Num++;
return true;
}
template<class Type> inline
bool array_append_items_at(Array<Type>* array, Type* items, usize item_num, usize idx)
{
GEN_ASSERT( array != nullptr);
GEN_ASSERT(* array != nullptr);
ArrayHeader* header = get_header(array);
if (idx >= header->Num)
{
return array_append_items(array, items, item_num);
}
if (item_num > header->Capacity)
{
if (! grow(array, header->Capacity + item_num))
return false;
header = get_header(array);
}
Type* target = array.Data + idx + item_num;
Type* src = array.Data + idx;
mem_move(target, src, (header->Num - idx) * sizeof(Type));
mem_copy(src, items, item_num * sizeof(Type));
header->Num += item_num;
return true;
}
template<class Type> inline
Type* array_back(Array<Type> array)
{
GEN_ASSERT(array != nullptr);
ArrayHeader* header = array_get_header(array);
if (header->Num <= 0)
return nullptr;
return & (array)[header->Num - 1];
}
template<class Type> inline
void array_clear(Array<Type> array) {
GEN_ASSERT(array != nullptr);
ArrayHeader* header = array_get_header(array);
header->Num = 0;
}
template<class Type> inline
bool array_fill(Array<Type> array, usize begin, usize end, Type value)
{
GEN_ASSERT(array != nullptr);
GEN_ASSERT(begin <= end);
ArrayHeader* header = array_get_header(array);
if (begin < 0 || end > header->Num)
return false;
for (ssize idx = ssize(begin); idx < ssize(end); idx++) {
array[idx] = value;
}
return true;
}
template<class Type> forceinline
void array_free(Array<Type>* array) {
GEN_ASSERT( array != nullptr);
GEN_ASSERT(* array != nullptr);
ArrayHeader* header = array_get_header(* array);
allocator_free(header->Allocator, header);
Type** Data = (Type**)array;
*Data = nullptr;
}
template<class Type> forceinline
ArrayHeader* array_get_header(Array<Type> array) {
GEN_ASSERT(array != nullptr);
Type* Data = array;
using NonConstType = TRemoveConst<Type>;
return rcast(ArrayHeader*, const_cast<NonConstType*>(Data)) - 1;
}
template<class Type> forceinline
bool array_grow(Array<Type>* array, usize min_capacity)
{
GEN_ASSERT( array != nullptr);
GEN_ASSERT(* array != nullptr);
GEN_ASSERT( min_capacity > 0 );
ArrayHeader* header = array_get_header(* array);
usize new_capacity = array_grow_formula(header->Capacity);
if (new_capacity < min_capacity)
new_capacity = min_capacity;
return array_set_capacity(array, new_capacity);
}
template<class Type> forceinline
usize array_num(Array<Type> array) {
GEN_ASSERT(array != nullptr);
return array_get_header(array)->Num;
}
template<class Type> forceinline
void array_pop(Array<Type> array) {
GEN_ASSERT(array != nullptr);
ArrayHeader* header = array_get_header(array);
GEN_ASSERT(header->Num > 0);
header->Num--;
}
template<class Type> inline
void array_remove_at(Array<Type> array, usize idx)
{
GEN_ASSERT(array != nullptr);
ArrayHeader* header = array_get_header(array);
GEN_ASSERT(idx < header->Num);
mem_move(array + idx, array + idx + 1, sizeof(Type) * (header->Num - idx - 1));
header->Num--;
}
template<class Type> inline
bool array_reserve(Array<Type>* array, usize new_capacity)
{
GEN_ASSERT( array != nullptr);
GEN_ASSERT(* array != nullptr);
ArrayHeader* header = array_get_header(array);
if (header->Capacity < new_capacity)
return set_capacity(array, new_capacity);
return true;
}
template<class Type> inline
bool array_resize(Array<Type>* array, usize num)
{
GEN_ASSERT( array != nullptr);
GEN_ASSERT(* array != nullptr);
ArrayHeader* header = array_get_header(* array);
if (header->Capacity < num) {
if (! array_grow( array, num))
return false;
header = array_get_header(* array);
}
header->Num = num;
return true;
}
template<class Type> inline
bool array_set_capacity(Array<Type>* array, usize new_capacity)
{
GEN_ASSERT( array != nullptr);
GEN_ASSERT(* array != nullptr);
ArrayHeader* header = array_get_header(* array);
if (new_capacity == header->Capacity)
return true;
if (new_capacity < header->Num)
{
header->Num = new_capacity;
return true;
}
ssize size = sizeof(ArrayHeader) + sizeof(Type) * new_capacity;
ArrayHeader* new_header = rcast(ArrayHeader*, alloc(header->Allocator, size));
if (new_header == nullptr)
return false;
mem_move(new_header, header, sizeof(ArrayHeader) + sizeof(Type) * header->Num);
new_header->Capacity = new_capacity;
allocator_free(header->Allocator, header);
Type** Data = (Type**)array;
* Data = rcast(Type*, new_header + 1);
return true;
}
// These are intended for use in the base library of gencpp and the C-variant of the library
// It provides a interoperability between the C++ and C implementation of arrays. (not letting these do any crazy substiution though)
// They are undefined in gen.hpp and gen.cpp at the end of the files.
// We cpp library expects the user to use the regular calls as they can resolve the type fine.
#define array_init(type, allocator) array_init <type> (allocator )
#define array_init_reserve(type, allocator, cap) array_init_reserve <type> (allocator, cap)
#define array_append_array(array, other) array_append_array < get_array_underlying_type(array) > (& array, other )
#define array_append(array, value) array_append < get_array_underlying_type(array) > (& array, value )
#define array_append_items(array, items, item_num) array_append_items < get_array_underlying_type(array) > (& array, items, item_num )
#define array_append_at(array, item, idx ) array_append_at < get_array_underlying_type(array) > (& array, item, idx )
#define array_append_at_items(array, items, item_num, idx) array_append_at_items< get_array_underlying_type(array) > (& items, item_num, idx )
#define array_back(array) array_back < get_array_underlying_type(array) > (array )
#define array_clear(array) array_clear < get_array_underlying_type(array) > (array )
#define array_fill(array, begin, end, value) array_fill < get_array_underlying_type(array) > (array, begin, end, value )
#define array_free(array) array_free < get_array_underlying_type(array) > (& array )
#define arary_grow(array, min_capacity) arary_grow < get_array_underlying_type(array) > (& array, min_capacity)
#define array_num(array) array_num < get_array_underlying_type(array) > (array )
#define arary_pop(array) arary_pop < get_array_underlying_type(array) > (array )
#define arary_remove_at(array, idx) arary_remove_at < get_array_underlying_type(array) > (idx)
#define arary_reserve(array, new_capacity) arary_reserve < get_array_underlying_type(array) > (& array, new_capacity )
#define arary_resize(array, num) arary_resize < get_array_underlying_type(array) > (& array, num)
#define arary_set_capacity(new_capacity) arary_set_capacity < get_array_underlying_type(array) > (& array, new_capacity )
#define arary_get_header(array) arary_get_header < get_array_underlying_type(array) > (array )
#pragma endregion Array
#pragma region HashTable
#define HashTable(Type) HashTable<Type>
template<class Type> struct HashTable;
#ifndef get_hashtable_underlying_type
#define get_hashtable_underlying_type(table) typename TRemovePtr<typeof(table)>:: DataType
#endif
struct HashTableFindResult {
ssize HashIndex;
ssize PrevIndex;
ssize EntryIndex;
};
template<class Type>
struct HashTableEntry {
u64 Key;
ssize Next;
Type Value;
};
#define HashTableEntry(Type) HashTableEntry<Type>
template<class Type> HashTable<Type> hashtable_init (AllocatorInfo allocator);
template<class Type> HashTable<Type> hashtable_init_reserve(AllocatorInfo allocator, usize num);
template<class Type> void hashtable_clear (HashTable<Type> table);
template<class Type> void hashtable_destroy (HashTable<Type>* table);
template<class Type> Type* hashtable_get (HashTable<Type> table, u64 key);
template<class Type> void hashtable_grow (HashTable<Type>* table);
template<class Type> void hashtable_rehash (HashTable<Type>* table, ssize new_num);
template<class Type> void hashtable_rehash_fast (HashTable<Type> table);
template<class Type> void hashtable_remove (HashTable<Type> table, u64 key);
template<class Type> void hashtable_remove_entry(HashTable<Type> table, ssize idx);
template<class Type> void hashtable_set (HashTable<Type>* table, u64 key, Type value);
template<class Type> ssize hashtable_slot (HashTable<Type> table, u64 key);
template<class Type> void hashtable_map (HashTable<Type> table, void (*map_proc)(u64 key, Type value));
template<class Type> void hashtable_map_mut (HashTable<Type> table, void (*map_proc)(u64 key, Type* value));
template<class Type> ssize hashtable__add_entry (HashTable<Type>* table, u64 key);
template<class Type> HashTableFindResult hashtable__find (HashTable<Type> table, u64 key);
template<class Type> bool hashtable__full (HashTable<Type> table);
static constexpr f32 HashTable_CriticalLoadScale = 0.7f;
template<typename Type>
struct HashTable
{
Array<ssize> Hashes;
Array<HashTableEntry<Type>> Entries;
#if ! GEN_C_LIKE_CPP
#pragma region Member Mapping
forceinline static HashTable init(AllocatorInfo allocator) { return hashtable_init<Type>(allocator); }
forceinline static HashTable init_reserve(AllocatorInfo allocator, usize num) { return hashtable_init_reserve<Type>(allocator, num); }
forceinline void clear() { clear<Type>(*this); }
forceinline void destroy() { destroy<Type>(*this); }
forceinline Type* get(u64 key) { return get<Type>(*this, key); }
forceinline void grow() { grow<Type>(*this); }
forceinline void rehash(ssize new_num) { rehash<Type>(*this, new_num); }
forceinline void rehash_fast() { rehash_fast<Type>(*this); }
forceinline void remove(u64 key) { remove<Type>(*this, key); }
forceinline void remove_entry(ssize idx) { remove_entry<Type>(*this, idx); }
forceinline void set(u64 key, Type value) { set<Type>(*this, key, value); }
forceinline ssize slot(u64 key) { return slot<Type>(*this, key); }
forceinline void map(void (*proc)(u64, Type)) { map<Type>(*this, proc); }
forceinline void map_mut(void (*proc)(u64, Type*)) { map_mut<Type>(*this, proc); }
#pragma endregion Member Mapping
#endif
using DataType = Type;
};
#if GEN_SUPPORT_CPP_REFERENCES
template<class Type> void destroy (HashTable<Type>& table) { destroy(& table); }
template<class Type> void grow (HashTable<Type>& table) { grow(& table); }
template<class Type> void rehash (HashTable<Type>& table, ssize new_num) { rehash(& table, new_num); }
template<class Type> void set (HashTable<Type>& table, u64 key, Type value) { set(& table, key, value); }
template<class Type> ssize add_entry(HashTable<Type>& table, u64 key) { add_entry(& table, key); }
#endif
template<typename Type> inline
HashTable<Type> hashtable_init(AllocatorInfo allocator) {
HashTable<Type> result = hashtable_init_reserve<Type>(allocator, 8);
return result;
}
template<typename Type> inline
HashTable<Type> hashtable_init_reserve(AllocatorInfo allocator, usize num)
{
HashTable<Type> result = { { nullptr }, { nullptr } };
result.Hashes = array_init_reserve<ssize>(allocator, num);
array_get_header(result.Hashes)->Num = num;
array_resize(& result.Hashes, num);
array_fill(result.Hashes, 0, num, (ssize)-1);
result.Entries = array_init_reserve<HashTableEntry<Type>>(allocator, num);
return result;
}
template<typename Type> forceinline
void hashtable_clear(HashTable<Type> table) {
GEN_ASSERT_NOT_NULL(table.Hashes);
GEN_ASSERT_NOT_NULL(table.Entries);
array_clear(table.Entries);
array_fill(table.Hashes, 0, array_num(table.Hashes), (ssize)-1);
}
template<typename Type> forceinline
void hashtable_destroy(HashTable<Type>* table) {
GEN_ASSERT_NOT_NULL(table->Hashes);
GEN_ASSERT_NOT_NULL(table->Entries);
if (table->Hashes && array_get_header(table->Hashes)->Capacity) {
array_free(table->Hashes);
array_free(table->Entries);
}
}
template<typename Type> forceinline
Type* hashtable_get(HashTable<Type> table, u64 key) {
GEN_ASSERT_NOT_NULL(table.Hashes);
GEN_ASSERT_NOT_NULL(table.Entries);
ssize idx = hashtable__find(table, key).EntryIndex;
if (idx >= 0)
return & table.Entries[idx].Value;
return nullptr;
}
template<typename Type> forceinline
void hashtable_map(HashTable<Type> table, void (*map_proc)(u64 key, Type value)) {
GEN_ASSERT_NOT_NULL(table.Hashes);
GEN_ASSERT_NOT_NULL(table.Entries);
GEN_ASSERT_NOT_NULL(map_proc);
for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) {
map_proc(table.Entries[idx].Key, table.Entries[idx].Value);
}
}
template<typename Type> forceinline
void hashtable_map_mut(HashTable<Type> table, void (*map_proc)(u64 key, Type* value)) {
GEN_ASSERT_NOT_NULL(table.Hashes);
GEN_ASSERT_NOT_NULL(table.Entries);
GEN_ASSERT_NOT_NULL(map_proc);
for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) {
map_proc(table.Entries[idx].Key, & table.Entries[idx].Value);
}
}
template<typename Type> forceinline
void hashtable_grow(HashTable<Type>* table) {
GEN_ASSERT_NOT_NULL(table);
GEN_ASSERT_NOT_NULL(table->Hashes);
GEN_ASSERT_NOT_NULL(table->Entries);
ssize new_num = array_grow_formula( array_num(table->Entries));
hashtable_rehash(table, new_num);
}
template<typename Type> inline
void hashtable_rehash(HashTable<Type>* table, ssize new_num)
{
GEN_ASSERT_NOT_NULL(table);
GEN_ASSERT_NOT_NULL(table->Hashes);
GEN_ASSERT_NOT_NULL(table->Entries);
ssize last_added_index;
HashTable<Type> new_ht = hashtable_init_reserve<Type>( array_get_header(table->Hashes)->Allocator, new_num);
for (ssize idx = 0; idx < ssize( array_num(table->Entries)); ++idx)
{
HashTableFindResult find_result;
HashTableEntry<Type>& entry = table->Entries[idx];
find_result = hashtable__find(new_ht, entry.Key);
last_added_index = hashtable__add_entry(& new_ht, entry.Key);
if (find_result.PrevIndex < 0)
new_ht.Hashes[find_result.HashIndex] = last_added_index;
else
new_ht.Entries[find_result.PrevIndex].Next = last_added_index;
new_ht.Entries[last_added_index].Next = find_result.EntryIndex;
new_ht.Entries[last_added_index].Value = entry.Value;
}
hashtable_destroy(table);
* table = new_ht;
}
template<typename Type> inline
void hashtable_rehash_fast(HashTable<Type> table)
{
GEN_ASSERT_NOT_NULL(table.Hashes);
GEN_ASSERT_NOT_NULL(table.Entries);
ssize idx;
for (idx = 0; idx < ssize(num(table.Entries)); idx++)
table.Entries[idx].Next = -1;
for (idx = 0; idx < ssize(num(table.Hashes)); idx++)
table.Hashes[idx] = -1;
for (idx = 0; idx < ssize(num(table.Entries)); idx++)
{
HashTableEntry<Type>* entry;
HashTableFindResult find_result;
entry = &table.Entries[idx];
find_result = find(table, entry->Key);
if (find_result.PrevIndex < 0)
table.Hashes[find_result.HashIndex] = idx;
else
table.Entries[find_result.PrevIndex].Next = idx;
}
}
template<typename Type> forceinline
void hashtable_remove(HashTable<Type> table, u64 key) {
GEN_ASSERT_NOT_NULL(table.Hashes);
GEN_ASSERT_NOT_NULL(table.Entries);
HashTableFindResult find_result = find(table, key);
if (find_result.EntryIndex >= 0) {
remove_at(table.Entries, find_result.EntryIndex);
rehash_fast(table);
}
}
template<typename Type> forceinline
void hashtable_remove_entry(HashTable<Type> table, ssize idx) {
GEN_ASSERT_NOT_NULL(table.Hashes);
GEN_ASSERT_NOT_NULL(table.Entries);
remove_at(table.Entries, idx);
}
template<typename Type> inline
void hashtable_set(HashTable<Type>* table, u64 key, Type value)
{
GEN_ASSERT_NOT_NULL(table);
GEN_ASSERT_NOT_NULL(table->Hashes);
GEN_ASSERT_NOT_NULL(table->Entries);
ssize idx;
HashTableFindResult find_result;
if (hashtable_full(* table))
hashtable_grow(table);
find_result = hashtable__find(* table, key);
if (find_result.EntryIndex >= 0) {
idx = find_result.EntryIndex;
}
else
{
idx = hashtable__add_entry(table, key);
if (find_result.PrevIndex >= 0) {
table->Entries[find_result.PrevIndex].Next = idx;
}
else {
table->Hashes[find_result.HashIndex] = idx;
}
}
table->Entries[idx].Value = value;
if (hashtable_full(* table))
hashtable_grow(table);
}
template<typename Type> forceinline
ssize hashtable_slot(HashTable<Type> table, u64 key) {
GEN_ASSERT_NOT_NULL(table.Hashes);
GEN_ASSERT_NOT_NULL(table.Entries);
for (ssize idx = 0; idx < ssize(num(table.Hashes)); ++idx)
if (table.Hashes[idx] == key)
return idx;
return -1;
}
template<typename Type> forceinline
ssize hashtable__add_entry(HashTable<Type>* table, u64 key) {
GEN_ASSERT_NOT_NULL(table);
GEN_ASSERT_NOT_NULL(table->Hashes);
GEN_ASSERT_NOT_NULL(table->Entries);
ssize idx;
HashTableEntry<Type> entry = { key, -1 };
idx = array_num(table->Entries);
array_append( table->Entries, entry);
return idx;
}
template<typename Type> inline
HashTableFindResult hashtable__find(HashTable<Type> table, u64 key)
{
GEN_ASSERT_NOT_NULL(table.Hashes);
GEN_ASSERT_NOT_NULL(table.Entries);
HashTableFindResult result = { -1, -1, -1 };
if (array_num(table.Hashes) > 0)
{
result.HashIndex = key % array_num(table.Hashes);
result.EntryIndex = table.Hashes[result.HashIndex];
while (result.EntryIndex >= 0)
{
if (table.Entries[result.EntryIndex].Key == key)
break;
result.PrevIndex = result.EntryIndex;
result.EntryIndex = table.Entries[result.EntryIndex].Next;
}
}
return result;
}
template<typename Type> forceinline
b32 hashtable_full(HashTable<Type> table) {
GEN_ASSERT_NOT_NULL(table.Hashes);
GEN_ASSERT_NOT_NULL(table.Entries);
usize critical_load = usize(HashTable_CriticalLoadScale * f32(array_num(table.Hashes)));
b32 result = array_num(table.Entries) > critical_load;
return result;
}
#define hashtable_init(type, allocator) hashtable_init <type >(allocator)
#define hashtable_init_reserve(type, allocator, num) hashtable_init_reserve<type >(allocator, num)
#define hashtable_clear(table) hashtable_clear < get_hashtable_underlying_type(table) >(table)
#define hashtable_destroy(table) hashtable_destroy < get_hashtable_underlying_type(table) >(& table)
#define hashtable_get(table, key) hashtable_get < get_hashtable_underlying_type(table) >(table, key)
#define hashtable_grow(table) hashtable_grow < get_hashtable_underlying_type(table) >(& table)
#define hashtable_rehash(table, new_num) hashtable_rehash < get_hashtable_underlying_type(table) >(& table, new_num)
#define hashtable_rehash_fast(table) hashtable_rehash_fast < get_hashtable_underlying_type(table) >(table)
#define hashtable_remove(table, key) hashtable_remove < get_hashtable_underlying_type(table) >(table, key)
#define hashtable_remove_entry(table, idx) hashtable_remove_entry< get_hashtable_underlying_type(table) >(table, idx)
#define hashtable_set(table, key, value) hashtable_set < get_hashtable_underlying_type(table) >(& table, key, value)
#define hashtable_slot(table, key) hashtable_slot < get_hashtable_underlying_type(table) >(table, key)
#define hashtable_map(table, map_proc) hashtable_map < get_hashtable_underlying_type(table) >(table, map_proc)
#define hashtable_map_mut(table, map_proc) hashtable_map_mut < get_hashtable_underlying_type(table) >(table, map_proc)
//#define hashtable_add_entry(table, key) hashtable_add_entry < get_hashtable_underlying_type(table) >(& table, key)
//#define hashtable_find(table, key) hashtable_find < get_hashtable_underlying_type(table) >(table, key)
//#define hashtable_full(table) hashtable_full < get_hashtable_underlying_type(table) >(table)
#pragma endregion HashTable
#pragma endregion Containers