#include "data.table.h"

SEXP vecseq(SEXP x, SEXP len, SEXP clamp)
{
  // Name taken from bit::vecseq, but,
  //   * implemented in C rather than R
  //   * takes len rather than y endpoints
  //   * no concat=FALSE or eval arguments as not needed.
  //   * Adds clamp to prevent very large vectors being created (unless allow.cartesian=TRUE)
  // Specially for use by [.data.table after binary search. Now so specialized that for general use
  // bit::vecseq is recommended (Jens has coded it in C now).
  R_len_t reslen,i,j,k, thisx;
  double limit;
  SEXP ans;

  if (!isInteger(x)) error("x must be an integer vector");
  if (!isInteger(len)) error("len must be an integer vector");
  if (LENGTH(x) != LENGTH(len)) error("x and len must be the same length");
  reslen = 0;
  for (i=0; i<LENGTH(len); i++) {
    if (INT_MAX-reslen < INTEGER(len)[i])
      error("Join results in more than 2^31 rows (internal vecseq reached physical limit). Very likely misspecified join. Check for duplicate key values in i each of which join to the same group in x over and over again. If that's ok, try by=.EACHI to run j for each group to avoid the large allocation. Otherwise, please search for this error message in the FAQ, Wiki, Stack Overflow and data.table issue tracker for advice.");
    reslen += INTEGER(len)[i];
  }
  if (!isNull(clamp)) {
    if (!isNumeric(clamp) || LENGTH(clamp)!=1) error("clamp must be a double vector length 1");
    limit = REAL(clamp)[0];
    if (limit<0) error("clamp must be positive");
    if (reslen>limit) error("Join results in %d rows; more than %d = nrow(x)+nrow(i). Check for duplicate key values in i each of which join to the same group in x over and over again. If that's ok, try by=.EACHI to run j for each group to avoid the large allocation. If you are sure you wish to proceed, rerun with allow.cartesian=TRUE. Otherwise, please search for this error message in the FAQ, Wiki, Stack Overflow and data.table issue tracker for advice.", reslen, (int)limit);
  }
  ans = PROTECT(allocVector(INTSXP, reslen));
  k = 0;
  for (i=0; i<LENGTH(len); i++) {
    thisx = INTEGER(x)[i];
    for (j=0; j<INTEGER(len)[i]; j++) {
      INTEGER(ans)[k++] = thisx++;
    }
  }
  UNPROTECT(1);
  return(ans);
}

