diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2019-01-15 07:30:53 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2019-01-15 07:30:53 -0800 |
commit | 4375946224455b2509d6ca27e48c2cd6d51a704e (patch) | |
tree | 075337981a301105ef8ce4f0ee01aa19e12030e9 | |
parent | 8ea9cc713f52fd0a1357aa5cded97ceb234b669a (diff) | |
download | txr-4375946224455b2509d6ca27e48c2cd6d51a704e.tar.gz txr-4375946224455b2509d6ca27e48c2cd6d51a704e.tar.bz2 txr-4375946224455b2509d6ca27e48c2cd6d51a704e.zip |
ffi: arrays: be more forgiving of length mismatches.
* ffi.c (min): New macro.
(ffi_array_put_common): Tolerate sequences which are shorter
than the array. Use seq_info to classify the sequence and use
separate code for the vector and list case, avoiding taking
the length of the list.
* txr.1: Documented.
-rw-r--r-- | ffi.c | 43 | ||||
-rw-r--r-- | txr.1 | 4 |
2 files changed, 38 insertions, 9 deletions
@@ -68,6 +68,8 @@ ? (size) \ : sizeof (ffi_arg)) +#define min(a, b) ((a) < (b) ? (a) : (b)) + #if HAVE_LITTLE_ENDIAN #define ifbe(expr) (0) #define ifbe2(expr1, expr2) (expr2) @@ -2382,19 +2384,42 @@ static void ffi_array_put_common(struct txr_ffi_type *tft, val vec, mem_t *dst, struct txr_ffi_type *etft = ffi_type_struct(eltype); cnum elsize = etft->size; int nt = tft->null_term; - cnum i; + cnum i = 0; ucnum offs = 0; + seq_info_t si = seq_info(vec); - for (i = 0; i < nelem; i++) { - if (nt && i == nelem - 1) { - memset(dst + offs, 0, elsize); - break; - } else { - val elval = ref(vec, num_fast(i)); - etft->put(etft, elval, dst + offs, self); - offs += elsize; + switch (si.kind) { + case SEQ_NIL: + case SEQ_LISTLIKE: + { + val iter = si.obj; + + for (; i < nelem - nt && !endp(iter); i++, iter = cdr(iter)) { + val elval = car(iter); + etft->put(etft, elval, dst + offs, self); + offs += elsize; + } } + break; + case SEQ_VECLIKE: + { + val v = si.obj; + cnum lim = min(nelem - nt, c_num(length(si.obj))); + + for (; i < lim; i++) { + val elval = ref(v, num_fast(i)); + etft->put(etft, elval, dst + offs, self); + offs += elsize; + } + } + break; + default: + uw_throwf(error_s, lit("~a: ~s isn't convertible to a C array"), self, + vec, nao); } + + if (i < nelem) + memset(dst + offs, 0, elsize * (nelem - i)); } static void ffi_array_put(struct txr_ffi_type *tft, val vec, mem_t *dst, @@ -59140,6 +59140,10 @@ simply iterates over the Lisp sequence, and performs an element for element conversion to .metn type . +If the sequence is shorter than the array, then the remaining elements +are filled with zero bits. If the sequence is longer than the array, then the +excess elements in the sequence are ignored. + Since Lisp arrays and C arrays do not share the same representation, temporary buffers are automatically created and destroyed by FFI to manage the conversion. |