1#pragma once
2
3#include <stdarg.h>
4
5#ifdef __cplusplus
6extern "C" {
7#endif
8
9/****************************************************************
10 * Constructors
11 */
12
13typedef struct {
14 PwCtorArgs* next;
15 uint16_t type_id;
16 /*
17 * Arguments for BasicMap and Map constructors.
18 */
19 unsigned capacity;
20} PwMapCtorArgs;
21
22[[nodiscard]] static inline bool pw_create_map(PwValuePtr result)
23{
24 return pw_create(PwTypeId_Map, result);
25}
26
27#define pw_map_va(result, ...) \
28 _pw_map_va(PwTypeId_Map, (result), __VA_ARGS__ __VA_OPT__(,) PwVaEnd())
29
30#define pw_map_va2(result_type, result, ...) \
31 _pw_map_va(result_type, (result), __VA_ARGS__ __VA_OPT__(,) PwVaEnd())
32
33#define pwva_map(...) \
34 __extension__ \
35 ({ \
36 _PwValue result = PW_NULL; \
37 if (!_pw_map_va(PwTypeId_Map, &result, __VA_ARGS__ __VA_OPT__(,) PwVaEnd())) { \
38 pw_clone2(¤t_task->status, &result); \
39 } \
40 result; \
41 })
42
43#define pwva_map2(result_type, ...) \
44 __extension__ \
45 ({ \
46 _PwValue result = PW_NULL; \
47 if (!_pw_map_va(result_type, &result, __VA_ARGS__ __VA_OPT__(,) PwVaEnd())) { \
48 pw_clone2(¤t_task->status, &result); \
49 } \
50 result; \
51 })
52
53[[nodiscard]] bool _pw_map_va(uint16_t result_type, PwValuePtr result, ...);
54/*
55 * Variadic constructor arguments are key-value pairs.
56 */
57
58/****************************************************************
59 * Update map: insert key-value pair or replace existing value.
60 */
61
62[[nodiscard]] bool pw_map_update(PwValuePtr map, PwValuePtr key, PwValuePtr value);
63/*
64 * `key` is deeply copied and `value` is cloned before adding.
65 */
66
67[[nodiscard]] bool _pw_map_update_va(PwValuePtr map, ...);
68/*
69 * Variadic functions accept values, not pointers.
70 * This encourages use cases when values are created during the call.
71 * If an error is occured, a Status value is pushed on stack.
72 * As long as statuses are prohibited, the function returns the first
73 * status encountered and destroys all passed arguments.
74 *
75 * CAVEAT: DO NOT PASS LOCAL VARIABLES BY VALUES!
76 */
77
78#define pw_map_update_va(map, ...) \
79 _pw_map_update_va((map) __VA_OPT__(,) __VA_ARGS__, PwVaEnd())
80
81[[nodiscard]] bool pw_map_update_ap(PwValuePtr map, va_list ap);
82
83/****************************************************************
84 * Check `key` is in `map`.
85 */
86
87#define pw_map_has_key(map, key) _Generic((key), \
88 nullptr_t: _pw_map_has_key_null, \
89 bool: _pw_map_has_key_bool, \
90 char: _pw_map_has_key_signed, \
91 unsigned char: _pw_map_has_key_unsigned, \
92 short: _pw_map_has_key_signed, \
93 unsigned short: _pw_map_has_key_unsigned, \
94 int: _pw_map_has_key_signed, \
95 unsigned int: _pw_map_has_key_unsigned, \
96 long: _pw_map_has_key_signed, \
97 unsigned long: _pw_map_has_key_unsigned, \
98 long long: _pw_map_has_key_signed, \
99 unsigned long long: _pw_map_has_key_unsigned, \
100 float: _pw_map_has_key_float, \
101 double: _pw_map_has_key_float, \
102 char*: _pw_map_has_key_ascii, \
103 char8_t*: _pw_map_has_key_utf8, \
104 char32_t*: _pw_map_has_key_utf32, \
105 PwValuePtr: _pw_map_has_key \
106 )((map), (key))
107
108bool _pw_map_has_key(PwValuePtr map, PwValuePtr key);
109
110[[nodiscard]] static inline bool _pw_map_has_key_null (PwValuePtr map, PwType_Null key) { _PwValue k = PW_NULL; return _pw_map_has_key(map, &k); }
111[[nodiscard]] static inline bool _pw_map_has_key_bool (PwValuePtr map, PwType_Bool key) { _PwValue k = PW_BOOL(key); return _pw_map_has_key(map, &k); }
112[[nodiscard]] static inline bool _pw_map_has_key_signed (PwValuePtr map, PwType_Signed key) { _PwValue k = PW_SIGNED(key); return _pw_map_has_key(map, &k); }
113[[nodiscard]] static inline bool _pw_map_has_key_unsigned(PwValuePtr map, PwType_Unsigned key) { _PwValue k = PW_UNSIGNED(key); return _pw_map_has_key(map, &k); }
114[[nodiscard]] static inline bool _pw_map_has_key_float (PwValuePtr map, PwType_Float key) { _PwValue k = PW_FLOAT(key); return _pw_map_has_key(map, &k); }
115[[nodiscard]] static inline bool _pw_map_has_key_ascii (PwValuePtr map, char* key) { _PwValue k = PwStaticString(key); return _pw_map_has_key(map, &k); }
116[[nodiscard]] static inline bool _pw_map_has_key_utf8 (PwValuePtr map, char8_t* key) { PwValue k = PW_NULL; if (!pw_create_string(key, &k)) { pw_panic("OOM"); } return _pw_map_has_key(map, &k); }
117[[nodiscard]] static inline bool _pw_map_has_key_utf32 (PwValuePtr map, char32_t* key) { _PwValue k = PwStaticStringUtf32(key); return _pw_map_has_key(map, &k); }
118
119
120/****************************************************************
121 * Get value by `key`. Return PW_ERROR_NO_KEY if `key`
122 * is not in the `map`.
123 */
124
125#define pw_map_get(map, key, result) _Generic((key), \
126 nullptr_t: _pw_map_get_null, \
127 bool: _pw_map_get_bool, \
128 char: _pw_map_get_signed, \
129 unsigned char: _pw_map_get_unsigned, \
130 short: _pw_map_get_signed, \
131 unsigned short: _pw_map_get_unsigned, \
132 int: _pw_map_get_signed, \
133 unsigned int: _pw_map_get_unsigned, \
134 long: _pw_map_get_signed, \
135 unsigned long: _pw_map_get_unsigned, \
136 long long: _pw_map_get_signed, \
137 unsigned long long: _pw_map_get_unsigned, \
138 float: _pw_map_get_float, \
139 double: _pw_map_get_float, \
140 char*: _pw_map_get_ascii, \
141 char8_t*: _pw_map_get_utf8, \
142 char32_t*: _pw_map_get_utf32, \
143 PwValuePtr: _pw_map_get \
144 )((map), (key), (result))
145
146[[nodiscard]] bool _pw_map_get(PwValuePtr map, PwValuePtr key, PwValuePtr result);
147
148[[nodiscard]] static inline bool _pw_map_get_null (PwValuePtr map, PwType_Null key, PwValuePtr result) { _PwValue k = PW_NULL; return _pw_map_get(map, &k, result); }
149[[nodiscard]] static inline bool _pw_map_get_bool (PwValuePtr map, PwType_Bool key, PwValuePtr result) { _PwValue k = PW_BOOL(key); return _pw_map_get(map, &k, result); }
150[[nodiscard]] static inline bool _pw_map_get_signed (PwValuePtr map, PwType_Signed key, PwValuePtr result) { _PwValue k = PW_SIGNED(key); return _pw_map_get(map, &k, result); }
151[[nodiscard]] static inline bool _pw_map_get_unsigned(PwValuePtr map, PwType_Unsigned key, PwValuePtr result) { _PwValue k = PW_UNSIGNED(key); return _pw_map_get(map, &k, result); }
152[[nodiscard]] static inline bool _pw_map_get_float (PwValuePtr map, PwType_Float key, PwValuePtr result) { _PwValue k = PW_FLOAT(key); return _pw_map_get(map, &k, result); }
153[[nodiscard]] static inline bool _pw_map_get_ascii (PwValuePtr map, char* key, PwValuePtr result) { _PwValue k = PwStaticString(key); return _pw_map_get(map, &k, result); }
154[[nodiscard]] static inline bool _pw_map_get_utf8 (PwValuePtr map, char8_t* key, PwValuePtr result) { PwValue k = PW_NULL; if (!pw_create_string(key, &k)) { pw_panic("OOM"); } return _pw_map_get(map, &k, result); }
155[[nodiscard]] static inline bool _pw_map_get_utf32 (PwValuePtr map, char32_t* key, PwValuePtr result) { _PwValue k = PwStaticStringUtf32(key); return _pw_map_get(map, &k, result); }
156
157
158/****************************************************************
159 * Delete item from map by `key`.
160 *
161 * Return true if value was deleted, false if no value was identified by key.
162 */
163
164#define pw_map_del(map, key) _Generic((key), \
165 nullptr_t: _pw_map_del_null, \
166 bool: _pw_map_del_bool, \
167 char: _pw_map_del_signed, \
168 unsigned char: _pw_map_del_unsigned, \
169 short: _pw_map_del_signed, \
170 unsigned short: _pw_map_del_unsigned, \
171 int: _pw_map_del_signed, \
172 unsigned int: _pw_map_del_unsigned, \
173 long: _pw_map_del_signed, \
174 unsigned long: _pw_map_del_unsigned, \
175 long long: _pw_map_del_signed, \
176 unsigned long long: _pw_map_del_unsigned, \
177 float: _pw_map_del_float, \
178 double: _pw_map_del_float, \
179 char*: _pw_map_del_ascii, \
180 char8_t*: _pw_map_del_utf8, \
181 char32_t*: _pw_map_del_utf32, \
182 PwValuePtr: _pw_map_del \
183 )((map), (key))
184
185[[nodiscard]] bool _pw_map_del(PwValuePtr map, PwValuePtr key);
186
187[[nodiscard]] static inline bool _pw_map_del_null (PwValuePtr map, PwType_Null key) { _PwValue k = PW_NULL; return _pw_map_del(map, &k); }
188[[nodiscard]] static inline bool _pw_map_del_bool (PwValuePtr map, PwType_Bool key) { _PwValue k = PW_BOOL(key); return _pw_map_del(map, &k); }
189[[nodiscard]] static inline bool _pw_map_del_signed (PwValuePtr map, PwType_Signed key) { _PwValue k = PW_SIGNED(key); return _pw_map_del(map, &k); }
190[[nodiscard]] static inline bool _pw_map_del_unsigned(PwValuePtr map, PwType_Unsigned key) { _PwValue k = PW_UNSIGNED(key); return _pw_map_del(map, &k); }
191[[nodiscard]] static inline bool _pw_map_del_float (PwValuePtr map, PwType_Float key) { _PwValue k = PW_FLOAT(key); return _pw_map_del(map, &k); }
192[[nodiscard]] static inline bool _pw_map_del_ascii (PwValuePtr map, char* key) { _PwValue k = PwStaticString(key); return _pw_map_del(map, &k); }
193[[nodiscard]] static inline bool _pw_map_del_utf8 (PwValuePtr map, char8_t* key) { PwValue k = PW_NULL; if (!pw_create_string(key, &k)) { pw_panic("OOM"); } return _pw_map_del(map, &k); }
194[[nodiscard]] static inline bool _pw_map_del_utf32 (PwValuePtr map, char32_t* key) { _PwValue k = PwStaticStringUtf32(key); return _pw_map_del(map, &k); }
195
196
197/****************************************************************
198 * Misc. functions.
199 */
200
201unsigned pw_map_length(PwValuePtr map);
202/*
203 * Return the number of items in `map`.
204 */
205
206[[nodiscard]] bool pw_map_item(PwValuePtr map, unsigned index, PwValuePtr key, PwValuePtr value);
207/*
208 * Get key-value pair from the map.
209 * If `index` is valid return true and write result to key and value.
210 *
211 * Example:
212 *
213 * PwValue key = PW_NULL;
214 * PwValue value = PW_NULL;
215 * if (pw_map_item(map, i, &key, &value)) {
216 * // success!
217 * }
218 */
219
220#ifdef __cplusplus
221}
222#endif