Skip to content

Commit 783d9d9

Browse files
committed
interim
1 parent 08d6414 commit 783d9d9

File tree

1 file changed

+48
-0
lines changed

1 file changed

+48
-0
lines changed

src/gsumm.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,59 @@ SEXP gforce(SEXP env, SEXP jsub, SEXP o, SEXP f, SEXP l, SEXP irowsArg) {
205205
UNPROTECT(1);
206206
ans = tt;
207207
}
208+
209+
// now replicate group values to match the number of rows in each group
210+
// in most cases gfuns return one value per group and there is little to do here
211+
// however, in first/last with na.rm=TRUE, each column could have a different
212+
// number of non-NA values, so those need to be padded
213+
lens = allocVector(INTSXP, ngrp); // TODO: avoid allocatation if not necessary
214+
int *anslens = INTEGER(lens);
215+
memset(anslens, 0, ngrp*sizeof(int));
216+
int anslen=0;
208217
for (int i=0; i<LENGTH(ans); ++i) {
209218
SEXP tt = VECTOR_ELT(ans, i);
219+
SEXP lens = getAttrib(tt, sym_lens);
220+
anslen=0;
221+
if (!isNull(lens)) {
222+
const int *ss = INTEGER(lens);
223+
anslen=0; // count again as the next column might make it bigger
224+
for (g=0; g<ngrp; ++g) {
225+
if (ss[g]>anslens[g]) anslens[g]=ss[g];
226+
anslen += anslens[g];
227+
}
228+
}
210229
setAttrib(tt, sym_lens, R_NilValue);
211230
setAttrib(tt, sym_first, R_NilValue);
212231
}
232+
// now we have the max size of each group across the columns, we can pad if necessary
233+
234+
// so, we either create another column, or we budge up/down the padding within the same allocated column
235+
// budging up/down many small groups will take a lot of reads and writes, albeit saving total memory. The extra
236+
// memory is only one-at-a-time per column, so choose speed over memory here
237+
238+
// now we know the final result size, allocate and fill
239+
for (int i=0; i<LENGTH(ans); ++i) {
240+
SEXP tt = VECTOR_ELT(ans, i);
241+
SEXP lens = getAttrib(tt, sym_lens); // how long the items are, we will never parallelize within column so we can sweep forwards
242+
const bool first = LOGICAL(getAttrib(tt, sym_first))[0];
243+
244+
col = allocVector(TYPEOF(tt), anslen);
245+
246+
anslen=0;
247+
248+
if (!isNull(lens)) {
249+
const int *ss = INTEGER(lens);
250+
anslen=0; // count again as the next column might make it bigger
251+
for (g=0; g<ngrp; ++g) {
252+
const int targetlen = anslens[g];
253+
thislen = ss[g];
254+
const int napad = anslen[g]-ss[g];
255+
if (!first) for (int i=0; i<napad; ++i) ASSIGNNA;
256+
for (int i=0; i<thislen; ++i) COPYVAL;
257+
if (first) for (int i=0; i<napad; ++i) ASSIGNNA;
258+
}
259+
}
260+
}
213261
UNPROTECT(1);
214262
return ans;
215263
}

0 commit comments

Comments
 (0)