Ответ 1
Это действительно зависит от того, что вы хотите использовать в качестве временной структуры, потому что в конце концов вам придется выделять вектор для результата в любом случае. Так что бы вы ни использовали, это не то, что вы вернетесь. Существует несколько возможностей:
- используйте
Calloc
+Realloc
+Free
, который позволяет вам развернуть временную память по мере необходимости. Когда у вас есть полный набор, вы выделяете вектор результата и возвращаете его. - если вы можете легко переоценить размер, вы можете перераспределить вектор результата и использовать
SETLENGTH
, прежде чем возвращать его. Есть проблемы с этим, хотя, потому что результат будет по-прежнему перенаправлен до дублирования позже. - Вы можете использовать то, что вы намекали, в котором есть скопированный список векторных блоков, т.е. выделять и защищать один парный список, который вы добавляете к хвосту в соответствии с вашими потребностями. В конце вы выделяете вектор возврата и копируете содержимое выделенных вами блоков. Это более сложное, чем оба из вышеперечисленных.
У каждого из них есть недостатки и преимущества, поэтому на самом деле это зависит от вашего приложения, чтобы выбрать наиболее подходящий для вас.
Изменить: добавлен пример использования подхода с парами. Я бы по-прежнему рекомендовал подход Realloc
, поскольку он намного проще, но тем не менее:
#define BLOCK_SIZE xxx /* some reasonable size for increments - could be adaptive, too */
SEXP block; /* last vector block */
SEXP root = PROTECT(list1(block = allocVector(REALSXP, BLOCK_SIZE)));
SEXP tail = root;
double *values = REAL(block);
int count = 0, total = 0;
do { /* your code to generate values - if you want to add one
first try to add it to the existing block, otherwise allocate new one */
if (count == BLOCK_SIZE) { /* add a new block when needed */
tail = SETCDR(tail, list1(block = allocVector(REALSXP, BLOCK_SIZE)));
values = REAL(block);
total += count;
count = 0;
}
values[count++] = next_value;
} while (...);
total += count;
/* when done, we need to create the result vector */
{
SEXP res = allocVector(REALSXP, total);
double *res_values = REAL(res);
while (root != R_NilValue) {
int size = (CDR(root) == R_NilValue) ? count : BLOCK_SIZE;
memcpy(res_values, REAL(CAR(root)), sizeof(double) * size);
res_values += size;
root = CDR(root);
}
UNPROTECT(1);
return res;
}