mirror of https://github.com/rusefi/bldc.git
Merge pull request #698 from laxsjo/master
add option for buf-resize to create a copy of the given array
This commit is contained in:
commit
36ed818e97
|
@ -4552,7 +4552,7 @@ The last byte in `seq` will be ignored as that is the null-terminator if `seq` i
|
|||
| ESC, Express | 6.05+ |
|
||||
|
||||
```clj
|
||||
(buf-resize arr delta-size opt-absolute-size)
|
||||
(buf-resize arr delta-size opt-absolute-size opt-copy-symbol)
|
||||
```
|
||||
|
||||
Change the length of array `arr` in bytes. A reference to `arr` is returned.
|
||||
|
@ -4567,6 +4567,14 @@ This extension can be used in two modes:
|
|||
Passing `nil` to `delta-size` while not passing any value for
|
||||
`opt-absolute-size` will result in an `eval_error`.
|
||||
|
||||
You can optionally pass the symbol `'copy` to `opt-copy-symbol` to specify that
|
||||
`arr` should be left unchanged and that a copy should instead be made. Don't
|
||||
worry about the exact position of the argument, the only important part is that
|
||||
`opt-copy-symbol` is last. So you can give a value for `opt-copy-symbol` even
|
||||
when `opt-absolute-size` isn't passed. You can also for completeness pass the
|
||||
symbol `'mut` to specify that the standard behaviour of modifying `arr` in place
|
||||
should remain in effect.
|
||||
|
||||
When growing the length of the array a new range will be allocated and the old
|
||||
data copied over. The new bytes will be initialised to zero. If the new length
|
||||
of the array is smaller than the previous the allocated range will simply be
|
||||
|
@ -4576,7 +4584,7 @@ It is possible to shrink an array to a length of zero.
|
|||
|
||||
**Note**
|
||||
The array will be resized in place. The returned reference to `arr` is just for
|
||||
convenience.
|
||||
convenience. (Unless `opt-copy-symbol` is `'copy` of course.)
|
||||
|
||||
Example where we remove the terminating null byte from a string buffer:
|
||||
```clj
|
||||
|
@ -4593,6 +4601,18 @@ Example where we increase the length of `buf` to 5:
|
|||
> [1 2 3 4 5]
|
||||
```
|
||||
|
||||
Example where we create a copy of `name` with the terminating null byte
|
||||
removed.
|
||||
```clj
|
||||
(def name "name")
|
||||
(def name-array (buf-resize name -1 'copy))
|
||||
|
||||
(print name)
|
||||
> "name"
|
||||
(print name-array)
|
||||
> [110 97 109 101]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Import Files
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
Copyright 2023 Rasmus Söderhielm rasmus.soderhielm@gmail.com
|
||||
|
||||
This file is part of the VESC firmware.
|
||||
|
||||
The VESC firmware is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The VESC firmware is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "symrepr.h"
|
||||
#include "lbm_defines.h"
|
||||
#include "lbm_types.h"
|
||||
#include "heap.h"
|
||||
#include "eval_cps.h"
|
||||
#include "lbm_flat_value.h"
|
||||
#include "commands.h"
|
||||
|
||||
#include "lbm_vesc_utils.h"
|
||||
|
||||
bool lbm_add_symbol_const_if_new(char *name, lbm_uint *id) {
|
||||
if (!lbm_get_symbol_by_name(name, id) && !lbm_add_symbol_const(name, id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
lbm_array_header_t *lbm_dec_array_header(lbm_value value) {
|
||||
if (!lbm_is_array_r(value)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (lbm_array_header_t *)lbm_car(value);
|
||||
}
|
||||
|
||||
void *lbm_dec_array_data(lbm_value value) {
|
||||
if (!lbm_is_array_r(value)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lbm_array_header_t *header = lbm_dec_array_header(value);
|
||||
if (!header->data) {
|
||||
return NULL;
|
||||
}
|
||||
return header->data;
|
||||
}
|
||||
|
||||
lbm_value lbm_allocate_empty_list(lbm_uint len) {
|
||||
lbm_value res = ENC_SYM_NIL;
|
||||
for (lbm_uint i = 0; i < len; i++) {
|
||||
res = lbm_cons(ENC_SYM_NIL, res);
|
||||
if (res == ENC_SYM_MERROR) {
|
||||
return ENC_SYM_MERROR;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
lbm_value lbm_allocate_empty_list_grid(lbm_uint height, lbm_uint width) {
|
||||
lbm_value outer = ENC_SYM_NIL;
|
||||
for (lbm_uint i = 0; i < height; i++) {
|
||||
lbm_value inner = ENC_SYM_NIL;
|
||||
for (lbm_uint j = 0; j < width; j++) {
|
||||
inner = lbm_cons(ENC_SYM_NIL, inner);
|
||||
if (inner == ENC_SYM_MERROR) {
|
||||
return ENC_SYM_MERROR;
|
||||
}
|
||||
}
|
||||
|
||||
outer = lbm_cons(inner, outer);
|
||||
if (outer == ENC_SYM_MERROR) {
|
||||
return ENC_SYM_MERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return outer;
|
||||
}
|
||||
|
||||
bool lbm_memory_shrink_bytes(void *array, lbm_uint size_bytes) {
|
||||
lbm_uint size_words = size_bytes / LBM_WORD_SIZE;
|
||||
if (size_bytes % LBM_WORD_SIZE != 0) {
|
||||
size_words += 1;
|
||||
}
|
||||
|
||||
return lbm_memory_shrink((lbm_uint *)array, size_words) > 0;
|
||||
}
|
||||
|
||||
bool lbm_array_shrink(lbm_value array, lbm_uint new_size) {
|
||||
if (!lbm_is_array_rw(array)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lbm_array_header_t *header = (lbm_array_header_t *)lbm_car(array);
|
||||
|
||||
if (!lbm_memory_shrink_bytes(header->data, new_size)) {
|
||||
return false;
|
||||
}
|
||||
header->size = new_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern const char *lbm_error_str_num_args;
|
||||
bool lbm_check_argn_range(lbm_uint argn, lbm_uint n_min, lbm_uint n_max) {
|
||||
if (!(n_min <= argn && argn <= n_max)) {
|
||||
lbm_set_error_reason((char *)lbm_error_str_num_args);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lbm_check_argn_least(lbm_uint argn, lbm_uint n_min) {
|
||||
if (!(n_min <= argn)) {
|
||||
lbm_set_error_reason((char *)lbm_error_str_num_args);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool f_pack_array(lbm_flat_value_t *result, void *data, size_t size) {
|
||||
if (!lbm_start_flatten(result, 5 + size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!f_lbm_array(result, size, data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lbm_finish_flatten(result)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
Copyright 2023 Rasmus Söderhielm rasmus.soderhielm@gmail.com
|
||||
|
||||
This file is part of the VESC firmware.
|
||||
|
||||
The VESC firmware is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The VESC firmware is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "lbm_types.h"
|
||||
#include "lbm_defines.h"
|
||||
#include "heap.h"
|
||||
#include "lbm_flat_value.h"
|
||||
|
||||
// Is this the right place to define this?
|
||||
/**
|
||||
* Bytes per word in the LBM memory.
|
||||
*/
|
||||
#define LBM_WORD_SIZE 4
|
||||
|
||||
/**
|
||||
* Extract the array header struct from a lbm value array.
|
||||
*
|
||||
* The type of the value is checked to be at least be a readable array (doesn't
|
||||
* have to be writeable though).
|
||||
*
|
||||
* @param value The lbm value to convert to an array header struct.
|
||||
* @return The extracted pointer to the array header struct if value was a
|
||||
* readable array. Null is returned otherwise. (@note: Null is also returned if
|
||||
* the lbm_value contained a null pointer, @todo: unsure exactly what layer that would
|
||||
* be right now though...)
|
||||
*/
|
||||
lbm_array_header_t *lbm_dec_array_header(lbm_value value);
|
||||
|
||||
/**
|
||||
* Wrapper around lbm_memory_shrink that takes number of bytes instead of number
|
||||
* of words. Shrinks the size of an pointer allocated in LBM memory to the
|
||||
* smallest possible size while still having capacity for the specified amount
|
||||
* of bytes.
|
||||
*
|
||||
* @param ptr Pointer to the allocated segment in LBM memory. Should have been
|
||||
* obtained through lbm_malloc or other similar way at some point.
|
||||
* @param size_bytes The new capacity of the allocation in bytes. Must be
|
||||
* smaller or equal to the previous capacity.
|
||||
* @return If the operation succeeded. The return value of lbm_memory_shrink is
|
||||
* directly passed through, that is: false is returned either if ptr didn't
|
||||
* point into the LBM memory/didn't point to the start of an allocated segment
|
||||
* or if the new size was larger than the previous (note that since this
|
||||
* function converts bytes to words, a larger size in bytes might not cause it
|
||||
* to fail, as the size in words could still be the same). Otherwise true is
|
||||
* returned.
|
||||
*/
|
||||
bool lbm_memory_shrink_bytes(void *ptr, lbm_uint size_bytes);
|
||||
|
||||
/**
|
||||
* Shrink an lbm array to the new specified size.
|
||||
*
|
||||
* @param lbm_value The array to shrink. Should hold an LBM value that
|
||||
* corresponds to an array.
|
||||
* @param new_size The new smaller array size.
|
||||
* @return Bool indicating if the array was successfully shrunk. False is
|
||||
* returned if array didn't hold a byte array value, or if new_len was larger
|
||||
* than the original size.
|
||||
*/
|
||||
bool lbm_array_shrink(lbm_value array, lbm_uint new_size);
|
||||
|
||||
/**
|
||||
* Check if the number of arguments is the specified range. Sets error-reason if
|
||||
* result is false.
|
||||
*
|
||||
* The range specified is inclusive!
|
||||
*
|
||||
* @param argn Number of arguments.
|
||||
* @param n_min Minimum number of arguments.
|
||||
* @param n_max Maximum number of arguments.
|
||||
*
|
||||
*/
|
||||
bool lbm_check_argn_range(lbm_uint argn, lbm_uint n_min, lbm_uint n_max);
|
||||
|
||||
/**
|
||||
* Check if the number of arguments is at large as long as specified. Sets
|
||||
* error-reason if result is false.
|
||||
*
|
||||
* The (open) range specified is inclusive!
|
||||
*
|
||||
* @param argn Number of arguments.
|
||||
* @param n_min Minimum number of arguments.
|
||||
*
|
||||
*/
|
||||
bool lbm_check_argn_least(lbm_uint argn, lbm_uint n_min);
|
||||
|
||||
#define LBM_CHECK_ARGN_RANGE(min, max) \
|
||||
if (!lbm_check_argn_range(argn, (min), (max))) { \
|
||||
return ENC_SYM_EERROR; \
|
||||
}
|
||||
#define LBM_CHECK_ARGN_LEAST(min) \
|
||||
if (!lbm_check_argn_least(argn, (min))) { \
|
||||
return ENC_SYM_EERROR; \
|
||||
}
|
|
@ -25,7 +25,8 @@ LISPBMSRC = $(LISPBM)/src/env.c \
|
|||
lispBM/lispif.c \
|
||||
lispBM/lispif_vesc_extensions.c \
|
||||
lispBM/lispif_vesc_dynamic_loader.c \
|
||||
lispBM/lispif_c_lib.c
|
||||
lispBM/lispif_c_lib.c \
|
||||
lispBM/lbm_vesc_utils.c
|
||||
|
||||
LISPBMINC = lispBM \
|
||||
$(LISPBM) \
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "extensions/math_extensions.h"
|
||||
#include "extensions/string_extensions.h"
|
||||
#include "lbm_constants.h"
|
||||
#include "lbm_vesc_utils.h"
|
||||
|
||||
#include "commands.h"
|
||||
#include "mc_interface.h"
|
||||
|
@ -222,6 +223,10 @@ typedef struct {
|
|||
lbm_uint rate_400k;
|
||||
lbm_uint rate_700k;
|
||||
|
||||
// Arrays
|
||||
lbm_uint copy;
|
||||
lbm_uint mut;
|
||||
|
||||
// Other
|
||||
lbm_uint half_duplex;
|
||||
} vesc_syms;
|
||||
|
@ -548,6 +553,12 @@ static bool compare_symbol(lbm_uint sym, lbm_uint *comp) {
|
|||
get_add_symbol("rate-700k", comp);
|
||||
}
|
||||
|
||||
else if (comp == &syms_vesc.copy) {
|
||||
get_add_symbol("copy", comp);
|
||||
} else if (comp == &syms_vesc.mut) {
|
||||
get_add_symbol("mut", comp);
|
||||
}
|
||||
|
||||
else if (comp == &syms_vesc.half_duplex) {
|
||||
get_add_symbol("half-duplex", comp);
|
||||
}
|
||||
|
@ -564,33 +575,6 @@ static bool is_symbol_true_false(lbm_value v) {
|
|||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around lbm_memory_shrink that takes number of bytes instead of number
|
||||
* of words. Shrinks the size of an pointer allocated in LBM memory to the
|
||||
* smallest possible size while still having capacity for the specified amount
|
||||
* of bytes.
|
||||
*
|
||||
* @param ptr Pointer to the allocated segment in LBM memory. Should have been
|
||||
* obtained through lbm_malloc or other similar way at some point.
|
||||
* @param size_bytes The new capacity of the allocation in bytes. Must be
|
||||
* smaller or equal to the previous capacity.
|
||||
* @return If the operation succeeded. The return value of lbm_memory_shrink is
|
||||
* directly passed through, that is: false is returned either if ptr didn't
|
||||
* point into the LBM memory/didn't point to the start of an allocated segment
|
||||
* or if the new size was larger than the previous (note that since this
|
||||
* function converts bytes to words, a larger size in bytes might not cause it
|
||||
* to fail, as the size in words could still be the same). Otherwise true is
|
||||
* returned.
|
||||
*/
|
||||
static bool lbm_memory_shrink_bytes(void *array, lbm_uint size_bytes) {
|
||||
lbm_uint size_words = size_bytes / LBM_WORD_SIZE;
|
||||
if (size_bytes % LBM_WORD_SIZE != 0) {
|
||||
size_words += 1;
|
||||
}
|
||||
|
||||
return lbm_memory_shrink((lbm_uint *)array, size_words) > 0;
|
||||
}
|
||||
|
||||
// Various commands
|
||||
|
||||
static lbm_value ext_print(lbm_value *args, lbm_uint argn) {
|
||||
|
@ -4664,15 +4648,41 @@ static lbm_value ext_buf_find(lbm_value *args, lbm_uint argn) {
|
|||
* reference only for convenience.
|
||||
*/
|
||||
static lbm_value ext_buf_resize(lbm_value *args, lbm_uint argn) {
|
||||
if ((argn != 2 && argn != 3) || !lbm_is_array_rw(args[0])
|
||||
|| (!lbm_is_number(args[1]) && !lbm_is_symbol_nil(args[1]))
|
||||
|| (argn == 3 && !lbm_is_number(args[2]))) {
|
||||
lbm_set_error_reason((char *)lbm_error_str_incorrect_arg);
|
||||
return ENC_SYM_TERROR;
|
||||
LBM_CHECK_ARGN_RANGE(2, 4);
|
||||
|
||||
bool should_copy = false;
|
||||
if (argn > 2 && lbm_is_symbol(args[argn - 1])) {
|
||||
lbm_uint sym = lbm_dec_sym(args[argn - 1]);
|
||||
if (compare_symbol(sym, &syms_vesc.copy)) {
|
||||
should_copy = true;
|
||||
} else if (compare_symbol(sym, &syms_vesc.mut)) {
|
||||
should_copy = false;
|
||||
} else {
|
||||
lbm_set_error_suspect(args[argn - 1]);
|
||||
return ENC_SYM_TERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!should_copy && !lbm_is_array_rw(args[0]))
|
||||
|| (should_copy && !lbm_is_array_r(args[0]))) {
|
||||
lbm_set_error_suspect(args[0]);
|
||||
return ENC_SYM_TERROR;
|
||||
}
|
||||
|
||||
bool delta_size_passed = !lbm_is_symbol_nil(args[1]);
|
||||
bool new_size_passed = argn == 3;
|
||||
bool new_size_passed = argn > 2 && lbm_is_number(args[2]);
|
||||
|
||||
if (delta_size_passed && !lbm_is_number(args[1])) {
|
||||
lbm_set_error_suspect(args[1]);
|
||||
return ENC_SYM_TERROR;
|
||||
}
|
||||
|
||||
if (argn == 4 && !lbm_is_number(args[2])) {
|
||||
// The case where argn is 3 is covered by the first check.
|
||||
lbm_set_error_suspect(args[2]);
|
||||
return ENC_SYM_TERROR;
|
||||
}
|
||||
|
||||
if (!delta_size_passed && !new_size_passed) {
|
||||
lbm_set_error_reason(
|
||||
"delta-size (arg 2) was nil while new-size wasn't provided (arg 3)"
|
||||
|
@ -4680,7 +4690,7 @@ static lbm_value ext_buf_resize(lbm_value *args, lbm_uint argn) {
|
|||
return ENC_SYM_EERROR;
|
||||
}
|
||||
|
||||
lbm_array_header_t *header = (lbm_array_header_t *)lbm_car(args[0]);
|
||||
lbm_array_header_t *header = lbm_dec_array_header(args[0]);
|
||||
if (header == NULL) {
|
||||
// Should be impossible, unless it contained null pointer to header.
|
||||
return ENC_SYM_FATAL_ERROR;
|
||||
|
@ -4701,36 +4711,54 @@ static lbm_value ext_buf_resize(lbm_value *args, lbm_uint argn) {
|
|||
}
|
||||
new_size = (uint32_t)new_size_signed;
|
||||
}
|
||||
|
||||
if (new_size == header->size) {
|
||||
return args[0];
|
||||
} else if (new_size < header->size) {
|
||||
uint32_t allocated_size = new_size;
|
||||
if (new_size == 0) {
|
||||
// arrays of size 0 still need some memory allocated for them.
|
||||
allocated_size = 1;
|
||||
}
|
||||
// We sadly can't trust the return value, as it fails if the allocation
|
||||
// was previously a single word long. So we just throw it away.
|
||||
lbm_memory_shrink_bytes(header->data, allocated_size);
|
||||
|
||||
header->size = new_size;
|
||||
|
||||
return args[0];
|
||||
} else {
|
||||
void *buffer = lbm_malloc_reserve(new_size);
|
||||
if (buffer == NULL) {
|
||||
if (should_copy) {
|
||||
void *buffer = lbm_malloc(new_size);
|
||||
if (!buffer) {
|
||||
return ENC_SYM_MERROR;
|
||||
}
|
||||
|
||||
memcpy(buffer, header->data, MIN(header->size, new_size));
|
||||
if (new_size > header->size) {
|
||||
memset(buffer + header->size, 0, new_size - header->size);
|
||||
}
|
||||
|
||||
lbm_value result;
|
||||
if (!lbm_lift_array(&result, buffer, new_size)) {
|
||||
return ENC_SYM_MERROR;
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
if (new_size == header->size) {
|
||||
return args[0];
|
||||
} else if (new_size < header->size) {
|
||||
uint32_t allocated_size = new_size;
|
||||
if (new_size == 0) {
|
||||
// arrays of size 0 still need some memory allocated for them.
|
||||
allocated_size = 1;
|
||||
}
|
||||
// We sadly can't trust the return value, as it fails if the allocation
|
||||
// was previously a single word long. So we just throw it away.
|
||||
lbm_memory_shrink_bytes(header->data, allocated_size);
|
||||
|
||||
header->size = new_size;
|
||||
|
||||
memcpy(buffer, header->data, header->size);
|
||||
memset(buffer + header->size, 0, new_size - header->size);
|
||||
return args[0];
|
||||
} else {
|
||||
void *buffer = lbm_malloc(new_size);
|
||||
if (buffer == NULL) {
|
||||
return ENC_SYM_MERROR;
|
||||
}
|
||||
|
||||
lbm_memory_free(header->data);
|
||||
header->data = buffer;
|
||||
header->size = new_size;
|
||||
memcpy(buffer, header->data, header->size);
|
||||
memset(buffer + header->size, 0, new_size - header->size);
|
||||
|
||||
return args[0];
|
||||
lbm_memory_free(header->data);
|
||||
header->data = buffer;
|
||||
header->size = new_size;
|
||||
|
||||
return args[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue