Skip to content

Commit f52580e

Browse files
Merge branch 'master' into constnessAndReadOnlyness
2 parents 9f86a9e + 293f3b0 commit f52580e

22 files changed

Lines changed: 110 additions & 123 deletions

NAMESPACE

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ S3method(split, data.table)
139139
export(dcast, melt)
140140
S3method(dcast, data.table)
141141
S3method(melt, data.table)
142-
S3method(melt, default)
143142

144143
# exported for historical reasons -- if reshape2 is higher on search path,
145144
# dcast(DT) will not dispatch since reshape2::dcast is not generic. So users

NEWS.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646

4747
9. `foverlaps()` no longer crashes due to out-of-bounds access to list and integer vectors when `y` has no rows or the non-range part of the join fails, [#7597](https://github.com/Rdatatable/data.table/issues/7597). Thanks to @nextpagesoft for the report and @aitap for the fix.
4848

49-
10. The dynamic library now exports only `R_init_data_table`, preventing symbol name conflicts like `hash_create` with PostgreSQL, [#7605](https://github.com/Rdatatable/data.table/issues/7605). Thanks to @ced75 for the report and @aitap for the fix
49+
10. The dynamic library now exports only `R_init_data_table`, preventing symbol name conflicts like `hash_create` with PostgreSQL, [#7605](https://github.com/Rdatatable/data.table/issues/7605). Thanks to @ced75 for the report and @aitap for the fix.
5050

5151
### Notes
5252

@@ -60,6 +60,8 @@
6060

6161
5. The data.table test suite is a bit more robust to lacking UTF-8 support via a new `requires_utf8` argument to `test()` to skip tests when UTF-8 support is not available, [#7336](https://github.com/Rdatatable/data.table/issues/7336). Thanks @MichaelChirico for the suggestion and @ben-schwen for the implementation.
6262

63+
6. `melt()` and `dcast()` no longer provide nudges when receiving incompatible inputs (e.g. data.frames). As of now, we only define methods for `data.table` inputs.
64+
6365
## data.table [v1.18.0](https://github.com/Rdatatable/data.table/milestone/37?closed=1) 23 December 2025
6466

6567
### BREAKING CHANGE

R/fcast.R

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ dcast = function(
1212
data, formula, fun.aggregate = NULL, ..., margins = NULL,
1313
subset = NULL, fill = NULL, value.var = guess(data)
1414
) {
15-
# TODO(>=1.19.0): Remove this, just let dispatch to 'default' method fail.
16-
if (!is.data.table(data))
17-
stopf("The %1$s generic in data.table has been passed a %2$s, but data.table::%1$s currently only has a method for data.tables. Please confirm your input is a data.table, with setDT(%3$s) or as.data.table(%3$s). If you intend to use a method from reshape2, try installing that package first, but do note that reshape2 is superseded and is no longer actively developed.", "dcast", class1(data), deparse(substitute(data))) # nocov
1815
UseMethod("dcast", data)
1916
}
2017

R/fmelt.R

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@ melt = function(data, ..., na.rm = FALSE, value.name = "value") {
77
UseMethod("melt", data)
88
}
99

10-
# TODO(>=1.19.0): Remove this, just let dispatch to 'default' method fail.
11-
melt.default = function(data, ..., na.rm = FALSE, value.name = "value") {
12-
stopf("The %1$s generic in data.table has been passed a %2$s and will attempt to redirect to the relevant reshape2 method; please note that reshape2 is superseded and is no longer actively developed, and this redirection is now deprecated. To continue using melt methods from reshape2 while both packages are attached, e.g. melt.list, you can prepend the namespace, i.e. reshape2::%1$s(%3$s). In the next version, this warning will become an error.", "melt", class1(data), deparse(substitute(data))) # nocov
13-
}
14-
1510
patterns = function(..., cols=character(0L), ignore.case=FALSE, perl=FALSE, fixed=FALSE, useBytes=FALSE) {
1611
# if ... has no names, names(list(...)) will be "";
1712
# this assures they'll be NULL instead

src/assign.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ SEXP assign(SEXP dt, SEXP rows, SEXP cols, SEXP newcolnames, SEXP values)
403403
error(_("i is type '%s'. Must be integer, or numeric is coerced with warning. If i is a logical subset, simply wrap with which(), and take the which() outside the loop if possible for efficiency."), type2char(TYPEOF(rows)));
404404
targetlen = length(rows);
405405
numToDo = 0;
406-
const int *rowsd = INTEGER(rows);
406+
const int *rowsd = INTEGER_RO(rows);
407407
for (int i=0; i<targetlen; ++i) {
408408
if ((rowsd[i]<0 && rowsd[i]!=NA_INTEGER) || rowsd[i]>nrow)
409409
error(_("i[%d] is %d which is out of range [1,nrow=%d]"), i+1, rowsd[i], nrow); // set() reaches here (test 2005.2); := reaches the same error in subset.c first
@@ -660,7 +660,7 @@ SEXP assign(SEXP dt, SEXP rows, SEXP cols, SEXP newcolnames, SEXP values)
660660
if (ndelete) {
661661
// delete any columns assigned NULL (there was a 'continue' earlier in loop above)
662662
int *tt = (int *)R_alloc(ndelete, sizeof(*tt));
663-
const int *colsd=INTEGER(cols), ncols=length(cols), ndt=length(dt);
663+
const int *colsd=INTEGER_RO(cols), ncols=length(cols), ndt=length(dt);
664664
for (int i=0, k=0; i<ncols; ++i) { // find which ones to delete and put them in tt
665665
// Aside: a new column being assigned NULL (something odd to do) would have been warned above, added above, and now deleted. Just
666666
// easier to code it this way; e.g. so that other columns may be added or removed ok by the same query.
@@ -743,7 +743,7 @@ const char *memrecycle(const SEXP target, const SEXP where, const int start, con
743743
// allow assigning level numbers to factor columns; test 425, 426, 429 and 1945
744744
const int nlevel = length(getAttrib(target, R_LevelsSymbol));
745745
if (isInteger(source)) {
746-
const int *sd = INTEGER(source);
746+
const int *sd = INTEGER_RO(source);
747747
for (int i=0; i<slen; ++i) {
748748
const int val = sd[i+soff];
749749
if ((val<1 && val!=NA_INTEGER) || val>nlevel) {
@@ -754,7 +754,7 @@ const char *memrecycle(const SEXP target, const SEXP where, const int start, con
754754
}
755755
}
756756
} else {
757-
const double *sd = REAL(source);
757+
const double *sd = REAL_RO(source);
758758
for (int i=0; i<slen; ++i) {
759759
const double val = sd[i+soff];
760760
// Since nlevel is an int, val < 1 || val > nlevel will deflect UB guarded against in PR #5832
@@ -800,7 +800,7 @@ const char *memrecycle(const SEXP target, const SEXP where, const int start, con
800800
const int nSource = length(source);
801801
int *newSourceD = INTEGER(newSource);
802802
if (sourceIsFactor) {
803-
const int *sourceD = INTEGER(source);
803+
const int *sourceD = INTEGER_RO(source);
804804
for (int i=0; i<nSource; ++i) { // convert source integers to refer to target levels
805805
const int val = sourceD[i];
806806
newSourceD[i] = val==NA_INTEGER ? NA_INTEGER : -hash_lookup(marks, sourceLevelsD[val-1], 0); // retains NA factor levels here via TL(NA_STRING); e.g. ordered factor

src/bmerge.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,8 @@ void bmerge_r(int xlowIn, int xuppIn, int ilowIn, int iuppIn, int col, int thisg
357357

358358
switch (TYPEOF(xc)) {
359359
case LGLSXP : case INTSXP : { // including factors
360-
const int *icv = isDataCol ? INTEGER(ic) : NULL;
361-
const int *xcv = INTEGER(xc);
360+
const int *icv = isDataCol ? INTEGER_RO(ic) : NULL;
361+
const int *xcv = INTEGER_RO(xc);
362362
const int ival = isDataCol ? icv[ir] : thisgrp;
363363
#define ISNAT(x) ((x)==NA_INTEGER)
364364
#define WRAP(x) (x) // wrap not needed for int
@@ -389,8 +389,8 @@ void bmerge_r(int xlowIn, int xuppIn, int ilowIn, int iuppIn, int col, int thisg
389389
#define WRAP(x) (x)
390390
DO(const int64_t xval=xcv[XIND(mid)], xval<ival, xval>ival, int64_t, ival-xcv[XIND(xlow)], xcv[XIND(xupp)]-ival, ival)
391391
} else {
392-
const double *icv = REAL(ic);
393-
const double *xcv = REAL(xc);
392+
const double *icv = REAL_RO(ic);
393+
const double *xcv = REAL_RO(xc);
394394
const double ival = icv[ir];
395395
const uint64_t ivalt = dtwiddle(ival); // TO: remove dtwiddle by dealing with NA, NaN, -Inf, +Inf up front
396396
#undef ISNAT

src/data.table.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ SEXP fitsInInt64R(SEXP x);
329329
bool allNA(SEXP x, bool errorForBadType);
330330
SEXP colnamesInt(SEXP x, SEXP cols, SEXP check_dups, SEXP skip_absent);
331331
bool INHERITS(SEXP x, SEXP char_);
332+
void copyVectorElements(SEXP dst, SEXP src, R_xlen_t n, bool deep_copy, const char *caller);
332333
SEXP copyAsPlain(SEXP x);
333334
void copySharedColumns(SEXP x);
334335
SEXP lock(SEXP x);

src/dogroups.c

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -526,25 +526,7 @@ SEXP growVector(SEXP x, const R_len_t newlen)
526526
UNPROTECT(1);
527527
return newx;
528528
}
529-
switch (TYPEOF(x)) {
530-
case RAWSXP: memcpy(RAW(newx), RAW_RO(x), len*RTYPE_SIZEOF(x)); break;
531-
case LGLSXP: memcpy(LOGICAL(newx), LOGICAL_RO(x), len*RTYPE_SIZEOF(x)); break;
532-
case INTSXP: memcpy(INTEGER(newx), INTEGER_RO(x), len*RTYPE_SIZEOF(x)); break;
533-
case REALSXP: memcpy(REAL(newx), REAL_RO(x), len*RTYPE_SIZEOF(x)); break;
534-
case CPLXSXP: memcpy(COMPLEX(newx), COMPLEX_RO(x), len*RTYPE_SIZEOF(x)); break;
535-
case STRSXP : {
536-
const SEXP *xd = SEXPPTR_RO(x);
537-
for (int i=0; i<len; ++i)
538-
SET_STRING_ELT(newx, i, xd[i]);
539-
} break;
540-
case VECSXP : {
541-
const SEXP *xd = SEXPPTR_RO(x);
542-
for (int i=0; i<len; ++i)
543-
SET_VECTOR_ELT(newx, i, xd[i]);
544-
} break;
545-
default : // # nocov
546-
internal_error(__func__, "type '%s' not supported", type2char(TYPEOF(x))); // # nocov
547-
}
529+
copyVectorElements(newx, x, (R_xlen_t)len, false, __func__);
548530
// if (verbose) Rprintf(_("Growing vector from %d to %d items of type '%s'\n"), len, newlen, type2char(TYPEOF(x)));
549531
// Would print for every column if here. Now just up in dogroups (one msg for each table grow).
550532
SHALLOW_DUPLICATE_ATTRIB(newx, x);

src/fifelse.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ SEXP fifelseR(SEXP l, SEXP a, SEXP b, SEXP na) {
9696
const int64_t bmask = len2>1 ? INT64_MAX : 0;
9797
const int64_t nmask = len3>1 ? INT64_MAX : 0;
9898

99-
const int *restrict pl = LOGICAL(l);
99+
const int *restrict pl = LOGICAL_RO(l);
100100
SEXP ans = PROTECT(allocVector(tans, len0)); nprotect++;
101101
if (!na_a)
102102
copyMostAttrib(a, ans);
@@ -237,7 +237,7 @@ SEXP fcaseR(SEXP rho, SEXP args) {
237237
if (!isLogical(whens)) {
238238
error(_("Argument #%d must be logical but was of type %s."), 2*i+1, type2char(TYPEOF(whens)));
239239
}
240-
const int *restrict pwhens = LOGICAL(whens);
240+
const int *restrict pwhens = LOGICAL_RO(whens);
241241
l = 0;
242242
if (i == 0) {
243243
n_ans = xlength(whens);
@@ -306,7 +306,7 @@ SEXP fcaseR(SEXP rho, SEXP args) {
306306
switch(TYPEOF(ans)) {
307307
case LGLSXP: {
308308
const int *restrict pthens;
309-
if (!naout) pthens = LOGICAL(thens); // the content is not useful if out is NA_LOGICAL scalar
309+
if (!naout) pthens = LOGICAL_RO(thens); // the content is not useful if out is NA_LOGICAL scalar
310310
int *restrict pans = LOGICAL(ans);
311311
const int pna = NA_LOGICAL;
312312
for (int64_t j=0; j<n_undecided; ++j) {
@@ -323,7 +323,7 @@ SEXP fcaseR(SEXP rho, SEXP args) {
323323
} break;
324324
case INTSXP: {
325325
const int *restrict pthens;
326-
if (!naout) pthens = INTEGER(thens); // the content is not useful if out is NA_LOGICAL scalar
326+
if (!naout) pthens = INTEGER_RO(thens); // the content is not useful if out is NA_LOGICAL scalar
327327
int *restrict pans = INTEGER(ans);
328328
const int pna = NA_INTEGER;
329329
for (int64_t j=0; j<n_undecided; ++j) {
@@ -340,7 +340,7 @@ SEXP fcaseR(SEXP rho, SEXP args) {
340340
} break;
341341
case REALSXP: {
342342
const double *restrict pthens;
343-
if (!naout) pthens = REAL(thens); // the content is not useful if out is NA_LOGICAL scalar
343+
if (!naout) pthens = REAL_RO(thens); // the content is not useful if out is NA_LOGICAL scalar
344344
double *restrict pans = REAL(ans);
345345
const double na_double = INHERITS(ans, char_integer64) ? NA_INT64_D : NA_REAL;
346346
const double pna = na_double;
@@ -358,7 +358,7 @@ SEXP fcaseR(SEXP rho, SEXP args) {
358358
} break;
359359
case CPLXSXP: {
360360
const Rcomplex *restrict pthens;
361-
if (!naout) pthens = COMPLEX(thens); // the content is not useful if out is NA_LOGICAL scalar
361+
if (!naout) pthens = COMPLEX_RO(thens); // the content is not useful if out is NA_LOGICAL scalar
362362
Rcomplex *restrict pans = COMPLEX(ans);
363363
const Rcomplex pna = NA_CPLX;
364364
for (int64_t j=0; j<n_undecided; ++j) {

src/fmelt.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ SEXP set_diff(SEXP x, int n) {
1919
if (n <= 0) error(_("'n' must be a positive integer"));
2020
SEXP table = PROTECT(seq_int(n, 1)); // TODO: using match to 1:n seems odd here, why use match at all
2121
SEXP xmatch = PROTECT(match(x, table, 0)); // Old comment:took a while to realise: matches vec against x - thanks to comment from Matt in assign.c!
22-
const int *ixmatch = INTEGER(xmatch);
22+
const int *ixmatch = INTEGER_RO(xmatch);
2323
int *buf = (int *) R_alloc(n, sizeof(*buf));
2424
int j=0;
2525
for (int i=0; i<n; ++i) {
@@ -39,7 +39,7 @@ SEXP which(SEXP x, Rboolean val) {
3939
int j=0, n = length(x);
4040
SEXP ans;
4141
if (!isLogical(x)) error(_("Argument to 'which' must be logical"));
42-
const int *ix = LOGICAL(x);
42+
const int *ix = LOGICAL_RO(x);
4343
int *buf = (int *) R_alloc(n, sizeof(*buf));
4444
for (int i=0; i<n; ++i) {
4545
if (ix[i] == val) {
@@ -70,7 +70,7 @@ static const char *concat(SEXP vec, SEXP idx) {
7070
int nidx=length(idx), nvec=length(vec);
7171
ans[0]='\0';
7272
if (nidx==0) return ans;
73-
const int *iidx = INTEGER(idx);
73+
const int *iidx = INTEGER_RO(idx);
7474
for (int i=0; i<nidx; ++i) {
7575
if (iidx[i]<1 || iidx[i]>nvec)
7676
internal_error(__func__, "'idx' must take values between 1 and length(vec); 1 <= idx <= %d", nvec); // # nocov
@@ -150,7 +150,7 @@ static SEXP unlist_(SEXP xint) {
150150
int *ians = INTEGER(ans), k=0;
151151
for (int i=0; i<n; ++i) {
152152
SEXP tmp = VECTOR_ELT(xint, i);
153-
const int *itmp = INTEGER(tmp), n2=length(tmp);
153+
const int *itmp = INTEGER_RO(tmp), n2=length(tmp);
154154
for (int j=0; j<n2; ++j)
155155
ians[k++] = itmp[j];
156156
}
@@ -522,7 +522,7 @@ SEXP getvaluecols(SEXP DT, SEXP dtnames, Rboolean valfactor, Rboolean verbose, s
522522
int thislen = 0;
523523
if (data->narm) {
524524
SEXP thisidx = VECTOR_ELT(data->not_NA_indices, j);
525-
ithisidx = INTEGER(thisidx);
525+
ithisidx = INTEGER_RO(thisidx);
526526
thislen = length(thisidx);
527527
}
528528
size_t size = RTYPE_SIZEOF(thiscol);
@@ -600,7 +600,7 @@ SEXP getvarcols(SEXP DT, SEXP dtnames, Rboolean varfactor, Rboolean verbose, str
600600
if (!varfactor) {
601601
SET_VECTOR_ELT(ansvars, 0, target=allocVector(STRSXP, data->totlen));
602602
if (!data->measure_is_list) {//one value column to output.
603-
const int *thisvaluecols = INTEGER(VECTOR_ELT(data->valuecols, 0));
603+
const int *thisvaluecols = INTEGER_RO(VECTOR_ELT(data->valuecols, 0));
604604
for (int j=0, ansloc=0; j<data->lmax; ++j) {
605605
const int thislen = data->narm ? length(VECTOR_ELT(data->not_NA_indices, j)) : data->nrow;
606606
SEXP str = STRING_ELT(dtnames, thisvaluecols[j]-1);
@@ -622,7 +622,7 @@ SEXP getvarcols(SEXP DT, SEXP dtnames, Rboolean varfactor, Rboolean verbose, str
622622
SEXP thisvaluecols = VECTOR_ELT(data->valuecols, 0);
623623
int len = length(thisvaluecols);
624624
levels = PROTECT(allocVector(STRSXP, len)); protecti++;
625-
const int *vd = INTEGER(thisvaluecols);
625+
const int *vd = INTEGER_RO(thisvaluecols);
626626
for (int j=0; j<len; ++j) SET_STRING_ELT(levels, j, STRING_ELT(dtnames, vd[j]-1));
627627
SEXP m = PROTECT(chmatch(levels, levels, 0)); protecti++; // do we have any dups?
628628
int numRemove = 0; // remove dups and any for which narm and all-NA
@@ -706,7 +706,7 @@ SEXP getidcols(SEXP DT, SEXP dtnames, Rboolean verbose, struct processData *data
706706
if (data->narm) {
707707
for (int j=0; j<data->lmax; ++j) {
708708
SEXP thisidx = VECTOR_ELT(data->not_NA_indices, j);
709-
const int *ithisidx = INTEGER(thisidx);
709+
const int *ithisidx = INTEGER_RO(thisidx);
710710
const int thislen = length(thisidx);
711711
for (int k=0; k<thislen; ++k)
712712
dtarget[counter + k] = dthiscol[ithisidx[k]-1];
@@ -725,7 +725,7 @@ SEXP getidcols(SEXP DT, SEXP dtnames, Rboolean verbose, struct processData *data
725725
if (data->narm) {
726726
for (int j=0; j<data->lmax; ++j) {
727727
SEXP thisidx = VECTOR_ELT(data->not_NA_indices, j);
728-
const int *ithisidx = INTEGER(thisidx);
728+
const int *ithisidx = INTEGER_RO(thisidx);
729729
const int thislen = length(thisidx);
730730
for (int k=0; k<thislen; ++k)
731731
itarget[counter + k] = ithiscol[ithisidx[k]-1];
@@ -740,7 +740,7 @@ SEXP getidcols(SEXP DT, SEXP dtnames, Rboolean verbose, struct processData *data
740740
if (data->narm) {
741741
for (int j=0; j<data->lmax; ++j) {
742742
SEXP thisidx = VECTOR_ELT(data->not_NA_indices, j);
743-
const int *ithisidx = INTEGER(thisidx);
743+
const int *ithisidx = INTEGER_RO(thisidx);
744744
const int thislen = length(thisidx);
745745
for (int k=0; k<thislen; ++k)
746746
SET_STRING_ELT(target, counter + k, STRING_ELT(thiscol, ithisidx[k]-1));
@@ -760,7 +760,7 @@ SEXP getidcols(SEXP DT, SEXP dtnames, Rboolean verbose, struct processData *data
760760
if (data->narm) {
761761
for (int j=0; j<data->lmax; ++j) {
762762
SEXP thisidx = VECTOR_ELT(data->not_NA_indices, j);
763-
const int *ithisidx = INTEGER(thisidx);
763+
const int *ithisidx = INTEGER_RO(thisidx);
764764
const int thislen = length(thisidx);
765765
for (int k=0; k<thislen; ++k)
766766
SET_VECTOR_ELT(target, counter + k, VECTOR_ELT(thiscol, ithisidx[k]-1));

0 commit comments

Comments
 (0)