/*
 *
 * $Header: /usr/u/wjr/src/ADT/RCS/vector.h,v 1.14 1992/08/20 21:09:19 rucklidg Exp $
 *
 * Copyright (c) 1990, 1991, 1992 Cornell University.  All Rights Reserved.  
 *  
 * Copyright (c) 1991, 1992 Xerox Corporation.  All Rights Reserved.  
 *  
 * Use, reproduction, preparation of derivative works, and distribution
 * of this software is permitted.  Any copy of this software or of any
 * derivative work must include both the above copyright notices of
 * Cornell University and Xerox Corporation and this paragraph.  Any
 * distribution of this software or derivative works must comply with all
 * applicable United States export control laws.  This software is made
 * available AS IS, and XEROX CORPORATION DISCLAIMS ALL WARRANTIES,
 * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
 * AND NOTWITHSTANDING ANY OTHER PROVISION CONTAINED HEREIN, ANY
 * LIABILITY FOR DAMAGES RESULTING FROM THE SOFTWARE OR ITS USE IS
 * EXPRESSLY DISCLAIMED, WHETHER ARISING IN CONTRACT, TORT (INCLUDING
 * NEGLIGENCE) OR STRICT LIABILITY, EVEN IF XEROX CORPORATION IS ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGES.
 */
/*
 * Header file for vector maintenance routines
 */

#ifndef VECTOR_H
#define VECTOR_H

/* For FILE */
#include <stdio.h>
#include "strings.h"

#ifdef	VECTOR_CHECKALL
/* Need eassert() and panic() */
#include "panic.h"
#endif


typedef unsigned char VectorType;


#define	VECTOR_BINARY	 ((VectorType)  1)   /* The vector types */
#define	VECTOR_GRAY	 ((VectorType)  2)
#define	VECTOR_SHORT	 ((VectorType)  3)
#define	VECTOR_LONG	 ((VectorType)  4)
#define	VECTOR_FLOAT	 ((VectorType)  5)
#define	VECTOR_DOUBLE	 ((VectorType)  6)
#define	VECTOR_PTR	 ((VectorType)  7)
#define VECTOR_RGB       ((VectorType)  8)
#define VECTOR_RGBF      ((VectorType)  9)
#define VECTOR_HSV       ((VectorType) 10)
#define VECTOR_STRUCT    ((VectorType) 11)


struct VectorHeader;

#define DEF_VEC(vecname, elemtype)                                                     \
  typedef struct {                                                                     \
    elemtype *data;                                                                    \
    struct VectorHeader *header;                                                       \
    struct {void *ptr;} userdata;                                                      \
  } *vecname
 
DEF_VEC(BinaryVector, char);
DEF_VEC(GrayVector, uchar);
DEF_VEC(ShortVector, short);
DEF_VEC(LongVector, long);
DEF_VEC(FloatVector, float);
DEF_VEC(DoubleVector, double);
DEF_VEC(PtrVector, void *);
DEF_VEC(RGBVector, RGB);
DEF_VEC(RGBFloatVector, RGBFloat);
DEF_VEC(HSVVector, HSV);

DEF_VEC(AnyVector, void);		     /* generic vector */

#undef DEF_VEC

typedef struct VectorHeader {		     /* An invisible vector header type */
  int length;
  int base;
  VectorType tag;
  AnyVector anyvec;
  short elemsize, headsize;
} VectorHeader;

					     /* Several types of vector */
					     /* and some manipulation routines */
extern void *vec_New_(VectorType type, int length, int base,
		      int elemsize, int headsize, void *dupVec);

extern void vec_Free_(void *vec, VectorType type);
extern void *vec_Dup_(void *vec, VectorHeader *header);
extern void vec_Init_(void *vec, VectorHeader *header, void *val);
extern void vec_SetOffset_(void *vec, VectorHeader *header, int base);
extern void vec_Apply_(void *f, void *vec, VectorHeader *header);


/* define a new structure vector type */
#define vecDefStructVector(VECNAME, ELEMTYPE, USERDATA)                                \
  typedef struct {                                                                     \
    ELEMTYPE *data;                                                                    \
    VectorHeader *header;                                                              \
    USERDATA userdata;                                                                 \
  } *VECNAME

typedef struct {void *ptr;} StdVecUserData;  /* standard vector user data field */

#define vecNewStruct(vectype, l)     vecNewOffsetStruct(vectype, (l), 0)
#define vecNewOffsetStruct(vectype, l, b)                                              \
     ({ vectype __v;                                                                   \
	(vectype) vec_New_(VECTOR_STRUCT, (l), (b),                                    \
		      sizeof(typeof(*(__v->data))), sizeof(typeof(*__v)), NULL);})


#define vecNew(t, l)               vecNewOffset((t), (l), 0)
#define vecNewOffset(t, l, b)      vec_New_((t), (l), (b), 0, 0, NULL)

#define vecNULL  ((AnyVector) NULL)


#ifndef	VECTOR_CHECKALL			     /* and some useful routines */
#define	vecGetLength(v)	({ (v)->header->length; })
#define	vecGetBase(v)	({ (v)->header->base; })
#define vecGetType(v)	({ (v)->header->tag; })
#define vecUserData(v)  ((v)->userdata)
#else
#define	vecGetLength(v)	({ assert((v) != NULL); (v)->header->length; })
#define	vecGetBase(v)	({ assert((v) != NULL); (v)->header->base; })
#define vecGetType(v)	({ assert((v) != NULL); (v)->header->tag; })
#define vecUserData(v)  (eassert((v) != NULL), ((v)->userdata))
#endif
			 
#define vecGetStore(v)     ({ &(vecRef((v), vecGetBase(v))); })
#define vecGetMax(v)       (vecGetBase(v) + vecGetLength(v) - 1)
#define vecAnyVector(v)    ((v) ? (v)->header.anyvec : (AnyVector) NULL)

#define vecFree(v)	   vec_Free_((void *)(v), vecGetType((v)))

#ifndef	VECTOR_CHECKALL
#define	vecDup(v)	   vec_Dup_((void *)(v), ((v)->header))
#define vecInit(v, val)    ({ typeof (*((v)->data)) __value = val;                     \
			      vec_Init_((void *)(v), ((v)->header), (void *) &__value);})
#define vecSetOffset(v, b)   vec_SetOffset_((void *)(v), ((v)->header), (b))
#define vecApply(func, v)  ({ void (*__func)(typeof (((v)->data)) valp, int i) = func; \
			      vec_Apply_((void *) __func, (void *)(v), ((v)->header));})
#else
#define	vecDup(v)	(eassert((v) != NULL), (vec_Dup_((void *)(v), ((v)->header))))
#define vecInit(v, val) (eassert((v) != NULL),                                         \
			 ({ typeof (*((v)->data)) __value = (val);                     \
			    vec_Init_((void *)(v), ((v)->header), (void *) &__value);}))
#define vecSetOffset(v, b) (eassert((v) != NULL),                                      \
			    (vec_SetOffset_((void *)(v), ((v)->header), (b))))
#define vecApply(func, v)  (eassert((v) != NULL), ({ void                              \
			      (*__func)(typeof (((v)->data)) valp, int i) = func;      \
			      vec_Apply_((void *) __func, (void *)(v), ((v)->header));}))
#endif

/* and an access routine - gives an *lvalue* */
#ifndef	VECTOR_CHECKALL
#define	vecRef(v, i)	(((v)->data)[(i)])
#else
static char __vecPanicStr[100];
#define	vecRef(v, i)	(eassert(v != NULL),                                           \
			 ((((i) < (v)->header->base) ||                                \
			   ((i) >= (v)->header->base + (v)->header->length))           \
			  ? ({ sprintf(__vecPanicStr,                                  \
				       "vector bounds check fail: "                    \
				       "%d <= %d < %d",                                \
				       (v)->header->base,                              \
				       (i),                                            \
				       (v)->header->base + (v)->header->width);        \
			       panic(__vecPanicStr);}), ((v)->data[0])                 \
			  : (((v)->data)[(i)])))
#endif

#endif
