GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/joels/Current/lispbm/src/extensions/array_extensions.c Lines: 405 419 96.7 %
Date: 2025-01-19 11:10:47 Branches: 133 189 70.4 %

Line Branch Exec Source
1
/*
2
    Copyright 2022, 2023, 2024 Joel Svensson        svenssonjoel@yahoo.se
3
    Copyright 2022, 2023 Benjamin Vedder
4
5
    This program is free software: you can redistribute it and/or modify
6
    it under the terms of the GNU General Public License as published by
7
    the Free Software Foundation, either version 3 of the License, or
8
    (at your option) any later version.
9
10
    This program is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
    GNU General Public License for more details.
14
15
    You should have received a copy of the GNU General Public License
16
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include "extensions/array_extensions.h"
20
21
#include "extensions.h"
22
#include "symrepr.h"
23
#include "lbm_memory.h"
24
25
#include <math.h>
26
27
static lbm_uint little_endian = 0;
28
static lbm_uint big_endian = 0;
29
30
static lbm_value array_extension_unsafe_free_array(lbm_value *args, lbm_uint argn);
31
static lbm_value array_extension_buffer_append_i8(lbm_value *args, lbm_uint argn);
32
static lbm_value array_extension_buffer_append_i16(lbm_value *args, lbm_uint argn);
33
static lbm_value array_extension_buffer_append_i32(lbm_value *args, lbm_uint argn);
34
static lbm_value array_extension_buffer_append_u8(lbm_value *args, lbm_uint argn);
35
static lbm_value array_extension_buffer_append_u16(lbm_value *args, lbm_uint argn);
36
static lbm_value array_extension_buffer_append_u24(lbm_value *args, lbm_uint argn);
37
static lbm_value array_extension_buffer_append_u32(lbm_value *args, lbm_uint argn);
38
static lbm_value array_extension_buffer_append_f32(lbm_value *args, lbm_uint argn);
39
40
static lbm_value array_extension_buffer_get_i8(lbm_value *args, lbm_uint argn);
41
static lbm_value array_extension_buffer_get_i16(lbm_value *args, lbm_uint argn);
42
static lbm_value array_extension_buffer_get_i32(lbm_value *args, lbm_uint argn);
43
static lbm_value array_extension_buffer_get_u8(lbm_value *args, lbm_uint argn);
44
static lbm_value array_extension_buffer_get_u16(lbm_value *args, lbm_uint argn);
45
static lbm_value array_extension_buffer_get_u24(lbm_value *args, lbm_uint argn);
46
static lbm_value array_extension_buffer_get_u32(lbm_value *args, lbm_uint argn);
47
static lbm_value array_extension_buffer_get_f32(lbm_value *args, lbm_uint argn);
48
49
static lbm_value array_extension_buffer_length(lbm_value *args, lbm_uint argn);
50
51
static lbm_value array_extensions_bufclear(lbm_value *args, lbm_uint argn);
52
static lbm_value array_extensions_bufcpy(lbm_value *args, lbm_uint argn);
53
static lbm_value array_extensions_bufset_bit(lbm_value *args, lbm_uint argn);
54
55
21588
void lbm_array_extensions_init(void) {
56
57
21588
  lbm_add_symbol_const("little-endian", &little_endian);
58
21588
  lbm_add_symbol_const("big-endian", &big_endian);
59
60
21588
  lbm_add_extension("free", array_extension_unsafe_free_array);
61
21588
  lbm_add_extension("bufset-i8", array_extension_buffer_append_i8);
62
21588
  lbm_add_extension("bufset-i16", array_extension_buffer_append_i16);
63
21588
  lbm_add_extension("bufset-i32", array_extension_buffer_append_i32);
64
21588
  lbm_add_extension("bufset-u8", array_extension_buffer_append_u8);
65
21588
  lbm_add_extension("bufset-u16", array_extension_buffer_append_u16);
66
21588
  lbm_add_extension("bufset-u24", array_extension_buffer_append_u24);
67
21588
  lbm_add_extension("bufset-u32", array_extension_buffer_append_u32);
68
21588
  lbm_add_extension("bufset-f32", array_extension_buffer_append_f32);
69
70
21588
  lbm_add_extension("bufget-i8", array_extension_buffer_get_i8);
71
21588
  lbm_add_extension("bufget-i16", array_extension_buffer_get_i16);
72
21588
  lbm_add_extension("bufget-i32", array_extension_buffer_get_i32);
73
21588
  lbm_add_extension("bufget-u8", array_extension_buffer_get_u8);
74
21588
  lbm_add_extension("bufget-u16", array_extension_buffer_get_u16);
75
21588
  lbm_add_extension("bufget-u24", array_extension_buffer_get_u24);
76
21588
  lbm_add_extension("bufget-u32", array_extension_buffer_get_u32);
77
21588
  lbm_add_extension("bufget-f32", array_extension_buffer_get_f32);
78
79
21588
  lbm_add_extension("buflen",  array_extension_buffer_length);
80
21588
  lbm_add_extension("bufclear", array_extensions_bufclear);
81
21588
  lbm_add_extension("bufcpy", array_extensions_bufcpy);
82
21588
  lbm_add_extension("bufset-bit", array_extensions_bufset_bit);
83
21588
}
84
85
112
lbm_value array_extension_unsafe_free_array(lbm_value *args, lbm_uint argn) {
86
112
  lbm_value res = ENC_SYM_EERROR;
87
112
  if (argn == 1) {
88
112
    if (lbm_is_array_rw(args[0])) {
89
112
      if (lbm_heap_explicit_free_array(args[0])) {
90
112
        res = ENC_SYM_TRUE;
91
      } else {
92
        res = ENC_SYM_NIL;
93
      }
94
    } else {
95
      res = ENC_SYM_TERROR;
96
    }
97
  }
98
112
  return res;
99
}
100
101
3528
static bool decode_append_args(lbm_value *error, lbm_value *args, lbm_uint argn, lbm_uint *index, bool *be, lbm_uint *a_size, uint8_t **a_data) {
102
3528
  *be = true;
103
3528
  *error = ENC_SYM_EERROR;
104
3528
  bool res = false;
105
3528
  switch(argn) {
106
980
  case 4:
107
980
    if (lbm_type_of(args[3]) == LBM_TYPE_SYMBOL &&
108
980
        lbm_dec_sym(args[3]) == little_endian) {
109
980
      *be = false;
110
    }
111
    /* fall through */
112
  case 3: {
113
3528
    lbm_array_header_t *array = lbm_dec_array_rw(args[0]);
114

6972
    if(array &&
115
6888
       lbm_is_number(args[1]) &&
116
3444
       lbm_is_number(args[2])) {
117
3444
      *a_size = array->size;
118
3444
      *a_data = (uint8_t*)array->data;
119
3444
      *index = lbm_dec_as_u32(args[1]);
120
3444
      res = true;
121
    } else {
122
84
      *error = ENC_SYM_TERROR;
123
    }
124
  }
125
  }
126
3528
  return res;
127
}
128
129
3444
static bool buffer_append_bytes(uint8_t *data, lbm_uint d_size, bool be, lbm_uint index, lbm_uint nbytes, lbm_uint value) {
130
131
3444
  lbm_uint last_index = index + (nbytes - 1);
132
3444
  bool res = false;
133
3444
  if (last_index < d_size) {
134
3220
    res = true;
135

3220
    switch(nbytes) {
136
1288
    case 1:
137
1288
      data[index]    = (uint8_t) value;
138
1288
      break;
139
644
    case 2:
140
644
      if (be) {
141
364
        data[index+1]  = (uint8_t)value;
142
364
        data[index]    = (uint8_t)(value >> 8);
143
      } else {
144
280
        data[index]    = (uint8_t)value;
145
280
        data[index +1] = (uint8_t)(value >> 8);
146
      }
147
644
      break;
148
280
    case 3:
149
280
      if (be) {
150
140
        data[index+2]  = (uint8_t)value;
151
140
        data[index+1]  = (uint8_t)(value >> 8);
152
140
        data[index]    = (uint8_t)(value >> 16);
153
      } else {
154
140
        data[index]    = (uint8_t)value;
155
140
        data[index+1]  = (uint8_t)(value >> 8);
156
140
        data[index+2]  = (uint8_t)(value >> 16);
157
      }
158
280
      break;
159
1008
    default:
160
1008
      if (be) {
161
728
        data[index+3]  = (uint8_t) value;
162
728
        data[index+2]  = (uint8_t) (value >> 8);
163
728
        data[index+1]  = (uint8_t) (value >> 16);
164
728
        data[index]    = (uint8_t) (value >> 24);
165
      } else {
166
280
        data[index]    = (uint8_t) value;
167
280
        data[index+1]  = (uint8_t) (value >> 8);
168
280
        data[index+2]  = (uint8_t) (value >> 16);
169
280
        data[index+3]  = (uint8_t) (value >> 24);
170
      }
171
1008
      break;
172
    }
173
224
  }
174
3444
  return res;
175
}
176
177
756
lbm_value array_extension_buffer_append_i8(lbm_value *args, lbm_uint argn) {
178
179
756
  lbm_value res = ENC_SYM_EERROR;
180
756
  uint8_t *data = NULL;
181
756
  lbm_uint d_size = 0;
182
756
  bool be = false;
183
756
  lbm_uint index = 0;
184
185
756
  if (decode_append_args(&res, args, argn, &index, &be, &d_size, &data)) {
186
672
    if (buffer_append_bytes(data, d_size, be, index, 1, (lbm_uint)lbm_dec_as_i32(args[2]))) {
187
644
      res = ENC_SYM_TRUE;
188
    }
189
  }
190
756
  return res;
191
}
192
193
588
lbm_value array_extension_buffer_append_i16(lbm_value *args, lbm_uint argn) {
194
195
588
  lbm_value res = ENC_SYM_EERROR;
196
588
  uint8_t *data = NULL;
197
588
  lbm_uint d_size = 0;
198
588
  bool be = false;
199
588
  lbm_uint index = 0;
200
201
588
  if (decode_append_args(&res, args, argn, &index, &be, &d_size, &data)) {
202
588
    if (buffer_append_bytes(data, d_size, be, index, 2, (lbm_uint)lbm_dec_as_i32(args[2]))) {
203
560
      res = ENC_SYM_TRUE;
204
    }
205
  }
206
588
  return res;
207
}
208
209
448
lbm_value array_extension_buffer_append_i32(lbm_value *args, lbm_uint argn) {
210
211
448
  lbm_value res = ENC_SYM_EERROR;
212
448
  uint8_t *data = NULL;
213
448
  lbm_uint d_size = 0;
214
448
  bool be = false;
215
448
  lbm_uint index = 0;
216
217
448
  if (decode_append_args(&res, args, argn, &index, &be, &d_size, &data)) {
218
448
    if (buffer_append_bytes(data, d_size, be, index, 4, (lbm_uint)lbm_dec_as_i32(args[2]))) {
219
420
      res = ENC_SYM_TRUE;
220
    }
221
  }
222
448
  return res;
223
}
224
225
226
672
lbm_value array_extension_buffer_append_u8(lbm_value *args, lbm_uint argn) {
227
228
672
  lbm_value res = ENC_SYM_EERROR;
229
672
  uint8_t *data = NULL;
230
672
  lbm_uint d_size = 0;
231
672
  bool be = false;
232
672
  lbm_uint index = 0;
233
234
672
  if (decode_append_args(&res, args, argn, &index, &be, &d_size, &data)) {
235
672
    if (buffer_append_bytes(data, d_size, be, index, 1, (lbm_uint)lbm_dec_as_u32(args[2]))) {
236
644
      res = ENC_SYM_TRUE;
237
    }
238
  }
239
672
  return res;
240
}
241
242
112
lbm_value array_extension_buffer_append_u16(lbm_value *args, lbm_uint argn) {
243
244
112
  lbm_value res = ENC_SYM_EERROR;
245
112
  uint8_t *data = NULL;
246
112
  lbm_uint d_size = 0;
247
112
  bool be = false;
248
112
  lbm_uint index = 0;
249
250
112
  if (decode_append_args(&res, args, argn, &index, &be, &d_size, &data)) {
251
112
    if (buffer_append_bytes(data, d_size, be, index, 2, (lbm_uint)lbm_dec_as_u32(args[2]))) {
252
84
      res = ENC_SYM_TRUE;
253
    }
254
  }
255
112
  return res;
256
}
257
258
308
lbm_value array_extension_buffer_append_u24(lbm_value *args, lbm_uint argn) {
259
260
308
  lbm_value res = ENC_SYM_EERROR;
261
308
  uint8_t *data = NULL;
262
308
  lbm_uint d_size = 0;
263
308
  bool be = false;
264
308
  lbm_uint index = 0;
265
266
308
  if (decode_append_args(&res, args, argn, &index, &be, &d_size, &data)) {
267
308
    if (buffer_append_bytes(data, d_size, be, index, 3, (lbm_uint)lbm_dec_as_u32(args[2]))) {
268
280
      res = ENC_SYM_TRUE;
269
    }
270
  }
271
308
  return res;
272
}
273
274
448
lbm_value array_extension_buffer_append_u32(lbm_value *args, lbm_uint argn) {
275
276
448
  lbm_value res = ENC_SYM_EERROR;
277
448
  uint8_t *data = NULL;
278
448
  lbm_uint d_size = 0;
279
448
  bool be = false;
280
448
  lbm_uint index = 0;
281
282
448
  if (decode_append_args(&res, args, argn, &index, &be, &d_size, &data)) {
283
448
    if (buffer_append_bytes(data, d_size, be, index, 4, (lbm_uint)lbm_dec_as_u32(args[2]))) {
284
420
      res = ENC_SYM_TRUE;
285
    }
286
  }
287
448
  return res;
288
}
289
290
196
static lbm_uint float_to_u(float number) {
291
  // Set subnormal numbers to 0 as they are not handled properly
292
  // using this method.
293
196
  if (fabsf(number) < 1.5e-38) {
294
    number = 0.0;
295
  }
296
297
196
  int e = 0;
298
196
  float sig = frexpf(number, &e);
299
196
  float sig_abs = fabsf(sig);
300
196
  uint32_t sig_i = 0;
301
302
196
  if (sig_abs >= 0.5) {
303
196
    sig_i = (uint32_t)((sig_abs - 0.5f) * 2.0f * 8388608.0f);
304
196
    e += 126;
305
  }
306
307
196
  uint32_t res = (((uint32_t)e & 0xFFu) << 23) | (uint32_t)(sig_i & 0x7FFFFFu);
308
196
  if (sig < 0) {
309
    res |= 1U << 31;
310
  }
311
312
196
  return res;
313
}
314
315
168
static lbm_float u_to_float(uint32_t v) {
316
317
168
  int e = (v >> 23) & 0xFF;
318
168
  uint32_t sig_i = v & 0x7FFFFF;
319
168
  bool neg = v & (1U << 31);
320
321
168
  float sig = 0.0;
322

168
  if (e != 0 || sig_i != 0) {
323
168
    sig = (float)sig_i / (8388608.0f * 2.0f) + 0.5f;
324
168
    e -= 126;
325
  }
326
327
168
  if (neg) {
328
    sig = -sig;
329
  }
330
331
168
  return ldexpf(sig, e);
332
}
333
334
196
lbm_value array_extension_buffer_append_f32(lbm_value *args, lbm_uint argn) {
335
336
196
  lbm_value res = ENC_SYM_EERROR;
337
196
  uint8_t *data = NULL;
338
196
  lbm_uint d_size = 0;
339
196
  bool be = false;
340
196
  lbm_uint index = 0;
341
342
196
  if (decode_append_args(&res, args, argn, &index, &be, &d_size, &data)) {
343
196
    if (buffer_append_bytes(data, d_size, be, index, 4, (lbm_uint)float_to_u(lbm_dec_as_float(args[2])))) {
344
168
      res = ENC_SYM_TRUE;
345
    }
346
  }
347
196
  return res;
348
}
349
350
/* (buffer-get-i8 buffer index) */
351
/* (buffer-get-i16 buffer index little-endian) */
352
353
4900
static bool decode_get_args(lbm_value *error, lbm_value *args, lbm_uint argn, lbm_uint *index, bool *be, lbm_uint *a_size, uint8_t **a_data) {
354
4900
  bool res = false;
355
356
4900
  *be=true;
357
358
4900
  switch(argn) {
359
1176
  case 3:
360
1176
    if (lbm_type_of(args[2]) == LBM_TYPE_SYMBOL &&
361
1176
        lbm_dec_sym(args[2]) == little_endian) {
362
1176
      *be = false;
363
    }
364
    /* fall through */
365
  case 2: {
366
4900
    lbm_array_header_t *array = lbm_dec_array_r(args[0]);
367

9800
    if (array &&
368
4900
        lbm_is_number(args[1])) {
369
4900
      *a_size = array->size;
370
4900
      *a_data = (uint8_t*)array->data;
371
4900
      *index = lbm_dec_as_u32(args[1]);
372
4900
      res = true;
373
    } else {
374
      *error = ENC_SYM_TERROR;
375
    }
376
  }
377
  }
378
4900
  return res;
379
}
380
381
4900
static bool buffer_get_uint(lbm_uint *r_value, uint8_t *data, lbm_uint d_size, bool be, lbm_uint index, lbm_uint nbytes) {
382
383
4900
  bool res = false;
384
4900
  lbm_uint last_index = index + (nbytes - 1);
385
386
4900
  if (last_index < d_size) {
387
4284
    lbm_uint value = 0;
388
4284
    res = true;
389

4284
    switch(nbytes) {
390
2268
    case 1:
391
2268
      value = (lbm_uint)data[index];
392
2268
      break;
393
644
    case 2:
394
644
      if (be) {
395
364
        value =
396
364
          (lbm_uint) data[index+1] |
397
364
          (lbm_uint) data[index] << 8;
398
      } else {
399
280
        value =
400
280
          (lbm_uint) data[index] |
401
280
          (lbm_uint) data[index+1] << 8;
402
      }
403
644
      break;
404
280
    case 3:
405
280
      if (be) {
406
140
        value =
407
140
          (lbm_uint) data[index+2] |
408
140
          (lbm_uint) data[index+1] << 8 |
409
140
          (lbm_uint) data[index] << 16;
410
      } else {
411
140
        value =
412
140
          (lbm_uint) data[index] |
413
140
          (lbm_uint) data[index+1] << 8 |
414
140
          (lbm_uint) data[index+2] << 16;
415
      }
416
280
      break;
417
1092
    case 4:
418
1092
      if (be) {
419
812
        value =
420
812
          (uint32_t) data[index+3] |
421
812
          (uint32_t) data[index+2] << 8 |
422
812
          (uint32_t) data[index+1] << 16 |
423
812
          (uint32_t) data[index] << 24;
424
      } else {
425
280
        value =
426
280
          (uint32_t) data[index] |
427
280
          (uint32_t) data[index+1] << 8 |
428
280
          (uint32_t) data[index+2] << 16 |
429
280
          (uint32_t) data[index+3] << 24;
430
      }
431
1092
      break;
432
    default:
433
      res = false;
434
    }
435
4284
    *r_value = value;
436
  }
437
4900
  return res;
438
}
439
440
441
442
1344
lbm_value array_extension_buffer_get_i8(lbm_value *args, lbm_uint argn) {
443
1344
  lbm_value res = ENC_SYM_EERROR;
444
1344
  uint8_t *data = NULL;
445
1344
  lbm_uint d_size = 0;
446
1344
  bool be = false;
447
1344
  lbm_uint index = 0;
448
1344
  lbm_uint value = 0;
449
450
1344
  if (decode_get_args(&res, args, argn, &index, &be, &d_size, &data)) {
451
1344
    if (buffer_get_uint(&value, data, d_size, be, index, 1)) {
452
1260
      res =lbm_enc_i((int8_t)value);
453
    }
454
  }
455
1344
  return res;
456
}
457
458
700
lbm_value array_extension_buffer_get_i16(lbm_value *args, lbm_uint argn) {
459
700
  lbm_value res = ENC_SYM_EERROR;
460
700
  uint8_t *data = NULL;
461
700
  lbm_uint d_size = 0;
462
700
  bool be = false;
463
700
  lbm_uint index = 0;
464
700
  lbm_uint value = 0;
465
466
700
  if (decode_get_args(&res, args, argn, &index, &be, &d_size, &data)) {
467
700
    if (buffer_get_uint(&value, data, d_size, be, index, 2)) {
468
560
      res =lbm_enc_i((int16_t)value);
469
    }
470
  }
471
700
  return res;
472
}
473
474
504
lbm_value array_extension_buffer_get_i32(lbm_value *args, lbm_uint argn) {
475
504
  lbm_value res = ENC_SYM_EERROR;
476
504
  uint8_t *data = NULL;
477
504
  lbm_uint d_size = 0;
478
504
  bool be = false;
479
504
  lbm_uint index = 0;
480
504
  lbm_uint value = 0;
481
482
504
  if (decode_get_args(&res, args, argn, &index, &be, &d_size, &data)) {
483
504
    if (buffer_get_uint(&value, data, d_size, be, index, 4)) {
484
420
      res =lbm_enc_i((int32_t)value);
485
    }
486
  }
487
504
  return res;
488
}
489
490
1092
lbm_value array_extension_buffer_get_u8(lbm_value *args, lbm_uint argn) {
491
1092
  lbm_value res = ENC_SYM_EERROR;
492
1092
  uint8_t *data = NULL;
493
1092
  lbm_uint d_size = 0;
494
1092
  bool be = false;
495
1092
  lbm_uint index = 0;
496
1092
  lbm_uint value = 0;
497
498
1092
  if (decode_get_args(&res, args, argn, &index, &be, &d_size, &data)) {
499
1092
    if (buffer_get_uint(&value, data, d_size, be, index, 1)) {
500
1008
      res = lbm_enc_i((uint8_t)value);
501
    }
502
  }
503
1092
  return res;
504
}
505
506
112
lbm_value array_extension_buffer_get_u16(lbm_value *args, lbm_uint argn) {
507
112
  lbm_value res = ENC_SYM_EERROR;
508
112
  uint8_t *data = NULL;
509
112
  lbm_uint d_size = 0;
510
112
  bool be = false;
511
112
  lbm_uint index = 0;
512
112
  lbm_uint value = 0;
513
514
112
  if (decode_get_args(&res, args, argn, &index, &be, &d_size, &data)) {
515
112
    if (buffer_get_uint(&value, data, d_size, be, index, 2)) {
516
84
      res = lbm_enc_i((uint16_t)value);
517
    }
518
  }
519
112
  return res;
520
}
521
522
364
lbm_value array_extension_buffer_get_u24(lbm_value *args, lbm_uint argn) {
523
364
  lbm_value res = ENC_SYM_EERROR;
524
364
  uint8_t *data = NULL;
525
364
  lbm_uint d_size = 0;
526
364
  bool be = false;
527
364
  lbm_uint index = 0;
528
364
  lbm_uint value = 0;
529
530
364
  if (decode_get_args(&res, args, argn, &index, &be, &d_size, &data)) {
531
364
    if (buffer_get_uint(&value, data, d_size, be, index, 3)) {
532
280
      res = lbm_enc_i((int32_t)value);
533
    }
534
  }
535
364
  return res;
536
}
537
538
588
lbm_value array_extension_buffer_get_u32(lbm_value *args, lbm_uint argn) {
539
588
  lbm_value res = ENC_SYM_EERROR;
540
588
  uint8_t *data = NULL;
541
588
  lbm_uint d_size = 0;
542
588
  bool be = false;
543
588
  lbm_uint index = 0;
544
588
  lbm_uint value = 0;
545
546
588
  if (decode_get_args(&res, args, argn, &index, &be, &d_size, &data)) {
547
588
    if (buffer_get_uint(&value, data, d_size, be, index, 4)) {
548
504
      res = lbm_enc_u32((uint32_t)value);
549
    }
550
  }
551
588
  return res;
552
}
553
554
196
lbm_value array_extension_buffer_get_f32(lbm_value *args, lbm_uint argn) {
555
196
  lbm_value res = ENC_SYM_EERROR;
556
196
  uint8_t *data = NULL;
557
196
  lbm_uint d_size = 0;
558
196
  bool be = false;
559
196
  lbm_uint index = 0;
560
196
  lbm_uint value = 0;
561
562
196
  if (decode_get_args(&res, args, argn, &index, &be, &d_size, &data)) {
563
196
    if (buffer_get_uint(&value, data, d_size, be, index, 4)) {
564
168
      res = lbm_enc_float(u_to_float((uint32_t)value));
565
    }
566
  }
567
196
  return res;
568
}
569
570
252
lbm_value array_extension_buffer_length(lbm_value *args, lbm_uint argn) {
571
252
  lbm_value res = ENC_SYM_EERROR;
572
  lbm_array_header_t *array;
573

504
  if (argn == 1 &&
574
504
      (array = lbm_dec_array_r(args[0])) &&
575
252
      lbm_heap_array_valid(args[0])) {
576
252
    res = lbm_enc_i((lbm_int)array->size);
577
  }
578
252
  return res;
579
}
580
581
//TODO: Have to think about 32 vs 64 bit here
582
560
static lbm_value array_extensions_bufclear(lbm_value *args, lbm_uint argn) {
583
560
  lbm_value res = ENC_SYM_EERROR;
584

560
  if (argn >= 1 && argn <= 4) {
585
504
    res = ENC_SYM_TERROR;
586
504
    if (lbm_is_array_rw(args[0])) {
587
504
      lbm_array_header_t *array = (lbm_array_header_t *)lbm_car(args[0]);
588
589
504
      uint8_t clear_byte = 0;
590
504
      if (argn >= 2) {
591
420
        if (!lbm_is_number(args[1])) {
592
          return res;
593
        }
594
420
        clear_byte = (uint8_t)lbm_dec_as_u32(args[1]);
595
      }
596
597
504
      uint32_t start = 0;
598
504
      if (argn >= 3) {
599
56
        if (!lbm_is_number(args[2])) {
600
          return res;
601
        }
602
56
        uint32_t start_new = lbm_dec_as_u32(args[2]);
603
56
        if (start_new < array->size) {
604
56
          start = start_new;
605
        } else {
606
          return res;
607
        }
608
      }
609
      // Truncates size on 64 bit build
610
504
      uint32_t len = (uint32_t)array->size - start;
611
504
      if (argn >= 4) {
612
28
        if (!lbm_is_number(args[3])) {
613
          return res;
614
        }
615
28
        uint32_t len_new = lbm_dec_as_u32(args[3]);
616
28
        if (len_new <= len) {
617
28
          len = len_new;
618
        }
619
      }
620
621
504
      memset((char*)array->data + start, clear_byte, len);
622
504
      res = ENC_SYM_TRUE;
623
    }
624
  }
625
560
  return res;
626
}
627
628
140
static lbm_value array_extensions_bufcpy(lbm_value *args, lbm_uint argn) {
629
140
  lbm_value res = ENC_SYM_EERROR;
630
631
140
  if (argn == 5) {
632
112
    res = ENC_SYM_TERROR;
633

168
    if (lbm_is_array_rw(args[0]) && lbm_is_number(args[1]) &&
634

112
        lbm_is_array_r(args[2]) && lbm_is_number(args[3]) &&lbm_is_number(args[4])) {
635
56
      lbm_array_header_t *array1 = (lbm_array_header_t *)lbm_car(args[0]);
636
637
56
      uint32_t start1 = lbm_dec_as_u32(args[1]);
638
639
56
      lbm_array_header_t *array2 = (lbm_array_header_t *)lbm_car(args[2]);
640
641
56
      uint32_t start2 = lbm_dec_as_u32(args[3]);
642
56
      uint32_t len = lbm_dec_as_u32(args[4]);
643
644

56
      if (start1 < array1->size && start2 < array2->size) {
645
56
        if (len > (array1->size - start1)) {
646
          len = ((uint32_t)array1->size - start1);
647
        }
648
56
        if (len > (array2->size - start2)) {
649
          len = ((uint32_t)array2->size - start2);
650
        }
651
652
56
        memcpy((char*)array1->data + start1, (char*)array2->data + start2, len);
653
      }
654
56
      res = ENC_SYM_TRUE;
655
    }
656
  }
657
140
  return res;
658
}
659
660
168
static lbm_value array_extensions_bufset_bit(lbm_value *args, lbm_uint argn) {
661
168
  lbm_value res = ENC_SYM_EERROR;
662
663
168
  if (argn == 3) {
664
84
    res = ENC_SYM_TERROR;
665

140
    if (lbm_is_array_rw(args[0]) &&
666
112
        lbm_is_number(args[1]) && lbm_is_number(args[2])) {
667
56
      lbm_array_header_t *array = (lbm_array_header_t *)lbm_car(args[0]);
668
669
56
      unsigned int pos = lbm_dec_as_u32(args[1]);
670
56
      unsigned int bit = lbm_dec_as_u32(args[2]) ? 1 : 0;
671
672
56
      unsigned int bytepos = pos / 8;
673
674
56
      if (bytepos < array->size) {
675
56
        unsigned int bitpos = pos % 8;
676
56
        ((uint8_t*)array->data)[bytepos] &= (uint8_t)~(1 << bitpos);
677
56
        ((uint8_t*)array->data)[bytepos] |= (uint8_t)(bit << bitpos);
678
      }
679
680
56
      res = ENC_SYM_TRUE;
681
    }
682
  }
683
168
  return res;
684
}