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(&current_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(&current_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