From 81c97fcb7736ee17d581d6c78af567e2f7d25ca0 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Thu, 11 Jul 2019 06:44:36 -0700 Subject: ffi: two-argument form of sizeof. If sizeof is given an extra argument (an expression which evaluates to an object), it can calculate the dynamic size of the FFI type in relation to representing that object. * ffi.c (dyn_size): New static function. (ffi_init): Register sys:dyn-size intrinsic. * share/txr/stdlib/ffi.tl (sizeof): Support additional argument, avoiding run-time compilation of the type expression with the help of load-time. * txr.1: Update documentation for sizeof macro. --- ffi.c | 8 ++++++++ share/txr/stdlib/ffi.tl | 8 ++++++-- txr.1 | 33 ++++++++++++++++++++++++++++----- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/ffi.c b/ffi.c index d411dda7..c18b7efe 100644 --- a/ffi.c +++ b/ffi.c @@ -5494,6 +5494,13 @@ val fill_obj(val obj, val type, val stream) return tft->in(tft, 1, data, obj, self); } +static val dyn_size(val type, val obj) +{ + val self = lit("sizeof"); + struct txr_ffi_type *tft = ffi_type_struct_checked(self, type); + return num(tft->dynsize(tft, obj, self)); +} + void ffi_init(void) { prot1(&ffi_typedef_hash); @@ -5625,6 +5632,7 @@ void ffi_init(void) reg_fun(intern(lit("put-obj"), user_package), func_n3o(put_obj, 2)); reg_fun(intern(lit("get-obj"), user_package), func_n2o(get_obj, 1)); reg_fun(intern(lit("fill-obj"), user_package), func_n3o(fill_obj, 2)); + reg_fun(intern(lit("dyn-size"), system_package), func_n2(dyn_size)); ffi_typedef_hash = make_hash(nil, nil, nil); ffi_init_types(); ffi_init_extra_types(); diff --git a/share/txr/stdlib/ffi.tl b/share/txr/stdlib/ffi.tl index cf5bd8a1..99c0da72 100644 --- a/share/txr/stdlib/ffi.tl +++ b/share/txr/stdlib/ffi.tl @@ -122,8 +122,12 @@ (defvarl ,var-sym (carray-cptr ,var-ref ,type-sym 1)) (defsymacro ,name (carray-ref ,var-sym 0))))) -(defmacro sizeof (type) - (ffi-size (ffi-type-compile type))) +(defmacro sizeof (type : (obj nil obj-p) :env menv) + (if obj-p + (if (constantp obj menv) + (sys:dyn-size (ffi-type-compile type) obj) + ^(sys:dyn-size (load-time (ffi-type-compile ',type)) ,obj)) + (ffi-size (ffi-type-compile type)))) (defmacro alignof (type) (ffi-alignof (ffi-type-compile type))) diff --git a/txr.1 b/txr.1 index 8f826635..86520746 100644 --- a/txr.1 +++ b/txr.1 @@ -64059,17 +64059,40 @@ as its value. .coNP Macro @ sizeof .synb -.mets (sizeof << type-syntax ) +.mets (sizeof < type-syntax <> [ object-expr ]) .syne .desc The macro .code sizeof calculates the size of the FFI type denoted by +.codn type-syntax . + +The +.meta type-syntax +expression is compiled to a type using +.codn ffi-type-compile . +The +.meta object-expr +expression is evaluated to an object value. + +If .code type-syntax -at macro-expansion time, and produces that -integer value as its expansion, such that there is no -run-time computation. It uses the -.code ffi-sizeof +denotes a variable length type, and the +.meta object-expr +argument is present, then a +.I "dynamic size" is computed: the actual number of bytes required to store +that object value as a foreign representation of the specified variable length +type. + +The +.code sizeof +macro arranges for the size calculation to be carried out at macro-expansion +time, if possible, so that the +.code sizeof +form is replaced by an integer constant. This is possible when the +.meta object-expr +is omitted, or if it is a constant expression according to the +.code constantp function. .coNP Macro @ alignof -- cgit v1.2.3