You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: NEWS.md
+3-1Lines changed: 3 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -87,7 +87,7 @@
87
87
88
88
8. A data.table with a column of class `vctrs_list_of` (from package {vctrs}) prints as expected, [#5948](https://github.com/Rdatatable/data.table/issues/5948). Before, they could be printed messily, e.g. printing every entry in a nested data.frame. Thanks @jesse-smith for the report, @DavisVaughan and @r2evans for contributing, and @MichaelChirico for the PR.
89
89
90
-
9. Fixed incorrect sorting of merges where the first column of a key is a factor with non-`sort()`-ed levels (e.g. `factor(1:2, 2:1)` and it is joined to a character column, [#5361](https://github.com/Rdatatable/data.table/issues/5361). Thanks to @gbrunick for the report and Benjamin Schwendinger for the fix.
90
+
9. Fixed incorrect sorting of merges where the first column of a key is a factor with non-`sort()`-ed levels (e.g. `factor(1:2, 2:1)` and it is joined to a character column, [#5361](https://github.com/Rdatatable/data.table/issues/5361). Thanks to @gbrunick for the report, Benjamin Schwendinger for the fix, and @MichaelChirico for a follow-up fix caught by revdep testing.
91
91
92
92
10. Spurious warnings from internal code in `cube()`, `rollup()`, and `groupingsets()` are no longer surfaced to the caller, [#6964](https://github.com/Rdatatable/data.table/issues/6964). Thanks @ferenci-tamas for the report and @venom1204 for the fix.
93
93
@@ -122,6 +122,8 @@
122
122
123
123
5. A GitHub Actions workflow is now in place to warn the entire maintainer team, as well as any contributor following the GitHub repository, when the package is at risk of archival on CRAN [#7008](https://github.com/Rdatatable/data.table/issues/7008). Thanks @tdhock for the original report and @Bisaloo and @TysonStanley for the fix.
124
124
125
+
6. Using a double vector in `set()`'s`i=`and/or`j=`nolongerthrowsawarningaboutpreferringinteger, [#6594](https://github.com/Rdatatable/data.table/issues/6594). While it may improve efficiency to use integer, there's no guarantee it's an improvement and the difference is likely to be minimal. The coercion will still be reported under `datatable.verbose=TRUE`. For package/production use cases, static analyzers such as `lintr::implicit_integer_linter()` can also report when numeric literals should be rewritten as integer literals.
126
+
125
127
## data.table [v1.17.8](https://github.com/Rdatatable/data.table/milestone/41) (6 July 2025)
Copy file name to clipboardExpand all lines: src/assign.c
+6-3Lines changed: 6 additions & 3 deletions
Original file line number
Diff line number
Diff line change
@@ -219,7 +219,7 @@ SEXP setdt_nrows(SEXP x)
219
219
if (Rf_inherits(xi, "POSIXlt")) {
220
220
error(_("Column %d has class 'POSIXlt'. Please convert it to POSIXct (using as.POSIXct) and run setDT() again. We do not recommend the use of POSIXlt at all because it uses 40 bytes to store one date."), i+1);
warning(_("Coerced i from numeric to integer. Please pass integer for efficiency; e.g., 2L rather than 2"));
368
+
if (verbose)
369
+
Rprintf(_("Coerced %s from numeric to integer. Passing integer directly may be more efficient, e.g., 2L rather than 2"), "i");
368
370
}
369
371
if (!isInteger(rows))
370
372
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)));
Copy file name to clipboardExpand all lines: src/openmp-utils.c
+34-26Lines changed: 34 additions & 26 deletions
Original file line number
Diff line number
Diff line change
@@ -12,14 +12,14 @@ static bool RestoreAfterFork = true; // see #2885 in v1.12.0
12
12
staticintgetIntEnv(constchar*name, intdef)
13
13
{
14
14
constchar*val=getenv(name);
15
-
if (val==NULL) returndef;
15
+
if (val==NULL) returndef;
16
16
size_tnchar=strlen(val);
17
-
if (nchar==0) returndef;
17
+
if (nchar==0) returndef;
18
18
char*end;
19
19
errno=0;
20
20
long intans=strtol(val, &end, 10); // ignores leading whitespace. If it fully consumed the string, *end=='\0' and isspace('\0')==false
21
21
while (isspace(*end)) end++; // ignore trailing whitespace
22
-
if (errno|| (size_t)(end-val)!=nchar||ans<1||ans>INT_MAX) {
22
+
if (errno|| (size_t)(end-val)!=nchar||ans<1||ans>INT_MAX) {
23
23
warning(_("Ignoring invalid %s==\"%s\". Not an integer >= 1. Please remove any characters that are not a digit [0-9]. See ?data.table::setDTthreads."), name, val);
24
24
returndef;
25
25
}
@@ -29,23 +29,24 @@ static int getIntEnv(const char *name, int def)
29
29
staticinlineintimin(inta, intb) { returna<b ? a : b; }
30
30
staticinlineintimax(inta, intb) { returna>b ? a : b; }
31
31
32
-
voidinitDTthreads(void) {
32
+
voidinitDTthreads(void)
33
+
{
33
34
// called at package startup from init.c
34
35
// also called by setDTthreads(threads=NULL) (default) to reread environment variables; see setDTthreads below
35
36
// No verbosity here in this setter. Verbosity is in getDTthreads(verbose=TRUE)
ans=imin(ans, omp_get_num_procs()); // num_procs is a hard limit; user cannot achieve more. ifndef _OPENMP then myomp.h defines this to be 1
39
40
} else {
40
41
// Only when R_DATATABLE_NUM_THREADS is unset (or <=0) do we use PROCS_PERCENT; #4514
41
42
intperc=getIntEnv("R_DATATABLE_NUM_PROCS_PERCENT", 50); // use "NUM_PROCS" to use the same name as the OpenMP function this uses
42
43
// 50% of logical CPUs by default; half of 8 is 4 on laptop with 4 cores. Leaves plenty of room for other processes: #3395 & #3298
43
-
if (perc<=1||perc>100) {
44
+
if (perc <= 1||perc>100) {
44
45
warning(_("Ignoring invalid R_DATATABLE_NUM_PROCS_PERCENT==%d. If used it must be an integer between 2 and 100. Default is 50. See ?setDTtheads."), perc);
45
46
// not allowing 1 is to catch attempts to use 1 or 1.0 to represent 100%.
46
47
perc=50;
47
48
}
48
-
ans=imax(omp_get_num_procs()*perc/100, 1); // imax for when formula would result in 0.
49
+
ans=imax(omp_get_num_procs()*perc / 100, 1); // imax for when formula would result in 0.
49
50
}
50
51
ans=imin(ans, omp_get_thread_limit()); // honors OMP_THREAD_LIMIT when OpenMP started; e.g. CRAN sets this to 2. Often INT_MAX meaning unlimited/unset
51
52
ans=imin(ans, omp_get_max_threads()); // honors OMP_NUM_THREADS when OpenMP started, plus reflects any omp_set_* calls made since
@@ -57,24 +58,27 @@ void initDTthreads(void) {
57
58
DTthrottle=imax(1, getIntEnv("R_DATATABLE_THROTTLE", 1024)); // 2nd thread is used only when n>1024, 3rd thread when n>2048, etc
// If a CPU has been unplugged (high end servers allow live hardware replacement) then omp_get_num_procs() will
124
129
// reflect that and a call to setDTthreads(threads=NULL) will update DTthreads.
125
130
} elseif (length(threads)) {
126
-
intn=0;
127
-
if (length(threads)!=1|| !isInteger(threads) || (n=INTEGER(threads)[0]) <0) { // <0 catches NA too since NA is negative (INT_MIN)
131
+
intn=0;
132
+
if (length(threads)!=1|| !isInteger(threads) || (n=INTEGER(threads)[0]) <0) { // <0 catches NA too since NA is negative (INT_MIN)
128
133
error(_("threads= must be either NULL or a single number >= 0. See ?setDTthreads."));
129
134
}
130
135
intnum_procs=imax(omp_get_num_procs(), 1); // max just in case omp_get_num_procs() returns <= 0 (perhaps error, or unsupported)
131
-
if (!isLogical(percent) ||length(percent)!=1||LOGICAL(percent)[0]==NA_LOGICAL) {
136
+
if (!isLogical(percent) ||length(percent)!=1||LOGICAL(percent)[0]==NA_LOGICAL) {
132
137
internal_error(__func__, "percent= must be TRUE or FALSE at C level"); // # nocov
133
138
}
134
139
if (LOGICAL(percent)[0]) {
135
-
if (n<2||n>100) internal_error(__func__, "threads==%d should be between 2 and 100 (percent=TRUE at C level)", n); // # nocov
136
-
n=num_procs*n/100; // if 0 it will be reset to 1 in the imax() below
140
+
if (n<2||n>100) internal_error(__func__, "threads==%d should be between 2 and 100 (percent=TRUE at C level)", n); // # nocov
141
+
n=num_procs*n / 100; // if 0 it will be reset to 1 in the imax() below
137
142
} else {
138
-
if (n==0||n>num_procs) n=num_procs; // setDTthreads(0) == setDTthread(percent=100); i.e. use all logical CPUs (the default in 1.12.0 and before, from 1.12.2 it's 50%)
143
+
if (n==0||n>num_procs) n=num_procs; // setDTthreads(0) == setDTthread(percent=100); i.e. use all logical CPUs (the default in 1.12.0 and before, from 1.12.2 it's 50%)
139
144
}
140
145
n=imin(n, omp_get_thread_limit()); // can't think why this might be different from its value on startup, but call it just in case
141
146
n=imin(n, getIntEnv("OMP_THREAD_LIMIT", INT_MAX)); // user might have called Sys.setenv(OMP_THREAD_LIMIT=) since startup and expect setDTthreads to respect it
error(_("Attempting to substitute '%s' element with object of type '%s' but it has to be 'symbol' type when substituting name of the call argument, functions 'as.name' and 'I' can be used to work out proper substitution, see ?substitute2 examples."), CHAR(STRING_ELT(arg_names, i)), type2char(TYPEOF(sym)));
18
19
SET_TAG(tmp, sym);
19
20
}
20
21
UNPROTECT(1); // chmatch
21
22
}
22
-
for (SEXPtmp=expr; tmp!=R_NilValue; tmp=CDR(tmp)) { // recursive call to substitute in nested expressions
23
+
for (SEXPtmp=expr; tmp!=R_NilValue; tmp=CDR(tmp)) { // recursive call to substitute in nested expressions
0 commit comments