/* * Copyright 2002, 2006 Adrian Thurston */ /* This file is part of Aapl. * * Aapl is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * Aapl 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 Lesser General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with Aapl; if not, write to the Free Software Foundation, Inc., 59 * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _AAPL_SVECTOR_H #define _AAPL_SVECTOR_H #include #include #include #include #include "table.h" #ifdef AAPL_NAMESPACE namespace Aapl { #endif /** * \addtogroup vector * @{ */ /** \class SVector * \brief Copy-on-write dynamic array. * * SVector is a variant of Vector that employs copy-on-write behaviour. The * SVector copy constructor and = operator make shallow copies. If a vector * that references shared data is modified with insert, replace, append, * prepend, setAs or remove, a new copy is made so as not to interfere with * the shared data. However, shared individual elements may be modified by * bypassing the SVector interface. * * SVector is a dynamic array that can be used to contain complex data * structures that have constructors and destructors as well as simple types * such as integers and pointers. * * SVector supports inserting, overwriting, and removing single or multiple * elements at once. Constructors and destructors are called wherever * appropriate. For example, before an element is overwritten, it's * destructor is called. * * SVector provides automatic resizing of allocated memory as needed and * offers different allocation schemes for controlling how the automatic * allocation is done. Two senses of the the length of the data is * maintained: the amount of raw memory allocated to the vector and the number * of actual elements in the vector. The various allocation schemes control * how the allocated space is changed in relation to the number of elements in * the vector. */ /*@}*/ /* SVector */ template < class T, class Resize = ResizeExpn > class SVector : public STable, public Resize { private: typedef STable BaseTable; public: /** * \brief Initialize an empty vector with no space allocated. * * If a linear resizer is used, the step defaults to 256 units of T. For a * runtime vector both up and down allocation schemes default to * Exponential. */ SVector() { } /** * \brief Create a vector that contains an initial element. * * The vector becomes one element in length. The element's copy * constructor is used to place the value in the vector. */ SVector(const T &val) { setAs(&val, 1); } /** * \brief Create a vector that contains an array of elements. * * The vector becomes len elements in length. Copy constructors are used * to place the new elements in the vector. */ SVector(const T *val, long len) { setAs(val, len); } /* Shallow copy. */ SVector( const SVector &v ); /** * \brief Free all memory used by the vector. * * The vector is reset to zero elements. Destructors are called on all * elements in the vector. The space allocated for the vector is freed. */ ~SVector() { empty(); } /* Delete all items. */ void empty(); /** * \brief Deep copy another vector into this vector. * * Copies the entire contents of the other vector into this vector. Any * existing contents are first deleted. Equivalent to setAs. */ void deepCopy( const SVector &v ) { setAs(v.data, v.length()); } /* Perform a shallow copy of another vector. */ SVector &operator=( const SVector &v ); /*@{*/ /** * \brief Insert one element at position pos. * * Elements in the vector from pos onward are shifted one space to the * right. The copy constructor is used to place the element into this * vector. If pos is greater than the length of the vector then undefined * behaviour results. If pos is negative then it is treated as an offset * relative to the length of the vector. */ void insert(long pos, const T &val) { insert(pos, &val, 1); } /* Insert an array of values. */ void insert(long pos, const T *val, long len); /** * \brief Insert all the elements from another vector at position pos. * * Elements in this vector from pos onward are shifted v.length() spaces * to the right. The element's copy constructor is used to copy the items * into this vector. The other vector is left unchanged. If pos is off the * end of the vector, then undefined behaviour results. If pos is negative * then it is treated as an offset relative to the length of the vector. * Equivalent to vector.insert(pos, other.data, other.length()). */ void insert(long pos, const SVector &v) { insert(pos, v.data, v.length()); } /* Insert len copies of val into the vector. */ void insertDup(long pos, const T &val, long len); /** * \brief Insert one new element using the default constrcutor. * * Elements in the vector from pos onward are shifted one space to the right. * The default constructor is used to init the new element. If pos is greater * than the length of the vector then undefined behaviour results. If pos is * negative then it is treated as an offset relative to the length of the * vector. */ void insertNew(long pos) { insertNew(pos, 1); } /* Insert len new items using default constructor. */ void insertNew(long pos, long len); /*@}*/ /*@{*/ /** * \brief Remove one element at position pos. * * The element's destructor is called. Elements to the right of pos are * shifted one space to the left to take up the free space. If pos is greater * than or equal to the length of the vector then undefined behavior results. * If pos is negative then it is treated as an offset relative to the length * of the vector. */ void remove(long pos) { remove(pos, 1); } /* Delete a number of elements. */ void remove(long pos, long len); /*@}*/ /*@{*/ /** * \brief Replace one element at position pos. * * If there is an existing element at position pos (if pos is less than the * length of the vector) then its destructor is called before the space is * used. The copy constructor is used to place the element into the vector. * If pos is greater than the length of the vector then undefined behaviour * results. If pos is negative then it is treated as an offset relative to * the length of the vector. */ void replace(long pos, const T &val) { replace(pos, &val, 1); } /* Replace with an array of values. */ void replace(long pos, const T *val, long len); /** * \brief Replace at position pos with all the elements of another vector. * * Replace at position pos with all the elements of another vector. The other * vector is left unchanged. If there are existing elements at the positions * to be replaced, then destructors are called before the space is used. Copy * constructors are used to place the elements into this vector. It is * allowable for the pos and length of the other vector to specify a * replacement that overwrites existing elements and creates new ones. If pos * is greater than the length of the vector then undefined behaviour results. * If pos is negative, then it is treated as an offset relative to the length * of the vector. */ void replace(long pos, const SVector &v) { replace(pos, v.data, v.length()); } /* Replace len items with len copies of val. */ void replaceDup(long pos, const T &val, long len); /** * \brief Replace at position pos with one new element. * * If there is an existing element at the position to be replaced (pos is * less than the length of the vector) then the element's destructor is * called before the space is used. The default constructor is used to * initialize the new element. If pos is greater than the length of the * vector then undefined behaviour results. If pos is negative, then it is * treated as an offset relative to the length of the vector. */ void replaceNew(long pos) { replaceNew(pos, 1); } /* Replace len items at pos with newly constructed objects. */ void replaceNew(long pos, long len); /*@}*/ /*@{*/ /** * \brief Set the contents of the vector to be val exactly. * * The vector becomes one element in length. Destructors are called on any * existing elements in the vector. The element's copy constructor is used to * place the val in the vector. */ void setAs(const T &val) { setAs(&val, 1); } /* Set to the contents of an array. */ void setAs(const T *val, long len); /** * \brief Set the vector to exactly the contents of another vector. * * The vector becomes v.length() elements in length. Destructors are called * on any existing elements. Copy constructors are used to place the new * elements in the vector. */ void setAs(const SVector &v) { setAs(v.data, v.length()); } /* Set as len copies of item. */ void setAsDup(const T &item, long len); /** * \brief Set the vector to exactly one new item. * * The vector becomes one element in length. Destructors are called on any * existing elements in the vector. The default constructor is used to * init the new item. */ void setAsNew() { setAsNew(1); } /* Set as newly constructed objects using the default constructor. */ void setAsNew(long len); /*@}*/ /*@{*/ /** * \brief Append one elment to the end of the vector. * * Copy constructor is used to place the element in the vector. */ void append(const T &val) { replace(BaseTable::length(), &val, 1); } /** * \brief Append len elements to the end of the vector. * * Copy constructors are used to place the elements in the vector. */ void append(const T *val, long len) { replace(BaseTable::length(), val, len); } /** * \brief Append the contents of another vector. * * The other vector is left unchanged. Copy constructors are used to place * the elements in the vector. */ void append(const SVector &v) { replace(BaseTable::length(), v.data, v.length()); } /** * \brief Append len copies of item. * * The copy constructor is used to place the item in the vector. */ void appendDup(const T &item, long len) { replaceDup(BaseTable::length(), item, len); } /** * \brief Append a single newly created item. * * The new element is initialized with the default constructor. */ void appendNew() { replaceNew(BaseTable::length(), 1); } /** * \brief Append len newly created items. * * The new elements are initialized with the default constructor. */ void appendNew(long len) { replaceNew(BaseTable::length(), len); } /*@}*/ /*@{*/ /** * \brief Prepend one elment to the front of the vector. * * Copy constructor is used to place the element in the vector. */ void prepend(const T &val) { insert(0, &val, 1); } /** * \brief Prepend len elements to the front of the vector. * * Copy constructors are used to place the elements in the vector. */ void prepend(const T *val, long len) { insert(0, val, len); } /** * \brief Prepend the contents of another vector. * * The other vector is left unchanged. Copy constructors are used to place * the elements in the vector. */ void prepend(const SVector &v) { insert(0, v.data, v.length()); } /** * \brief Prepend len copies of item. * * The copy constructor is used to place the item in the vector. */ void prependDup(const T &item, long len) { insertDup(0, item, len); } /** * \brief Prepend a single newly created item. * * The new element is initialized with the default constructor. */ void prependNew() { insertNew(0, 1); } /** * \brief Prepend len newly created items. * * The new elements are initialized with the default constructor. */ void prependNew(long len) { insertNew(0, len); } /*@}*/ /* Convenience access. */ T &operator[](int i) const { return BaseTable::data[i]; } long size() const { return BaseTable::length(); } /* Various classes for setting the iterator */ struct Iter; struct IterFirst { IterFirst( const SVector &v ) : v(v) { } const SVector &v; }; struct IterLast { IterLast( const SVector &v ) : v(v) { } const SVector &v; }; struct IterNext { IterNext( const Iter &i ) : i(i) { } const Iter &i; }; struct IterPrev { IterPrev( const Iter &i ) : i(i) { } const Iter &i; }; /** * \brief Shared Vector Iterator. * \ingroup iterators */ struct Iter { /* Construct, assign. */ Iter() : ptr(0), ptrBeg(0), ptrEnd(0) { } /* Construct. */ Iter( const SVector &v ); Iter( const IterFirst &vf ); Iter( const IterLast &vl ); inline Iter( const IterNext &vn ); inline Iter( const IterPrev &vp ); /* Assign. */ Iter &operator=( const SVector &v ); Iter &operator=( const IterFirst &vf ); Iter &operator=( const IterLast &vl ); inline Iter &operator=( const IterNext &vf ); inline Iter &operator=( const IterPrev &vl ); /** \brief Less than end? */ bool lte() const { return ptr != ptrEnd; } /** \brief At end? */ bool end() const { return ptr == ptrEnd; } /** \brief Greater than beginning? */ bool gtb() const { return ptr != ptrBeg; } /** \brief At beginning? */ bool beg() const { return ptr == ptrBeg; } /** \brief At first element? */ bool first() const { return ptr == ptrBeg+1; } /** \brief At last element? */ bool last() const { return ptr == ptrEnd-1; } /* Return the position. */ long pos() const { return ptr - ptrBeg - 1; } T &operator[](int i) const { return ptr[i]; } /** \brief Implicit cast to T*. */ operator T*() const { return ptr; } /** \brief Dereference operator returns T&. */ T &operator *() const { return *ptr; } /** \brief Arrow operator returns T*. */ T *operator->() const { return ptr; } /** \brief Move to next item. */ T *operator++() { return ++ptr; } /** \brief Move to next item. */ T *operator++(int) { return ptr++; } /** \brief Move to next item. */ T *increment() { return ++ptr; } /** \brief Move to previous item. */ T *operator--() { return --ptr; } /** \brief Move to previous item. */ T *operator--(int) { return ptr--; } /** \brief Move to previous item. */ T *decrement() { return --ptr; } /** \brief Return the next item. Does not modify this. */ inline IterNext next() const { return IterNext(*this); } /** \brief Return the previous item. Does not modify this. */ inline IterPrev prev() const { return IterPrev(*this); } /** \brief The iterator is simply a pointer. */ T *ptr; /* For testing endpoints. */ T *ptrBeg, *ptrEnd; }; /** \brief Return first element. */ IterFirst first() { return IterFirst( *this ); } /** \brief Return last element. */ IterLast last() { return IterLast( *this ); } protected: void makeRawSpaceFor(long pos, long len); void setAsCommon(long len); long replaceCommon(long pos, long len); long insertCommon(long pos, long len); void upResize(long len); void upResizeDup(long len); void upResizeFromEmpty(long len); void downResize(long len); void downResizeDup(long len); }; /** * \brief Perform a shallow copy of the vector. * * Takes a reference to the contents of the other vector. */ template SVector:: SVector(const SVector &v) { /* Take a reference to other, if any data is allocated. */ if ( v.data == 0 ) BaseTable::data = 0; else { /* Get the source header, up the refcount and ref it. */ STabHead *srcHead = ((STabHead*) v.data) - 1; srcHead->refCount += 1; BaseTable::data = (T*) (srcHead + 1); } } /** * \brief Shallow copy another vector into this vector. * * Takes a reference to the other vector. The contents of this vector are * first emptied. * * \returns A reference to this. */ template SVector & SVector:: operator=( const SVector &v ) { /* First clean out the current contents. */ empty(); /* Take a reference to other, if any data is allocated. */ if ( v.data == 0 ) BaseTable::data = 0; else { /* Get the source header, up the refcount and ref it. */ STabHead *srcHead = ((STabHead*) v.data) - 1; srcHead->refCount += 1; BaseTable::data = (T*) (srcHead + 1); } return *this; } /* Init a vector iterator with just a vector. */ template SVector:: Iter::Iter( const SVector &v ) { long length; if ( v.data == 0 || (length=(((STabHead*)v.data)-1)->tabLen) == 0 ) ptr = ptrBeg = ptrEnd = 0; else { ptr = v.data; ptrBeg = v.data-1; ptrEnd = v.data+length; } } /* Init a vector iterator with the first of a vector. */ template SVector:: Iter::Iter( const IterFirst &vf ) { long length; if ( vf.v.data == 0 || (length=(((STabHead*)vf.v.data)-1)->tabLen) == 0 ) ptr = ptrBeg = ptrEnd = 0; else { ptr = vf.v.data; ptrBeg = vf.v.data-1; ptrEnd = vf.v.data+length; } } /* Init a vector iterator with the last of a vector. */ template SVector:: Iter::Iter( const IterLast &vl ) { long length; if ( vl.v.data == 0 || (length=(((STabHead*)vl.v.data)-1)->tabLen) == 0 ) ptr = ptrBeg = ptrEnd = 0; else { ptr = vl.v.data+length-1; ptrBeg = vl.v.data-1; ptrEnd = vl.v.data+length; } } /* Init a vector iterator with the next of some other iterator. */ template SVector:: Iter::Iter( const IterNext &vn ) : ptr(vn.i.ptr+1), ptrBeg(vn.i.ptrBeg), ptrEnd(vn.i.ptrEnd) { } /* Init a vector iterator with the prev of some other iterator. */ template SVector:: Iter::Iter( const IterPrev &vp ) : ptr(vp.i.ptr-1), ptrBeg(vp.i.ptrBeg), ptrEnd(vp.i.ptrEnd) { } /* Set a vector iterator with some vector. */ template typename SVector::Iter & SVector::Iter::operator=( const SVector &v ) { long length; if ( v.data == 0 || (length=(((STabHead*)v.data)-1)->tabLen) == 0 ) ptr = ptrBeg = ptrEnd = 0; else { ptr = v.data; ptrBeg = v.data-1; ptrEnd = v.data+length; } return *this; } /* Set a vector iterator with the first element in a vector. */ template typename SVector::Iter & SVector::Iter::operator=( const IterFirst &vf ) { long length; if ( vf.v.data == 0 || (length=(((STabHead*)vf.v.data)-1)->tabLen) == 0 ) ptr = ptrBeg = ptrEnd = 0; else { ptr = vf.v.data; ptrBeg = vf.v.data-1; ptrEnd = vf.v.data+length; } return *this; } /* Set a vector iterator with the last element in a vector. */ template typename SVector::Iter & SVector::Iter::operator=( const IterLast &vl ) { long length; if ( vl.v.data == 0 || (length=(((STabHead*)vl.v.data)-1)->tabLen) == 0 ) ptr = ptrBeg = ptrEnd = 0; else { ptr = vl.v.data+length-1; ptrBeg = vl.v.data-1; ptrEnd = vl.v.data+length; } return *this; } /* Set a vector iterator with the next of some other iterator. */ template typename SVector::Iter & SVector::Iter::operator=( const IterNext &vn ) { ptr = vn.i.ptr+1; ptrBeg = vn.i.ptrBeg; ptrEnd = vn.i.ptrEnd; return *this; } /* Set a vector iterator with the prev of some other iterator. */ template typename SVector::Iter & SVector::Iter::operator=( const IterPrev &vp ) { ptr = vp.i.ptr-1; ptrBeg = vp.i.ptrBeg; ptrEnd = vp.i.ptrEnd; return *this; } /* Up resize the data for len elements using Resize::upResize to tell us the * new length. Reads and writes allocLen. Does not read or write length. * Assumes that there is some data allocated already. */ template void SVector:: upResize(long len) { /* Get the current header. */ STabHead *head = ((STabHead*)BaseTable::data) - 1; /* Ask the resizer what the new length will be. */ long newLen = Resize::upResize(head->allocLen, len); /* Did the data grow? */ if ( newLen > head->allocLen ) { head->allocLen = newLen; /* Table exists already, resize it up. */ head = (STabHead*) realloc( head, sizeof(STabHead) + sizeof(T) * newLen ); if ( head == 0 ) throw std::bad_alloc(); /* Save the data pointer. */ BaseTable::data = (T*) (head + 1); } } /* Allocates a new buffer for an up resize that requires a duplication of the * data. Uses Resize::upResize to get the allocation length. Reads and writes * allocLen. This upResize does write the new length. Assumes that there is * some data allocated already. */ template void SVector:: upResizeDup(long len) { /* Get the current header. */ STabHead *head = ((STabHead*)BaseTable::data) - 1; /* Ask the resizer what the new length will be. */ long newLen = Resize::upResize(head->allocLen, len); /* Dereferencing the existing data, decrement the refcount. */ head->refCount -= 1; /* Table exists already, resize it up. */ head = (STabHead*) malloc( sizeof(STabHead) + sizeof(T) * newLen ); if ( head == 0 ) throw std::bad_alloc(); head->refCount = 1; head->allocLen = newLen; head->tabLen = len; /* Save the data pointer. */ BaseTable::data = (T*) (head + 1); } /* Up resize the data for len elements using Resize::upResize to tell us the * new length. Reads and writes allocLen. This upresize DOES write length. * Assumes that no data is allocated. */ template void SVector:: upResizeFromEmpty(long len) { /* There is no table yet. If the len is zero, then there is no need to * create a table. */ if ( len > 0 ) { /* Ask the resizer what the new length will be. */ long newLen = Resize::upResize(0, len); /* If len is greater than zero then we are always allocating the table. */ STabHead *head = (STabHead*) malloc( sizeof(STabHead) + sizeof(T) * newLen ); if ( head == 0 ) throw std::bad_alloc(); /* Set up the header and save the data pointer. Note that we set the * length here. This differs from the other upResizes. */ head->refCount = 1; head->allocLen = newLen; head->tabLen = len; BaseTable::data = (T*) (head + 1); } } /* Down resize the data for len elements using Resize::downResize to determine * the new length. Reads and writes allocLen. Does not read or write length. */ template void SVector:: downResize(long len) { /* If there is already no length, then there is nothing we can do. */ if ( BaseTable::data != 0 ) { /* Get the current header. */ STabHead *head = ((STabHead*)BaseTable::data) - 1; /* Ask the resizer what the new length will be. */ long newLen = Resize::downResize( head->allocLen, len ); /* Did the data shrink? */ if ( newLen < head->allocLen ) { if ( newLen == 0 ) { /* Simply free the data. */ free( head ); BaseTable::data = 0; } else { /* Save the new allocated length. */ head->allocLen = newLen; /* Not shrinking to size zero, realloc it to the smaller size. */ head = (STabHead*) realloc( head, sizeof(STabHead) + sizeof(T) * newLen ); if ( head == 0 ) throw std::bad_alloc(); /* Save the new data ptr. */ BaseTable::data = (T*) (head + 1); } } } } /* Allocate a new buffer for a down resize and duplication of the array. The * new array will be len long and allocation size will be determined using * Resize::downResize with the old array's allocLen. Does not actually copy * any data. Reads and writes allocLen and writes the new len. */ template void SVector:: downResizeDup(long len) { /* If there is already no length, then there is nothing we can do. */ if ( BaseTable::data != 0 ) { /* Get the current header. */ STabHead *head = ((STabHead*)BaseTable::data) - 1; /* Ask the resizer what the new length will be. */ long newLen = Resize::downResize( head->allocLen, len ); /* Detaching from the existing head, decrement the refcount. */ head->refCount -= 1; /* Not shrinking to size zero, malloc it to the smaller size. */ head = (STabHead*) malloc( sizeof(STabHead) + sizeof(T) * newLen ); if ( head == 0 ) throw std::bad_alloc(); /* Save the new allocated length. */ head->refCount = 1; head->allocLen = newLen; head->tabLen = len; /* Save the data pointer. */ BaseTable::data = (T*) (head + 1); } } /** * \brief Free all memory used by the vector. * * The vector is reset to zero elements. Destructors are called on all * elements in the vector. The space allocated for the vector is freed. */ template void SVector:: empty() { if ( BaseTable::data != 0 ) { /* Get the header and drop the refcount on the data. */ STabHead *head = ((STabHead*) BaseTable::data) - 1; head->refCount -= 1; /* If the refcount just went down to zero nobody else is referencing * the data. */ if ( head->refCount == 0 ) { /* Call All destructors. */ T *pos = BaseTable::data; for ( long i = 0; i < head->tabLen; pos++, i++ ) pos->~T(); /* Free the data space. */ free( head ); } /* Clear the pointer. */ BaseTable::data = 0; } } /* Prepare for setting the contents of the vector to some array len long. * Handles reusing the existing space, detaching from a common space or * growing from zero length automatically. */ template void SVector:: setAsCommon(long len) { if ( BaseTable::data != 0 ) { /* Get the header. */ STabHead *head = ((STabHead*)BaseTable::data) - 1; /* If the refCount is one, then we can reuse the space. Otherwise we * must detach from the referenced data create new space. */ if ( head->refCount == 1 ) { /* Call All destructors. */ T *pos = BaseTable::data; for ( long i = 0; i < head->tabLen; pos++, i++ ) pos->~T(); /* Adjust the allocated length. */ if ( len < head->tabLen ) downResize( len ); else if ( len > head->tabLen ) upResize( len ); if ( BaseTable::data != 0 ) { /* Get the header again and set the length. */ head = ((STabHead*)BaseTable::data) - 1; head->tabLen = len; } } else { /* Just detach from the data. */ head->refCount -= 1; BaseTable::data = 0; /* Make enough space. This will set the length. */ upResizeFromEmpty( len ); } } else { /* The table is currently empty. Make enough space. This will set the * length. */ upResizeFromEmpty( len ); } } /** * \brief Set the contents of the vector to be len elements exactly. * * The vector becomes len elements in length. Destructors are called on any * existing elements in the vector. Copy constructors are used to place the * new elements in the vector. */ template void SVector:: setAs(const T *val, long len) { /* Common stuff for setting the array to len long. */ setAsCommon( len ); /* Copy data in. */ T *dst = BaseTable::data; const T *src = val; for ( long i = 0; i < len; i++, dst++, src++ ) new(dst) T(*src); } /** * \brief Set the vector to len copies of item. * * The vector becomes len elements in length. Destructors are called on any * existing elements in the vector. The element's copy constructor is used to * copy the item into the vector. */ template void SVector:: setAsDup(const T &item, long len) { /* Do the common stuff for setting the array to len long. */ setAsCommon( len ); /* Copy item in one spot at a time. */ T *dst = BaseTable::data; for ( long i = 0; i < len; i++, dst++ ) new(dst) T(item); } /** * \brief Set the vector to exactly len new items. * * The vector becomes len elements in length. Destructors are called on any * existing elements in the vector. Default constructors are used to init the * new items. */ template void SVector:: setAsNew(long len) { /* Do the common stuff for setting the array to len long. */ setAsCommon( len ); /* Create items using default constructor. */ T *dst = BaseTable::data; for ( long i = 0; i < len; i++, dst++ ) new(dst) T(); } /* Make space in vector for a replacement at pos of len items. Handles reusing * existing space, detaching or growing from zero space. */ template long SVector:: replaceCommon(long pos, long len) { if ( BaseTable::data != 0 ) { /* Get the header. */ STabHead *head = ((STabHead*)BaseTable::data) - 1; /* If we are given a negative position to replace at then treat it as * a position relative to the length. This doesn't have any meaning * unless the length is at least one. */ if ( pos < 0 ) pos = head->tabLen + pos; /* The end is the one past the last item that we want to write to. */ long i, endPos = pos + len; if ( head->refCount == 1 ) { /* We can reuse the space. Make sure we have enough space. */ if ( endPos > head->tabLen ) { upResize( endPos ); /* Get the header again, whose addr may have changed after * resizing. */ head = ((STabHead*)BaseTable::data) - 1; /* Delete any objects we need to delete. */ T *item = BaseTable::data + pos; for ( i = pos; i < head->tabLen; i++, item++ ) item->~T(); /* We are extending the vector, set the new data length. */ head->tabLen = endPos; } else { /* Delete any objects we need to delete. */ T *item = BaseTable::data + pos; for ( i = pos; i < endPos; i++, item++ ) item->~T(); } } else { /* Use endPos to calc the end of the vector. */ long newLen = endPos; if ( newLen < head->tabLen ) newLen = head->tabLen; /* Duplicate and grow up to endPos. This will set the length. */ upResizeDup( newLen ); /* Copy from src up to pos. */ const T *src = (T*) (head + 1); T *dst = BaseTable::data; for ( i = 0; i < pos; i++, dst++, src++) new(dst) T(*src); /* Copy any items after the replace range. */ for ( i += len, src += len, dst += len; i < head->tabLen; i++, dst++, src++ ) new(dst) T(*src); } } else { /* There is no data initially, must grow from zero. This will set the * new length. */ upResizeFromEmpty( len ); } return pos; } /** * \brief Replace len elements at position pos. * * If there are existing elements at the positions to be replaced, then * destructors are called before the space is used. Copy constructors are used * to place the elements into the vector. It is allowable for the pos and * length to specify a replacement that overwrites existing elements and * creates new ones. If pos is greater than the length of the vector then * undefined behaviour results. If pos is negative, then it is treated as an * offset relative to the length of the vector. */ template void SVector:: replace(long pos, const T *val, long len) { /* Common work for replacing in the vector. */ pos = replaceCommon( pos, len ); /* Copy data in using copy constructor. */ T *dst = BaseTable::data + pos; const T *src = val; for ( long i = 0; i < len; i++, dst++, src++ ) new(dst) T(*src); } /** * \brief Replace at position pos with len copies of an item. * * If there are existing elements at the positions to be replaced, then * destructors are called before the space is used. The copy constructor is * used to place the element into this vector. It is allowable for the pos and * length to specify a replacement that overwrites existing elements and * creates new ones. If pos is greater than the length of the vector then * undefined behaviour results. If pos is negative, then it is treated as an * offset relative to the length of the vector. */ template void SVector:: replaceDup(long pos, const T &val, long len) { /* Common replacement stuff. */ pos = replaceCommon( pos, len ); /* Copy data in using copy constructor. */ T *dst = BaseTable::data + pos; for ( long i = 0; i < len; i++, dst++ ) new(dst) T(val); } /** * \brief Replace at position pos with len new elements. * * If there are existing elements at the positions to be replaced, then * destructors are called before the space is used. The default constructor is * used to initialize the new elements. It is allowable for the pos and length * to specify a replacement that overwrites existing elements and creates new * ones. If pos is greater than the length of the vector then undefined * behaviour results. If pos is negative, then it is treated as an offset * relative to the length of the vector. */ template void SVector:: replaceNew(long pos, long len) { /* Do the common replacement stuff. */ pos = replaceCommon( pos, len ); /* Copy data in using copy constructor. */ T *dst = BaseTable::data + pos; for ( long i = 0; i < len; i++, dst++ ) new(dst) T(); } /** * \brief Remove len elements at position pos. * * Destructor is called on all elements removed. Elements to the right of pos * are shifted len spaces to the left to take up the free space. If pos is * greater than or equal to the length of the vector then undefined behavior * results. If pos is negative then it is treated as an offset relative to the * length of the vector. */ template void SVector:: remove(long pos, long len) { /* If there is no data, we can't delete anything anyways. */ if ( BaseTable::data != 0 ) { /* Get the header. */ STabHead *head = ((STabHead*)BaseTable::data) - 1; /* If we are given a negative position to remove at then * treat it as a position relative to the length. */ if ( pos < 0 ) pos = head->tabLen + pos; /* The first position after the last item deleted. */ long endPos = pos + len; /* The New data length. */ long i, newLen = head->tabLen - len; if ( head->refCount == 1 ) { /* We are the only ones using the data. We can reuse * the existing space. */ /* The place in the data we are deleting at. */ T *dst = BaseTable::data + pos; /* Call Destructors. */ T *item = BaseTable::data + pos; for ( i = 0; i < len; i += 1, item += 1 ) item->~T(); /* Shift data over if necessary. */ long lenToSlideOver = head->tabLen - endPos; if ( len > 0 && lenToSlideOver > 0 ) memmove(BaseTable::data + pos, dst + len, sizeof(T)*lenToSlideOver); /* Shrink the data if necessary. */ downResize( newLen ); if ( BaseTable::data != 0 ) { /* Get the header again (because of the resize) and set the * new data length. */ head = ((STabHead*)BaseTable::data) - 1; head->tabLen = newLen; } } else { /* Must detach from the common data. Just copy the non-deleted * items from the common data. */ /* Duplicate and grow down to newLen. This will set the length. */ downResizeDup( newLen ); /* Copy over just the non-deleted parts. */ const T *src = (T*) (head + 1); T *dst = BaseTable::data; for ( i = 0; i < pos; i++, dst++, src++ ) new(dst) T(*src); /* ... and the second half. */ for ( i += len, src += len; i < head->tabLen; i++, src++, dst++ ) new(dst) T(*src); } } } /* Shift over existing data. Handles reusing existing space, detaching or * growing from zero space. */ template long SVector:: insertCommon(long pos, long len) { if ( BaseTable::data != 0 ) { /* Get the header. */ STabHead *head = ((STabHead*)BaseTable::data) - 1; /* If we are given a negative position to insert at then treat it as a * position relative to the length. This only has meaning if there is * existing data. */ if ( pos < 0 ) pos = head->tabLen + pos; /* Calculate the new length. */ long i, newLen = head->tabLen + len; if ( head->refCount == 1 ) { /* Up resize, we are growing. */ upResize( newLen ); /* Get the header again, (the addr may have changed after * resizing). */ head = ((STabHead*)BaseTable::data) - 1; /* Shift over data at insert spot if needed. */ if ( len > 0 && pos < head->tabLen ) { memmove( BaseTable::data + pos + len, BaseTable::data + pos, sizeof(T)*(head->tabLen - pos) ); } /* Grow the length by the len inserted. */ head->tabLen += len; } else { /* Need to detach from the existing array. Copy over the other * parts. This will set the length. */ upResizeDup( newLen ); /* Copy over the parts around the insert. */ const T *src = (T*) (head + 1); T *dst = BaseTable::data; for ( i = 0; i < pos; i++, dst++, src++ ) new(dst) T(*src); /* ... and the second half. */ for ( dst += len; i < head->tabLen; i++, src++, dst++ ) new(dst) T(*src); } } else { /* There is no existing data. Start from zero. This will set the * length. */ upResizeFromEmpty( len ); } return pos; } /** * \brief Insert len elements at position pos. * * Elements in the vector from pos onward are shifted len spaces to the right. * The copy constructor is used to place the elements into this vector. If pos * is greater than the length of the vector then undefined behaviour results. * If pos is negative then it is treated as an offset relative to the length * of the vector. */ template void SVector:: insert(long pos, const T *val, long len) { /* Do the common insertion stuff. */ pos = insertCommon( pos, len ); /* Copy data in element by element. */ T *dst = BaseTable::data + pos; const T *src = val; for ( long i = 0; i < len; i++, dst++, src++ ) new(dst) T(*src); } /** * \brief Insert len copies of item at position pos. * * Elements in the vector from pos onward are shifted len spaces to the right. * The copy constructor is used to place the element into this vector. If pos * is greater than the length of the vector then undefined behaviour results. * If pos is negative then it is treated as an offset relative to the length * of the vector. */ template void SVector:: insertDup(long pos, const T &item, long len) { /* Do the common insertion stuff. */ pos = insertCommon( pos, len ); /* Copy the data item in one at a time. */ T *dst = BaseTable::data + pos; for ( long i = 0; i < len; i++, dst++ ) new(dst) T(item); } /** * \brief Insert len new elements using the default constructor. * * Elements in the vector from pos onward are shifted len spaces to the right. * Default constructors are used to init the new elements. If pos is off the * end of the vector then undefined behaviour results. If pos is negative then * it is treated as an offset relative to the length of the vector. */ template void SVector:: insertNew(long pos, long len) { /* Do the common insertion stuff. */ pos = insertCommon( pos, len ); /* Init new data with default constructors. */ T *dst = BaseTable::data + pos; for ( long i = 0; i < len; i++, dst++ ) new(dst) T(); } /* Makes space for len items, Does not init the items in any way. If pos is * greater than the length of the vector then undefined behaviour results. * Updates the length of the vector. */ template void SVector:: makeRawSpaceFor(long pos, long len) { if ( BaseTable::data != 0 ) { /* Get the header. */ STabHead *head = ((STabHead*)BaseTable::data) - 1; /* Calculate the new length. */ long i, newLen = head->tabLen + len; if ( head->refCount == 1 ) { /* Up resize, we are growing. */ upResize( newLen ); /* Get the header again, (the addr may have changed after * resizing). */ head = ((STabHead*)BaseTable::data) - 1; /* Shift over data at insert spot if needed. */ if ( len > 0 && pos < head->tabLen ) { memmove( BaseTable::data + pos + len, BaseTable::data + pos, sizeof(T)*(head->tabLen - pos) ); } /* Grow the length by the len inserted. */ head->tabLen += len; } else { /* Need to detach from the existing array. Copy over the other * parts. This will set the length. */ upResizeDup( newLen ); /* Copy over the parts around the insert. */ const T *src = (T*) (head + 1); T *dst = BaseTable::data; for ( i = 0; i < pos; i++, dst++, src++ ) new(dst) T(*src); /* ... and the second half. */ for ( dst += len; i < head->tabLen; i++, src++, dst++ ) new(dst) T(*src); } } else { /* There is no existing data. Start from zero. This will set the * length. */ upResizeFromEmpty( len ); } } #ifdef AAPL_NAMESPACE } #endif #endif /* _AAPL_SVECTOR_H */