/* -*-Mode: C++;-*- * PRCS - The Project Revision Control System * Copyright (C) 1997 Josh MacDonald * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: dynarray.cc 1.2.1.1.1.5.1.8.2.7.1.1 Tue, 05 Feb 2002 07:58:12 -0800 jmacd $ */ #include "prcs.h" #define generic template #define selftype Dynarray #define member selftype:: #define MAYBECNEWVEC(zeroit, type, elts) ((zeroit) ? NEWVEC0(type, elts) : NEWVEC(type, elts)) #define MAYBECEXPANDVEC(zeroit, T, V, N, I) (T*)((zeroit) ? EXPANDVEC0(V, N, I) : EXPANDVEC(V, N, I)) static int nearest_pow (int x) { int i = 1; while (i <= x) i <<= 1; return i < 16 ? 16 : i; } generic int member v_length(const T* p) const { int l = 0; while (*p++ != 0) l += 1; return l; } generic member Dynarray() :_vec(NULL), _filled(0), _alloc(0) {} generic member Dynarray(const T *s, int N0) { ASSERT(N0 < 0 || ZeroTerm, "Can't end a non-zero-terminated vector"); if (N0 < 0) N0 = v_length(s); int i = nearest_pow (N0 + ZeroTerm); _vec = MAYBECNEWVEC(ZeroTerm, T, i); _filled = N0; _alloc = i; for(i = 0; i < N0; i += 1) _vec[i] = s[i]; } generic member Dynarray(int N0) { int i = nearest_pow(N0 + ZeroTerm); _vec = MAYBECNEWVEC(ZeroTerm, T, i); _filled = 0; _alloc = i; } generic member Dynarray(const T c, int N0) { int i = nearest_pow(N0 + ZeroTerm); _vec = MAYBECNEWVEC(ZeroTerm, T, i); _filled = N0; _alloc = i; for(i = 0; i < N0; i += 1) _vec[i] = c; } generic member Dynarray(const selftype& s) { _vec = MAYBECNEWVEC(ZeroTerm, T, s._alloc); _filled = s.length(); _alloc = s._alloc; for(int i = 0; i < s.length(); i += 1) _vec[i] = s.index(i); } generic member ~Dynarray() { if (_alloc > 0) free(_vec); } generic void member maybe_expand(int elts) { modify(); if (!_vec) { ASSERT (_filled == 0, "otherwise an error"); _alloc = nearest_pow (elts + ZeroTerm); _vec = MAYBECNEWVEC(ZeroTerm, T, _alloc); } else if (_filled + elts > _alloc - ZeroTerm) { int goalsize = nearest_pow (_filled + elts + ZeroTerm); _vec = MAYBECEXPANDVEC(ZeroTerm, T, _vec, _alloc, goalsize - _alloc); _alloc = goalsize; } } generic void member expand(int elts, const T& val) { modify(); if(_filled < elts) { maybe_expand(elts - _filled); while(_filled < elts) { _vec[_filled] = val; _filled += 1; } } } generic void member append(const T c) { modify(); maybe_expand(1); _vec[_filled] = c; _filled += 1; } generic void member append(const T *s, int N0) { modify(); ASSERT(s != NULL, "Tried to dereference null pointer"); ASSERT(N0 < 0 || ZeroTerm, "Can't end a non-zero-terminated vector"); if (N0 < 0) N0 = v_length (s); maybe_expand (N0); memcpy (_vec + _filled, s, sizeof(T) * N0); _filled += N0; } generic void member append(const selftype& s) { modify(); maybe_expand (s.length()); memcpy (_vec + _filled, s._vec, s.length() * sizeof(T)); _filled += s.length(); } generic void member prepend(const T c) { modify(); maybe_expand(1); memmove(_vec + 1, _vec, sizeof(c) * _filled); _vec[0] = c; _filled += 1; } generic void member truncate(unsigned int N) { modify(); _filled = N; if(ZeroTerm) { memset(_vec + N, 0, sizeof(T) * (_alloc - N)); } } generic void member index(int N, const T& elt) { modify(); ASSERT(N < _filled, "indexed past end of array"); _vec[N] = elt; } generic void member assign(const T* s, int N) { modify(); if (N < 0) N = v_length(s); if (N > _filled) maybe_expand(N - _filled); memmove(_vec, s, N * sizeof(*s)); if (ZeroTerm) { int old_filled = _filled; _filled = N; if (_filled < old_filled) memset(_vec + _filled, 0, sizeof(*s) * (old_filled - _filled)); } else { _filled = N; } } generic void member assign(const selftype& s) { assign(s.cast(), s.length()); } generic void member sort(int (*compare)(const void*, const void*)) { modify(); qsort(_vec, _filled, sizeof(T), compare); } /* Const methods. */ generic member operator const T*() const { return cast(); } generic const T* member cast() const { ASSERT(this != NULL, "no null objects please"); if (_vec) { if(ZeroTerm) ASSERT(_vec[_filled] == 0, "not zero-terminated"); return _vec; } else { /*ASSERT (_filled == 0 && ZeroTerm, "what?");*/ _alloc = 16; _vec = MAYBECNEWVEC(ZeroTerm, T, 16); return _vec; } } generic int member length() const { return _filled; } generic T member index(int N) const { ASSERT(N < (_filled + ZeroTerm), "indexed past end of array"); if (_vec) return _vec[N]; else { ASSERT (_filled == 0, "what?"); return 0; } } generic T member last_index() const { return index(length() - 1); } #if defined(__MWERKS__) && defined(EXPLICIT_TEMPLATES) /* Some methods in Dynarray are not defined, propably because * they haven't been used yet. However, to instantiate them * there must be something. */ generic void member prepend(const T * , int N) { ASSERT(false, "Undefined method Dynarray::prepend(const T *, int) called"); } generic void member prepend(const selftype &) { ASSERT(false, "Undefined method Dynarray::prepend(const Dynarray&) called"); } generic void member operator=(const selftype &) { ASSERT(false, "Undefined method Dynarray::operator=(const Dynarray&) called"); } #endif #undef member #undef generic #undef selftype #if EXPLICIT_TEMPLATES #include "dynarray.tl" #endif