// #define type <type of array>
// #define type_null <value to return for empty array>
#define TOKENIZE(a,b) a##b
#define TEMPLATE(a,b) TOKENIZE(a,b)
#define type_null TEMPLATE(type,_null)

// TO DO: add macro to compute element starting at end of array
// IDEA: realloc that can take a pointer anywhere in the malloced buffer

#define push TEMPLATE(type,Push)
// push - add element to beginning (prepend)
void push(type **array,int *len,type value) {
  int i;
  len[0]++;
  array[0] = realloc(array[0],len[0] * sizeof(type));
  for (i=len[0]-1;i>0;i--) {
    array[0][i] = array[0][i-1];
  }
  array[0][0] = value;
}

#define pop TEMPLATE(type,Pop)
// pop - remove element from beginning (delete)
type pop(type **array,int *len) {
  type ret;
  int i;

  if (len[0] == 0) return (type)type_null;
  ret = array[0][0];
  for (i=0;i<len[0]-1;i++) {
    array[0][i] = array[0][i+1];
  }
  len[0]--;
  array[0] = realloc(array[0],len[0] * sizeof(type));
  return ret;
}

#define pull TEMPLATE(type,Pull)
// pull - remove element from end (delete)
type pull(type **array,int *len) {
  type ret;
  if (len[0] == 0) return (type)type_null;
  ret = array[0][len[0]-1];
  len[0]--;
  array[0] = realloc(array[0],len[0] * sizeof(type));
  return ret;
}

#define queue TEMPLATE(type,Queue)
// queue - add element to end (append)
void queue(type **array,int *len,type value) {
  len[0]++;
  array[0] = realloc(array[0],len[0] * sizeof(type));
  array[0][len[0]-1] = value;
}

#define delete TEMPLATE(type,Delete)
// delete - remove elements from array
void delete(type **array,int *len,int offset,int count) {
  int i;
  if (offset >= len[0] || offset < 0) return;
  if (offset+count > len[0]) count = len[0] - offset;
  for (i=offset;i<len[0]-count;i++) {
    array[0][i] = array[0][i+count];
  }
  len[0]-=count;
  array[0] = realloc(array[0],len[0] * sizeof(type));
}

#define before TEMPLATE(type,Insert)
// before - insert element into array before the specified offset
void before(type **array,int *len,int offset,type value) {
  int i;
  if (offset >= len[0] || offset < 0) return;
  len[0]++;
  array[0] = realloc(array[0],len[0] * sizeof(type));
  for (i=len[0];i>offset;i--) {
    array[0][i] = array[0][i-1];
  }
  array[0][offset] = value;
}

// push(array,len,value) == before(array,len,0,value);

// after - insert element into array after the specified offset
// queue(array,len,value) == after(array,len,len[0]-1,value);

// subarr - return a new array containing part of the current array

#undef F0
#undef F1
#undef push
#undef pop
#undef pull
#undef queue
#undef type
