Closed joshuaulrich closed 1 year ago
I'm not sure this is a bug in xts, or a bug at all. I added the following code to the top of src/dimnames.c
:
if (MAYBE_SHARED(x)) {
x = duplicate(x);
}
But then "dimnames<-"(z, NULL)
no longer mutated x
or y
, but it also didn't update z
like it should have.
I also tried to only duplicate when "dimnames<-"(x, NULL)
was called, but not when dimnames(x) <- NULL
was called. The results were the same as in the previous comment. Patch below:
diff --git a/R/dimnames.R b/R/dimnames.R
index 82bf759..a9810ce 100644
--- a/R/dimnames.R
+++ b/R/dimnames.R
@@ -31,5 +31,6 @@ function(x) {
`dimnames<-.xts` <-
function(x, value) {
- .Call("xts_set_dimnames", x, value, PACKAGE = "xts")
+ duplicate.x <- match.call()$x != as.symbol("*tmp*")
+ .Call("xts_set_dimnames", x, value, duplicate.x, PACKAGE = "xts")
}
diff --git a/inst/include/xts.h b/inst/include/xts.h
index d94ed22..d38328c 100644
--- a/inst/include/xts.h
+++ b/inst/include/xts.h
@@ -98,7 +98,7 @@ SEXP xts_period_max(SEXP data, SEXP index);
SEXP xts_period_sum(SEXP data, SEXP index);
SEXP xts_period_prod(SEXP data, SEXP index);
-SEXP xts_set_dimnames(SEXP x, SEXP value);
+SEXP xts_set_dimnames(SEXP x, SEXP value, SEXP duplicate_x);
void copyAttributes(SEXP x, SEXP y); // internal only
diff --git a/inst/unitTests/runit.xts.methods.R b/inst/unitTests/runit.xts.methods.R
index eb1d72d..a76ed65 100644
--- a/inst/unitTests/runit.xts.methods.R
+++ b/inst/unitTests/runit.xts.methods.R
@@ -1,7 +1,5 @@
#
# RUnit tests for the following 'xts' methods:
-# rbind
-# cbind
#
test.rbind_zero_length_non_zero_length_POSIXct_errors <- function() {
xpz <- xts( , as.POSIXct("2017-01-01"))
@@ -272,3 +270,23 @@ test.subset_i_ISO8601 <- function() {
checkIdentical(bin, sub, sprintf(fmt, "1999/2000-01"))
}
}
+
+test.set_dimnames_does_not_mutate <- function() {
+ dn <- list(NULL, c("a", "b"))
+ z <- y <- x <- .xts(cbind(1:2, 1:2), 1:2, dimnames = dn)
+ DN <- list(NULL, toupper(dn[[2]]))
+ dimnames(y) <- DN
+ RUnit::checkIdentical(dimnames(x), dn)
+ RUnit::checkIdentical(dimnames(y), DN)
+ RUnit::checkIdentical(dimnames(z), dn)
+}
+
+test.set_dimnames_backtick_does_not_mutate <- function() {
+ dn <- list(NULL, c("a", "b"))
+ z <- y <- x <- .xts(cbind(1:2, 1:2), 1:2, dimnames = dn)
+ DN <- list(NULL, toupper(dn[[2]]))
+ `dimnames<-`(y, DN)
+ RUnit::checkIdentical(dimnames(x), dn)
+ RUnit::checkIdentical(dimnames(y), DN)
+ RUnit::checkIdentical(dimnames(z), dn)
+}
diff --git a/src/dimnames.c b/src/dimnames.c
index 856b76d..fb0e1c1 100644
--- a/src/dimnames.c
+++ b/src/dimnames.c
@@ -25,7 +25,10 @@ SEXP dimnames_zoo (SEXP x) {
return(getAttrib(x, R_DimNamesSymbol));
}
-SEXP xts_set_dimnames (SEXP x, SEXP value) {
+SEXP xts_set_dimnames (SEXP x, SEXP value, SEXP duplicate_x) {
+ if (LOGICAL(duplicate_x)[0]) {
+ x = duplicate(x);
+ }
if (R_NilValue == value) {
setAttrib(x, R_DimNamesSymbol, R_NilValue);
} else {
diff --git a/src/init.c b/src/init.c
index 005d155..aaea950 100644
--- a/src/init.c
+++ b/src/init.c
@@ -43,7 +43,7 @@ R_CallMethodDef callMethods[] = {
{"xts_period_max", (DL_FUNC) &xts_period_max, 2},
{"xts_period_sum", (DL_FUNC) &xts_period_sum, 2},
{"xts_period_prod", (DL_FUNC) &xts_period_prod, 2},
- {"xts_set_dimnames", (DL_FUNC) &xts_set_dimnames, 2},
+ {"xts_set_dimnames", (DL_FUNC) &xts_set_dimnames, 3},
{NULL, NULL, 0}
};
Calling
"dimnames<-"
on a shared xts object will change the column names for all shared objects. Only the object"dimnames<-"
is called with should be changed. I.e., it should beduplicated()
before dimnames are changed. The relevant code is in the C functionxts_set_dimnames()
.Session Info