Skip to content

Commit 3846cc9

Browse files
committed
memrecycle(): replace TRUELENGTH marks with a hash
1 parent 5782a7a commit 3846cc9

File tree

1 file changed

+9
-24
lines changed

1 file changed

+9
-24
lines changed

src/assign.c

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -827,29 +827,18 @@ const char *memrecycle(const SEXP target, const SEXP where, const int start, con
827827
const int nTargetLevels=length(targetLevels), nSourceLevels=length(sourceLevels);
828828
const SEXP *targetLevelsD=STRING_PTR_RO(targetLevels), *sourceLevelsD=STRING_PTR_RO(sourceLevels);
829829
SEXP newSource = PROTECT(allocVector(INTSXP, length(source))); protecti++;
830-
savetl_init();
830+
hashtab * marks = hash_create((size_t)nTargetLevels + nSourceLevels);
831831
for (int k=0; k<nTargetLevels; ++k) {
832832
const SEXP s = targetLevelsD[k];
833-
const int tl = TRUELENGTH(s);
834-
if (tl>0) {
835-
savetl(s);
836-
} else if (tl<0) {
837-
// # nocov start
838-
for (int j=0; j<k; ++j) SET_TRUELENGTH(s, 0); // wipe our negative usage and restore 0
839-
savetl_end(); // then restore R's own usage (if any)
840-
internal_error(__func__, "levels of target are either not unique or have truelength<0"); // # nocov
841-
// # nocov end
842-
}
843-
SET_TRUELENGTH(s, -k-1);
833+
hash_set(marks, s, -k-1);
844834
}
845835
int nAdd = 0;
846836
for (int k=0; k<nSourceLevels; ++k) {
847837
const SEXP s = sourceLevelsD[k];
848-
const int tl = TRUELENGTH(s);
838+
const int tl = hash_lookup(marks, s, 0);
849839
if (tl>=0) {
850840
if (!sourceIsFactor && s==NA_STRING) continue; // don't create NA factor level when assigning character to factor; test 2117
851-
if (tl>0) savetl(s);
852-
SET_TRUELENGTH(s, -nTargetLevels-(++nAdd));
841+
hash_set(marks, s, -nTargetLevels-(++nAdd));
853842
} // else, when sourceIsString, it's normal for there to be duplicates here
854843
}
855844
const int nSource = length(source);
@@ -858,45 +847,41 @@ const char *memrecycle(const SEXP target, const SEXP where, const int start, con
858847
const int *sourceD = INTEGER(source);
859848
for (int i=0; i<nSource; ++i) { // convert source integers to refer to target levels
860849
const int val = sourceD[i];
861-
newSourceD[i] = val==NA_INTEGER ? NA_INTEGER : -TRUELENGTH(sourceLevelsD[val-1]); // retains NA factor levels here via TL(NA_STRING); e.g. ordered factor
850+
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
862851
}
863852
} else {
864853
const SEXP *sourceD = STRING_PTR_RO(source);
865854
for (int i=0; i<nSource; ++i) { // convert source integers to refer to target levels
866855
const SEXP val = sourceD[i];
867-
newSourceD[i] = val==NA_STRING ? NA_INTEGER : -TRUELENGTH(val);
856+
newSourceD[i] = val==NA_STRING ? NA_INTEGER : -hash_lookup(marks, val, 0);
868857
}
869858
}
870859
source = newSource;
871-
for (int k=0; k<nTargetLevels; ++k) SET_TRUELENGTH(targetLevelsD[k], 0); // don't need those anymore
860+
for (int k=0; k<nTargetLevels; ++k) hash_set(marks, targetLevelsD[k], 0); // don't need those anymore
872861
if (nAdd) {
873862
// cannot grow the levels yet as that would be R call which could fail to alloc and we have no hook to clear up
874863
SEXP *temp = (SEXP *)malloc(nAdd * sizeof(SEXP *));
875864
if (!temp) {
876865
// # nocov start
877-
for (int k=0; k<nSourceLevels; ++k) SET_TRUELENGTH(sourceLevelsD[k], 0);
878-
savetl_end();
879866
error(_("Unable to allocate working memory of %zu bytes to combine factor levels"), nAdd*sizeof(SEXP *));
880867
// # nocov end
881868
}
882869
for (int k=0, thisAdd=0; thisAdd<nAdd; ++k) { // thisAdd<nAdd to stop early when the added ones are all reached
883870
SEXP s = sourceLevelsD[k];
884-
int tl = TRUELENGTH(s);
871+
int tl = hash_lookup(marks, s, 0);
885872
if (tl) { // tl negative here
886873
if (tl != -nTargetLevels-thisAdd-1) internal_error(__func__, "extra level check sum failed"); // # nocov
887874
temp[thisAdd++] = s;
888-
SET_TRUELENGTH(s,0);
875+
hash_set(marks, s, 0);
889876
}
890877
}
891-
savetl_end();
892878
setAttrib(target, R_LevelsSymbol, targetLevels=growVector(targetLevels, nTargetLevels + nAdd));
893879
for (int k=0; k<nAdd; ++k) {
894880
SET_STRING_ELT(targetLevels, nTargetLevels+k, temp[k]);
895881
}
896882
free(temp);
897883
} else {
898884
// all source levels were already in target levels, but not with the same integers; we're done
899-
savetl_end();
900885
}
901886
// now continue, but with the mapped integers in the (new) source
902887
}

0 commit comments

Comments
 (0)