Skip to content

Commit 154aabd

Browse files
Refactored duplicated logic in setDT and [,:=] to use a helper function
1 parent cabb4a4 commit 154aabd

File tree

1 file changed

+28
-33
lines changed

1 file changed

+28
-33
lines changed

R/data.table.R

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@ methods::setPackageName("data.table",.global)
2222
is.data.table = function(x) inherits(x, "data.table")
2323
is.ff = function(x) inherits(x, "ff") # define this in data.table so that we don't have to require(ff), but if user is using ff we'd like it to work
2424

25+
# Helper function to process assignment operations in lists or environments.
26+
# Used internally for efficient recursive assignments in data.table.
27+
28+
process_assignment <- function(name, x, parent_env) {
29+
k = eval(name[[2L]], parent_env, parent_env)
30+
if (is.list(k)) {
31+
origj = j = if (name[[1L]] == "$") as.character(name[[3L]]) else eval(name[[3L]], parent_env, parent_env)
32+
if (is.character(j)) {
33+
if (length(j) != 1L)
34+
stopf("Cannot assign to an under-allocated recursively indexed list -- L[[i]][,:=] syntax is only valid when i is length 1, but its length is %d", length(j))
35+
j = match(j, names(k))
36+
if (is.na(j))
37+
stopf("Item '%s' not found in names of input list", origj)
38+
}
39+
.Call(Csetlistelt, k, as.integer(j), x)
40+
} else if (is.environment(k) && exists(as.character(name[[3L]]), k)) {
41+
assign(as.character(name[[3L]]), x, k, inherits = FALSE)
42+
}
43+
}
44+
2545
#NCOL = function(x) {
2646
# # copied from base, but additionally covers data.table via is.list()
2747
# # because NCOL in base explicitly tests using is.data.frame()
@@ -1222,22 +1242,9 @@ replace_dot_alias = function(e) {
12221242
setalloccol(x, n, verbose=verbose) # always assigns to calling scope; i.e. this scope
12231243
if (is.name(name)) {
12241244
assign(as.character(name),x,parent.frame(),inherits=TRUE)
1225-
} else if (.is_simple_extraction(name)) { # TODO(#6702): use a helper here as the code is very similar to setDT().
1226-
k = eval(name[[2L]], parent.frame(), parent.frame())
1227-
if (is.list(k)) {
1228-
origj = j = if (name[[1L]] == "$") as.character(name[[3L]]) else eval(name[[3L]], parent.frame(), parent.frame())
1229-
if (is.character(j)) {
1230-
if (length(j)!=1L) stopf("Cannot assign to an under-allocated recursively indexed list -- L[[i]][,:=] syntax is only valid when i is length 1, but its length is %d", length(j))
1231-
j = match(j, names(k))
1232-
if (is.na(j)) internal_error("item '%s' not found in names of list", origj) # nocov
1233-
}
1234-
.Call(Csetlistelt,k,as.integer(j), x)
1235-
} else if (is.environment(k) && exists(as.character(name[[3L]]), k)) {
1236-
assign(as.character(name[[3L]]), x, k, inherits=FALSE)
1237-
} else if (isS4(k)) {
1238-
.Call(CsetS4elt, k, as.character(name[[3L]]), x)
1239-
}
1240-
} # TO DO: else if env$<- or list$<-
1245+
} else if (name %iscall% c('$', '[[') && is.name(name[[2L]])) {
1246+
process_assignment(name, x, parent.frame())
1247+
}
12411248
}
12421249
}
12431250
}
@@ -2970,25 +2977,13 @@ setDT = function(x, keep.rownames=FALSE, key=NULL, check.names=FALSE) {
29702977
if (is.name(name)) {
29712978
name = as.character(name)
29722979
assign(name, x, parent.frame(), inherits=TRUE)
2973-
} else if (.is_simple_extraction(name)) {
2974-
# common case is call from 'lapply()'
2975-
k = eval(name[[2L]], parent.frame(), parent.frame())
2976-
if (is.list(k)) {
2977-
origj = j = if (name[[1L]] == "$") as.character(name[[3L]]) else eval(name[[3L]], parent.frame(), parent.frame())
2978-
if (length(j) == 1L) {
2979-
if (is.character(j)) {
2980-
j = match(j, names(k))
2981-
if (is.na(j))
2982-
stopf("Item '%s' not found in names of input list", origj)
2983-
}
2984-
}
2985-
.Call(Csetlistelt, k, as.integer(j), x)
2986-
} else if (is.environment(k) && exists(as.character(name[[3L]]), k)) {
2987-
assign(as.character(name[[3L]]), x, k, inherits=FALSE)
2988-
} else if (isS4(k)) {
2980+
} else if (name %iscall% c('$', '[[') && is.name(name[[2L]])) {
2981+
process_assignment(name, x, parent.frame())
2982+
}
2983+
else if (isS4(k)) {
29892984
.Call(CsetS4elt, k, as.character(name[[3L]]), x)
29902985
}
2991-
} else if (name %iscall% "get") { # #6725
2986+
else if (name %iscall% "get") { # #6725
29922987
# edit 'get(nm, env)' call to be 'assign(nm, x, envir=env)'
29932988
name = match.call(get, name)
29942989
name[[1L]] = quote(assign)

0 commit comments

Comments
 (0)