123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350 |
- /*
- * Copyright 2002, 2006 Adrian Thurston <thurston@cs.queensu.ca>
- */
- /* 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 <new>
- #include <string.h>
- #include <stdlib.h>
- #include <assert.h>
- #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<T>, public Resize
- {
- private:
- typedef STable<T> 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 <class T, class Resize> SVector<T, Resize>::
- SVector(const SVector<T, Resize> &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 <class T, class Resize> SVector<T, Resize> &
- SVector<T, Resize>:: 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 <class T, class Resize> SVector<T, Resize>::
- 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 <class T, class Resize> SVector<T, Resize>::
- 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 <class T, class Resize> SVector<T, Resize>::
- 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 <class T, class Resize> SVector<T, Resize>::
- 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 <class T, class Resize> SVector<T, Resize>::
- 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 <class T, class Resize> typename SVector<T, Resize>::Iter &
- SVector<T, Resize>::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 <class T, class Resize> typename SVector<T, Resize>::Iter &
- SVector<T, Resize>::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 <class T, class Resize> typename SVector<T, Resize>::Iter &
- SVector<T, Resize>::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 <class T, class Resize> typename SVector<T, Resize>::Iter &
- SVector<T, Resize>::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 <class T, class Resize> typename SVector<T, Resize>::Iter &
- SVector<T, Resize>::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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> long SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> long SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 <class T, class Resize> void SVector<T, Resize>::
- 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 */
|