/* vector.c -- dynamically sized vectors * * This code is Copyright (c) 2013, by the authors of nmh. See the * COPYRIGHT file in the root directory of the nmh distribution for * complete copyright information. */ /* * This file defines several kinds of vectors: * bvector: bit vector * svector: vector of char arrays * ivector: vector of ints * * The interfaces provide only the capabilities needed by nmh. The * implementations rely on dynamic allocation, so that a vector * can be as large as needed, as long as it fits in (virtual) memory. */ #include #include /* The default size of a struct bvector's bits, measured in bits. * The struct's tiny member is used for storage. */ #define BVEC_INIT_SIZE (sizeof *(((bvector_t)NULL)->tiny) * CHAR_BIT) /* The default number of char pointers in a struct svector. */ #define SVEC_INIT_SIZE 256 /* The default number of ints in a struct ivector. */ #define IVEC_INIT_SIZE 256 /* * These try to hide the type of the "bits" member of bvector. But if * that is changed to a type that's wider than unsigned long, the 1ul * constants in the code below must also be changed to a 1 that's at * least as wide as the new type. */ /* The *sizeof* struct bvector's bits member. Not its size in bits. */ #define BVEC_SIZEOF_BITS (sizeof *(((bvector_t)NULL)->bits)) /* The number of bits held in one element of the bits member. */ #define BVEC_BITS_BITS (BVEC_SIZEOF_BITS * CHAR_BIT) /* The index of bit n in struct bvector's bits member. */ #define BVEC_WORD(n) ((n) / BVEC_BITS_BITS) /* The index of bit n within a single struct bvector's bits member. */ #define BVEC_OFFSET(n) ((n) % BVEC_BITS_BITS) /* The number of elements bits needs to cover bit n, measured in bytes. */ #define BVEC_BYTES(n) (((n) / BVEC_BITS_BITS + 1) * BVEC_SIZEOF_BITS) /* bvector_resize ensures the storage used for bits can cover bit * newsize. It always increases the size of the storage used for bits, * even if newsize would have been covered by the existing storage. * Thus it's normally only called when it's known the storage must grow. */ static void bvector_resize (bvector_t vec, size_t newsize); bvector_t bvector_create (void) { bvector_t vec; /* See "wider than unsigned long" comment above. */ assert (sizeof *vec->bits <= sizeof 1ul); NEW(vec); bvector_init(vec); return vec; } void bvector_init(struct bvector *bv) { bv->bits = bv->tiny; bv->maxsize = BVEC_INIT_SIZE; memset(bv->tiny, 0, sizeof bv->tiny); } void bvector_copy (bvector_t dest, bvector_t src) { size_t bytes = BVEC_BYTES(src->maxsize); if (dest->bits != dest->tiny) free(dest->bits); if (bytes <= sizeof dest->tiny) dest->bits = dest->tiny; else dest->bits = mh_xmalloc (bytes); memcpy (dest->bits, src->bits, bytes); dest->maxsize = src->maxsize; } void bvector_free (bvector_t vec) { bvector_fini(vec); free (vec); } void bvector_fini(struct bvector *bv) { if (bv->bits != bv->tiny) free(bv->bits); } void bvector_clear (bvector_t vec, size_t n) { if (n < vec->maxsize) vec->bits[BVEC_WORD(n)] &= ~(1ul << BVEC_OFFSET(n)); } void bvector_clear_all (bvector_t vec) { memset (vec->bits, 0, BVEC_BYTES(vec->maxsize)); } void bvector_set (bvector_t vec, size_t n) { size_t word = BVEC_WORD(n); size_t offset = BVEC_OFFSET(n); if (n >= vec->maxsize) bvector_resize (vec, n); vec->bits[word] |= 1ul << offset; } unsigned int bvector_at (bvector_t vec, size_t i) { if (i < vec->maxsize) return !!(vec->bits[BVEC_WORD(i)] & (1ul << BVEC_OFFSET(i))); return 0; } static void bvector_resize (bvector_t vec, size_t newsize) { size_t oldsize = vec->maxsize; size_t bytes; while ((vec->maxsize *= 2) < newsize) ; bytes = BVEC_BYTES(vec->maxsize); if (vec->bits == vec->tiny) { vec->bits = mh_xmalloc(bytes); memcpy(vec->bits, vec->tiny, sizeof vec->tiny); } else vec->bits = mh_xrealloc(vec->bits, bytes); memset(vec->bits + (oldsize / BVEC_BITS_BITS), 0, (vec->maxsize - oldsize) / CHAR_BIT); } unsigned long bvector_first_bits (bvector_t vec) { return *vec->bits; } struct svector { char **strs; size_t maxsize; size_t size; }; static void svector_resize (svector_t, size_t); svector_t svector_create (size_t init_size) { svector_t vec; size_t bytes; NEW(vec); vec->maxsize = init_size ? init_size : SVEC_INIT_SIZE; bytes = vec->maxsize * sizeof (char *); vec->strs = mh_xcalloc (1, bytes); vec->size = 0; return vec; } void svector_free (svector_t vec) { free (vec->strs); free (vec); } char * svector_push_back (svector_t vec, char *s) { if (++vec->size >= vec->maxsize) svector_resize (vec, vec->size); return vec->strs[vec->size-1] = s; } char * svector_at (svector_t vec, size_t i) { if (i >= vec->maxsize) svector_resize (vec, i); return vec->strs[i]; } /* * Return address of first element that stringwise matches s. * The caller can replace the contents of the return address. */ char ** svector_find (svector_t vec, const char *s) { size_t i; char **str = vec->strs; for (i = 0; i < vec->size; ++i, ++str) { if (*str && ! strcmp(*str, s)) { return str; } } return NULL; } char ** svector_strs (svector_t vec) { return vec->strs; } size_t svector_size (svector_t vec) { return vec->size; } static void svector_resize (svector_t vec, size_t maxsize) { size_t old_maxsize = vec->maxsize; while ((vec->maxsize *= 2) < maxsize) ; vec->strs = mh_xrealloc (vec->strs, vec->maxsize * sizeof (char *)); memset(vec->strs + old_maxsize, 0, (vec->maxsize - old_maxsize) * sizeof *vec->strs); } struct ivector { int *ints; size_t maxsize; size_t size; }; static void ivector_resize (ivector_t, size_t); ivector_t ivector_create (size_t init_size) { ivector_t vec; size_t bytes; NEW(vec); vec->maxsize = init_size ? init_size : IVEC_INIT_SIZE; bytes = vec->maxsize * sizeof (int); vec->ints = mh_xcalloc (1, bytes); vec->size = 0; return vec; } void ivector_free (ivector_t vec) { free (vec->ints); free (vec); } int ivector_push_back (ivector_t vec, int n) { if (++vec->size >= vec->maxsize) ivector_resize (vec, vec->size); return vec->ints[vec->size-1] = n; } int ivector_at (ivector_t vec, size_t i) { if (i >= vec->maxsize) ivector_resize (vec, i); return vec->ints[i]; } int * ivector_atp (ivector_t vec, size_t i) { if (i >= vec->maxsize) ivector_resize (vec, i); return &vec->ints[i]; } static void ivector_resize (ivector_t vec, size_t maxsize) { size_t old_maxsize = vec->maxsize; while ((vec->maxsize *= 2) < maxsize) ; vec->ints = mh_xrealloc (vec->ints, vec->maxsize * sizeof (int)); memset(vec->ints + old_maxsize, 0, (vec->maxsize - old_maxsize) * sizeof *vec->ints); }