/*
  Implementation of arrays that can grow in size.

  Diego Zamboni, Mar 7, 1997.

  */

/* Chunk sizes in which the array grows */
#define EXT_ARRAY_CHUNK_SIZE  50

typedef struct ext_array_struct {
    int size;   /* Total number of units which have been allocated for
		   storage of the extendable array */
    int elems;  /* last_elem+1 */
    int last_elem; /* Largest index of all elements which have been set */
    void *data;
} extendable_array;

/* This is all implemented with macros to allow for specification of
   types. */

/* Inserts an element in the next available free spot in the array */
#define EXT_ARRAY_ADD(var,type,val) \
{\
   EXT_ARRAY_SET(var,type,var.elems,val);\
}

/* Initialize a variable of type extendable_array */
#define EXT_ARRAY_INIT(var,type,inisize) \
{\
  int i;\
  var.size=inisize;\
  var.elems=0;\
  var.last_elem=-1;\
  var.data=(type *)malloc(sizeof(type) * inisize);\
  for (i=0; i < inisize; i++)\
    ((type *)var.data)[i] = 0;\
}


/* Set the n-th element of the array to a value, extending the array
 * if necessary.  All elements which are added to the array and not
 * explicitly set to a value are given the value of 0. */
#define EXT_ARRAY_SET(var,type,n,val) \
{\
     int ext_index;\
     if(n >= var.size) {\
	var.data = (type *)realloc(var.data,\
				   sizeof(type)*\
				   (((n/EXT_ARRAY_CHUNK_SIZE)+1)*\
				    EXT_ARRAY_CHUNK_SIZE));\
	var.size = (((n/EXT_ARRAY_CHUNK_SIZE)+1)*\
		    EXT_ARRAY_CHUNK_SIZE);\
     }\
     if (n >= var.elems){\
       for (ext_index=var.elems; ext_index <= n; ext_index++)\
	 ((type *) var.data)[ext_index] = 0;\
	var.elems = n+1;\
     }\
     if(n >= var.last_elem) {\
	var.last_elem = n;\
     }\
     ((type *) var.data)[n]=val;\
}\

/* Initialize for n elements and set elements to val.  We can save a lot of
 * manipulations of parts of var until we're finished. */
#define EXT_ARRAY_INIT_N_SET(var,type,inisize,val) \
{\
  int i;\
  (var).size=(inisize);\
  (var).data=(type *)malloc(sizeof(type) * (inisize));\
  for (i=0; i < (inisize); i++)\
    ((type *)var.data)[i] = (val);\
  (var).elems = (inisize);\
  (var).last_elem = (inisize);\
}

/* Get the value of an element.  If index is out of range, returns 0 */
#define EXT_ARRAY_GET(var,type,n) \
((n < var.elems && n >= 0) ? (((type *)(var.data))[n]) : (type) 0)

/* Free memory used by extended array - array must be initialized to become
   usable again. */
/* written by Jason Rennie <jr6b+@andrew.cmu.edu> for ifile */
#define EXT_ARRAY_FREE(var,type) \
{\
   free((type *)var.data);\
   var.data = NULL;\
}

/* Free memory used by elements of array (elements MUST be pointers) */
/* written by Jason Rennie <jr6b+@andrew.cmu.edu> for ifile */
#define EXT_ARRAY_FREE_ELEMS(var,type) \
{\
  int i;\
  for (i=0; i < var.elems; i++) \
    {\
       if (((type *)var.data)[i] != NULL) \
       {\
	  free(((type *)var.data)[i]); \
	  ((type *)var.data)[i] = NULL; \
       }\
    }\
  var.elems=0;\
  var.last_elem=-1;\
}
