/* ,file-id archive://[lord]/378/vu/./ar.c/1998-05-18
 */
/*	Copyright (C) 1997 Tom Lord
 * 
 * This program is provided to you under the terms of the Liberty Software
 * License.  You are NOT permitted to redistribute, modify, or use it
 * except in very specific ways described by that license.
 *
 * This software comes with NO WARRANTY.
 * 
 * You should have received a copy of the Liberty Software License
 * along with this software; see the file =LICENSE.  If not, write to
 * the Tom Lord, 1810 Francisco St. #2, Berkeley CA, 94703, USA.  
 */



#include "xmalloc.h"
#include "ar.h"

/* int asize (void * base);
 *
 *   Return the number of elements in the array. 
 *   If "base == 0", return 0.
 */
int
asize (void * base)
{
  if (!base)
    return 0;
  else
    {
      int * size;
      size = (int *)(base - 1);
      return *size;
    }
}

/* void * aref (void ** base, int n, int szof);
 *
 *   Return the address of the Nth element of an array,
 *   expanding the array to N elements, if necessary.
 *
 *   SZOF is the size, in bytes, of one element.
 *   BASE is a pointer to a pointer to the array.
 *
 *   This function may resize and relocate the array.
 *   If it does, "*BASE" is updated to point to the new
 *   location of the array.
 */
void *
aref (void ** base, int n, int szof)
{
  int * size;
  char * b;

  if (!*base)
    {
      b = sizeof (void *) + (char *)xmalloc (sizeof (void *) + szof * (n + 1));
      size = (int *)(b - sizeof (void *));
      memset (b, 0, szof * (n + 1));
      *size = n + 1;
      *base = b;
    }
  else
    {
      b = (char *)*base;
      size = (int *)(b - sizeof (void *));
      if (*size < (n + 1))
	{
	  int old_size;
	  old_size = *size;
	  b = sizeof (void *) + (char *)xrealloc (size, (sizeof (void *) + szof * (n + 1)));
	  size = (int *)(b - sizeof (void *));
	  memset (b + old_size * szof, 0, (n + 1 - old_size) * szof);
	  *size = n + 1;
	  *base = b;
	}
    }
  return b + szof * n;
}


/* void asetsize (void ** base, int n, int szof);
 *
 *   Resize the array so that it contains exactly N
 *   elements.
 *
 *   SZOF is the size, in bytes, of one element.
 *   BASE is a pointer to a pointer to the array.
 *
 *   This function may resize and relocate the array.
 *   If it does, "*BASE" is updated to point to the new
 *   location of the array.
 */
void
asetsize (void ** base, int n, int szof)
{
  if (!szof && !*base)
    return;

  aref (base, n - 1, szof);
  *((int *)(*base - 1)) = n;
}

/* void * apush (void ** base, int szof);
 *
 *   Return the address of a new N+1th element
 *   in an array previously containing only N elements.
 *
 *   SZOF is the size, in bytes, of one element.
 *   BASE is a pointer to a pointer to the array.
 *
 *   This function may resize and relocate the array.
 *   If it does, "*BASE" is updated to point to the new
 *   location of the array.
 */
void *
apush (void ** base, int szof)
{
  return aref (base, asize (*base), szof);
}

/* void * apop (void ** base, int szof);
 *
 *   Return the address of the N-1th element
 *   in an array previously containing N elements.
 *   Resize the array so that it contains only N-1 
 *   elements.
 *
 *   SZOF is the size, in bytes, of one element.
 *   BASE is a pointer to a pointer to the array.
 *
 *   This function may resize and relocate the array.
 *   If it does, "*BASE" is updated to point to the new
 *   location of the array.
 */
void *
apop (void ** base, int szof)
{
  asetsize (base, asize (*base) - 1, szof);
  return aref (base, asize (*base) - 1, szof);
}

/* void afree (void ** base);
 * 
 *    Release storage associated with the array pointed
 *    to by "*BASE".  Set "*BASE" to 0.
 */
void
afree (void ** base)
{
  xfree ((char *)*base - sizeof (void *));
  *base = 0;
}


