1#pragma once
  2
  3#include <stdarg.h>
  4#include <uchar.h>
  5
  6#include <pw_iterator.h>
  7#include <pw_string.h>
  8
  9#ifdef __cplusplus
 10extern "C" {
 11#endif
 12
 13/****************************************************************
 14 * Constructors
 15 */
 16
 17PW_STRUCT(PwArrayCtorArgs) {
 18    PwCtorArgs* next;
 19    uint16_t type_id;
 20    /*
 21     * Arguments for BasicArray and Array constructors.
 22     */
 23    unsigned capacity;
 24};
 25
 26[[nodiscard]] static inline bool pw_create_array(PwValuePtr result)
 27{
 28    return pw_create(PwTypeId_Array, result);
 29}
 30
 31#define pw_array_va(result, ...)  \
 32    _pw_array_va(PwTypeId_Array, (result), __VA_ARGS__ __VA_OPT__(,) PwVaEnd())
 33
 34#define pw_array_va2(result_type, result, ...)  \
 35    _pw_array_va(result_type, (result), __VA_ARGS__ __VA_OPT__(,) PwVaEnd())
 36
 37#define pwva_array(...) \
 38    __extension__ \
 39    ({  \
 40        _PwValue result = PW_NULL;  \
 41        if (!_pw_array_va(PwTypeId_Array, &result, __VA_ARGS__  __VA_OPT__(,) PwVaEnd())) {  \
 42            result = pw_get_status();  \
 43        }  \
 44        result;  \
 45    })
 46
 47#define pwva_array2(result_type, ...) \
 48    __extension__ \
 49    ({  \
 50        _PwValue result = PW_NULL;  \
 51        if (!_pw_array_va((result_type), &result, __VA_ARGS__  __VA_OPT__(,) PwVaEnd())) {  \
 52            result = pw_get_status();  \
 53        }  \
 54        result;  \
 55    })
 56
 57[[nodiscard]] extern bool _pw_array_va(uint16_t result_type, PwValuePtr result, ...);
 58/*
 59 * Variadic array constructor arguments are array items.
 60 */
 61
 62/****************************************************************
 63 * Append and insert functions
 64 */
 65
 66#define pw_array_append(array, item) _Generic((item), \
 67             nullptr_t: _pw_array_append_null,      \
 68                  bool: _pw_array_append_bool,      \
 69                  char: _pw_array_append_signed,    \
 70         unsigned char: _pw_array_append_unsigned,  \
 71                 short: _pw_array_append_signed,    \
 72        unsigned short: _pw_array_append_unsigned,  \
 73                   int: _pw_array_append_signed,    \
 74          unsigned int: _pw_array_append_unsigned,  \
 75                  long: _pw_array_append_signed,    \
 76         unsigned long: _pw_array_append_unsigned,  \
 77             long long: _pw_array_append_signed,    \
 78    unsigned long long: _pw_array_append_unsigned,  \
 79                 float: _pw_array_append_float,     \
 80                double: _pw_array_append_float,     \
 81                 char*: _pw_array_append_ascii,     \
 82              char8_t*: _pw_array_append_utf8,      \
 83             char32_t*: _pw_array_append_utf32,     \
 84            PwValuePtr: _pw_array_append            \
 85    )((array), (item))
 86
 87[[nodiscard]] bool _pw_array_append(PwValuePtr array, PwValuePtr item);
 88/*
 89 * The basic append function.
 90 *
 91 * `item` is cloned before appending.
 92 */
 93
 94[[nodiscard]] static inline bool _pw_array_append_null    (PwValuePtr array, PwType_Null     item) { _PwValue v = PW_NULL;           return _pw_array_append(array, &v); }
 95[[nodiscard]] static inline bool _pw_array_append_bool    (PwValuePtr array, PwType_Bool     item) { _PwValue v = PW_BOOL(item);     return _pw_array_append(array, &v); }
 96[[nodiscard]] static inline bool _pw_array_append_signed  (PwValuePtr array, PwType_Signed   item) { _PwValue v = PW_SIGNED(item);   return _pw_array_append(array, &v); }
 97[[nodiscard]] static inline bool _pw_array_append_unsigned(PwValuePtr array, PwType_Unsigned item) { _PwValue v = PW_UNSIGNED(item); return _pw_array_append(array, &v); }
 98[[nodiscard]] static inline bool _pw_array_append_float   (PwValuePtr array, PwType_Float    item) { _PwValue v = PW_FLOAT(item);    return _pw_array_append(array, &v); }
 99[[nodiscard]] static inline bool _pw_array_append_ascii   (PwValuePtr array, char*           item) { _PwValue v = PwStaticString(item); return _pw_array_append(array, &v); }
100[[nodiscard]] static inline bool _pw_array_append_utf8    (PwValuePtr array, char8_t*        item) { PwValue v = PW_NULL; if (!pw_create_string(&v, item)) { return false; } return _pw_array_append(array, &v); }
101[[nodiscard]] static inline bool _pw_array_append_utf32   (PwValuePtr array, char32_t*       item) { _PwValue v = PwStaticStringUtf32(item); return _pw_array_append(array, &v); }
102
103[[nodiscard]] bool _pw_array_append_va(PwValuePtr array, ...);
104/*
105 * Variadic functions accept values, not pointers.
106 * This encourages use cases when values are created during the call.
107 * If an error is occured, a Status value is pushed on stack.
108 * As long as statuses are prohibited, the function returns the first
109 * status encountered and destroys all passed arguments.
110 *
111 * CAVEAT: DO NOT PASS LOCAL VARIABLES BY VALUES!
112 */
113
114#define pw_array_append_va(array, ...)  \
115    _pw_array_append_va(array __VA_OPT__(,) __VA_ARGS__, PwVaEnd())
116
117[[nodiscard]] bool pw_array_append_ap(PwValuePtr array, va_list ap);
118/*
119 * Append items to the `array`.
120 * Item are cloned before appending.
121 */
122
123[[nodiscard]] bool pw_array_extend(PwValuePtr array, PwValuePtr items);
124/*
125 * Append multiple items to array
126 */
127
128#define pw_array_insert(array, index, item) _Generic((item), \
129             nullptr_t: _pw_array_insert_null,      \
130                  bool: _pw_array_insert_bool,      \
131                  char: _pw_array_insert_signed,    \
132         unsigned char: _pw_array_insert_unsigned,  \
133                 short: _pw_array_insert_signed,    \
134        unsigned short: _pw_array_insert_unsigned,  \
135                   int: _pw_array_insert_signed,    \
136          unsigned int: _pw_array_insert_unsigned,  \
137                  long: _pw_array_insert_signed,    \
138         unsigned long: _pw_array_insert_unsigned,  \
139             long long: _pw_array_insert_signed,    \
140    unsigned long long: _pw_array_insert_unsigned,  \
141                 float: _pw_array_insert_float,     \
142                double: _pw_array_insert_float,     \
143                 char*: _pw_array_insert_ascii,     \
144              char8_t*: _pw_array_insert_utf8,      \
145             char32_t*: _pw_array_insert_utf32,     \
146            PwValuePtr: _pw_array_insert            \
147    )((array), (index), (item))
148
149[[nodiscard]] bool _pw_array_insert(PwValuePtr array, unsigned index, PwValuePtr item);
150/*
151 * The basic insert function.
152 *
153 * `item` is cloned before inserting.
154 */
155
156[[nodiscard]] static inline bool _pw_array_insert_null    (PwValuePtr array, unsigned index, PwType_Null     item) { _PwValue v = PW_NULL;              return _pw_array_insert(array, index, &v); }
157[[nodiscard]] static inline bool _pw_array_insert_bool    (PwValuePtr array, unsigned index, PwType_Bool     item) { _PwValue v = PW_BOOL(item);        return _pw_array_insert(array, index, &v); }
158[[nodiscard]] static inline bool _pw_array_insert_signed  (PwValuePtr array, unsigned index, PwType_Signed   item) { _PwValue v = PW_SIGNED(item);      return _pw_array_insert(array, index, &v); }
159[[nodiscard]] static inline bool _pw_array_insert_unsigned(PwValuePtr array, unsigned index, PwType_Unsigned item) { _PwValue v = PW_UNSIGNED(item);    return _pw_array_insert(array, index, &v); }
160[[nodiscard]] static inline bool _pw_array_insert_float   (PwValuePtr array, unsigned index, PwType_Float    item) { _PwValue v = PW_FLOAT(item);       return _pw_array_insert(array, index, &v); }
161[[nodiscard]] static inline bool _pw_array_insert_ascii   (PwValuePtr array, unsigned index, char*           item) { _PwValue v = PwStaticString(item); return _pw_array_insert(array, index, &v); }
162[[nodiscard]] static inline bool _pw_array_insert_utf8    (PwValuePtr array, unsigned index, char8_t*        item) { PwValue v = PW_NULL; if (!pw_create_string(&v, item)) { return false; } return _pw_array_insert(array, index, &v); }
163[[nodiscard]] static inline bool _pw_array_insert_utf32   (PwValuePtr array, unsigned index, char32_t*       item) { _PwValue v = PwStaticStringUtf32(item); return _pw_array_insert(array, index, &v); }
164
165
166/****************************************************************
167 * Join array items. Return string value.
168 */
169
170#define pw_array_join(array, separator, result) _Generic((separator), \
171              char32_t: _pw_array_join_c32,    \
172                   int: _pw_array_join_c32,    \
173                 char*: _pw_array_join_ascii,  \
174              char8_t*: _pw_array_join_utf8,   \
175             char32_t*: _pw_array_join_utf32,  \
176            PwValuePtr: _pw_array_join         \
177    )((array), (separator), (result))
178
179#define JOIN_IMPL  \
180    {  \
181        PwValue sep = PW_STRING();  \
182        if (!pw_string_append(&sep, separator)) {  \
183            return false;  \
184        }  \
185        return _pw_array_join(array, &sep, result);  \
186    }
187
188[[nodiscard]] bool _pw_array_join(PwValuePtr array, PwValuePtr separator, PwValuePtr result);
189[[nodiscard]] static inline bool _pw_array_join_c32  (PwValuePtr array, char32_t   separator, PwValuePtr result) JOIN_IMPL
190[[nodiscard]] static inline bool _pw_array_join_ascii(PwValuePtr array, char*      separator, PwValuePtr result) JOIN_IMPL
191[[nodiscard]] static inline bool _pw_array_join_utf8 (PwValuePtr array, char8_t*   separator, PwValuePtr result) JOIN_IMPL
192[[nodiscard]] static inline bool _pw_array_join_utf32(PwValuePtr array, char32_t*  separator, PwValuePtr result) JOIN_IMPL
193
194#undef JOIN_IMPL
195
196/****************************************************************
197 * Get/set array items
198 */
199
200[[nodiscard]] bool pw_array_pull(PwValuePtr array, PwValuePtr result);
201/*
202 * Extract first item from the array.
203 */
204
205[[nodiscard]] bool pw_array_pop(PwValuePtr array, PwValuePtr result);
206/*
207 * Extract last item from the array.
208 */
209
210#define pw_array_item(array, index, result) _Generic((index), \
211             int: _pw_array_item_signed,  \
212         ssize_t: _pw_array_item_signed,  \
213        unsigned: _pw_array_item  \
214    )((array), (index), (result))
215/*
216 * Clone array item to result.
217 * Negative indexes are allowed for signed version,
218 * where -1 is the index of last item.
219 */
220
221[[nodiscard]] static inline bool _pw_array_item_signed(PwValuePtr array, ssize_t index, PwValuePtr result)
222{
223    return pw_call(RandomAccess, get_item_s, array, index, result);
224}
225
226[[nodiscard]] static inline bool _pw_array_item(PwValuePtr array, unsigned index, PwValuePtr result)
227{
228    return pw_call(RandomAccess, get_item_u, array, index, result);
229}
230
231#define pw_array_set_item(array, index, item) _Generic((index), \
232             int: _pw_array_set_item_signed,  \
233         ssize_t: _pw_array_set_item_signed,  \
234        unsigned: _pw_array_set_item  \
235    )((array), (index), (item))
236/*
237 * Set item at specific index.
238 * Negative indexes are allowed for signed version,
239 * where -1 is the index of last item.
240 * Return PwStatus.
241 */
242
243[[nodiscard]] static inline bool _pw_array_set_item_signed(PwValuePtr array, ssize_t index, PwValuePtr item)
244{
245    return pw_call(RandomAccess, set_item_s, array, index, item);
246}
247
248[[nodiscard]] static inline bool _pw_array_set_item(PwValuePtr array, unsigned index, PwValuePtr item)
249{
250    return pw_call(RandomAccess, set_item_u, array, index, item);
251}
252
253/****************************************************************
254 * Iterator
255 */
256
257extern uint16_t PwTypeId_ArrayIterator;
258
259[[nodiscard]] static inline bool pw_create_array_iterator(PwValuePtr array, PwValuePtr result)
260/*
261 * Return ArrayIterator that supports multiple (TBD) iteration interfaces:
262 *   - LineReader
263 */
264{
265    PwIteratorCtorArgs args = {
266        .type_id = PwTypeId_ArrayIterator,
267        .iterable = array
268    };
269    return pw_create2(PwTypeId_ArrayIterator, &args, result);
270}
271
272/****************************************************************
273 * Miscellaneous array functions
274 */
275
276[[nodiscard]] bool pw_array_resize(PwValuePtr array, unsigned desired_capacity);
277
278unsigned pw_array_length(PwValuePtr array);
279
280[[nodiscard]] bool pw_array_del(PwValuePtr array, unsigned start_index, unsigned end_index);
281/*
282 * Delete items from array.
283 * `end_index` is exclusive, i.e. the number of items to delete equals to end_index - start_index..
284 */
285
286[[nodiscard]] bool pw_array_clean(PwValuePtr array);
287/*
288 * Delete all items from array.
289 */
290
291[[nodiscard]] bool pw_array_slice2(PwValuePtr array, unsigned start_index, unsigned end_index, PwValuePtr result, uint16_t result_type);
292/*
293 * Make shallow copy of the given range of array.
294 */
295
296[[nodiscard]] static inline bool pw_array_slice(PwValuePtr array, unsigned start_index, unsigned end_index, PwValuePtr result)
297{
298    return pw_array_slice2(array, start_index, end_index, result, array->type_id);
299}
300
301[[nodiscard]] static inline bool pw_array_copy(PwValuePtr result, PwValuePtr array)
302{
303    return pw_array_slice(array, 0, UINT_MAX, result);
304}
305
306
307#ifdef __cplusplus
308}
309#endif