-
Notifications
You must be signed in to change notification settings - Fork 4
/
ok_lib.h
1771 lines (1441 loc) · 60.3 KB
/
ok_lib.h
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
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
ok-lib
https://github.com/brackeen/ok-lib
Copyright (c) 2016-2020 David Brackeen
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef OK_LIB_H
#define OK_LIB_H
/**
@file
Generic vector and hash maps for C. Requires C99 or newer, works best with C11.
By default, including "ok_lib.h" defines the ok_lib functions as `static` (that is, private to the
.c file that included it).
## Options - defined before #include "ok_lib.h"
| Option | Description |
|-------------------------------|-----------------------------------------------------------------|
| #define OK_LIB_DEFINE | Define the functions publicly, so they are available when |
| | linking. |
|-------------------------------|-----------------------------------------------------------------|
| #define OK_LIB_DECLARE | Declare function prototypes without defining the functions |
| | themselves (that is, use existing public `ok_lib` functions). |
|-------------------------------|-----------------------------------------------------------------|
| #define OK_LIB_USE_STDATOMIC | Force usage of <stdatomic.h>. If not defined, `ok_lib` checks |
| | the compiler version to determine whether to use it. |
|-------------------------------|-----------------------------------------------------------------|
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h> // free, qsort
#include <string.h> // strcmp, memset, memcpy
// @cond configuration
#if defined(OK_LIB_DEFINE) || defined(OK_LIB_DECLARE)
# ifdef __cplusplus
# define OK_LIB_API extern "C"
# else
# define OK_LIB_API
# endif
#else
# define OK_LIB_API static
# define OK_LIB_DEFINE
#endif
#ifdef __cplusplus
# define OK_MUTABLE mutable
#else
# define OK_MUTABLE
#endif
// @endcond
// MARK: Static assertion
/**
Static assertion, using the built-in _Static_assert if available.
@param condition The constant expression to check. If 0, a compile-time error occurs.
@param msg The message to display if compilation fails. Only works on C11 or C++11.
*/
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
# define ok_static_assert _Static_assert
#elif defined(__cplusplus) && (__cplusplus >= 201103L)
# define ok_static_assert static_assert
#else
# define ok_static_assert(condition, msg) ((void) sizeof(char[(condition) ? 1 : -1]))
#endif
/**
Check if two variables have the same type.
*/
#if defined(__GNUC__)
# define ok_types_compatible(A, B) __builtin_types_compatible_p(__typeof(A), __typeof(B))
#else
# define ok_types_compatible(A, B) (sizeof(A) == sizeof(B))
#endif
// MARK: Vector
/**
Declares a generic `ok_vec` struct or typedef.
For example, and array of `int`s can be declared as a typedef:
typedef struct ok_vec_of(int) vec_int_t;
or a struct:
struct vec_int_s ok_vec_of(int);
@tparam value_type The type to contain in the vector.
@return `{ value_type *values; size_t count; size_t capacity; }`
*/
#define ok_vec_of(value_type) \
{ value_type *values; size_t count; size_t capacity; }
/**
A macro to initialize a vector statically.
typedef struct ok_vec_of(int) vec_int_t;
vec_int_t int_vec = OK_VEC_INIT;
When finished using the vector, the #ok_vec_deinit() function must be called.
*/
#define OK_VEC_INIT { NULL, 0, 0 }
/**
Inits a vector.
When finished using the vector, the #ok_vec_deinit() function must be called.
@param vec Pointer to the vector.
*/
#define ok_vec_init(vec) \
memset((vec), 0, sizeof(*(vec)))
/**
Deinits the vector. The vector may be used again by calling #ok_vec_init().
@param vec Pointer to the vector.
*/
#define ok_vec_deinit(vec) \
free((void *)(vec)->values)
/**
Removes all elements from the vector, setting the count to 0. The capacity of the vector is not
changed.
@param vec Pointer to the vector.
*/
#define ok_vec_clear(vec) \
(vec)->count = 0
/**
Gets the number of elements in the vector.
@param vec Pointer to the vector.
@return size_t The number of elements in the vector.
*/
#define ok_vec_count(vec) \
(vec)->count
/**
Gets a pointer to the first element in a vector.
@param vec Pointer to the vector.
@return A pointer to the first element. If the vector is empty, the result is undefined.
*/
#define ok_vec_begin(vec) \
((vec)->values)
/**
Gets a pointer to the element following the last element in a vector.
The pointer should only be used for iteration, and should not be accessed directly.
@param vec Pointer to the vector.
@return A pointer to the element following the last element.
*/
#define ok_vec_end(vec) \
((vec)->values + (vec)->count)
/**
Gets a pointer to the last element in a vector.
@param vec Pointer to the vector.
@return A pointer to the last element. If the vector is empty, the result is undefined.
*/
#define ok_vec_last(vec) \
((vec)->values + ((vec)->count - 1))
/**
Gets an element in a vector.
@param vec Pointer to the vector.
@param i The index in the vector, from 0 to `(ok_vec_count(vec) - 1)`. If the index is outside of
the valid range, the result is undefined, and this function may crash.
@return The element at the index.
*/
#define ok_vec_get(vec, i) \
(*((vec)->values + (i)))
/**
Gets a pointer to an element in a vector.
@param vec Pointer to the vector.
@param i The index in the vector, from 0 to `(ok_vec_count(vec) - 1)`. If the index is outside of
the valid range, the result is undefined.
@return A pointer to the element at the index.
*/
#define ok_vec_get_ptr(vec, i) \
((vec)->values + (i))
/**
Adds a value to the end of a vector.
@param vec Pointer to the vector.
@param value The value to add.
@return `true` if the value was successfully added to the vector, `false` otherwise (out of memory
error).
*/
#define ok_vec_push(vec, value) \
(ok_vec_ensure_capacity(vec, 1) ? ((vec)->values[((vec)->count++)] = (value), 1) : 0)
/**
Adds space for a value at the end of a vector, returning a pointer to the newly added location.
@param vec Pointer to the vector.
@return The pointer to the new location, or `NULL` if failure (out of memory error).
*/
#define ok_vec_push_new(vec) \
(ok_vec_ensure_capacity(vec, 1) ? ((vec)->values + ((vec)->count++)) : NULL)
/**
Adds all the elements from one vector into another.
@param vec Pointer to the vector to add elements to.
@param vec2 Pointer to a vector to get elements from.
@return `true` if the values in `vec2` were successfully added to the vector, `false` otherwise
(out of memory error).
*/
#define ok_vec_push_all(vec, vec2) \
(ok_vec_ensure_capacity(vec, (vec2)->count) ? \
(memcpy((vec)->values + (vec)->count, (vec2)->values, sizeof(*(vec)->values) * (vec2)->count), \
((vec)->count += (vec2)->count)) : 0)
/**
Inserts a value at the specified location in the vector. The element currently at that
location, and all subsequent elements, are moved to the right by one position.
@param vec Pointer to the vector.
@param index `size_t` The index at which to insert the element. If the index is greater than or
equal to number of elements in the vector, the value is added to the end, like #ok_vec_push().
@param value The value to insert.
*/
#define ok_vec_insert_at(vec, index, value) \
do { \
if (ok_vec_ensure_capacity(vec, 1)) { \
size_t _i1 = (index); \
if (_i1 + 1 < (vec)->count) { \
memmove((vec)->values + _i1 + 1, (vec)->values + _i1, \
((vec)->count - _i1 - 1) * sizeof(*(vec)->values)); \
} \
(vec)->values[_i1] = (value); \
(vec)->count++; \
} \
} while (0)
/**
Removes an element at the specified location in the vector.
@param vec Pointer to the vector.
@param index `size_t` The index of the element to remove. If the index is greater than or
equal to number of elements in the vector, the size of the vector is reduced by one.
*/
#define ok_vec_remove_at(vec, index) \
do { \
size_t _i2 = (index); \
if (_i2 + 1 < (vec)->count) { \
memmove((vec)->values + _i2, (vec)->values + _i2 + 1, \
((vec)->count - _i2 - 1) * sizeof(*(vec)->values)); \
} \
if ((vec)->count > 0) { \
(vec)->count--; \
} \
} while (0)
/**
Removes the first element in the vector that equals the specified value.
This function uses the equality operator `==` to test for equal values, which will fail to
compile if values are structs.
@param vec Pointer to the vector.
@param value The value to find and remove.
*/
#define ok_vec_remove(vec, value) \
do { \
for (size_t _i3 = 0; _i3 < (vec)->count; _i3++) { \
if ((vec)->values[_i3] == (value)) { \
ok_vec_remove_at(vec, _i3); \
break; \
} \
} \
} while (0)
/**
Foreach macro that iterates over the values in the vector.
The vector should not be modified during iteration. A call to #ok_vec_push()
during iteration could cause as crash.
The `break` and `continue` keywords are supported during iteration.
Example:
ok_vec_foreach(vec, char *value) {
printf("Value: %s\n", value);
}
@param vec Pointer to the vector.
@param var The value type and name.
*/
#define ok_vec_foreach(vec, var) \
for (size_t _keep = 1, _i = 0, _len = (vec)->count; _keep && _i < _len; _keep = 1 - _keep, _i++) \
for (var = *((vec)->values + _i); _keep; _keep = 1 - _keep)
/**
Foreach macro that iterates over the values in the vector, in reverse order.
The vector should not be modified during iteration. A call to #ok_vec_push()
during iteration could cause as crash.
The `break` and `continue` keywords are supported during iteration.
Example:
ok_vec_foreach_rev(vec, char *value) {
printf("Value: %s\n", value);
}
@param vec Pointer to the vector.
@param var The value type and name.
*/
#define ok_vec_foreach_rev(vec, var) \
for (size_t _keep = 1, _i = 0, _len = (vec)->count; _keep && _i < _len; _keep = 1 - _keep, _i++) \
for (var = *((vec)->values + (_len - _i - 1)); _keep; _keep = 1 - _keep)
/**
Foreach macro that iterates over pointers to the values in the vector.
The vector should not be modified during iteration. A call to #ok_vec_push()
during iteration could cause as crash.
The `break` and `continue` keywords are supported during iteration.
Example:
ok_vec_foreach_ptr(vec, char **value) {
printf("Value: %s\n", *value);
}
@param vec Pointer to the vector.
@param var The value type and name.
*/
#define ok_vec_foreach_ptr(vec, var) \
for (size_t _keep = 1, _i = 0, _len = (vec)->count; _keep && _i < _len; _keep = 1 - _keep, _i++) \
for (var = (vec)->values + _i; _keep; _keep = 1 - _keep)
/**
Foreach macro that iterates over pointers to the values in the vector.
The vector should not be modified during iteration. A call to #ok_vec_push()
during iteration could cause as crash.
The `break` and `continue` keywords are supported during iteration.
Example:
ok_vec_foreach_ptr_rev(vec, char **value) {
printf("Value: %s\n", *value);
}
@param vec Pointer to the vector.
@param var The value type and name.
*/
#define ok_vec_foreach_ptr_rev(vec, var) \
for (size_t _keep = 1, _i = 0, _len = (vec)->count; _keep && _i < _len; _keep = 1 - _keep, _i++) \
for (var = (vec)->values + (_len - _i - 1); _keep; _keep = 1 - _keep)
/**
Applies a function to each element in a vector.
@param vec Pointer to the vector.
@param func The function.
*/
#define ok_vec_apply(vec, func) \
for (size_t _i = 0, _len = (vec)->count; _i < _len; _i++) func(*((vec)->values + _i))
/**
Applies a function to a pointer to each element in a vector.
@param vec Pointer to the vector.
@param func The function.
*/
#define ok_vec_apply_ptr(vec, func) \
for (size_t _i = 0, _len = (vec)->count; _i < _len; _i++) func(((vec)->values + _i))
/**
Sorts elements in a vector
@param vec Pointer to the vector.
@param compare_func Pointer to a function that compares two elements. Uses the same syntax as
`qsort`.
*/
#define ok_vec_sort(vec, compare_func) \
qsort((void *)(vec)->values, (vec)->count, sizeof(*((vec)->values)), compare_func)
/**
Ensures that a vector has enough space for additional elements.
@param vec Pointer to the vector.
@param additional_count The number of addtional elements to make room for.
@return `true` if successful, `false` otherwise (out of memory error).
*/
#define ok_vec_ensure_capacity(vec, additional_count) \
(((vec)->count + (size_t)(additional_count) <= (vec)->capacity) ? true : \
_ok_vec_realloc((void **)&(vec)->values, (vec)->count + (size_t)(additional_count), \
sizeof(*(vec)->values), &(vec)->capacity))
// MARK: Map
/**
Declares a generic `ok_map` struct or typedef.
For example, a map of string keys with `int` values can be declared as a typedef:
typedef struct ok_map_of(const char *, int) my_map_t;
or a struct:
struct my_map_s ok_map_of(const char *, int);
@tparam key_type The key type.
@tparam value_type The value type.
@return Internal structure members in curly braces.
*/
#define ok_map_of(key_type, value_type) { \
/* The `entry` struct has two purposes:
1) Let the compiler determine member alignment and stride for the bucket array.
2) Provide temp space for arguments and return values.
The hash member must be first. */ \
OK_MUTABLE struct { \
ok_hash_t hash; \
key_type k; \
value_type v; \
} entry; \
OK_MUTABLE value_type *v_ptr; \
struct _ok_map *m; \
ok_hash_t (*key_hash_func)(key_type); \
}
/**
Inits a map, automatically chooising hash and equals functions if possible. If not possible,
a compile-time error occurs.
When using C11, this function works when keys are integers, floats, or strings. When using C99,
this function only works with const string keys (that is, `const char *`).
To init a map with a custom key, use #ok_map_init_custom() instead.
When finished using the map, the #ok_map_deinit() function must be called.
@param map Pointer to the map.
@return bool `true` if success, `false` otherwise (out of memory error).
*/
#define ok_map_init(map) \
ok_map_init_with_capacity(map, 0)
/**
Inits a map.
When finished using the map, the #ok_map_deinit() function must be called.
@param map Pointer to the map.
@param hash_func The function to calculate the hash of the key. The signature of the function
is `ok_hash_t hash_func(key_type)`. For example, see #ok_const_str_hash().
@param equals_func The function to determine if two keys are equal. The signature of the function
is `bool equals_func(void *, void *)`, where the parameters are pointers to the
key. For example, see #ok_str_equals().
@return bool `true` if success, `false` otherwise (out of memory error).
*/
#define ok_map_init_custom(map, hash_func, equals_func) \
ok_map_init_custom_with_capacity(map, hash_func, equals_func, 0)
/**
Inits a map with the specified initial capacity, automatically chooising hash and equals functions
if possible. If not possible, a compile-time error occurs.
When using C11, this function works when keys are integers, floats, or strings. When using C99,
this function only works with const string keys (that is, `const char *`).
To init a map with a custom key, use #ok_map_init_custom_with_capacity() instead.
When finished using the map, the #ok_map_deinit() function must be called.
@param map Pointer to the map.
@param capacity The initial capacity. If 0, the default capacity is used. The actual capacity will
be a power-of-two integer greater than or equal to the requested capacity.
@return bool `true` if success, `false` otherwise (out of memory error).
*/
#define ok_map_init_with_capacity(map, capacity) \
ok_map_init_custom_with_capacity(map, ok_default_hash((map)->entry.k), \
ok_default_equals((map)->entry.k), capacity)
/**
Inits a map.
When finished using the map, the #ok_map_deinit() function must be called.
@param map Pointer to the map.
@param hash_func The function to calculate the hash of the key. The signature of the function
is `ok_hash_t hash_func(key_type)`. For example, see #ok_str_hash().
@param equals_func The function to determine if two keys are equal. The signature of the function
is `bool equals_func(void *, void *)`, where the parameters are pointers to the
key. For example, see #ok_str_equals().
@param capacity The initial capacity. If 0, the default capacity is used. The actual capacity
may be a power-of-two integer greater than or equal to the requested capacity.
@return bool `true` if success, `false` otherwise (out of memory error).
*/
#define ok_map_init_custom_with_capacity(map, hash_func, equals_func, capacity) ( \
memset((map), 0, sizeof(*(map))), \
(map)->key_hash_func = hash_func, \
(((map)->m = _ok_map_create(capacity, equals_func, \
OK_OFFSETOF(&(map)->entry, &(map)->entry.k), \
OK_OFFSETOF(&(map)->entry, &(map)->entry.v), \
sizeof((map)->entry))) != NULL) \
)
/**
Deinits the map. The map may be used again by calling #ok_map_init().
@param map Pointer to the map.
*/
#define ok_map_deinit(map) \
_ok_map_free((map)->m)
/**
Gets the number of elements in the map.
@param map Pointer to the map.
@return size_t The number of elements in the map.
*/
#define ok_map_count(map) \
_ok_map_count((map)->m)
/**
Gets the capacity of a hash map. The capacity never shrinks.
@param map Pointer to the map. If `NULL`, the default capacity is returned.
@return size_t The capacity.
*/
#define ok_map_capacity(map) \
_ok_map_capacity((map) ? (map)->m : NULL)
/**
Puts a key-value pair into the map. If the key already exists in the map, it is replaced with
the new value.
@param map Pointer to the map.
@param key The key.
@param value The value.
@return `true` if the operation was successful, `false` otherwise (out of memory).
*/
#define ok_map_put(map, key, value) ( \
(map)->entry.k = (key), \
(map)->entry.v = (value), \
_ok_map_put(&(map)->m, &(map)->entry.k, sizeof((map)->entry.k), \
(map)->key_hash_func((map)->entry.k), \
&(map)->entry.v, sizeof((map)->entry.v)) \
)
/**
Get a pointer to the value associated with a key, creating a new mapping if the key does not exist
in the map.
If the key didn't previously exist in the map, the value is undefined.
Example:
* *ok_map_put_and_get_ptr(map, "jenny") = "867-5309";
The returned pointer should be considered temporary. It may be invalid, and should not be used,
after any modification to the map (like a call to #ok_map_put() or #ok_map_remove().)
@param map Pointer to the map.
@param key The key.
@return A pointer to the value, or `NULL` for out-of-memory error.
*/
#define ok_map_put_and_get_ptr(map, key) ( \
(map)->entry.k = (key), \
_ok_map_put_and_get_ptr(&(map)->m, &(map)->entry.k, sizeof((map)->entry.k), \
(map)->key_hash_func((map)->entry.k), \
(void **)&(map)->v_ptr, sizeof((map)->entry.v)), \
(map)->v_ptr \
)
/**
Copies mappings from one map to another. The hash maps must have the same types, hash functions,
amd equals functions.
@param map Pointer to the map.
@param from_map Pointer to the map to copy mappings from.
@return `true` if all of the mappings from `from_map` were copied to the map. If `false`,
(out of memory error), some of the mappings may have been copied before failure.
*/
#define ok_map_put_all(map, from_map) (\
((sizeof((map)->entry) == sizeof((from_map)->entry) && \
(map)->key_hash_func == (from_map)->key_hash_func) ? \
_ok_map_put_all(&(map)->m, (from_map)->m, sizeof((map)->entry.k), \
sizeof((map)->entry.v)) : \
false) \
)
/**
Gets a value from the map. If the key doesn't exist in the map, returns a zeroed-out value
(`0`, `0.0`, `{0}`, `NULL`, etc.).
@param map Pointer to the map.
@param key The key.
@return The value, or zero if the key doesn't exist in the map.
*/
#define ok_map_get(map, key) ( \
(map)->entry.k = (key), \
_ok_map_get((map)->m, &(map)->entry.k, (map)->key_hash_func((map)->entry.k), \
(void *)&(map)->entry.v, sizeof((map)->entry.v)), \
(map)->entry.v \
)
/**
Get a pointer to the value associated with a key, or `NULL` if the key does not exist in the map.
The returned pointer should be considered temporary. It may be invalid, and should not be used,
after any modification to the map (like a call to #ok_map_put() or #ok_map_remove().)
@param map Pointer to the map.
@param key The key.
@return A pointer to the value, or `NULL` if the key does not exist in the map.
*/
#define ok_map_get_ptr(map, key) ( \
(map)->entry.k = (key), \
_ok_map_get_ptr((map)->m, &(map)->entry.k, (map)->key_hash_func((map)->entry.k), \
(void **)&(map)->v_ptr), \
(map)->v_ptr \
)
/**
Checks if a key exists in the map.
@param map Pointer to the map.
@param key The key.
@return bool `true` if the key exists, `false` otherwise.
*/
#define ok_map_contains(map, key) ( \
(map)->entry.k = (key), \
_ok_map_contains((map)->m, &(map)->entry.k, (map)->key_hash_func((map)->entry.k)) \
)
/**
Removes a key from the map.
@param map Pointer to the map.
@param key The key to remove.
@return `true` if the key was in the map (thus removed), `false` otherwise.
*/
#define ok_map_remove(map, key) ( \
(map)->entry.k = (key), \
_ok_map_remove((map)->m, &(map)->entry.k, (map)->key_hash_func((map)->entry.k)) \
)
/**
Foreach macro that iterates over the keys and values in the map. The mappings are not returned in
any particular order, and the order may change as the map is modified.
The map should not be modified during iteration. A call to #ok_map_put() or #ok_map_remove()
during iteration could cause as crash.
The `break` and `continue` keywords are supported during iteration.
Example:
ok_map_foreach(map, const char *key, char *value) {
printf("Name: %s Phone: %s\n", key, value);
}
@param map Pointer to the map.
@param key_var The key type and name.
@param value_var The value type and name.
*/
#define ok_map_foreach(map, key_var, value_var) \
for (size_t _keep = 1, _keep2 = 1, *_i = NULL; _keep && \
((_i = (size_t *)_ok_map_next((map)->m, _i, (void *)&(map)->entry.k, \
sizeof((map)->entry.k), (void *)&(map)->entry.v, \
sizeof((map)->entry.v))) != NULL); \
_keep = 1 - _keep, _keep2 = 1 - _keep2) \
for (key_var = (map)->entry.k; _keep && _keep2; _keep2 = 1 - _keep2) \
for (value_var = (map)->entry.v; _keep; _keep = 1 - _keep)
// MARK: Concurrent queue
/**
The default capacity of a queue. This is the minimum capacity; queues can grow in size.
*/
#define OK_QUEUE_DEFAULT_CAPACITY 16
/**
A macro to initialize a queue statically.
typedef struct ok_queue_of(int) my_queue_t;
my_queue_t queue = OK_QUEUE_INIT;
When finished using the queue, the #ok_queue_deinit() function must be called.
*/
#define OK_QUEUE_INIT { { NULL, NULL, NULL, false, false, OK_QUEUE_DEFAULT_CAPACITY }, NULL }
/**
Declares a generic `ok_queue` struct or typedef.
For example, a ok_queue with `int` values can be declared as a typedef:
typedef struct ok_queue_of(int) my_queue_t;
or a struct:
struct my_queue_s ok_queue_of(int);
@tparam value_type The value type.
@return Internal structure members in curly braces.
*/
#define ok_queue_of(value_type) { \
struct _ok_queue q; \
value_type *v; \
}
/**
Inits a queue with the default minimum capacity.
To init a queue with a custom minimum capacity, use #ok_queue_init_with_capacity() instead.
This function is not thread safe. If two threads attempt to init a queue at the same time, the
result is undefined.
When finished using the queue, the #ok_queue_deinit() function must be called.
@tparam queue Pointer to the queue.
*/
#define ok_queue_init(queue) \
ok_queue_init_with_capacity(queue, OK_QUEUE_DEFAULT_CAPACITY)
/**
Inits a queue with a custom minimum capacity. The queue may grow in size larger than the specified
capacity.
This function is not thread safe. If two threads attempt to init a queue at the same time, the
result is undefined.
When finished using the queue, the #ok_queue_deinit() function must be called.
@tparam queue Pointer to the queue.
@tparam capacity The minimum number of values the queue can hold.
*/
#define ok_queue_init_with_capacity(queue, capacity) \
_ok_queue_init(&(queue)->q, sizeof(*(queue)->v), capacity)
/**
Deinits the queue. The queue may be used again by calling #ok_queue_init().
@tparam queue Pointer to the queue.
*/
#define ok_queue_deinit(queue) \
ok_queue_deinit_with_deallocator(queue, NULL)
/**
Deinits the queue and deallocates its remaining values. Each remaining value is
removed from the queue and sent as a param to the deallocator function.
The queue may be used again by calling #ok_queue_init().
@tparam queue Pointer to the queue.
@tparam deallocator The deallocator function, declared as `void (*deallocator)(void *)`.
*/
#define ok_queue_deinit_with_deallocator(queue, deallocator) \
_ok_queue_deinit(&(queue)->q, sizeof(*(queue)->v), (deallocator))
/**
Adds a value to the back of the queue.
@tparam queue Pointer to the queue.
@tparam value The value to add. Must be an addressable rvalue.
*/
#define ok_queue_push(queue, value) do { \
ok_static_assert(ok_types_compatible(*(queue)->v, value), "Incompatible types"); \
_ok_queue_push(&(queue)->q, sizeof(*(queue)->v), &(value)); \
} while (0)
/**
Attempts to remove a value from the front of the queue.
@tparam queue Pointer to the queue.
@tparam value_ptr The address to store the removed value.
@return true on success, false if the queue is empty.
*/
#define ok_queue_pop(queue, value_ptr) (\
sizeof(char[ok_types_compatible(*(queue)->v, *(value_ptr)) ? 1 : -1]) && /* Type check */ \
_ok_queue_pop(&(queue)->q, sizeof(*(queue)->v), (value_ptr)) \
)
// MARK: Declarations: Hash functions
/// The hash type, which is returned from hash functions.
typedef uint32_t ok_hash_t;
/// Gets the default hash function for the specified key type. Uses _Generic, so it requires C11.
#ifndef ok_default_hash
# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
# define ok_default_hash(key) _Generic(key, \
uint8_t : ok_uint8_hash, \
int8_t : ok_int8_hash, \
uint16_t : ok_uint16_hash, \
int16_t : ok_int16_hash, \
uint32_t : ok_uint32_hash, \
int32_t : ok_int32_hash, \
uint64_t : ok_uint64_hash, \
int64_t : ok_int64_hash, \
float : ok_float_hash, \
double : ok_double_hash, \
char * : ok_str_hash, \
const char * : ok_const_str_hash, \
void * : ok_ptr_hash, \
const void * : ok_const_ptr_hash)
# else
// Force compile error if type is not 'char *`
# define ok_default_hash(key) (ok_static_assert(sizeof(_ok_is_char(*key)) == sizeof(bool) && \
sizeof(*key) == sizeof(char), \
"Only works with `char *` type"), \
ok_const_str_hash)
# endif
#endif
static inline bool _ok_is_char(char);
/// Gets the hash for a uint8_t.
OK_LIB_API ok_hash_t ok_uint8_hash(uint8_t key);
/// Gets the hash for a int8_t.
OK_LIB_API ok_hash_t ok_int8_hash(int8_t key);
/// Gets the hash for a uint16_t.
OK_LIB_API ok_hash_t ok_uint16_hash(uint16_t key);
/// Gets the hash for a int16_t.
OK_LIB_API ok_hash_t ok_int16_hash(int16_t key);
/// Gets the hash for a uint32_t.
OK_LIB_API ok_hash_t ok_uint32_hash(uint32_t key);
/// Gets the hash for a int32_t.
OK_LIB_API ok_hash_t ok_int32_hash(int32_t key);
/// Gets the hash for a uint64_t.
OK_LIB_API ok_hash_t ok_uint64_hash(uint64_t key);
/// Gets the hash for a int64_t.
OK_LIB_API ok_hash_t ok_int64_hash(int64_t key);
/// Gets the hash for a float.
OK_LIB_API ok_hash_t ok_float_hash(float key);
/// Gets the hash for a double.
OK_LIB_API ok_hash_t ok_double_hash(double key);
/// Gets the hash for a string.
OK_LIB_API ok_hash_t ok_str_hash(char *key);
/// Gets the hash for a string.
OK_LIB_API ok_hash_t ok_const_str_hash(const char *key);
/// Combines two hashes into one.
OK_LIB_API ok_hash_t ok_hash_combine(ok_hash_t hash_a, ok_hash_t hash_b);
// MARK: Declarations: Equals functions
/// Gets the default equals function for the specified key type. Uses _Generic, so it requires C11.
#ifndef ok_default_equals
# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
# define ok_default_equals(key) _Generic(key, \
uint8_t : ok_8bit_equals, \
int8_t : ok_8bit_equals, \
uint16_t : ok_16bit_equals, \
int16_t : ok_16bit_equals, \
uint32_t : ok_32bit_equals, \
int32_t : ok_32bit_equals, \
uint64_t : ok_64bit_equals, \
int64_t : ok_64bit_equals, \
float : ok_32bit_equals, \
double : ok_64bit_equals, \
char * : ok_str_equals, \
const char * : ok_str_equals)
# else
# define ok_default_equals(key) ok_str_equals
# endif
#endif
/// Checks if two 8-bit values are equal.
OK_LIB_API bool ok_8bit_equals(const void *v1, const void *v2);
/// Checks if two 16-bit values are equal.
OK_LIB_API bool ok_16bit_equals(const void *v1, const void *v2);
/// Checks if two 32-bit values are equal.
OK_LIB_API bool ok_32bit_equals(const void *v1, const void *v2);
/// Checks if two 64-bit values are equal.
OK_LIB_API bool ok_64bit_equals(const void *v1, const void *v2);
/// Checks if two strings are equal.
OK_LIB_API bool ok_str_equals(const void *a, const void *b);
// MARK: Declarations: Private functions
// @cond private
#define OK_PTR_INC(ptr, offset) ((uint8_t *)(ptr) + (offset))
#define OK_OFFSETOF(base_ptr, ptr) ((size_t)((uint8_t *)(ptr) - (uint8_t *)(base_ptr)))
struct _ok_map;
struct _ok_queue_block;
struct _ok_queue;
OK_LIB_API bool _ok_vec_realloc(void **values, size_t min_capacity, size_t element_size,
size_t *capacity);
OK_LIB_API struct _ok_map *_ok_map_create(size_t initial_capacity,
bool (*key_equals_func)(const void *key1,
const void *key2),
size_t key_offset, size_t value_offset,
size_t bucket_stride);
OK_LIB_API void _ok_map_free(struct _ok_map *map);
OK_LIB_API size_t _ok_map_count(const struct _ok_map *map);
OK_LIB_API size_t _ok_map_capacity(const struct _ok_map *map);
OK_LIB_API bool _ok_map_contains(const struct _ok_map *map, const void *key,
ok_hash_t key_hash);
OK_LIB_API bool _ok_map_put(struct _ok_map **map, const void *key,
size_t key_size, ok_hash_t key_hash,
const void *value, size_t value_size);
OK_LIB_API void _ok_map_put_and_get_ptr(struct _ok_map **map, const void *key,
size_t key_size, ok_hash_t key_hash,
void **value_ptr, size_t value_size);
OK_LIB_API bool _ok_map_put_all(struct _ok_map **map,
const struct _ok_map *from_map,
size_t key_size, size_t value_size);
OK_LIB_API void _ok_map_get(const struct _ok_map *map, const void *key,
ok_hash_t key_hash, void *value, size_t value_size);
OK_LIB_API void _ok_map_get_ptr(const struct _ok_map *map, const void *key,
ok_hash_t key_hash, void **value_ptr);
OK_LIB_API bool _ok_map_remove(struct _ok_map *map, const void *key,
ok_hash_t key_hash);
OK_LIB_API void *_ok_map_next(const struct _ok_map *map, void *iterator, void *key,
size_t key_size, void *value, size_t value_size);
OK_LIB_API struct _ok_queue_block *_ok_queue_new_block(const struct _ok_queue *queue,
size_t value_size);
OK_LIB_API void _ok_queue_free_block(struct _ok_queue_block *block);