Nothing
# Variadic FFI bindings
ffi_var_spec <- tcc_ffi() |>
tcc_bind(
sum3 = list(
args = list("i32"),
variadic = TRUE,
varargs = list("i32", "i32", "i32"),
returns = "i32"
),
add_mix = list(
args = list("f64"),
variadic = TRUE,
varargs = list("i32", "f64"),
returns = "f64"
)
)
expect_true(Rtinycc:::is_rtinycc_bound_symbol(ffi_var_spec$symbols$sum3))
expect_identical(ffi_var_spec$symbols$sum3$varargs_mode, "prefix")
expect_equal(length(ffi_var_spec$symbols$sum3$varargs_type_info), 3L)
expect_true(all(vapply(
ffi_var_spec$symbols$sum3$varargs_type_info,
Rtinycc:::is_rtinycc_ffi_type,
logical(1)
)))
expect_identical(
Rtinycc:::ffi_type_family(ffi_var_spec$symbols$add_mix$varargs_type_info[[
2
]]),
"f64"
)
ffi_var <- tcc_ffi() |>
tcc_source(
"
#include <stdarg.h>
int sum3(int base, ...) {
va_list ap;
va_start(ap, base);
int a = va_arg(ap, int);
int b = va_arg(ap, int);
int c = va_arg(ap, int);
va_end(ap);
return base + a + b + c;
}
double add_mix(double x, ...) {
va_list ap;
va_start(ap, x);
int i = va_arg(ap, int);
double d = va_arg(ap, double);
va_end(ap);
return x + (double)i + d;
}
"
) |>
tcc_bind(
sum3 = list(
args = list("i32"),
variadic = TRUE,
varargs = list("i32", "i32", "i32"),
returns = "i32"
),
add_mix = list(
args = list("f64"),
variadic = TRUE,
varargs = list("i32", "f64"),
returns = "f64"
)
) |>
tcc_compile()
expect_equal(ffi_var$sum3(10L, 1L, 2L, 3L), 16L)
expect_equal(ffi_var$add_mix(1.5, 2L, 3.25), 6.75)
expect_error(
ffi_var$sum3(10L, 1L, 2L),
info = "variadic binding enforces declared total argument count"
)
# Opt-in prefix arity: allow up to N typed varargs via varargs_min = 0
ffi_var_prefix <- tcc_ffi() |>
tcc_source(
"\
#include <stdarg.h>\
\
int sum_n(int n, ...) {\
va_list ap;\
va_start(ap, n);\
int s = 0;\
for (int i = 0; i < n; i++) s += va_arg(ap, int);\
va_end(ap);\
return s;\
}\
"
) |>
tcc_bind(
sum_n = list(
args = list("i32"),
variadic = TRUE,
varargs = list("i32", "i32", "i32"),
varargs_min = 0L,
returns = "i32"
)
) |>
tcc_compile()
expect_equal(ffi_var_prefix$sum_n(0L), 0L)
expect_equal(ffi_var_prefix$sum_n(2L, 10L, 20L), 30L)
expect_equal(ffi_var_prefix$sum_n(3L, 1L, 2L, 3L), 6L)
expect_error(
ffi_var_prefix$sum_n(4L, 1L, 2L, 3L, 4L),
info = "variadic prefix mode enforces max declared tail"
)
expect_error(
tcc_ffi() |>
tcc_bind(
bad = list(args = list("i32"), varargs = list("i32"), returns = "i32")
),
info = "varargs requires variadic=TRUE"
)
expect_error(
tcc_ffi() |>
tcc_bind(bad = list(args = list("i32"), variadic = TRUE, returns = "i32")),
info = "variadic requires varargs or varargs_types"
)
expect_error(
tcc_ffi() |>
tcc_bind(
bad = list(
args = list("i32"),
variadic = TRUE,
varargs = list("integer_array"),
returns = "i32"
)
),
info = "variadic varargs must be scalar types"
)
expect_error(
tcc_ffi() |>
tcc_bind(
bad = list(
args = list("i32"),
variadic = TRUE,
varargs = list("callback:void(int)"),
returns = "i32"
)
),
info = "variadic varargs reject callback families at constructor normalization"
)
expect_error(
tcc_ffi() |>
tcc_bind(
bad = list(
args = list("i32"),
variadic = TRUE,
varargs_types = list("sexp"),
returns = "i32"
)
),
info = "variadic varargs_types reject sexp at constructor normalization"
)
# True variadic mode with allowed types + min/max arity
ffi_var_types_spec <- tcc_ffi() |>
tcc_bind(
probe_types = list(
args = list("i32"),
variadic = TRUE,
varargs_types = list("f64", "i32"),
varargs_min = 1L,
varargs_max = 2L,
returns = "f64"
)
)
expect_identical(ffi_var_types_spec$symbols$probe_types$varargs_mode, "types")
expect_equal(ffi_var_types_spec$symbols$probe_types$varargs_min, 1L)
expect_equal(ffi_var_types_spec$symbols$probe_types$varargs_max, 2L)
expect_true(all(vapply(
ffi_var_types_spec$symbols$probe_types$varargs_type_info,
Rtinycc:::is_rtinycc_ffi_type,
logical(1)
)))
ffi_var_types <- tcc_ffi() |>
tcc_source(
"\
#include <stdarg.h>\
\
double probe_types(int tag, ...) {\
va_list ap;\
va_start(ap, tag);\
double out = 0.0;\
if (tag == 1) out = (double)va_arg(ap, int);\
else if (tag == 2) out = va_arg(ap, double);\
else if (tag == 3) out = (double)va_arg(ap, int) + va_arg(ap, double);\
va_end(ap);\
return out;\
}\
"
) |>
tcc_bind(
probe_types = list(
args = list("i32"),
variadic = TRUE,
varargs_types = list("f64", "i32"),
varargs_min = 1L,
varargs_max = 2L,
returns = "f64"
)
) |>
tcc_compile()
expect_equal(ffi_var_types$probe_types(1L, 2L), 2)
expect_equal(ffi_var_types$probe_types(2L, 2.5), 2.5)
expect_equal(ffi_var_types$probe_types(3L, 1L, 2.5), 3.5)
expect_error(
ffi_var_types$probe_types(0L),
info = "true variadic mode enforces varargs_min"
)
expect_error(
ffi_var_types$probe_types(4L, 1L, 2L, 3L),
info = "true variadic mode enforces varargs_max"
)
expect_error(
tcc_ffi() |>
tcc_bind(
bad = list(
args = list("i32"),
variadic = TRUE,
varargs = list("i32"),
varargs_types = list("i32"),
returns = "i32"
)
),
info = "cannot set both varargs and varargs_types"
)
expect_error(
tcc_ffi() |>
tcc_bind(
bad = list(
args = list("i32"),
variadic = TRUE,
varargs_types = list("i32"),
varargs_min = 2L,
varargs_max = 1L,
returns = "i32"
)
),
info = "varargs_min <= varargs_max"
)
expect_error(
tcc_ffi() |>
tcc_bind(
bad = list(
args = list("i32"),
variadic = TRUE,
varargs = list("i32", "i32"),
varargs_min = 3L,
returns = "i32"
)
),
info = "varargs_min must be between 0 and length(varargs)"
)
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.