From e2ba7a2f6f4fafd99fcda34213e3ca3f5757a9ed Mon Sep 17 00:00:00 2001 From: Jan Gorecki Date: Thu, 9 Jul 2026 13:05:38 +0200 Subject: [PATCH 1/8] add resizeVector to C exports --- src/data.table.h | 1 + src/frollapply.c | 6 ++++++ src/init.c | 1 + 3 files changed, 8 insertions(+) diff --git a/src/data.table.h b/src/data.table.h index 43dfdc5eb4..dbfe495edb 100644 --- a/src/data.table.h +++ b/src/data.table.h @@ -308,6 +308,7 @@ SEXP memcpyDT(SEXP dest, SEXP src, SEXP offset, SEXP size); SEXP memcpyVectoradaptive(SEXP dest, SEXP src, SEXP offset, SEXP size); SEXP memcpyDTadaptive(SEXP dest, SEXP src, SEXP offset, SEXP size); SEXP copyAsGrowable(SEXP x); +SEXP resizeVector(SEXP x, SEXP size); // nafill.c void nafillDouble(double *x, uint_fast64_t nx, unsigned int type, double fill, bool nan_is_na, ans_t *ans, bool verbose); diff --git a/src/frollapply.c b/src/frollapply.c index e4ccf2864b..3abdf2079d 100644 --- a/src/frollapply.c +++ b/src/frollapply.c @@ -87,3 +87,9 @@ SEXP copyAsGrowable(SEXP x) { UNPROTECT(1); return ret; } + +SEXP resizeVector(SEXP x, SEXP size) { + R_xlen_t newlen = INTEGER_RO(size)[0]; + R_resizeVector(x, newlen); + return x; +} diff --git a/src/init.c b/src/init.c index 5cf786d19e..069223b982 100644 --- a/src/init.c +++ b/src/init.c @@ -161,6 +161,7 @@ static const R_CallMethodDef callMethods[] = { {"CmemcpyVectoradaptive", (DL_FUNC)&memcpyVectoradaptive, -1}, {"CmemcpyDTadaptive", (DL_FUNC)&memcpyDTadaptive, -1}, {"CcopyAsGrowable", (DL_FUNC)©AsGrowable, -1}, + {"CresizeVector", (DL_FUNC)&resizeVector, -1}, {"Cfrolladapt", (DL_FUNC)&frolladapt, -1}, {"Cis_direct_child", (DL_FUNC)&is_direct_child, -1}, {NULL, NULL, 0}}; From 7ae8b9c8b0828070b1deb2437dfda889423ba72d Mon Sep 17 00:00:00 2001 From: Jan Gorecki Date: Fri, 10 Jul 2026 21:57:51 +0200 Subject: [PATCH 2/8] input validation --- src/frollapply.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/frollapply.c b/src/frollapply.c index 3abdf2079d..25ab5c072c 100644 --- a/src/frollapply.c +++ b/src/frollapply.c @@ -89,6 +89,11 @@ SEXP copyAsGrowable(SEXP x) { } SEXP resizeVector(SEXP x, SEXP size) { + if (!( + isInteger(size) && LENGTH(size) == 1 && INTEGER_RO(size)[0] != NA_INTEGER + )) error(_("'size' must be length 1 non-NA integer value.")); + if (!isVector(x)) + error(_("'x' must be a vector.")); R_xlen_t newlen = INTEGER_RO(size)[0]; R_resizeVector(x, newlen); return x; From b8cf6bc3a476bc3f6ab87a6e71127f1f7c5c0dee Mon Sep 17 00:00:00 2001 From: Jan Gorecki Date: Fri, 10 Jul 2026 22:15:21 +0200 Subject: [PATCH 3/8] add unit tests --- inst/tests/tests.Rraw | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 80df54b6aa..42926cdd06 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -21775,3 +21775,18 @@ test(2377.44, copy(dt)[!(a < 5 & b != "d"), .ROW := NULL], dt[1:3]) dt = data.table(a=1:3) test(2377.91, truelength(dt$a), 0L) test(2377.92, {setallocrow(dt); truelength(dt$a)}, 3L) + +# test R C API via data.table #7810 +set.seed(108) +x = rnorm(100L) +test(2378.01, length(x) == 100L && truelength(x) == 0L) +x = .Call(data.table:::CcopyAsGrowable, x) +test(2378.02, length(x) == 100L && truelength(x) == 100L) +.Call(data.table:::CresizeVector, x, 50L) |> invisible() +test(2378.03, length(x) == 50L && truelength(x) == 100L) +.Call(data.table:::CresizeVector, x, 49L) |> invisible() +test(2378.04, length(x) == 49L && truelength(x) == 100L) +.Call(data.table:::CresizeVector, x, 51L) |> invisible() +test(2378.05, length(x) == 51L && truelength(x) == 100L) +test(2378.91, .Call(data.table:::CresizeVector, x, 2), error = "must be length 1 non-NA integer value") +test(2378.92, .Call(data.table:::CresizeVector, NULL, 2L), error = "must be a vector") From 2967786f12781ea1b641c61d979d869d692af5e2 Mon Sep 17 00:00:00 2001 From: Jan Gorecki Date: Fri, 10 Jul 2026 22:18:36 +0200 Subject: [PATCH 4/8] no need ::: and too much output --- inst/tests/tests.Rraw | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 42926cdd06..d36ace3f8a 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -85,6 +85,8 @@ if (exists("test.data.table", .GlobalEnv, inherits=FALSE)) { which.last = data.table:::which.last `-.IDate` = data.table:::`-.IDate` haszlib = data.table:::haszlib + CcopyAsGrowable = data.table:::CcopyAsGrowable + CresizeVector = data.table:::CresizeVector # Also, for functions that are masked by other packages, we need to map the data.table one. Or else, # the other package's function would be picked up. As above, we only need to do this because we desire @@ -21780,13 +21782,13 @@ test(2377.92, {setallocrow(dt); truelength(dt$a)}, 3L) set.seed(108) x = rnorm(100L) test(2378.01, length(x) == 100L && truelength(x) == 0L) -x = .Call(data.table:::CcopyAsGrowable, x) +x = .Call(CcopyAsGrowable, x) test(2378.02, length(x) == 100L && truelength(x) == 100L) -.Call(data.table:::CresizeVector, x, 50L) |> invisible() +.Call(CresizeVector, x, 50L) |> invisible() test(2378.03, length(x) == 50L && truelength(x) == 100L) -.Call(data.table:::CresizeVector, x, 49L) |> invisible() +.Call(CresizeVector, x, 49L) |> invisible() test(2378.04, length(x) == 49L && truelength(x) == 100L) -.Call(data.table:::CresizeVector, x, 51L) |> invisible() +.Call(CresizeVector, x, 51L) |> invisible() test(2378.05, length(x) == 51L && truelength(x) == 100L) -test(2378.91, .Call(data.table:::CresizeVector, x, 2), error = "must be length 1 non-NA integer value") -test(2378.92, .Call(data.table:::CresizeVector, NULL, 2L), error = "must be a vector") +test(2378.91, .Call(CresizeVector, x, 2), error = "must be length 1 non-NA integer value") +test(2378.92, .Call(CresizeVector, NULL, 2L), error = "must be a vector") From 106dee8724b71fa2d224d00f4f67b75fbb8e8d41 Mon Sep 17 00:00:00 2001 From: Jan Gorecki Date: Sat, 11 Jul 2026 11:16:54 +0200 Subject: [PATCH 5/8] remove base R pipe --- inst/tests/tests.Rraw | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index d36ace3f8a..b34a8f9515 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -21784,11 +21784,11 @@ x = rnorm(100L) test(2378.01, length(x) == 100L && truelength(x) == 0L) x = .Call(CcopyAsGrowable, x) test(2378.02, length(x) == 100L && truelength(x) == 100L) -.Call(CresizeVector, x, 50L) |> invisible() +invisible(.Call(CresizeVector, x, 50L)) test(2378.03, length(x) == 50L && truelength(x) == 100L) -.Call(CresizeVector, x, 49L) |> invisible() +invisible(.Call(CresizeVector, x, 49L)) test(2378.04, length(x) == 49L && truelength(x) == 100L) -.Call(CresizeVector, x, 51L) |> invisible() +invisible(.Call(CresizeVector, x, 51L)) test(2378.05, length(x) == 51L && truelength(x) == 100L) test(2378.91, .Call(CresizeVector, x, 2), error = "must be length 1 non-NA integer value") test(2378.92, .Call(CresizeVector, NULL, 2L), error = "must be a vector") From d428bd94f2f8d2e7a3a068229d555f8b10ea2116 Mon Sep 17 00:00:00 2001 From: Jan Gorecki Date: Sat, 11 Jul 2026 11:22:29 +0200 Subject: [PATCH 6/8] check for non-negative, tests --- inst/tests/tests.Rraw | 6 ++++-- src/frollapply.c | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index b34a8f9515..1a2a52655c 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -21790,5 +21790,7 @@ invisible(.Call(CresizeVector, x, 49L)) test(2378.04, length(x) == 49L && truelength(x) == 100L) invisible(.Call(CresizeVector, x, 51L)) test(2378.05, length(x) == 51L && truelength(x) == 100L) -test(2378.91, .Call(CresizeVector, x, 2), error = "must be length 1 non-NA integer value") -test(2378.92, .Call(CresizeVector, NULL, 2L), error = "must be a vector") +test(2378.91, .Call(CresizeVector, x, 2), error = "must be length 1 non-NA non-negative integer value") +test(2378.92, .Call(CresizeVector, x, 2:3), error = "must be length 1 non-NA non-negative integer value") +test(2378.93, .Call(CresizeVector, x, -2L), error = "must be length 1 non-NA non-negative integer value") +test(2378.94, .Call(CresizeVector, NULL, 2L), error = "must be a vector") diff --git a/src/frollapply.c b/src/frollapply.c index 25ab5c072c..d9a64f1e5b 100644 --- a/src/frollapply.c +++ b/src/frollapply.c @@ -90,8 +90,8 @@ SEXP copyAsGrowable(SEXP x) { SEXP resizeVector(SEXP x, SEXP size) { if (!( - isInteger(size) && LENGTH(size) == 1 && INTEGER_RO(size)[0] != NA_INTEGER - )) error(_("'size' must be length 1 non-NA integer value.")); + isInteger(size) && LENGTH(size) == 1 && INTEGER_RO(size)[0] >= 0 + )) error(_("'size' must be length 1 non-NA non-negative integer value.")); if (!isVector(x)) error(_("'x' must be a vector.")); R_xlen_t newlen = INTEGER_RO(size)[0]; From 84f5f6bf6d8e08d96f0b4a3c7a2df13e8e07fd71 Mon Sep 17 00:00:00 2001 From: Jan Gorecki Date: Sat, 11 Jul 2026 11:24:16 +0200 Subject: [PATCH 7/8] add test for size=0 --- inst/tests/tests.Rraw | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 1a2a52655c..a0f2c624b9 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -21786,10 +21786,12 @@ x = .Call(CcopyAsGrowable, x) test(2378.02, length(x) == 100L && truelength(x) == 100L) invisible(.Call(CresizeVector, x, 50L)) test(2378.03, length(x) == 50L && truelength(x) == 100L) +invisible(.Call(CresizeVector, x, 0L)) +test(2378.04, length(x) == 0L && truelength(x) == 100L) invisible(.Call(CresizeVector, x, 49L)) -test(2378.04, length(x) == 49L && truelength(x) == 100L) +test(2378.05, length(x) == 49L && truelength(x) == 100L) invisible(.Call(CresizeVector, x, 51L)) -test(2378.05, length(x) == 51L && truelength(x) == 100L) +test(2378.06, length(x) == 51L && truelength(x) == 100L) test(2378.91, .Call(CresizeVector, x, 2), error = "must be length 1 non-NA non-negative integer value") test(2378.92, .Call(CresizeVector, x, 2:3), error = "must be length 1 non-NA non-negative integer value") test(2378.93, .Call(CresizeVector, x, -2L), error = "must be length 1 non-NA non-negative integer value") From ba930e9d66f0e60720ec073b759d84ca708e2ca6 Mon Sep 17 00:00:00 2001 From: Jan Gorecki Date: Sat, 11 Jul 2026 13:06:47 +0200 Subject: [PATCH 8/8] test for NA as well --- inst/tests/tests.Rraw | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index a0f2c624b9..2dec33a23d 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -21795,4 +21795,5 @@ test(2378.06, length(x) == 51L && truelength(x) == 100L) test(2378.91, .Call(CresizeVector, x, 2), error = "must be length 1 non-NA non-negative integer value") test(2378.92, .Call(CresizeVector, x, 2:3), error = "must be length 1 non-NA non-negative integer value") test(2378.93, .Call(CresizeVector, x, -2L), error = "must be length 1 non-NA non-negative integer value") -test(2378.94, .Call(CresizeVector, NULL, 2L), error = "must be a vector") +test(2378.94, .Call(CresizeVector, x, NA_integer_), error = "must be length 1 non-NA non-negative integer value") +test(2378.95, .Call(CresizeVector, NULL, 2L), error = "must be a vector")