Skip to content

Commit e13ea60

Browse files
set(): only reallocate the table if resizing would fail otherwise (#7606)
* Regression tests * set(): only reallocate if resizing would fail * Update R/data.table.R Co-authored-by: Michael Chirico <chiricom@google.com> * Rename test variables Co-Authored-By: Michael Chirico <michaelchirico4@gmail.com> * Cache j %chin% names(x) Co-Authored-By: Benjamin Schwendinger <52290390+ben-schwen@users.noreply.github.com --------- Co-authored-by: Michael Chirico <chiricom@google.com> Co-authored-by: Michael Chirico <michaelchirico4@gmail.com>
1 parent d6ac127 commit e13ea60

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

R/data.table.R

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2986,20 +2986,33 @@ setcolorder = function(x, neworder=key(x), before=NULL, after=NULL, skip_absent=
29862986
invisible(x)
29872987
}
29882988

2989-
.set_needs_alloccol = function(x, value) {
2989+
.set_needs_alloccol = function(x, j, value) {
2990+
# set() will try to resize x when adding or removing columns
2991+
# when removing a column, value can be NULL or list with NULLs inside
2992+
removing = is.null(value) || (is.list(value) && length(value) == length(j) && any(vapply_1b(value, is.null)))
2993+
# columns can be created by name
2994+
adding = if (is.character(j)) {
2995+
jexists = j %chin% names(x)
2996+
!all(jexists)
2997+
} else FALSE
2998+
2999+
if (!(removing || adding)) return(FALSE)
3000+
29903001
# automatically allocate more space when tl <= ncol (either full or loaded from disk)
2991-
if (truelength(x) <= length(x)) return(TRUE)
2992-
if (selfrefok(x, verbose=FALSE) >= 1L) return(FALSE)
2993-
# value can be NULL or list with NULLs inside
2994-
if (is.null(value)) return(TRUE)
2995-
if (!is.list(value)) return(FALSE)
2996-
any(vapply_1b(value, is.null))
3002+
# (or if a resize operation would otherwise fail)
3003+
if (selfrefok(x, verbose=FALSE) < 1L || truelength(x) <= length(x))
3004+
return(TRUE)
3005+
3006+
if (adding)
3007+
return(truelength(x) < length(x) + sum(!jexists))
3008+
3009+
FALSE
29973010
}
29983011

29993012
set = function(x,i=NULL,j,value) # low overhead, loopable
30003013
{
30013014
# If removing columns from a table that's not selfrefok, need to call setalloccol first, #7488
3002-
if (.set_needs_alloccol(x, value)) {
3015+
if (.set_needs_alloccol(x, j, value)) {
30033016
name = substitute(x)
30043017
setalloccol(x, verbose=FALSE)
30053018
if (is.name(name)) {

inst/tests/tests.Rraw

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21497,3 +21497,15 @@ test(2363.1, foverlaps(x, y, by.x, by.y), foverlaps(x, y2, by.x, by.y))
2149721497
test(2363.2, foverlaps(x, y2, by.x, by.y, type="any", mult="all"), foverlaps(x, y2, by.x, by.y, type="any", mult="first"))
2149821498
test(2363.3, foverlaps(x, y, by.x, by.y, which=TRUE, mult="first", nomatch=NULL), foverlaps(x, y2, by.x, by.y, which=TRUE, mult="first", nomatch=NULL))
2149921499
rm(x, y, y2)
21500+
21501+
# internal use of set() causes non-resizable data.tables to be re-assigned in the wrong frame, #7604
21502+
# bmerge -> coerce_col
21503+
x = structure(list(a = as.double(2:3), b = list("foo", "bar")), class = c("data.table", "data.frame"))
21504+
y = structure(list(a = 1:3), class = c("data.table", "data.frame"))
21505+
test(2364.1, x[y, on = "a"], data.table(a = 1:3, b = list(NULL, "foo", "bar")))
21506+
x = structure(list(a = factor("a", levels = letters)), class = c("data.table", "data.frame"))
21507+
y = data.table(a = factor("a", levels = letters))
21508+
setdroplevels(x)
21509+
setdroplevels(y)
21510+
test(2364.2, levels(x$a), levels(y$a))
21511+
rm(x, y)

0 commit comments

Comments
 (0)