/* -*-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<class T, int DefaultSize, bool ZeroTerm>
#define selftype Dynarray<T, DefaultSize, ZeroTerm>
#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
syntax highlighted by Code2HTML, v. 0.9.1