1#include "include/pw.h"
2#include "src/types/array/array_internal.h"
3
4[[nodiscard]] unsigned pw_array_length(PwValuePtr self)
5{
6 _PwArray* array = get_array(self);
7 if (array) {
8 return _pw_array_length(array);
9 } else {
10 return false;
11 }
12}
13
14[[nodiscard]] bool _pw_array_va(uint16_t result_type, PwValuePtr result, ...)
15{
16 va_list ap;
17 va_start(ap);
18 if (!pw_create(result_type, result)) {
19 _pw_destroy_args(ap);
20 va_end(ap);
21 return false;
22 }
23 bool ret = pw_array_append_ap(result, ap);
24 if (!ret) {
25 pw_destroy(result);
26 }
27 va_end(ap);
28 return ret;
29}
30
31[[nodiscard]] bool _pw_array_append_va(PwValuePtr array, ...)
32{
33 va_list ap;
34 va_start(ap);
35 bool ret = pw_array_append_ap(array, ap);
36 va_end(ap);
37 return ret;
38}
39
40[[nodiscard]] bool pw_array_append_ap(PwValuePtr self, va_list ap)
41{
42 _PwArray* array = _pw_array_noiter_cow(self);
43 if (!array) {
44 return false;
45 }
46 unsigned num_appended = 0;
47 for (;;) {
48 PwValue arg = va_arg(ap, _PwValue);
49 if (pw_is_status(&arg)) {
50 if (pw_is_va_end(&arg)) {
51 return true;
52 }
53 pw_set_status(pw_clone(&arg));
54 goto failure;
55 }
56 if (_pw_array_is_immutable(array)) {
57 if (!pw_is_immutable(&arg)) {
58 pw_set_status(PwStatus(PweImmutableRequired));
59 goto failure;
60 }
61 }
62 if (!_pw_array_append_item(self, array, &arg)) {
63 goto failure;
64 }
65 pw_destroy(&arg); // the item is cloned when added to the array
66 num_appended++;
67 }
68
69failure:
70 // rollback
71 while (num_appended--) {
72 PwValue v = PW_NULL;
73 if (_pw_array_pop(self, array, &v)) {
74 pw_destroy(&v);
75 }
76 }
77 // consume args
78 _pw_destroy_args(ap);
79 return false;
80}
81
82[[nodiscard]] bool pw_array_clean(PwValuePtr self)
83{
84 _PwArray* array = _pw_array_noiter_cow(self);
85 if (!array) {
86 return false;
87 }
88 return _pw_array_del(self, array, 0, UINT_MAX);
89}
90
91[[nodiscard]] bool pw_array_resize(PwValuePtr self, unsigned desired_capacity)
92{
93 _PwArray* array = _pw_array_noiter_cow(self);
94 if (!array) {
95 return false;
96 }
97 return _pw_array_resize(self->type_id, array, desired_capacity);
98}
99
100[[nodiscard]] bool _pw_array_append(PwValuePtr self, PwValuePtr item)
101{
102 _PwArray* array = _pw_array_noiter_cow2(self, item);
103 if (!array) {
104 return false;
105 }
106 return _pw_array_append_item(self, array, item);
107}
108
109[[nodiscard]] bool _pw_array_insert(PwValuePtr self, unsigned index, PwValuePtr item)
110{
111 _PwArray* array = _pw_array_noiter_cow2(self, item);
112 if (!array) {
113 return false;
114 }
115 return _pw_array_ins(self, array, index, item);
116}
117
118[[nodiscard]] bool pw_array_pull(PwValuePtr self, PwValuePtr result)
119{
120 _PwArray* array = _pw_array_noiter_cow(self);
121 if (!array) {
122 return false;
123 }
124 return _pw_array_pull(self, array, result);
125}
126
127[[nodiscard]] bool pw_array_del(PwValuePtr self, unsigned start_index, unsigned end_index)
128{
129 _PwArray* array = _pw_array_noiter_cow(self);
130 if (!array) {
131 return false;
132 }
133 return _pw_array_del(self, array, start_index, end_index);
134}
135
136[[nodiscard]] bool pw_array_pop(PwValuePtr self, PwValuePtr result)
137{
138 _PwArray* array = _pw_array_noiter_cow(self);
139 if (!array) {
140 return false;
141 }
142 return _pw_array_pop(self, array, result);
143}
144
145[[nodiscard]] bool pw_array_slice2(PwValuePtr self, unsigned start_index, unsigned end_index,
146 PwValuePtr result, uint16_t result_type)
147// XXX make this array interface method
148{
149 _PwArray* src_array = get_array(self);
150 if (!src_array) {
151 return false;
152 }
153 unsigned length = _pw_array_length(src_array);
154
155 if (end_index > length) {
156 end_index = length;
157 }
158 if (start_index > end_index) {
159 start_index = end_index;
160 }
161 unsigned slice_len = end_index - start_index;
162 PwArrayCtorArgs args = {
163 .type_id = PwTypeId_BasicArray,
164 .capacity = slice_len
165 };
166 if (!pw_create2(result_type, &args, result)) {
167 return false;
168 }
169 if (slice_len == 0) {
170 goto done;
171 }
172
173 _PwArray* dest_array = _pw_get_struct_ptr(result, PwTypeId_BasicArray);
174
175 pw_hard_assert(dest_array->capacity >= slice_len);
176
177 PwValuePtr src_item_ptr = _pw_array_items_ptr(src_array, start_index);
178 PwValuePtr dest_item_ptr = _pw_array_items_ptr(dest_array, 0);
179 for (unsigned i = start_index; i < end_index; i++) {
180 __pw_clone(dest_item_ptr, src_item_ptr); // no need to destroy dest_item, so use __pw_clone here
181 src_item_ptr++;
182 dest_item_ptr++;
183 dest_array->length++;
184 }
185
186done:
187 if (_pw_array_is_immutable(src_array)) {
188 // all items of ser_array are immutable, so just set the flag
189 *((uintptr_t*) &dest_array->items) |= 1;
190 }
191 return true;
192}
193
194[[nodiscard]] bool _pw_array_join(PwValuePtr array, PwValuePtr separator, PwValuePtr result)
195{
196 pw_destroy(result); // to be sure
197
198 if (!pw_is_string(separator)) {
199 pw_exception(
200 PW_STATUS(PweIncompatibleType),
201 "Bad separator type for pw_array_join: %u, %s",
202 separator->type_id, pw_get_type_name(separator->type_id)
203 );
204 return false;
205 }
206 unsigned num_items = pw_array_length(array);
207 if (num_items == 0) {
208 *result = PwString();
209 return true;
210 }
211 if (num_items == 1) {
212 PwValue item = PW_NULL;
213 if (!pw_array_item(array, 0, &item)) {
214 return false;
215 }
216 if (pw_is_string(&item)) {
217 pw_move(result, &item);
218 return true;
219 } else {
220 // XXX skipping non-string values
221 *result = PwString();
222 return true;
223 }
224 }
225
226 uint8_t max_char_size = separator->str_params.char_size;
227 unsigned separator_len = pw_strlen(separator);
228
229 // calculate total length and max char width of string items
230 unsigned result_len = 0;
231 for (unsigned i = 0; i < num_items; i++) {
232 if (i) {
233 result_len += separator_len;
234 }
235 PwValue item = PW_NULL;
236 if (!pw_array_item(array, i, &item)) {
237 return false;
238 }
239 uint8_t char_size;
240 if (pw_is_string(&item)) {
241 char_size = item.str_params.char_size;
242 result_len += pw_strlen(&item);
243 } else {
244 // XXX skipping non-string values
245 continue;
246 }
247 if (max_char_size < char_size) {
248 max_char_size = char_size;
249 }
250 }
251
252 // join array items
253 if (!pw_create_empty_string(result_len, max_char_size, result)) {
254 return false;
255 }
256 for (unsigned i = 0; i < num_items; i++) {
257 PwValue item = PW_NULL;
258 if (!pw_array_item(array, i, &item)) {
259 return false;
260 }
261 if (pw_is_string(&item)) {
262 if (i) {
263 if (!_pw_string_append(result, separator)) {
264 pw_destroy(result);
265 return false;
266 }
267 }
268 if (!_pw_string_append(result, &item)) {
269 pw_destroy(result);
270 return false;
271 }
272 }
273 }
274 return true;
275}
276
277[[nodiscard]] bool pw_array_extend(PwValuePtr dest, PwValuePtr items)
278{
279 pw_assert(pw_is_array(items));
280 if (pw_iteration_in_progress(dest)) {
281 return false;
282 }
283 _PwArray* array = get_array(dest);
284 if (_pw_array_is_immutable(array)) {
285 unsigned n = array->length;
286 for (unsigned i = 0; i < n; i++) {
287 PwValue item = PW_NULL;
288 if (!_pw_array_item(items, i, &item)) {
289 return false;
290 }
291 if (!pw_is_immutable(&item)) {
292 pw_set_status(PwStatus(PweImmutableRequired));
293 return false;
294 }
295 }
296 array = _pw_array_copy_on_write(dest, array);
297 if (!array) {
298 return false;
299 }
300 }
301 unsigned n = pw_array_length(items);
302 for (unsigned i = 0; i < n; i++) {
303 PwValue item = PW_NULL;
304 if (!_pw_array_item(items, i, &item)) {
305 return false;
306 }
307 if (!_pw_array_append_item(dest, array, &item)) {
308 return false;
309 }
310 }
311 return true;
312}