Skip to content

Commit f0aaaf9

Browse files
allow rbind for integer64 and character/complex/vector (#5874)
* allow rbind for integer64 and character/complex * update comments * delete carried over line * add vector support * add coverage * add CODEOWNER * update NEWS * restore merge cut * internal error * trailing ws * more trailing * refine comments * internal error * fix re-attach bit64 * test imaginary components in complex case --------- Co-authored-by: Michael Chirico <[email protected]>
1 parent 713c701 commit f0aaaf9

File tree

4 files changed

+26
-4
lines changed

4 files changed

+26
-4
lines changed

CODEOWNERS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
/src/shift.c @ben-schwen @michaelchirico
3636
/man/shift.Rd @ben-schwen @michaelchirico
3737

38+
# rbind
39+
/src/rbindlist.c @ben-schwen
40+
/man/rbindlist.Rd @ben-schwen
41+
3842
# translations
3943
/inst/po/ @michaelchirico
4044
/po/ @michaelchirico

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ rowwiseDT(
6161

6262
8. `dt[, col]` now returns a copy of `col` also when it is a list column, as in any other case, [#4877](https://github.com/Rdatatable/data.table/issues/4877). Thanks to @tlapak for reporting and the PR.
6363

64+
9. `rbindlist` and `rbind` binding `bit64::integer64` columns with `character`/`complex`/`list` columns now works, [#5504](https://github.com/Rdatatable/data.table/issues/5504). Thanks to @MichaelChirico for the request and @ben-schwen for the PR.
65+
6466
## NOTES
6567

6668
1. Tests run again when some Suggests packages are missing, [#6411](https://github.com/Rdatatable/data.table/issues/6411). Thanks @aadler for the note and @MichaelChirico for the fix.

inst/tests/tests.Rraw

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18736,7 +18736,7 @@ test(2264.8, print(DT, show.indices=TRUE), output=ans)
1873618736
if (test_bit64) local({
1873718737
DT = data.table(a = 'abc', b = as.integer64(1))
1873818738
suppressPackageStartupMessages(unloadNamespace("bit64"))
18739-
on.exit(suppressPackageStartupMessages(library(bit64)))
18739+
on.exit(suppressPackageStartupMessages(library(bit64, pos="package:base")))
1874018740
test(2265, DT, output="abc\\s*1$")
1874118741
})
1874218742

@@ -19208,3 +19208,17 @@ test(2287.1, address(dt[, A]) != address(dt[, A]))
1920819208
l = dt[, A]
1920919209
dt[1L, A := .(list(1L))]
1921019210
test(2287.2, !identical(DT$A[[1L]], l[[1L]]))
19211+
19212+
# rbind do not copy class/attributes for integer64 and CPLXSXP/STRSXP/VECSXP #5504
19213+
if (test_bit64) {
19214+
a = data.table(as.integer64(c(1,2)))
19215+
b = data.table(c("a","b"))
19216+
c = data.table(complex(real = 3:4, imaginary = 5:6))
19217+
d = data.table(list(3.5, 4L))
19218+
test(2288.1, rbind(a,b), data.table(c("1","2","a","b")))
19219+
test(2288.2, rbind(b,a), data.table(c("a","b","1","2")))
19220+
test(2288.3, rbind(a,c), data.table(complex(real = 1:4, imaginary = c(0, 0, 5:6))))
19221+
test(2288.4, rbind(c,a), data.table(complex(real = c(3:4, 1:2), imaginary = c(5:6, 0, 0))))
19222+
test(2288.5, rbind(a,d), data.table(list(as.integer64(1), as.integer64(2), 3.5, 4L)))
19223+
test(2288.6, rbind(d,a), data.table(list(3.5, 4L, as.integer64(1), as.integer64(2))))
19224+
}

src/rbindlist.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -338,12 +338,13 @@ SEXP rbindlist(SEXP l, SEXP usenamesArg, SEXP fillArg, SEXP idcolArg, SEXP ignor
338338

339339
if (!foundName) { static char buff[12]; snprintf(buff,12,"V%d",j+1), SET_STRING_ELT(ansNames, idcol+j, mkChar(buff)); foundName=buff; }
340340
if (factor) maxType=INTSXP; // if any items are factors then a factor is created (could be an option)
341-
if (int64 && maxType!=REALSXP)
341+
if (int64 && !(maxType==REALSXP || maxType==STRSXP || maxType==VECSXP || maxType==CPLXSXP))
342342
internal_error(__func__, "column %d of result is determined to be integer64 but maxType=='%s' != REALSXP", j+1, type2char(maxType)); // # nocov
343343
if (date && INHERITS(firstCol, char_IDate)) maxType=INTSXP; // first encountered Date determines class and type #5309
344344
SEXP target;
345345
SET_VECTOR_ELT(ans, idcol+j, target=allocVector(maxType, nrow)); // does not initialize logical & numerics, but does initialize character and list
346-
if (!factor) copyMostAttrib(firstCol, target); // all but names,dim and dimnames; mainly for class. And if so, we want a copy here, not keepattr's SET_ATTRIB.
346+
// #5504 do not copy class for mixing int64 and higher maxTypes CPLXSXP/STRSXP/VECSXP
347+
if (!factor && !(int64 && (maxType==STRSXP || maxType==VECSXP || maxType==CPLXSXP))) copyMostAttrib(firstCol, target); // all but names,dim and dimnames; mainly for class. And if so, we want a copy here, not keepattr's SET_ATTRIB.
347348

348349
if (factor && anyNotStringOrFactor) {
349350
// in future warn, or use list column instead ... warning(_("Column %d contains a factor but not all items for the column are character or factor"), idcol+j+1);
@@ -539,7 +540,8 @@ SEXP rbindlist(SEXP l, SEXP usenamesArg, SEXP fillArg, SEXP idcolArg, SEXP ignor
539540
bool listprotect = (TYPEOF(target)==VECSXP || TYPEOF(target)==EXPRSXP) && TYPEOF(thisCol)!=TYPEOF(target);
540541
// do an as.list() on the atomic column; #3528
541542
if (listprotect) {
542-
thisCol = PROTECT(coerceVector(thisCol, TYPEOF(target)));
543+
// coerceAs for int64 to copy attributes (coerceVector does not copy atts)
544+
thisCol = PROTECT(INHERITS(thisCol, char_integer64) ? coerceAs(thisCol, target, ScalarLogical(TRUE)) : coerceVector(thisCol, TYPEOF(target)));
543545
// else coerces if needed within memrecycle; with a no-alloc direct coerce from 1.12.4 (PR #3909)
544546
const char *ret = memrecycle(target, R_NilValue, ansloc, thisnrow, thisCol, 0, -1, idcol+j+1, foundName);
545547
UNPROTECT(1); // earlier unprotect rbindlist calls with lots of lists #4536

0 commit comments

Comments
 (0)