GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/joels/Current/lispbm/src/extensions/array_extensions.c Lines: 406 420 96.7 %
Date: 2024-12-05 14:36:58 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
21672
void lbm_array_extensions_init(void) {
56
57
21672
  lbm_add_symbol_const("little-endian", &little_endian);
58
21672
  lbm_add_symbol_const("big-endian", &big_endian);
59
60
21672
  lbm_add_extension("free", array_extension_unsafe_free_array);
61
21672
  lbm_add_extension("bufset-i8", array_extension_buffer_append_i8);
62
21672
  lbm_add_extension("bufset-i16", array_extension_buffer_append_i16);
63
21672
  lbm_add_extension("bufset-i32", array_extension_buffer_append_i32);
64
21672
  lbm_add_extension("bufset-u8", array_extension_buffer_append_u8);
65
21672
  lbm_add_extension("bufset-u16", array_extension_buffer_append_u16);
66
21672
  lbm_add_extension("bufset-u24", array_extension_buffer_append_u24);
67
21672
  lbm_add_extension("bufset-u32", array_extension_buffer_append_u32);
68
21672
  lbm_add_extension("bufset-f32", array_extension_buffer_append_f32);
69
70
21672
  lbm_add_extension("bufget-i8", array_extension_buffer_get_i8);
71
21672
  lbm_add_extension("bufget-i16", array_extension_buffer_get_i16);
72
21672
  lbm_add_extension("bufget-i32", array_extension_buffer_get_i32);
73
21672
  lbm_add_extension("bufget-u8", array_extension_buffer_get_u8);
74
21672
  lbm_add_extension("bufget-u16", array_extension_buffer_get_u16);
75
21672
  lbm_add_extension("bufget-u24", array_extension_buffer_get_u24);
76
21672
  lbm_add_extension("bufget-u32", array_extension_buffer_get_u32);
77
21672
  lbm_add_extension("bufget-f32", array_extension_buffer_get_f32);
78
79
21672
  lbm_add_extension("buflen",  array_extension_buffer_length);
80
21672
  lbm_add_extension("bufclear", array_extensions_bufclear);
81
21672
  lbm_add_extension("bufcpy", array_extensions_bufcpy);
82
21672
  lbm_add_extension("bufset-bit", array_extensions_bufset_bit);
83
21672
}
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

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

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

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

9800
    if (lbm_is_array_r(args[0]) &&
368
4900
        lbm_is_number(args[1])) {
369
4900
      lbm_array_header_t *array = (lbm_array_header_t *)lbm_car(args[0]);
370
4900
      *a_size = array->size;
371
4900
      *a_data = (uint8_t*)array->data;
372
4900
      *index = lbm_dec_as_u32(args[1]);
373
4900
      res = true;
374
    } else {
375
      *error = ENC_SYM_TERROR;
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

504
  if (argn == 1 &&
573
504
      lbm_is_array_r(args[0]) &&
574
252
      lbm_heap_array_valid(args[0])) {
575
252
    lbm_array_header_t *array = (lbm_array_header_t *)lbm_car(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
}