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