Skip to content

Commit 253f14e

Browse files
author
maechler
committed
x["a"] <- val should not end up calling EnlargeVector() and hence losing dim+dimnames
git-svn-id: https://svn.r-project.org/R/trunk@89130 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent 680fa55 commit 253f14e

File tree

4 files changed

+58
-46
lines changed

4 files changed

+58
-46
lines changed

doc/NEWS.Rd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,10 @@
444444
\PR{18304}. Its behaviour remains back compatible for now, but can
445445
be switched to future behaviour via enviroment variable
446446
\env{R_sequence_recycle}, or explicit \code{recycle = TRUE}.
447+
448+
\item Subassignment, \code{x[ind] <- val}, to 1-dimensional
449+
\code{array}s no longer \dQuote{drops} them to simple vectors when
450+
\code{ind} is a name, fixing \PR{18973}, reported by \I{Thomas Soeiro}.
447451
}
448452
}
449453
}

src/main/subassign.c

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ static SEXP EnlargeVector(SEXP x, R_xlen_t newlen)
192192
}
193193

194194
if (newlen > len) {
195-
double expanded_nlen = newlen * expand;
195+
double expanded_nlen = (double)newlen * expand;
196196
if (expanded_nlen <= R_XLEN_T_MAX)
197197
newtruelen = (R_xlen_t) expanded_nlen;
198198
else
@@ -322,8 +322,8 @@ static bool dispatch_asvector(SEXP *x, SEXP call, SEXP rho) {
322322
Level 2 is used in do_subassign2_dflt.
323323
This does not coerce when assigning into a list.
324324
*/
325-
326-
static int SubassignTypeFix(SEXP *x, SEXP *y, R_xlen_t stretch, int level,
325+
static int SubassignTypeFix(SEXP *x, SEXP *y, R_xlen_t stretch,
326+
int level,
327327
SEXP call, SEXP rho)
328328
{
329329
/* A rather pointless optimization, but level 2 used to be handled
@@ -494,11 +494,11 @@ static int SubassignTypeFix(SEXP *x, SEXP *y, R_xlen_t stretch, int level,
494494
default:
495495
error(_("incompatible types (from %s to %s) in subassignment type fix"),
496496
R_typeToChar(*x), R_typeToChar(*y));
497-
}
497+
} //--- end switch(which)
498498

499499
if (stretch) {
500500
PROTECT(*y);
501-
*x = EnlargeVector(*x, stretch);
501+
*x = EnlargeVector(*x, stretch); // FIXME: 1d-array w/ {dim,dimnames} |--> vector w/ names
502502
UNPROTECT(1);
503503
}
504504
SET_OBJECT(*x, x_is_object);
@@ -507,7 +507,7 @@ static int SubassignTypeFix(SEXP *x, SEXP *y, R_xlen_t stretch, int level,
507507
return(100 * TYPEOF(*x) + TYPEOF(*y));
508508
else
509509
return(which);
510-
}
510+
} // SubassignTypeFix
511511

512512
#ifdef LONG_VECTOR_SUPPORT
513513
static R_INLINE R_xlen_t gi(SEXP indx, R_xlen_t i)
@@ -642,7 +642,6 @@ static SEXP VectorAssign(SEXP call, SEXP rho, SEXP x, SEXP s, SEXP y)
642642

643643
/* Check to see if we have special matrix subscripting. */
644644
/* If so, we manufacture a real subscript vector. */
645-
646645
PROTECT(s);
647646
if (ATTRIB(s) != R_NilValue) { /* pretest to speed up simple case */
648647
SEXP dim = getAttrib(x, R_DimSymbol);
@@ -1612,13 +1611,11 @@ NORET static void errorMissingSubscript(SEXP x)
16121611

16131612
attribute_hidden SEXP do_subassign_dflt(SEXP call, SEXP op, SEXP args, SEXP rho)
16141613
{
1615-
SEXP subs, x, y;
1616-
int nsubs, oldtype;
1617-
16181614
PROTECT(args);
16191615

1620-
nsubs = SubAssignArgs(args, &x, &subs, &y);
1621-
PROTECT(y); /* gets cut loose in SubAssignArs */
1616+
SEXP subs, x, y;
1617+
int nsubs = SubAssignArgs(args, &x, &subs, &y);
1618+
PROTECT(y); /* gets cut loose in SubAssignArgs */
16221619

16231620
/* make sure the LHS is duplicated if it matches one of the indices */
16241621
/* otherwise this gets the wrong answer:
@@ -1642,7 +1639,7 @@ attribute_hidden SEXP do_subassign_dflt(SEXP call, SEXP op, SEXP args, SEXP rho)
16421639
x = SETCAR(args, shallow_duplicate(CAR(args)));
16431640

16441641
bool S4 = IS_S4_OBJECT(x); // {before it is changed}
1645-
oldtype = 0;
1642+
int oldtype = 0;
16461643
if (TYPEOF(x) == LISTSXP || TYPEOF(x) == LANGSXP) {
16471644
oldtype = TYPEOF(x);
16481645
x = PairToVectorList(x);
@@ -1770,12 +1767,12 @@ attribute_hidden SEXP
17701767
do_subassign2_dflt(SEXP call, SEXP op, SEXP args, SEXP rho)
17711768
{
17721769
SEXP dims, indx, names, newname, subs, x, xtop, xup, y, thesub = R_NilValue, xOrig = R_NilValue;
1773-
int i, ndims, nsubs, which, len = 0 /* -Wall */;
1770+
int i, ndims, which, len = 0 /* -Wall */;
17741771
R_xlen_t stretch, offset, off = -1; /* -Wall */
17751772

17761773
PROTECT(args);
17771774

1778-
nsubs = SubAssignArgs(args, &x, &subs, &y);
1775+
int nsubs = SubAssignArgs(args, &x, &subs, &y);
17791776
PROTECT(y); /* gets cut loose in SubAssignArgs */
17801777

17811778
/* Handle NULL left-hand sides. If the right-hand side */

src/main/subscript.c

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -586,16 +586,16 @@ static SEXP nullSubscript(R_xlen_t n)
586586
static SEXP
587587
logicalSubscript(SEXP s, R_xlen_t ns, R_xlen_t nx, R_xlen_t *stretch, SEXP call)
588588
{
589-
R_xlen_t count, i, nmax, i1, i2;
590-
int canstretch;
591-
SEXP indx;
592-
canstretch = *stretch > 0;
589+
bool canstretch = *stretch > 0;
593590
if (!canstretch && ns > nx) {
594591
ECALL(call, _("(subscript) logical subscript too long"));
595592
}
596-
nmax = (ns > nx) ? ns : nx;
597593
*stretch = (ns > nx) ? ns : 0;
598594
if (ns == 0) return(allocVector(INTSXP, 0));
595+
R_xlen_t count, i, i1, i2,
596+
nmax = (ns > nx) ? ns : nx;
597+
SEXP indx; // result
598+
599599
const int *ps = LOGICAL_RO(s); /* Calling LOCICAL_RO here may force a
600600
large allocation, but no larger than
601601
the one made by R_alloc below. This
@@ -709,11 +709,9 @@ logicalSubscript(SEXP s, R_xlen_t ns, R_xlen_t nx, R_xlen_t *stretch, SEXP call)
709709

710710
static SEXP negativeSubscript(SEXP s, R_xlen_t ns, R_xlen_t nx, SEXP call)
711711
{
712-
SEXP indx;
713-
R_xlen_t stretch = 0;
714-
R_xlen_t i;
715-
PROTECT(indx = allocVector(LGLSXP, nx));
712+
SEXP indx = PROTECT(allocVector(LGLSXP, nx));
716713
int *pindx = LOGICAL(indx);
714+
R_xlen_t i;
717715
for (i = 0; i < nx; i++)
718716
pindx[i] = 1;
719717
const int *ps = INTEGER_RO(s);
@@ -722,19 +720,19 @@ static SEXP negativeSubscript(SEXP s, R_xlen_t ns, R_xlen_t nx, SEXP call)
722720
if (ix != 0 && ix != NA_INTEGER && -ix <= nx)
723721
pindx[-ix - 1] = 0;
724722
}
723+
R_xlen_t stretch = 0;
725724
s = logicalSubscript(indx, nx, nx, &stretch, call);
726725
UNPROTECT(1);
727726
return s;
728727
}
729728

730729
static SEXP positiveSubscript(SEXP s, R_xlen_t ns, R_xlen_t nx)
731730
{
732-
SEXP indx;
733731
R_xlen_t i, zct = 0;
734732
const int *ps = INTEGER_RO(s);
735733
for (i = 0; i < ns; i++) if (ps[i] == 0) zct++;
736734
if (zct) {
737-
indx = allocVector(INTSXP, (ns - zct));
735+
SEXP indx = allocVector(INTSXP, (ns - zct));
738736
int *pindx = INTEGER(indx);
739737
for (i = 0, zct = 0; i < ns; i++)
740738
if (ps[i] != 0)
@@ -748,15 +746,13 @@ static SEXP
748746
integerSubscript(SEXP s, R_xlen_t ns, R_xlen_t nx, R_xlen_t *stretch,
749747
SEXP call, SEXP x)
750748
{
751-
R_xlen_t i;
752-
int ii, max, canstretch;
753-
bool isna = false, neg = false;
754-
canstretch = *stretch > 0;
749+
bool isna = false, neg = false,
750+
canstretch = *stretch > 0;
755751
*stretch = 0;
756-
max = 0;
752+
int max = 0;
757753
const int *ps = INTEGER_RO(s);
758-
for (i = 0; i < ns; i++) {
759-
ii = ps[i];
754+
for (R_xlen_t i = 0; i < ns; i++) {
755+
int ii = ps[i];
760756
if (ii < 0) {
761757
if (ii == NA_INTEGER)
762758
isna = true;
@@ -786,7 +782,7 @@ static SEXP
786782
realSubscript(SEXP s, R_xlen_t ns, R_xlen_t nx, R_xlen_t *stretch,
787783
SEXP call, SEXP x)
788784
{
789-
int canstretch = *stretch > 0;
785+
bool canstretch = *stretch > 0;
790786
*stretch = 0;
791787
double min = 0, max = 0;
792788
const double *ps = REAL_RO(s);
@@ -886,21 +882,23 @@ realSubscript(SEXP s, R_xlen_t ns, R_xlen_t nx, R_xlen_t *stretch,
886882
*/
887883

888884
static SEXP
889-
stringSubscript(SEXP s, R_xlen_t ns, R_xlen_t nx, SEXP names,
885+
stringSubscript(SEXP s, R_xlen_t ns /* = xlength(s) */, R_xlen_t nx /* = xlength(x) */,
886+
SEXP names,
890887
R_xlen_t *stretch, SEXP call, SEXP x, int dim)
891888
{
892-
SEXP indx, indexnames = R_NilValue;
893-
R_xlen_t i, j, nnames, extra, sub;
894-
int canstretch = *stretch > 0;
895889
/* product may overflow, so check factors as well. */
896890
bool usehashing = ( ((ns > 1000 && nx) || (nx > 1000 && ns)) || (ns * nx > 15*nx + ns) );
897891
int nprotect = 0;
898-
899892
PROTECT(s);
900893
PROTECT(names);
901894
nprotect += 2;
902-
nnames = nx;
903-
extra = nnames;
895+
896+
SEXP indx, indexnames = R_NilValue;
897+
bool canstretch = *stretch > 0;
898+
*stretch = 0;
899+
R_xlen_t i, sub,
900+
nnames = nx,
901+
extra = nnames;
904902

905903
/* Process each of the subscripts. First we compare with the names
906904
* on the vector and then (if there is no match) with each of the
@@ -927,7 +925,7 @@ stringSubscript(SEXP s, R_xlen_t ns, R_xlen_t nx, SEXP names,
927925
for (i = 0; i < ns; i++) {
928926
sub = 0;
929927
if (names != R_NilValue) {
930-
for (j = 0; j < nnames; j++) {
928+
for (R_xlen_t j = 0; j < nnames; j++) {
931929
SEXP names_j = STRING_ELT(names, j);
932930
if (NonNullStringMatch(STRING_ELT(s, i), names_j)) {
933931
sub = j + 1;
@@ -969,10 +967,11 @@ stringSubscript(SEXP s, R_xlen_t ns, R_xlen_t nx, SEXP names,
969967
}
970968
/* We return the new names as the names attribute of the returned
971969
subscript vector. */
972-
if (extra != nnames)
970+
if (extra != nnames) {
973971
setAttrib(indx, R_UseNamesSymbol, indexnames);
974-
if (canstretch)
975-
*stretch = extra;
972+
if (canstretch)
973+
*stretch = extra;
974+
}
976975
UNPROTECT(nprotect);
977976
return indx;
978977
}
@@ -1090,7 +1089,6 @@ makeSubscript(SEXP x, SEXP s, R_xlen_t *stretch, SEXP call)
10901089
case STRSXP:
10911090
{
10921091
SEXP names = PROTECT(getAttrib(x, R_NamesSymbol));
1093-
/* *stretch = 0; */
10941092
ans = stringSubscript(s, ns, nx, names, stretch, call, x, -1);
10951093
UNPROTECT(1); /* names */
10961094
break;

tests/reg-tests-1e.R

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2449,6 +2449,19 @@ for(recycl in c(FALSE, TRUE)) withAutoprint({
24492449
})
24502450

24512451

2452+
## <1d-arrary>[<name>] <- <val> -- dropped dim & dimnames in transforming to atomic vector -- PR#18973
2453+
mk1d <- function(N) {
2454+
stopifnot(length(N) == 1, N >= 1, is.integer(n <- 1:N))
2455+
array(n, dimnames = list(letters[n]))
2456+
}
2457+
chk1d <- function(a)
2458+
stopifnot(is.array(a), length(d <- dim(a)) == 1L, is.list(dn <- dimnames(a)), length(dn) == 1L)
2459+
str(x <- mk1d(3)); chk1d(x)
2460+
x[1] <- 99 ; chk1d(x)
2461+
x["a"] <- 100; chk1d(x)
2462+
## x["a"] <- .. did drop dim() & dimnames() {getting names() instead}.
2463+
2464+
24522465

24532466
## keep at end
24542467
rbind(last = proc.time() - .pt,

0 commit comments

Comments
 (0)