• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kos-lang / kos / 11712809211

06 Nov 2024 10:17PM UTC coverage: 96.457% (+0.01%) from 96.444%
11712809211

push

github

cdragan
core: use error reporting from lexer in parser

20 of 20 new or added lines in 2 files covered. (100.0%)

2 existing lines in 2 files now uncovered.

24528 of 25429 relevant lines covered (96.46%)

871470.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.7
/core/kos_array.c
1
/* SPDX-License-Identifier: MIT
2
 * SPDX-FileCopyrightText: Copyright (c) 2014-2024 Chris Dragan
3
 */
4

5
#include "../inc/kos_array.h"
6
#include "../inc/kos_atomic.h"
7
#include "../inc/kos_constants.h"
8
#include "../inc/kos_instance.h"
9
#include "../inc/kos_error.h"
10
#include "../inc/kos_object.h"
11
#include "../inc/kos_utils.h"
12
#include "kos_config.h"
13
#include "kos_debug.h"
14
#include "kos_heap.h"
15
#include "kos_math.h"
16
#include "kos_object_internal.h"
17
#include "kos_perf.h"
18
#include "kos_try.h"
19
#include <assert.h>
20

21
KOS_DECLARE_STATIC_CONST_STRING(str_err_empty,         "array is empty");
22
KOS_DECLARE_STATIC_CONST_STRING(str_err_invalid_index, "array index is out of range");
23
KOS_DECLARE_STATIC_CONST_STRING(str_err_not_array,     "object is not an array");
24
KOS_DECLARE_STATIC_CONST_STRING(str_err_read_only,     "array is read-only");
25

26
DECLARE_STATIC_CONST_OBJECT(tombstone, OBJ_OPAQUE, 0xA0);
27
DECLARE_STATIC_CONST_OBJECT(closed,    OBJ_OPAQUE, 0xA1);
28

29
/* TOMBSTONE indicates that an array element has been deleted due to a resize. */
30
#define TOMBSTONE KOS_CONST_ID(tombstone)
31
/* CLOSED indicates that an array element has been moved to a new buffer. */
32
#define CLOSED    KOS_CONST_ID(closed)
33

34
#define KOS_buffer_alloc_size(cap) (KOS_align_up((uint32_t)sizeof(KOS_ARRAY_STORAGE) \
35
                                                   + (uint32_t)(((cap) - 1) * sizeof(KOS_OBJ_ID)), \
36
                                                 1U << KOS_OBJ_ALIGN_BITS))
37

38
static void atomic_fill_ptr(KOS_ATOMIC(KOS_OBJ_ID) *dest,
699,047✔
39
                            unsigned                count,
40
                            KOS_OBJ_ID              value)
41
{
42
    KOS_ATOMIC(KOS_OBJ_ID) *const end = dest + count;
699,047✔
43
    while (dest < end) {
20,933,700✔
44
        KOS_atomic_write_relaxed_ptr(*dest, value);
20,234,700✔
45
        ++dest;
20,234,700✔
46
    }
47
}
699,047✔
48

49
static KOS_ARRAY_STORAGE *alloc_buffer(KOS_CONTEXT ctx, uint32_t capacity)
200,891✔
50
{
51
    KOS_ARRAY_STORAGE *buf            = KOS_NULL;
200,891✔
52
    const uint32_t     buf_alloc_size = KOS_buffer_alloc_size(capacity);
200,891✔
53

54
    if (capacity < KOS_MAX_ARRAY_SIZE)
200,891✔
55
        buf = (KOS_ARRAY_STORAGE *)kos_alloc_object(ctx,
200,890✔
56
                                                    KOS_ALLOC_MOVABLE,
57
                                                    OBJ_ARRAY_STORAGE,
58
                                                    buf_alloc_size);
59
    else
60
        KOS_raise_exception(ctx, KOS_STR_OUT_OF_MEMORY);
1✔
61

62
    if (buf) {
200,891✔
63
        assert(kos_get_object_type(buf->header) == OBJ_ARRAY_STORAGE);
200,815✔
64

65
        capacity = 1U + (buf_alloc_size - sizeof(KOS_ARRAY_STORAGE)) / sizeof(KOS_OBJ_ID);
200,815✔
66
        KOS_atomic_write_relaxed_u32(buf->capacity,       capacity);
200,815✔
67
        KOS_atomic_write_relaxed_u32(buf->num_slots_open, capacity);
200,815✔
68
        KOS_atomic_write_relaxed_ptr(buf->next,           KOS_BADPTR);
200,815✔
69
    }
70

71
    return buf;
200,891✔
72
}
73

74
KOS_OBJ_ID KOS_new_array(KOS_CONTEXT ctx,
490,940✔
75
                         uint32_t    size)
76
{
77
    const uint32_t array_obj_size = KOS_align_up((uint32_t)sizeof(KOS_ARRAY), 1U << KOS_OBJ_ALIGN_BITS);
490,940✔
78
    const uint32_t buf_alloc_size = size ? KOS_buffer_alloc_size(size) : 0;
490,940✔
79
    const int      buf_built_in   = array_obj_size + buf_alloc_size <= 256U;
490,940✔
80
    const uint32_t alloc_size     = buf_built_in ? array_obj_size + buf_alloc_size : array_obj_size;
490,940✔
81
    KOS_ARRAY     *array          = KOS_NULL;
490,940✔
82

83
    if (size < KOS_MAX_ARRAY_SIZE)
490,940✔
84
        array = (KOS_ARRAY *)kos_alloc_object(ctx,
490,940✔
85
                                              KOS_ALLOC_MOVABLE,
86
                                              OBJ_ARRAY,
87
                                              alloc_size);
88
    else
UNCOV
89
        KOS_raise_exception(ctx, KOS_STR_OUT_OF_MEMORY);
×
90

91
    if (array) {
490,948✔
92
        KOS_ARRAY_STORAGE *storage = KOS_NULL;
490,849✔
93

94
        KOS_atomic_write_relaxed_u32(array->flags, 0);
490,849✔
95

96
        if (buf_built_in) {
490,849✔
97
            if (buf_alloc_size) {
365,724✔
98

99
                const uint32_t capacity = 1U + (buf_alloc_size - sizeof(KOS_ARRAY_STORAGE)) / sizeof(KOS_OBJ_ID);
306,819✔
100

101
                storage = (KOS_ARRAY_STORAGE *)((uintptr_t)array + array_obj_size);
306,819✔
102
                kos_set_object_type_size(storage->header, OBJ_ARRAY_STORAGE, buf_alloc_size);
306,819✔
103

104
                KOS_atomic_write_relaxed_u32(storage->capacity,       capacity);
306,819✔
105
                KOS_atomic_write_relaxed_u32(storage->num_slots_open, capacity);
306,819✔
106
                KOS_atomic_write_relaxed_ptr(storage->next,           KOS_BADPTR);
306,819✔
107

108
                kos_set_object_size(array->header, array_obj_size);
306,819✔
109

110
                KOS_atomic_write_relaxed_ptr(array->data, OBJID(ARRAY_STORAGE, storage));
306,819✔
111
            }
112
            else
113
                KOS_atomic_write_relaxed_ptr(array->data, KOS_BADPTR);
58,905✔
114
        }
115
        else {
116
            KOS_LOCAL saved_array;
117

118
            KOS_atomic_write_relaxed_ptr(array->data, KOS_BADPTR);
125,125✔
119

120
            KOS_init_local_with(ctx, &saved_array, OBJID(ARRAY, array));
125,125✔
121

122
            storage = alloc_buffer(ctx, size);
125,125✔
123

124
            if (storage) {
125,125✔
125
                array = OBJPTR(ARRAY, saved_array.o);
125,120✔
126

127
                KOS_atomic_write_relaxed_ptr(array->data, OBJID(ARRAY_STORAGE, storage));
125,120✔
128
            }
129
            else
130
                array = KOS_NULL;
5✔
131

132
            KOS_destroy_top_local(ctx, &saved_array);
125,125✔
133
        }
134

135
        if (array) {
490,849✔
136

137
            KOS_atomic_write_relaxed_u32(array->size, size);
490,843✔
138

139
            if (storage) {
490,843✔
140
                const uint32_t capacity = KOS_atomic_read_relaxed_u32(storage->capacity);
431,938✔
141

142
                if (size)
431,938✔
143
                    atomic_fill_ptr(&storage->buf[0], size, KOS_VOID);
431,938✔
144

145
                if (size < capacity)
431,939✔
146
                    atomic_fill_ptr(&storage->buf[size], capacity - size, TOMBSTONE);
191,479✔
147
            }
148
        }
149
    }
150

151
    return OBJID(ARRAY, array);
490,947✔
152
}
153

154
static KOS_ARRAY_STORAGE *get_data(KOS_OBJ_ID obj_id)
4,698,480✔
155
{
156
    const KOS_OBJ_ID buf_obj = kos_get_array_storage(obj_id);
4,698,480✔
157
    return IS_BAD_PTR(buf_obj) ? KOS_NULL : OBJPTR(ARRAY_STORAGE, buf_obj);
4,698,480✔
158
}
159

160
static KOS_ARRAY_STORAGE *get_next(KOS_ARRAY_STORAGE *storage)
1,650✔
161
{
162
    const KOS_OBJ_ID buf_obj = KOS_atomic_read_acquire_obj(storage->next);
1,650✔
163
    return IS_BAD_PTR(buf_obj) ? KOS_NULL : OBJPTR(ARRAY_STORAGE, buf_obj);
1,650✔
164
}
165

166
static void copy_buf(KOS_CONTEXT        ctx,
42,079✔
167
                     KOS_ARRAY         *array,
168
                     KOS_ARRAY_STORAGE *old_buf,
169
                     KOS_ARRAY_STORAGE *new_buf)
170
{
171
    KOS_ATOMIC(KOS_OBJ_ID) *src      = &old_buf->buf[0];
42,079✔
172
    KOS_ATOMIC(KOS_OBJ_ID) *dst      = &new_buf->buf[0];
42,079✔
173
    const uint32_t          capacity = KOS_atomic_read_relaxed_u32(old_buf->capacity);
42,079✔
174
    const uint32_t          fuzz     = KOS_atomic_read_relaxed_u32(old_buf->num_slots_open);
42,079✔
175
    uint32_t                i        = (capacity - fuzz) % capacity;
42,079✔
176

177
    for (;;) {
694,473✔
178
        KOS_OBJ_ID in_dst   = TOMBSTONE;
736,552✔
179
        int        salvaged = 0;
736,552✔
180

181
        /* Salvage item to the new buffer */
182
        for (;;) {
10,240✔
183
            const KOS_OBJ_ID value = KOS_atomic_read_relaxed_obj(src[i]);
746,792✔
184

185
            /* Another thread copied it */
186
            if (value == CLOSED)
746,792✔
187
                break;
59,282✔
188

189
            /* Write value to new buffer */
190
            if ( ! KOS_atomic_cas_strong_ptr(dst[i], in_dst, value))
687,510✔
191
                /* Another thread wrote something to dest */
192
                break;
127,782✔
193
            in_dst = value;
561,036✔
194

195
            /* Close the slot in the old buffer */
196
            if (KOS_atomic_cas_weak_ptr(src[i], value, CLOSED)) {
561,036✔
197
                salvaged = 1;
566,597✔
198
                break;
566,597✔
199
            }
200
            /* If failed to close, someone wrote a new value, try again */
201
        }
202

203
        if (salvaged)
204
            KOS_PERF_CNT(array_salvage_success);
205
        else
206
            KOS_PERF_CNT(array_salvage_fail);
207

208
        /* Exit early if another thread finished it */
209
        if ( ! salvaged && KOS_atomic_read_relaxed_u32(old_buf->num_slots_open) == 0)
753,661✔
210
            break;
778✔
211

212
        /* Update number of closed slots */
213
        if (salvaged && KOS_atomic_add_i32(old_buf->num_slots_open, -1) == 1)
752,883✔
214
            break;
58,410✔
215

216
        /* Try next slot */
217
        ++i;
694,473✔
218
        if (i == capacity)
694,473✔
219
            i = 0;
339✔
220
    }
221

222
    (void)KOS_atomic_cas_strong_ptr(array->data,
59,188✔
223
                                    OBJID(ARRAY_STORAGE, old_buf),
224
                                    OBJID(ARRAY_STORAGE, new_buf));
225
}
41,903✔
226

227
KOS_OBJ_ID KOS_array_read(KOS_CONTEXT ctx, KOS_OBJ_ID obj_id, int idx)
2,798,820✔
228
{
229
    KOS_OBJ_ID elem = KOS_BADPTR;
2,798,820✔
230

231
    assert( ! IS_BAD_PTR(obj_id));
2,798,820✔
232

233
    if ((GET_OBJ_TYPE(obj_id) != OBJ_ARRAY) || kos_seq_fail())
2,798,820✔
234
        KOS_raise_exception(ctx, KOS_CONST_ID(str_err_not_array));
10,040✔
235
    else {
236
        const uint32_t size   = KOS_atomic_read_relaxed_u32(OBJPTR(ARRAY, obj_id)->size);
2,793,270✔
237
        const uint32_t bufidx = (idx < 0) ? ((uint32_t)idx + size) : (uint32_t)idx;
2,793,270✔
238

239
        if (bufidx < size) {
2,793,270✔
240
            KOS_ARRAY_STORAGE *buf = get_data(obj_id);
2,788,060✔
241

242
            for (;;) {
243
                elem = KOS_atomic_read_relaxed_obj(buf->buf[bufidx]);
2,786,820✔
244

245
                if (elem == TOMBSTONE) {
2,786,820✔
246
                    KOS_raise_exception(ctx, KOS_CONST_ID(str_err_invalid_index));
×
247
                    elem = KOS_BADPTR;
×
248
                    break;
×
249
                }
250

251
                if (elem == CLOSED)
2,786,820✔
252
                    buf = get_next(buf);
717✔
253
                else
254
                    break;
2,786,100✔
255
            }
256
        }
257
        else
258
            KOS_raise_exception(ctx, KOS_CONST_ID(str_err_invalid_index));
5,206✔
259
    }
260

261
    return elem;
2,800,140✔
262
}
263

264
int KOS_array_write(KOS_CONTEXT ctx, KOS_OBJ_ID obj_id, int idx, KOS_OBJ_ID value)
1,028,620✔
265
{
266
    int error = KOS_ERROR_EXCEPTION;
1,028,620✔
267

268
    assert( ! IS_BAD_PTR(obj_id));
1,028,620✔
269

270
    if (GET_OBJ_TYPE(obj_id) != OBJ_ARRAY)
1,028,620✔
271
        KOS_raise_exception(ctx, KOS_CONST_ID(str_err_not_array));
×
272
    else if (KOS_atomic_read_relaxed_u32(OBJPTR(ARRAY, obj_id)->flags) & KOS_READ_ONLY)
1,031,160✔
273
        KOS_raise_exception(ctx, KOS_CONST_ID(str_err_read_only));
10✔
274
    else {
275
        const uint32_t   size   = KOS_atomic_read_relaxed_u32(OBJPTR(ARRAY, obj_id)->size);
1,031,150✔
276
        const uint32_t   bufidx = (idx < 0) ? ((uint32_t)idx + size) : (uint32_t)idx;
1,031,150✔
277

278
        if (bufidx < size) {
1,031,150✔
279

280
            KOS_ARRAY_STORAGE *buf = get_data(obj_id);
1,026,780✔
281

282
            for (;;) {
935✔
283

284
                KOS_OBJ_ID cur = KOS_atomic_read_relaxed_obj(buf->buf[bufidx]);
1,030,540✔
285

286
                if (cur == TOMBSTONE) {
1,030,540✔
287
                    KOS_raise_exception(ctx, KOS_CONST_ID(str_err_invalid_index));
×
288
                    break;
×
289
                }
290

291
                if (cur == CLOSED) {
1,030,540✔
292
                    KOS_ARRAY_STORAGE *new_buf = get_next(buf);
933✔
293
                    copy_buf(ctx, OBJPTR(ARRAY, obj_id), buf, new_buf);
933✔
294
                    buf = new_buf;
2,959✔
295
                }
296
                else if (KOS_atomic_cas_weak_ptr(buf->buf[bufidx], cur, value)) {
1,029,600✔
297
                    error = KOS_SUCCESS;
1,038,110✔
298
                    break;
1,038,110✔
299
                }
300
            }
301
        }
302
        else
303
            KOS_raise_exception(ctx, KOS_CONST_ID(str_err_invalid_index));
4,368✔
304
    }
305

306
    return error;
1,040,050✔
307
}
308

309
KOS_OBJ_ID KOS_array_cas(KOS_CONTEXT ctx,
9✔
310
                         KOS_OBJ_ID  obj_id,
311
                         int         idx,
312
                         KOS_OBJ_ID  old_value,
313
                         KOS_OBJ_ID  new_value)
314
{
315
    KOS_OBJ_ID retval = KOS_BADPTR;
9✔
316

317
    assert( ! IS_BAD_PTR(obj_id));
9✔
318

319
    if (GET_OBJ_TYPE(obj_id) != OBJ_ARRAY)
9✔
320
        KOS_raise_exception(ctx, KOS_CONST_ID(str_err_not_array));
×
321
    else if (KOS_atomic_read_relaxed_u32(OBJPTR(ARRAY, obj_id)->flags) & KOS_READ_ONLY)
9✔
322
        KOS_raise_exception(ctx, KOS_CONST_ID(str_err_read_only));
1✔
323
    else {
324
        const uint32_t size   = KOS_atomic_read_relaxed_u32(OBJPTR(ARRAY, obj_id)->size);
8✔
325
        const uint32_t bufidx = (idx < 0) ? ((uint32_t)idx + size) : (uint32_t)idx;
8✔
326

327
        if (bufidx < size) {
8✔
328

329
            KOS_ARRAY_STORAGE *buf = get_data(obj_id);
6✔
330

331
            for (;;) {
×
332

333
                KOS_OBJ_ID cur = KOS_atomic_read_relaxed_obj(buf->buf[bufidx]);
6✔
334

335
                if (cur == TOMBSTONE) {
6✔
336
                    KOS_raise_exception(ctx, KOS_CONST_ID(str_err_invalid_index));
×
337
                    break;
×
338
                }
339

340
                if (cur == CLOSED) {
6✔
341
                    KOS_ARRAY_STORAGE *new_buf = get_next(buf);
×
342
                    copy_buf(ctx, OBJPTR(ARRAY, obj_id), buf, new_buf);
×
343
                    buf = new_buf;
×
344
                }
345
                else if (cur != old_value) {
6✔
346
                    retval = cur;
2✔
347
                    break;
2✔
348
                }
349
                else if (KOS_atomic_cas_weak_ptr(buf->buf[bufidx], cur, new_value)) {
4✔
350
                    retval = cur;
4✔
351
                    break;
4✔
352
                }
353
            }
354
        }
355
        else
356
            KOS_raise_exception(ctx, KOS_CONST_ID(str_err_invalid_index));
2✔
357
    }
358

359
    return retval;
9✔
360
}
361

362
static int resize_storage(KOS_CONTEXT ctx,
75,405✔
363
                          KOS_OBJ_ID  obj_id,
364
                          uint32_t    new_capacity)
365
{
366
    KOS_ARRAY_STORAGE *old_buf;
367
    KOS_ARRAY_STORAGE *new_buf;
368
    KOS_LOCAL          array;
369
    int                error = KOS_ERROR_EXCEPTION;
75,405✔
370

371
    KOS_init_local_with(ctx, &array, obj_id);
75,405✔
372

373
    new_buf = alloc_buffer(ctx, new_capacity);
75,405✔
374

375
    if (new_buf) {
75,405✔
376

377
        old_buf = get_data(array.o);
75,335✔
378

379
        atomic_fill_ptr(&new_buf->buf[0], KOS_atomic_read_relaxed_u32(new_buf->capacity), TOMBSTONE);
75,335✔
380

381
        if ( ! old_buf)
75,335✔
382
            (void)KOS_atomic_cas_strong_ptr(OBJPTR(ARRAY, array.o)->data, KOS_BADPTR, OBJID(ARRAY_STORAGE, new_buf));
34,189✔
383
        else if (KOS_atomic_cas_strong_ptr(old_buf->next, KOS_BADPTR, OBJID(ARRAY_STORAGE, new_buf)))
41,146✔
384
            copy_buf(ctx, OBJPTR(ARRAY, array.o), old_buf, new_buf);
41,146✔
385
        else {
386
            KOS_ARRAY_STORAGE *const buf = get_next(old_buf);
×
387

388
            copy_buf(ctx, OBJPTR(ARRAY, array.o), old_buf, buf);
×
389
        }
390

391
        error = KOS_SUCCESS;
75,335✔
392
    }
393

394
    KOS_destroy_top_local(ctx, &array);
75,405✔
395

396
    return error;
75,405✔
397
}
398

399
int kos_array_copy_storage(KOS_CONTEXT ctx,
813✔
400
                           KOS_OBJ_ID  obj_id)
401
{
402
    KOS_ARRAY_STORAGE *buf;
403
    uint32_t           capacity;
404

405
    assert( ! IS_BAD_PTR(obj_id));
813✔
406
    assert(GET_OBJ_TYPE(obj_id) == OBJ_ARRAY);
813✔
407

408
    buf      = get_data(obj_id);
813✔
409
    capacity = buf ? KOS_atomic_read_relaxed_u32(buf->capacity) : 0U;
813✔
410

411
    return resize_storage(ctx, obj_id, capacity);
813✔
412
}
413

414
int KOS_array_reserve(KOS_CONTEXT ctx, KOS_OBJ_ID obj_id, uint32_t new_capacity)
74,601✔
415
{
416
    int       error = KOS_ERROR_EXCEPTION;
74,601✔
417
    KOS_LOCAL array;
418

419
    assert( ! IS_BAD_PTR(obj_id));
74,601✔
420

421
    KOS_init_local_with(ctx, &array, obj_id);
74,601✔
422

423
    if (GET_OBJ_TYPE(array.o) != OBJ_ARRAY)
74,601✔
424
        KOS_raise_exception(ctx, KOS_CONST_ID(str_err_not_array));
5✔
425
    else if (KOS_atomic_read_relaxed_u32(OBJPTR(ARRAY, array.o)->flags) & KOS_READ_ONLY)
74,596✔
426
        KOS_raise_exception(ctx, KOS_CONST_ID(str_err_read_only));
3✔
427
    else {
428
        KOS_ARRAY_STORAGE *old_buf  = get_data(array.o);
74,593✔
429
        uint32_t           capacity = old_buf ? KOS_atomic_read_relaxed_u32(old_buf->capacity) : 0U;
74,593✔
430

431
        error = KOS_SUCCESS;
74,593✔
432

433
        while (new_capacity > capacity) {
149,115✔
434
            error = resize_storage(ctx, array.o, new_capacity);
74,592✔
435
            if (error)
74,592✔
436
                break;
70✔
437

438
            old_buf = get_data(array.o);
74,522✔
439
            assert(old_buf);
74,522✔
440
            capacity = KOS_atomic_read_relaxed_u32(old_buf->capacity);
74,522✔
441
        }
442
    }
443

444
    KOS_destroy_top_local(ctx, &array);
74,601✔
445

446
    return error;
74,601✔
447
}
448

449
int KOS_array_resize(KOS_CONTEXT ctx, KOS_OBJ_ID obj_id, uint32_t size)
142,777✔
450
{
451
    int       error = KOS_ERROR_EXCEPTION;
142,777✔
452
    KOS_LOCAL array;
453

454
    assert( ! IS_BAD_PTR(obj_id));
142,777✔
455

456
    KOS_init_local_with(ctx, &array, obj_id);
142,777✔
457

458
#ifdef CONFIG_MAD_GC
459
    error = kos_trigger_mad_gc(ctx);
460
    if (error) {
461
        KOS_destroy_top_local(ctx, &array);
462
        return error;
463
    }
464
    error = KOS_ERROR_EXCEPTION;
465
#endif
466

467
    if (GET_OBJ_TYPE(array.o) != OBJ_ARRAY)
142,777✔
468
        KOS_raise_exception(ctx, KOS_CONST_ID(str_err_not_array));
5✔
469
    else if (KOS_atomic_read_relaxed_u32(OBJPTR(ARRAY, array.o)->flags) & KOS_READ_ONLY)
142,772✔
470
        KOS_raise_exception(ctx, KOS_CONST_ID(str_err_read_only));
6✔
471
    else {
472
        KOS_ARRAY_STORAGE *buf      = get_data(array.o);
142,766✔
473
        const uint32_t     capacity = buf ? KOS_atomic_read_relaxed_u32(buf->capacity) : 0U;
142,766✔
474
        uint32_t           old_size;
475

476
        if (size > capacity) {
142,766✔
477
            const uint32_t new_cap = KOS_max(capacity * 2, size);
21,503✔
478

479
            TRY(KOS_array_reserve(ctx, array.o, new_cap));
21,503✔
480

481
            buf = get_data(array.o);
21,481✔
482
        }
483

484
        old_size = KOS_atomic_swap_u32(OBJPTR(ARRAY, array.o)->size, size);
142,744✔
485

486
        if (size != old_size) {
142,744✔
487
            if (size > old_size) {
141,869✔
488
                const KOS_OBJ_ID void_obj = KOS_VOID;
31,461✔
489
                /* TODO try to improve this */
490
                KOS_ATOMIC(KOS_OBJ_ID) *ptr = &buf->buf[old_size];
31,461✔
491
                KOS_ATOMIC(KOS_OBJ_ID) *end = &buf->buf[size];
31,461✔
492
                while (ptr < end)
9,914,800✔
493
                    KOS_atomic_write_relaxed_ptr(*(ptr++), void_obj);
9,883,340✔
494
            }
495
            else {
496
                /* TODO try to improve this */
497
                KOS_ATOMIC(KOS_OBJ_ID) *ptr = &buf->buf[size];
110,408✔
498
                KOS_ATOMIC(KOS_OBJ_ID) *end = &buf->buf[old_size];
110,408✔
499
                while (ptr < end)
274,195✔
500
                    KOS_atomic_write_relaxed_ptr(*(ptr++), TOMBSTONE);
163,787✔
501
            }
502
        }
503

504
        error = KOS_SUCCESS;
142,744✔
505
    }
506

507
cleanup:
142,777✔
508
    KOS_destroy_top_local(ctx, &array);
142,777✔
509

510
    return error;
142,777✔
511
}
512

513
KOS_OBJ_ID KOS_array_slice(KOS_CONTEXT ctx,
454✔
514
                           KOS_OBJ_ID  obj_id,
515
                           int64_t     begin,
516
                           int64_t     end)
517
{
518
    KOS_LOCAL array;
519
    KOS_LOCAL ret;
520

521
    assert( ! IS_BAD_PTR(obj_id));
454✔
522

523
    KOS_init_local(ctx, &ret);
454✔
524
    KOS_init_local_with(ctx, &array, obj_id);
454✔
525

526
    if (GET_OBJ_TYPE(array.o) != OBJ_ARRAY)
454✔
527
        KOS_raise_exception(ctx, KOS_CONST_ID(str_err_not_array));
6✔
528
    else {
529
        const uint32_t len = KOS_get_array_size(array.o);
448✔
530

531
        ret.o = KOS_new_array(ctx, 0);
448✔
532

533
        if (len && ! IS_BAD_PTR(ret.o)) {
448✔
534

535
            uint32_t new_len;
536
            int64_t  new_len_64;
537

538
            begin = KOS_fix_index(begin, len);
364✔
539
            end   = KOS_fix_index(end, len);
364✔
540

541
            if (end < begin)
364✔
542
                end = begin;
2✔
543

544
            new_len_64 = end - begin;
364✔
545
            assert(new_len_64 <= 0xFFFFFFFF);
364✔
546
            new_len = (uint32_t)new_len_64;
364✔
547

548
            if (new_len) {
364✔
549

550
                KOS_ARRAY_STORAGE *dest_buf = alloc_buffer(ctx, new_len);
361✔
551

552
                if (dest_buf) {
361✔
553
                    KOS_ARRAY   *const new_array = OBJPTR(ARRAY, ret.o);
360✔
554
                    KOS_ARRAY_STORAGE *src_buf   = get_data(array.o);
360✔
555
                    uint32_t           idx       = 0;
360✔
556

557
                    KOS_ATOMIC(KOS_OBJ_ID) *dest = &dest_buf->buf[0];
360✔
558

559
                    KOS_atomic_write_relaxed_ptr(new_array->data, OBJID(ARRAY_STORAGE, dest_buf));
360✔
560

561
                    while (idx < new_len) {
2,327✔
562

563
                        const KOS_OBJ_ID value =
1,967✔
564
                            KOS_atomic_read_relaxed_obj(src_buf->buf[begin + idx]);
1,967✔
565

566
                        if (value == TOMBSTONE) {
1,967✔
567
                            new_len = idx;
×
568
                            break;
×
569
                        }
570

571
                        if (value == CLOSED) {
1,967✔
572
                            src_buf = get_next(src_buf);
×
573
                            continue;
×
574
                        }
575

576
                        KOS_atomic_write_relaxed_ptr(*(dest++), value);
1,967✔
577
                        ++idx;
1,967✔
578
                    }
579

580
                    KOS_atomic_write_relaxed_u32(new_array->size, new_len);
360✔
581

582
                    if (new_len < KOS_atomic_read_relaxed_u32(dest_buf->capacity))
360✔
583
                        atomic_fill_ptr(&dest_buf->buf[new_len],
296✔
584
                                        KOS_atomic_read_relaxed_u32(dest_buf->capacity) - new_len,
296✔
585
                                        TOMBSTONE);
296✔
586
                }
587
                else
588
                    ret.o = KOS_BADPTR;
1✔
589
            }
590
        }
591
    }
592

593
    return KOS_destroy_top_locals(ctx, &array, &ret);
454✔
594
}
595

596
int KOS_array_insert(KOS_CONTEXT ctx,
17,864✔
597
                     KOS_OBJ_ID  dest_obj_id,
598
                     int64_t     dest_begin,
599
                     int64_t     dest_end,
600
                     KOS_OBJ_ID  src_obj_id,
601
                     int64_t     src_begin,
602
                     int64_t     src_end)
603
{
604
    /* TODO rewrite lock-free */
605

606
    int                error   = KOS_SUCCESS;
17,864✔
607
    uint32_t           dest_len;
608
    uint32_t           src_len = 0;
17,864✔
609
    uint32_t           dest_delta;
610
    uint32_t           src_delta;
611
    KOS_LOCAL          src;
612
    KOS_LOCAL          dest;
613
    KOS_ARRAY_STORAGE *dest_buf;
614
    KOS_ARRAY_STORAGE *src_buf = KOS_NULL;
17,864✔
615

616
    assert( ! IS_BAD_PTR(src_obj_id));
17,864✔
617
    assert( ! IS_BAD_PTR(dest_obj_id));
17,864✔
618

619
    KOS_init_local_with(ctx, &dest, dest_obj_id);
17,864✔
620
    KOS_init_local_with(ctx, &src,  src_obj_id);
17,864✔
621

622
    if (GET_OBJ_TYPE(dest.o) != OBJ_ARRAY)
17,864✔
623
        RAISE_EXCEPTION_STR(str_err_not_array);
5✔
624
    else if (KOS_atomic_read_relaxed_u32(OBJPTR(ARRAY, dest.o)->flags) & KOS_READ_ONLY)
17,859✔
625
        RAISE_EXCEPTION_STR(str_err_read_only);
4✔
626
    else if (src_begin != src_end && GET_OBJ_TYPE(src.o) != OBJ_ARRAY)
17,855✔
627
        RAISE_EXCEPTION_STR(str_err_not_array);
5✔
628

629
    dest_len = KOS_get_array_size(dest.o);
17,850✔
630

631
    dest_begin = KOS_fix_index(dest_begin, dest_len);
17,850✔
632
    dest_end   = KOS_fix_index(dest_end, dest_len);
17,850✔
633

634
    if (dest_end < dest_begin)
17,850✔
635
        dest_end = dest_begin;
1✔
636

637
    dest_delta = (uint32_t)(dest_end - dest_begin);
17,850✔
638

639
    if (src_begin != src_end) {
17,850✔
640
        src_len   = KOS_get_array_size(src.o);
17,836✔
641
        src_begin = KOS_fix_index(src_begin, src_len);
17,836✔
642
        src_end   = KOS_fix_index(src_end, src_len);
17,836✔
643

644
        if (src_end < src_begin)
17,836✔
645
            src_end = src_begin;
1✔
646
    }
647

648
    src_delta = (uint32_t)(src_end - src_begin);
17,850✔
649

650
    if (src_delta > dest_delta)
17,850✔
651
        TRY(KOS_array_resize(ctx, dest.o, dest_len - dest_delta + src_delta));
17,739✔
652

653
    dest_buf = get_data(dest.o);
17,848✔
654
    if (src_begin != src_end)
17,848✔
655
        src_buf = get_data(src.o);
17,815✔
656

657
    if (src.o != dest.o || src_end <= dest_begin || src_begin >= dest_end || ! src_delta) {
17,848✔
658

659
        if (src_delta != dest_delta && dest_end < dest_len)
17,836✔
660
            kos_atomic_move_ptr((KOS_ATOMIC(void *) *)&dest_buf->buf[dest_end - dest_delta + src_delta],
14,856✔
661
                                (KOS_ATOMIC(void *) *)&dest_buf->buf[dest_end],
14,856✔
662
                                (unsigned)(dest_len - dest_end));
663

664
        if (src.o == dest.o && src_begin >= dest_end)
17,836✔
665
            src_begin += src_delta - dest_delta;
3✔
666

667
        if (src_delta)
17,836✔
668
            kos_atomic_move_ptr((KOS_ATOMIC(void *) *)&dest_buf->buf[dest_begin],
17,803✔
669
                                (KOS_ATOMIC(void *) *)&src_buf->buf[src_begin],
17,803✔
670
                                src_delta);
671
    }
672
    else if (dest_delta >= src_delta) {
12✔
673

674
        if (src_begin != dest_begin)
3✔
675
            kos_atomic_move_ptr((KOS_ATOMIC(void *) *)&dest_buf->buf[dest_begin],
2✔
676
                                (KOS_ATOMIC(void *) *)&dest_buf->buf[src_begin],
2✔
677
                                src_delta);
678

679
        if (dest_end < dest_len)
3✔
680
            kos_atomic_move_ptr((KOS_ATOMIC(void *) *)&dest_buf->buf[dest_begin + src_delta],
1✔
681
                                (KOS_ATOMIC(void *) *)&dest_buf->buf[dest_end],
1✔
682
                                (unsigned)(dest_len - dest_end));
683
    }
684
    else {
685

686
        const int64_t mid = KOS_min(dest_begin + src_delta, src_end);
9✔
687

688
        if (dest_end < dest_len)
9✔
689
            kos_atomic_move_ptr((KOS_ATOMIC(void *) *)&dest_buf->buf[dest_begin + src_delta],
6✔
690
                                (KOS_ATOMIC(void *) *)&dest_buf->buf[dest_end],
6✔
691
                                (unsigned)(dest_len - dest_end));
692
        if (mid > src_begin)
9✔
693
            kos_atomic_move_ptr((KOS_ATOMIC(void *) *)&dest_buf->buf[dest_begin],
9✔
694
                                (KOS_ATOMIC(void *) *)&dest_buf->buf[src_begin],
9✔
695
                                (unsigned)(mid - src_begin));
696

697
        if (mid < src_end)
9✔
698
            kos_atomic_move_ptr((KOS_ATOMIC(void *) *)&dest_buf->buf[dest_begin + mid - src_begin],
1✔
699
                                (KOS_ATOMIC(void *) *)&dest_buf->buf[mid + src_delta - dest_delta],
1✔
700
                                (unsigned)(src_end - mid));
701
    }
702

703
    if (src_delta < dest_delta)
17,848✔
704
        TRY(KOS_array_resize(ctx, dest.o, dest_len - dest_delta + src_delta));
19✔
705

706
cleanup:
17,848✔
707
    KOS_destroy_top_locals(ctx, &src, &dest);
17,864✔
708

709
    return error;
17,864✔
710
}
711

712
int KOS_array_push(KOS_CONTEXT ctx,
421,816✔
713
                   KOS_OBJ_ID  obj_id,
714
                   KOS_OBJ_ID  value_id,
715
                   uint32_t   *idx)
716
{
717
    int                error = KOS_SUCCESS;
421,816✔
718
    KOS_LOCAL          array;
719
    KOS_LOCAL          value;
720
    KOS_ARRAY_STORAGE *buf;
721
    uint32_t           len;
722

723
    assert( ! IS_BAD_PTR(obj_id));
421,816✔
724

725
    KOS_init_local_with(ctx, &value, value_id);
421,816✔
726
    KOS_init_local_with(ctx, &array, obj_id);
421,816✔
727

728
    if (GET_OBJ_TYPE(array.o) != OBJ_ARRAY)
421,816✔
729
        RAISE_EXCEPTION_STR(str_err_not_array);
10✔
730
    else if (KOS_atomic_read_relaxed_u32(OBJPTR(ARRAY, array.o)->flags) & KOS_READ_ONLY)
421,806✔
731
        RAISE_EXCEPTION_STR(str_err_read_only);
2✔
732

733
    buf = get_data(array.o);
421,804✔
734

735
    /* Increment index */
736
    for (;;) {
53,034✔
737

738
        const uint32_t capacity = buf ? KOS_atomic_read_relaxed_u32(buf->capacity) : 0;
474,838✔
739

740
        len = KOS_get_array_size(array.o);
474,838✔
741

742
        if (len >= capacity) {
474,838✔
743
            const uint32_t new_cap = KOS_max(capacity * 2, len + 1);
53,082✔
744

745
            TRY(KOS_array_reserve(ctx, array.o, new_cap));
53,082✔
746

747
            buf = get_data(array.o);
53,034✔
748
            continue;
53,034✔
749
        }
750

751
        if (KOS_atomic_cas_weak_u32(OBJPTR(ARRAY, array.o)->size, len, len+1))
421,756✔
752
            break;
421,756✔
753
    }
754

755
    /* Write new value */
756
    for (;;) {
×
757

758
        const KOS_OBJ_ID cur_value = KOS_atomic_read_relaxed_ptr(buf->buf[len]);
421,756✔
759

760
        if (cur_value == CLOSED) {
421,756✔
761
            buf = get_next(buf);
×
762
            continue;
×
763
        }
764

765
        /* TODO What if cur_value != TOMBSTONE ??? ABA? */
766

767
        if (KOS_atomic_cas_weak_ptr(buf->buf[len], cur_value, value.o))
421,756✔
768
            break;
421,756✔
769
    }
770

771
    if (idx)
421,756✔
772
        *idx = len;
186,651✔
773

774
cleanup:
235,105✔
775
    KOS_destroy_top_locals(ctx, &array, &value);
421,816✔
776

777
    return error;
421,816✔
778
}
779

780
KOS_OBJ_ID KOS_array_pop(KOS_CONTEXT ctx,
49✔
781
                         KOS_OBJ_ID  obj_id)
782
{
783
    int       error = KOS_SUCCESS;
49✔
784
    uint32_t  len;
785
    KOS_LOCAL array;
786
    KOS_LOCAL ret;
787

788
    assert( ! IS_BAD_PTR(obj_id));
49✔
789

790
    KOS_init_local(ctx, &ret);
49✔
791
    KOS_init_local_with(ctx, &array, obj_id);
49✔
792

793
    if (GET_OBJ_TYPE(array.o) != OBJ_ARRAY)
49✔
794
        RAISE_EXCEPTION_STR(str_err_not_array);
7✔
795
    else if (KOS_atomic_read_relaxed_u32(OBJPTR(ARRAY, array.o)->flags) & KOS_READ_ONLY)
42✔
796
        RAISE_EXCEPTION_STR(str_err_read_only);
1✔
797

798
    len = KOS_get_array_size(array.o);
41✔
799

800
    if (len == 0)
41✔
801
        RAISE_EXCEPTION_STR(str_err_empty);
4✔
802

803
    ret.o = KOS_array_read(ctx, array.o, (int)len-1);
37✔
804
    TRY_OBJID(ret.o);
37✔
805

806
    error = KOS_array_resize(ctx, array.o, len-1);
37✔
807

808
cleanup:
49✔
809
    ret.o = KOS_destroy_top_locals(ctx, &array, &ret);
49✔
810

811
    return error ? KOS_BADPTR : ret.o;
49✔
812
}
813

814
int KOS_array_fill(KOS_CONTEXT ctx,
26✔
815
                   KOS_OBJ_ID  obj_id,
816
                   int64_t     begin,
817
                   int64_t     end,
818
                   KOS_OBJ_ID  value)
819
{
820
    uint32_t           len;
821
    KOS_ARRAY_STORAGE *buf;
822

823
    if (GET_OBJ_TYPE(obj_id) != OBJ_ARRAY) {
26✔
824
        KOS_raise_exception(ctx, KOS_CONST_ID(str_err_not_array));
1✔
825
        return KOS_ERROR_EXCEPTION;
1✔
826
    }
827
    else if (KOS_atomic_read_relaxed_u32(OBJPTR(ARRAY, obj_id)->flags) & KOS_READ_ONLY) {
25✔
828
        KOS_raise_exception(ctx, KOS_CONST_ID(str_err_read_only));
1✔
829
        return KOS_ERROR_EXCEPTION;
1✔
830
    }
831

832
    len = KOS_get_array_size(obj_id);
24✔
833

834
    begin = KOS_fix_index(begin, len);
24✔
835
    end   = KOS_fix_index(end, len);
24✔
836

837
    buf = get_data(obj_id);
24✔
838

839
    while (begin < end) {
65,636✔
840

841
        KOS_OBJ_ID cur = KOS_atomic_read_relaxed_obj(buf->buf[begin]);
65,612✔
842

843
        if (cur == TOMBSTONE)
65,612✔
844
            break;
×
845

846
        if (cur == CLOSED) {
65,612✔
847
            KOS_ARRAY_STORAGE *new_buf = get_next(buf);
×
848
            copy_buf(ctx, OBJPTR(ARRAY, obj_id), buf, new_buf);
×
849
            buf = new_buf;
×
850
        }
851
        else {
852
            if (KOS_atomic_cas_weak_ptr(buf->buf[begin], cur, value))
65,612✔
853
                ++begin;
65,612✔
854
        }
855
    }
856

857
    return KOS_SUCCESS;
24✔
858
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc