summaryrefslogtreecommitdiffstats
path: root/ffi.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-05-06 08:33:07 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-05-06 08:33:07 -0700
commit7880c9b565ab438e1bf0250a967acdbf8d04cb42 (patch)
treee62180dae2480480a1eb5715ecdbdc1b82525629 /ffi.c
parent1e8a60d62a9eb8ef9b8db31b55bfa075fa8c9c7b (diff)
downloadtxr-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.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/ffi.c b/ffi.c
index 8052f8dc..8a314adf 100644
--- a/ffi.c
+++ b/ffi.c
@@ -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);