
/*
 * Portable Object Compiler (c) 1998.  All Rights Reserved.
 * $Id$
 */

/*
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Library General Public License as published 
 * by the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "config.h"
#include <assert.h>
#include <string.h>
#include "idarray.h"
#include "ocstring.h"
#include "ascfiler.h"

#define DEFAULT_CAPACITY (16)

@implementation IdArray

/*****************************************************************************
 *
 * Creation
 *
 ****************************************************************************/


#if 0
static void 
idfill(id *p, id v, int c)
{
  while (c--) {
    *p++ = v;
  }
}
#endif

static void 
init(idary_t self, id v, int c)
{
  id *p = (id *) OC_Calloc(c * sizeof(id));

  self->capacity = c;
  self->ptr = p;
}

+ new
{
  id newObj = [super new];

  init([newObj idaryvalue], nil, DEFAULT_CAPACITY);
  return newObj;
}

+ new:(unsigned)n
{
  id newObj = [super new];

  init([newObj idaryvalue], nil, n);
  return newObj;
}

+ with:(int)nArgs,...
{
  /* use OC macros for porting to SunOS4 */
  unsigned i;
  OC_VA_LIST vp;
  id newObject = [self new:nArgs];

  /* #if 0 this piece of code if problems with stdarg
   * typically this means the driver is not configured with
   * the right -builtintype
   * or builtinfunction flags (because the macros might expand to these)
   * 
   * alternative solution: check the .P output (-retain) and 
   * do a setenv OBJCOPT -builtinfunction __builtin_foo
   * (and please let me know)
   */

#ifdef NSTDARG
  [self notImplemented];
#else
  OC_VA_START(vp, nArgs);
  for (i = 0; i < nArgs; i++) {
    id anObject = OC_VA_ARG(vp, id);

    [newObject at:i put:anObject];
  }
  OC_VA_END(vp);
#endif

  return newObject;
}

static void 
idncpy(id *p, id *q, int n)
{
  while (n--) {
    *p++ = *q++;
  }
}

static void 
copy(idary_t dst, idary_t src)
{
  int n = src->capacity;

  dst->capacity = n;
  dst->ptr = (id *) OC_Malloc(n * sizeof(id));

  idncpy(dst->ptr, src->ptr, n);
}

- copy
{
  id aCopy = [super copy];

  copy([aCopy idaryvalue], (&value));
  return aCopy;
}

static void 
idndeepcpy(id *p, id *q, int n)
{
  while (n--) {
    *p++ = [*q++ deepCopy];
  }
}

static void 
deepcopy(idary_t dst, idary_t src)
{
  int n = src->capacity;

  dst->capacity = n;
  dst->ptr = (id *) OC_Malloc(n * sizeof(id));

  idndeepcpy(dst->ptr, src->ptr, n);
}

- deepCopy
{
  id aCopy = [super copy];

  deepcopy([aCopy idaryvalue], (&value));
  return aCopy;
}

static void 
clear(idary_t self)
{
  OC_Free(self->ptr);
  self->ptr = NULL;
}

- free
{
  clear((&value));
  return [super free];
}

/*****************************************************************************
 *
 * Interrogation
 *
 ****************************************************************************/

- (idary_t) idaryvalue
{
  return (&value);
}

static unsigned 
getsize(idary_t self)
{
  unsigned s = 0;
  int i = self->capacity;

  while (i--)
    if ((self->ptr) [i])
      s++;
  return s;
}

- (unsigned) size
{
  return getsize((&value));
}

static id 
at(idary_t self, int i)
{
  if (0 <= i && i < self->capacity) {
    return (self->ptr) [i];
  } else {
    [IdArray error:"Index out of bounds"];
    return nil;
  }
}

- at:(unsigned)anOffset
{
  return at((&value), anOffset);
}

static id 
idputid(id *self, id c)
{
  id r = *self;

  *self = c;
  return r;
}

static id 
putat(idary_t self, int i, id c)
{
  if (0 <= i && i < self->capacity) {
    return idputid(self->ptr + i, c);
  } else {
    [IdArray error:"Index out of bounds"];
    return nil;
  }
}

- at:(unsigned)anOffset put:anObject
{
  return putat((&value), anOffset, anObject);
}

/*****************************************************************************
 *
 * Resizing
 *
 ****************************************************************************/

- (unsigned) capacity
{
  return ((&value)->capacity);
}

static void 
resize(idary_t self, unsigned c)
{
  int min, n;
  id *newp = (id *) OC_Realloc(self->ptr, c * sizeof(id));

  n = self->capacity;
  min = (n < c) ? n : c;
  memset(newp + min, 0, sizeof(id) * (c - min));

  self->ptr = newp;
  self->capacity = c;
}

- capacity:(unsigned)nSlots
{
  resize((&value), nSlots);
  return self;
}

static void 
removenils(id *to, id *limit)
{
  id *from;

  while ((to < limit) && (*to != nil)) {
    to++;
  }
  for (from = to + 1; from < limit; from++) {
    if (*from)
      *to++ = *from;
  }
  while (to < limit) {
    *to++ = nil;
  }
}

static void 
packcontents(idary_t self)
{
  removenils(self->ptr, self->ptr + self->capacity);
}

- packContents
{
  packcontents((&value));
  return self;
}

/*****************************************************************************
 *
 * Printing
 *
 ****************************************************************************/

- printOn:(IOD)aFile
{
  unsigned i, n = [self size];

  if (n) {
    id o = [self at:0];

    if (o)
      [o printOn:aFile];
    else
      fprintf(aFile, "nil");
  }
  for (i = 0; i < n; i++) {
    id o = [self at:i];

    fprintf(aFile, ",");
    if (o)
      [o printOn:aFile];
    else
      fprintf(aFile, "nil");
  }

  return self;
}

/*****************************************************************************
 *
 * Archiving
 *
 ****************************************************************************/

#ifdef __PORTABLE_OBJC__
static void 
idfileout(id aFiler, id *p, int n)
{
  while (n--) {
    [aFiler fileOut:p++ type:'@'];
  }
}

static void 
idfilein(id aFiler, id *p, int n)
{
  while (n--) {
    [aFiler fileIn:p++ type:'@'];
  }
}

static void 
fileout(id aFiler, idary_t self)
{
  [aFiler fileOut:&self->capacity type:'i'];
  idfileout(aFiler, self->ptr, self->capacity);
}

static void 
filein(id aFiler, idary_t self)
{
  [aFiler fileIn:&self->capacity type:'i'];
  self->ptr = (id *) OC_Malloc(self->capacity * sizeof(id));

  idfilein(aFiler, self->ptr, self->capacity);
}

- fileOutOn:aFiler
{
  [super fileOutOn:aFiler];
  fileout(aFiler, (&value));
  return self;
}

- fileInFrom:aFiler
{
  [super fileInFrom:aFiler];
  filein(aFiler, (&value));
  return self;
}

#endif				/* __PORTABLE_OBJC__ */

@end
 
