diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2017-05-06 08:33:07 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2017-05-06 08:33:07 -0700 |
commit | 7880c9b565ab438e1bf0250a967acdbf8d04cb42 (patch) | |
tree | e62180dae2480480a1eb5715ecdbdc1b82525629 /ffi.c | |
parent | 1e8a60d62a9eb8ef9b8db31b55bfa075fa8c9c7b (diff) | |
download | txr-7880c9b565ab438e1bf0250a967acdbf8d04cb42.tar.gz txr-7880c9b565ab438e1bf0250a967acdbf8d04cb42.tar.bz2 txr-7880c9b565ab438e1bf0250a967acdbf8d04cb42.zip |
ffi: varray feature
If an array dimension is void, it is a varray. The C
representation is pointer. The size is inferred
from the length of the object. Doesn't support get
method.
* ffi.c (struct txr_ffi_type): New bitfield flag, is_varray.
(ffi_varray_alloc): New function.
(ffi_array_in, ffi_array_put, ffi_array_out): Check is_varray
flag and use dynamic array size from object.
(ffi_type_compile): If the array dimension is the symbol
void, create a varray: a mongrel created using
make_ffi_type_pointer, but using the array functions,
plus alloc and free handlers, and the is_varray flag
being set.
Diffstat (limited to 'ffi.c')
-rw-r--r-- | ffi.c | 30 |
1 files changed, 27 insertions, 3 deletions
@@ -94,6 +94,7 @@ struct txr_ffi_type { cnum size, align; cnum nelem; unsigned null_term : 1; + unsigned is_varray : 1; unsigned char_conv : 1; unsigned wchar_conv : 1; unsigned bchar_conv : 1; @@ -239,6 +240,15 @@ static mem_t *ffi_fixed_alloc(struct txr_ffi_type *tft, val obj, val self) return chk_malloc(tft->size); } +static mem_t *ffi_varray_alloc(struct txr_ffi_type *tft, val obj, val self) +{ + ucnum len = c_unum(length(obj)); + size_t size = tft->size * len; + if (size < len || size < tft->size) + uw_throwf(error_s, lit("~s: array size overflow"), self, nao); + return chk_malloc(size); +} + static void ffi_noop_free(void *ptr) { } @@ -926,7 +936,7 @@ static val ffi_array_in(struct txr_ffi_type *tft, mem_t *src, val vec, val self) { val eltype = tft->mtypes; - cnum nelem = tft->nelem; + cnum nelem = if3(tft->is_varray, c_num(length(vec)), tft->nelem); if (tft->char_conv) { val str; @@ -1004,7 +1014,7 @@ static void ffi_array_put(struct txr_ffi_type *tft, val vec, mem_t *dst, val eltype = tft->mtypes; struct txr_ffi_type *etft = ffi_type_struct(eltype); cnum elsize = etft->size; - cnum nelem = tft->nelem, i; + cnum i, nelem = if3(tft->is_varray, c_num(length(vec)), tft->nelem); int nt = tft->null_term; ucnum offs = 0; @@ -1026,7 +1036,7 @@ static void ffi_array_out(struct txr_ffi_type *tft, int copy, val vec, val eltype = tft->mtypes; struct txr_ffi_type *etft = ffi_type_struct(eltype); cnum elsize = etft->size; - cnum nelem = tft->nelem, i; + cnum i, nelem = if3(tft->is_varray, c_num(length(vec)), tft->nelem); int nt = tft->null_term; ucnum offs = 0; @@ -1309,6 +1319,20 @@ val ffi_type_compile(val syntax) val eltype_syntax = caddr(syntax); val eltype = ffi_type_compile(eltype_syntax); + if (dim == void_s) { + val type = make_ffi_type_pointer(syntax, vec_s, sizeof (mem_t *), + ffi_array_put, ffi_void_get, + ffi_array_in, ffi_array_out, + eltype); + struct txr_ffi_type *tft = ffi_type_struct(type); + if (sym == zarray_s) + tft->null_term = 1; + tft->is_varray = 1; + tft->alloc = ffi_varray_alloc; + tft->free = free; + return type; + } + if (minusp(dim)) uw_throwf(error_s, lit("~a: negative dimension in ~s"), self, syntax, nao); |