2 * Copyright 2002, 2006 Adrian Thurston <thurston@cs.queensu.ca>
5 /* This file is part of Aapl.
7 * Aapl is free software; you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free
9 * Software Foundation; either version 2.1 of the License, or (at your option)
12 * Aapl is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with Aapl; if not, write to the Free Software Foundation, Inc., 59
19 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #ifndef _AAPL_SVECTOR_H
23 #define _AAPL_SVECTOR_H
41 * \brief Copy-on-write dynamic array.
43 * SVector is a variant of Vector that employs copy-on-write behaviour. The
44 * SVector copy constructor and = operator make shallow copies. If a vector
45 * that references shared data is modified with insert, replace, append,
46 * prepend, setAs or remove, a new copy is made so as not to interfere with
47 * the shared data. However, shared individual elements may be modified by
48 * bypassing the SVector interface.
50 * SVector is a dynamic array that can be used to contain complex data
51 * structures that have constructors and destructors as well as simple types
52 * such as integers and pointers.
54 * SVector supports inserting, overwriting, and removing single or multiple
55 * elements at once. Constructors and destructors are called wherever
56 * appropriate. For example, before an element is overwritten, it's
57 * destructor is called.
59 * SVector provides automatic resizing of allocated memory as needed and
60 * offers different allocation schemes for controlling how the automatic
61 * allocation is done. Two senses of the the length of the data is
62 * maintained: the amount of raw memory allocated to the vector and the number
63 * of actual elements in the vector. The various allocation schemes control
64 * how the allocated space is changed in relation to the number of elements in
71 template < class T, class Resize = ResizeExpn > class SVector :
72 public STable<T>, public Resize
75 typedef STable<T> BaseTable;
79 * \brief Initialize an empty vector with no space allocated.
81 * If a linear resizer is used, the step defaults to 256 units of T. For a
82 * runtime vector both up and down allocation schemes default to
88 * \brief Create a vector that contains an initial element.
90 * The vector becomes one element in length. The element's copy
91 * constructor is used to place the value in the vector.
93 SVector(const T &val) { setAs(&val, 1); }
96 * \brief Create a vector that contains an array of elements.
98 * The vector becomes len elements in length. Copy constructors are used
99 * to place the new elements in the vector.
101 SVector(const T *val, long len) { setAs(val, len); }
104 SVector( const SVector &v );
107 SVector(STabHead *head);
110 * \brief Free all memory used by the vector.
112 * The vector is reset to zero elements. Destructors are called on all
113 * elements in the vector. The space allocated for the vector is freed.
115 ~SVector() { empty(); }
117 /* Delete all items. */
121 * \brief Deep copy another vector into this vector.
123 * Copies the entire contents of the other vector into this vector. Any
124 * existing contents are first deleted. Equivalent to setAs.
126 void deepCopy( const SVector &v ) { setAs(v.data, v.length()); }
128 /* Perform a shallow copy of another vector. */
129 SVector &operator=( const SVector &v );
131 /* Perform a shallow copy of another vector by the header. */
132 SVector &operator=( STabHead *head );
137 * \brief Insert one element at position pos.
139 * Elements in the vector from pos onward are shifted one space to the
140 * right. The copy constructor is used to place the element into this
141 * vector. If pos is greater than the length of the vector then undefined
142 * behaviour results. If pos is negative then it is treated as an offset
143 * relative to the length of the vector.
145 void insert(long pos, const T &val) { insert(pos, &val, 1); }
147 /* Insert an array of values. */
148 void insert(long pos, const T *val, long len);
151 * \brief Insert all the elements from another vector at position pos.
153 * Elements in this vector from pos onward are shifted v.length() spaces
154 * to the right. The element's copy constructor is used to copy the items
155 * into this vector. The other vector is left unchanged. If pos is off the
156 * end of the vector, then undefined behaviour results. If pos is negative
157 * then it is treated as an offset relative to the length of the vector.
158 * Equivalent to vector.insert(pos, other.data, other.length()).
160 void insert(long pos, const SVector &v) { insert(pos, v.data, v.length()); }
162 /* Insert len copies of val into the vector. */
163 void insertDup(long pos, const T &val, long len);
166 * \brief Insert one new element using the default constrcutor.
168 * Elements in the vector from pos onward are shifted one space to the right.
169 * The default constructor is used to init the new element. If pos is greater
170 * than the length of the vector then undefined behaviour results. If pos is
171 * negative then it is treated as an offset relative to the length of the
174 void insertNew(long pos) { insertNew(pos, 1); }
176 /* Insert len new items using default constructor. */
177 void insertNew(long pos, long len);
182 * \brief Remove one element at position pos.
184 * The element's destructor is called. Elements to the right of pos are
185 * shifted one space to the left to take up the free space. If pos is greater
186 * than or equal to the length of the vector then undefined behavior results.
187 * If pos is negative then it is treated as an offset relative to the length
190 void remove(long pos) { remove(pos, 1); }
192 /* Delete a number of elements. */
193 void remove(long pos, long len);
198 * \brief Replace one element at position pos.
200 * If there is an existing element at position pos (if pos is less than the
201 * length of the vector) then its destructor is called before the space is
202 * used. The copy constructor is used to place the element into the vector.
203 * If pos is greater than the length of the vector then undefined behaviour
204 * results. If pos is negative then it is treated as an offset relative to
205 * the length of the vector.
207 void replace(long pos, const T &val) { replace(pos, &val, 1); }
209 /* Replace with an array of values. */
210 void replace(long pos, const T *val, long len);
213 * \brief Replace at position pos with all the elements of another vector.
215 * Replace at position pos with all the elements of another vector. The other
216 * vector is left unchanged. If there are existing elements at the positions
217 * to be replaced, then destructors are called before the space is used. Copy
218 * constructors are used to place the elements into this vector. It is
219 * allowable for the pos and length of the other vector to specify a
220 * replacement that overwrites existing elements and creates new ones. If pos
221 * is greater than the length of the vector then undefined behaviour results.
222 * If pos is negative, then it is treated as an offset relative to the length
225 void replace(long pos, const SVector &v) { replace(pos, v.data, v.length()); }
227 /* Replace len items with len copies of val. */
228 void replaceDup(long pos, const T &val, long len);
231 * \brief Replace at position pos with one new element.
233 * If there is an existing element at the position to be replaced (pos is
234 * less than the length of the vector) then the element's destructor is
235 * called before the space is used. The default constructor is used to
236 * initialize the new element. If pos is greater than the length of the
237 * vector then undefined behaviour results. If pos is negative, then it is
238 * treated as an offset relative to the length of the vector.
240 void replaceNew(long pos) { replaceNew(pos, 1); }
242 /* Replace len items at pos with newly constructed objects. */
243 void replaceNew(long pos, long len);
249 * \brief Set the contents of the vector to be val exactly.
251 * The vector becomes one element in length. Destructors are called on any
252 * existing elements in the vector. The element's copy constructor is used to
253 * place the val in the vector.
255 void setAs(const T &val) { setAs(&val, 1); }
257 /* Set to the contents of an array. */
258 void setAs(const T *val, long len);
261 * \brief Set the vector to exactly the contents of another vector.
263 * The vector becomes v.length() elements in length. Destructors are called
264 * on any existing elements. Copy constructors are used to place the new
265 * elements in the vector.
267 void setAs(const SVector &v) { setAs(v.data, v.length()); }
269 /* Set as len copies of item. */
270 void setAsDup(const T &item, long len);
273 * \brief Set the vector to exactly one new item.
275 * The vector becomes one element in length. Destructors are called on any
276 * existing elements in the vector. The default constructor is used to
279 void setAsNew() { setAsNew(1); }
281 /* Set as newly constructed objects using the default constructor. */
282 void setAsNew(long len);
287 * \brief Append one elment to the end of the vector.
289 * Copy constructor is used to place the element in the vector.
291 void append(const T &val) { replace(BaseTable::length(), &val, 1); }
294 * \brief Append len elements to the end of the vector.
296 * Copy constructors are used to place the elements in the vector.
298 void append(const T *val, long len) { replace(BaseTable::length(), val, len); }
301 * \brief Append the contents of another vector.
303 * The other vector is left unchanged. Copy constructors are used to place
304 * the elements in the vector.
306 void append(const SVector &v)
307 { replace(BaseTable::length(), v.data, v.length()); }
310 * \brief Append len copies of item.
312 * The copy constructor is used to place the item in the vector.
314 void appendDup(const T &item, long len) { replaceDup(BaseTable::length(), item, len); }
317 * \brief Append a single newly created item.
319 * The new element is initialized with the default constructor.
321 void appendNew() { replaceNew(BaseTable::length(), 1); }
324 * \brief Append len newly created items.
326 * The new elements are initialized with the default constructor.
328 void appendNew(long len) { replaceNew(BaseTable::length(), len); }
334 * \brief Prepend one elment to the front of the vector.
336 * Copy constructor is used to place the element in the vector.
338 void prepend(const T &val) { insert(0, &val, 1); }
341 * \brief Prepend len elements to the front of the vector.
343 * Copy constructors are used to place the elements in the vector.
345 void prepend(const T *val, long len) { insert(0, val, len); }
348 * \brief Prepend the contents of another vector.
350 * The other vector is left unchanged. Copy constructors are used to place
351 * the elements in the vector.
353 void prepend(const SVector &v) { insert(0, v.data, v.length()); }
356 * \brief Prepend len copies of item.
358 * The copy constructor is used to place the item in the vector.
360 void prependDup(const T &item, long len) { insertDup(0, item, len); }
363 * \brief Prepend a single newly created item.
365 * The new element is initialized with the default constructor.
367 void prependNew() { insertNew(0, 1); }
370 * \brief Prepend len newly created items.
372 * The new elements are initialized with the default constructor.
374 void prependNew(long len) { insertNew(0, len); }
377 /* Convenience access. */
378 T &operator[](int i) const { return BaseTable::data[i]; }
379 long size() const { return BaseTable::length(); }
381 /* Various classes for setting the iterator */
383 struct IterFirst { IterFirst( const SVector &v ) : v(v) { } const SVector &v; };
384 struct IterLast { IterLast( const SVector &v ) : v(v) { } const SVector &v; };
385 struct IterNext { IterNext( const Iter &i ) : i(i) { } const Iter &i; };
386 struct IterPrev { IterPrev( const Iter &i ) : i(i) { } const Iter &i; };
389 * \brief Shared Vector Iterator.
394 /* Construct, assign. */
395 Iter() : ptr(0), ptrBeg(0), ptrEnd(0) { }
398 Iter( const SVector &v );
399 Iter( const IterFirst &vf );
400 Iter( const IterLast &vl );
401 inline Iter( const IterNext &vn );
402 inline Iter( const IterPrev &vp );
405 Iter &operator=( const SVector &v );
406 Iter &operator=( const IterFirst &vf );
407 Iter &operator=( const IterLast &vl );
408 inline Iter &operator=( const IterNext &vf );
409 inline Iter &operator=( const IterPrev &vl );
411 /** \brief Less than end? */
412 bool lte() const { return ptr != ptrEnd; }
414 /** \brief At end? */
415 bool end() const { return ptr == ptrEnd; }
417 /** \brief Greater than beginning? */
418 bool gtb() const { return ptr != ptrBeg; }
420 /** \brief At beginning? */
421 bool beg() const { return ptr == ptrBeg; }
423 /** \brief At first element? */
424 bool first() const { return ptr == ptrBeg+1; }
426 /** \brief At last element? */
427 bool last() const { return ptr == ptrEnd-1; }
429 /* Return the position. */
430 long pos() const { return ptr - ptrBeg - 1; }
431 T &operator[](int i) const { return ptr[i]; }
433 /** \brief Implicit cast to T*. */
434 operator T*() const { return ptr; }
436 /** \brief Dereference operator returns T&. */
437 T &operator *() const { return *ptr; }
439 /** \brief Arrow operator returns T*. */
440 T *operator->() const { return ptr; }
442 /** \brief Move to next item. */
443 T *operator++() { return ++ptr; }
445 /** \brief Move to next item. */
446 T *operator++(int) { return ptr++; }
448 /** \brief Move to next item. */
449 T *increment() { return ++ptr; }
451 /** \brief Move to previous item. */
452 T *operator--() { return --ptr; }
454 /** \brief Move to previous item. */
455 T *operator--(int) { return ptr--; }
457 /** \brief Move to previous item. */
458 T *decrement() { return --ptr; }
460 /** \brief Return the next item. Does not modify this. */
461 inline IterNext next() const { return IterNext(*this); }
463 /** \brief Return the previous item. Does not modify this. */
464 inline IterPrev prev() const { return IterPrev(*this); }
466 /** \brief The iterator is simply a pointer. */
469 /* For testing endpoints. */
473 /** \brief Return first element. */
474 IterFirst first() { return IterFirst( *this ); }
476 /** \brief Return last element. */
477 IterLast last() { return IterLast( *this ); }
480 void makeRawSpaceFor(long pos, long len);
482 void setAsCommon(long len);
483 long replaceCommon(long pos, long len);
484 long insertCommon(long pos, long len);
486 void upResize(long len);
487 void upResizeDup(long len);
488 void upResizeFromEmpty(long len);
489 void downResize(long len);
490 void downResizeDup(long len);
494 /* Create a vector with an intial number of elements and size. */
495 template <class T, class Resize> SVector<T, Resize>::
496 SVector( long size, long allocLen )
498 /* Allocate the space if we are given a positive allocLen. */
499 if ( allocLen > 0 ) {
500 /* Allocate the data needed. */
501 STabHead *head = (STabHead*) malloc( sizeof(STabHead) +
502 sizeof(T) * allocLen );
504 throw std::bad_alloc();
506 /* Set up the header and save the data pointer. */
508 head->allocLen = allocLen;
510 BaseTable::data = (T*) (head + 1);
513 /* Grow to the size specified. If we did not have enough space
514 * allocated that is ok. Table will be grown to the right size. */
520 * \brief Perform a shallow copy of the vector.
522 * Takes a reference to the contents of the other vector.
524 template <class T, class Resize> SVector<T, Resize>::
525 SVector(const SVector<T, Resize> &v)
527 /* Take a reference to other, if any data is allocated. */
531 /* Get the source header, up the refcount and ref it. */
532 STabHead *srcHead = ((STabHead*) v.data) - 1;
533 srcHead->refCount += 1;
534 BaseTable::data = (T*) (srcHead + 1);
540 * \brief Perform a shallow copy of the vector from only the header.
542 * Takes a reference to the contents specified by the header.
544 template <class T, class Resize> SVector<T, Resize>::
545 SVector(STabHead *head)
547 /* Take a reference to other, if the header is no-null. */
552 BaseTable::data = (T*) (head + 1);
559 * \brief Shallow copy another vector into this vector.
561 * Takes a reference to the other vector. The contents of this vector are
564 * \returns A reference to this.
566 template <class T, class Resize> SVector<T, Resize> &
567 SVector<T, Resize>:: operator=( const SVector &v )
569 /* First clean out the current contents. */
572 /* Take a reference to other, if any data is allocated. */
576 /* Get the source header, up the refcount and ref it. */
577 STabHead *srcHead = ((STabHead*) v.data) - 1;
578 srcHead->refCount += 1;
579 BaseTable::data = (T*) (srcHead + 1);
585 * \brief Shallow copy another vector into this vector from only the header.
587 * Takes a reference to the other header vector. The contents of this vector
590 * \returns A reference to this.
592 template <class T, class Resize> SVector<T, Resize> &
593 SVector<T, Resize>::operator=( STabHead *head )
595 /* First clean out the current contents. */
598 /* Take a reference to other, if the header is no-null. */
603 BaseTable::data = (T*) (head + 1);
608 /* Init a vector iterator with just a vector. */
609 template <class T, class Resize> SVector<T, Resize>::
610 Iter::Iter( const SVector &v )
613 if ( v.data == 0 || (length=(((STabHead*)v.data)-1)->tabLen) == 0 )
614 ptr = ptrBeg = ptrEnd = 0;
618 ptrEnd = v.data+length;
622 /* Init a vector iterator with the first of a vector. */
623 template <class T, class Resize> SVector<T, Resize>::
624 Iter::Iter( const IterFirst &vf )
627 if ( vf.v.data == 0 || (length=(((STabHead*)vf.v.data)-1)->tabLen) == 0 )
628 ptr = ptrBeg = ptrEnd = 0;
631 ptrBeg = vf.v.data-1;
632 ptrEnd = vf.v.data+length;
636 /* Init a vector iterator with the last of a vector. */
637 template <class T, class Resize> SVector<T, Resize>::
638 Iter::Iter( const IterLast &vl )
641 if ( vl.v.data == 0 || (length=(((STabHead*)vl.v.data)-1)->tabLen) == 0 )
642 ptr = ptrBeg = ptrEnd = 0;
644 ptr = vl.v.data+length-1;
645 ptrBeg = vl.v.data-1;
646 ptrEnd = vl.v.data+length;
650 /* Init a vector iterator with the next of some other iterator. */
651 template <class T, class Resize> SVector<T, Resize>::
652 Iter::Iter( const IterNext &vn )
660 /* Init a vector iterator with the prev of some other iterator. */
661 template <class T, class Resize> SVector<T, Resize>::
662 Iter::Iter( const IterPrev &vp )
670 /* Set a vector iterator with some vector. */
671 template <class T, class Resize> typename SVector<T, Resize>::Iter &
672 SVector<T, Resize>::Iter::operator=( const SVector &v )
675 if ( v.data == 0 || (length=(((STabHead*)v.data)-1)->tabLen) == 0 )
676 ptr = ptrBeg = ptrEnd = 0;
680 ptrEnd = v.data+length;
685 /* Set a vector iterator with the first element in a vector. */
686 template <class T, class Resize> typename SVector<T, Resize>::Iter &
687 SVector<T, Resize>::Iter::operator=( const IterFirst &vf )
690 if ( vf.v.data == 0 || (length=(((STabHead*)vf.v.data)-1)->tabLen) == 0 )
691 ptr = ptrBeg = ptrEnd = 0;
694 ptrBeg = vf.v.data-1;
695 ptrEnd = vf.v.data+length;
700 /* Set a vector iterator with the last element in a vector. */
701 template <class T, class Resize> typename SVector<T, Resize>::Iter &
702 SVector<T, Resize>::Iter::operator=( const IterLast &vl )
705 if ( vl.v.data == 0 || (length=(((STabHead*)vl.v.data)-1)->tabLen) == 0 )
706 ptr = ptrBeg = ptrEnd = 0;
708 ptr = vl.v.data+length-1;
709 ptrBeg = vl.v.data-1;
710 ptrEnd = vl.v.data+length;
715 /* Set a vector iterator with the next of some other iterator. */
716 template <class T, class Resize> typename SVector<T, Resize>::Iter &
717 SVector<T, Resize>::Iter::operator=( const IterNext &vn )
720 ptrBeg = vn.i.ptrBeg;
721 ptrEnd = vn.i.ptrEnd;
725 /* Set a vector iterator with the prev of some other iterator. */
726 template <class T, class Resize> typename SVector<T, Resize>::Iter &
727 SVector<T, Resize>::Iter::operator=( const IterPrev &vp )
730 ptrBeg = vp.i.ptrBeg;
731 ptrEnd = vp.i.ptrEnd;
735 /* Up resize the data for len elements using Resize::upResize to tell us the
736 * new length. Reads and writes allocLen. Does not read or write length.
737 * Assumes that there is some data allocated already. */
738 template <class T, class Resize> void SVector<T, Resize>::
741 /* Get the current header. */
742 STabHead *head = ((STabHead*)BaseTable::data) - 1;
744 /* Ask the resizer what the new length will be. */
745 long newLen = Resize::upResize(head->allocLen, len);
747 /* Did the data grow? */
748 if ( newLen > head->allocLen ) {
749 head->allocLen = newLen;
751 /* Table exists already, resize it up. */
752 head = (STabHead*) realloc( head, sizeof(STabHead) +
753 sizeof(T) * newLen );
755 throw std::bad_alloc();
757 /* Save the data pointer. */
758 BaseTable::data = (T*) (head + 1);
762 /* Allocates a new buffer for an up resize that requires a duplication of the
763 * data. Uses Resize::upResize to get the allocation length. Reads and writes
764 * allocLen. This upResize does write the new length. Assumes that there is
765 * some data allocated already. */
766 template <class T, class Resize> void SVector<T, Resize>::
767 upResizeDup(long len)
769 /* Get the current header. */
770 STabHead *head = ((STabHead*)BaseTable::data) - 1;
772 /* Ask the resizer what the new length will be. */
773 long newLen = Resize::upResize(head->allocLen, len);
775 /* Dereferencing the existing data, decrement the refcount. */
778 /* Table exists already, resize it up. */
779 head = (STabHead*) malloc( sizeof(STabHead) + sizeof(T) * newLen );
781 throw std::bad_alloc();
784 head->allocLen = newLen;
787 /* Save the data pointer. */
788 BaseTable::data = (T*) (head + 1);
791 /* Up resize the data for len elements using Resize::upResize to tell us the
792 * new length. Reads and writes allocLen. This upresize DOES write length.
793 * Assumes that no data is allocated. */
794 template <class T, class Resize> void SVector<T, Resize>::
795 upResizeFromEmpty(long len)
797 /* There is no table yet. If the len is zero, then there is no need to
800 /* Ask the resizer what the new length will be. */
801 long newLen = Resize::upResize(0, len);
803 /* If len is greater than zero then we are always allocating the table. */
804 STabHead *head = (STabHead*) malloc( sizeof(STabHead) +
805 sizeof(T) * newLen );
807 throw std::bad_alloc();
809 /* Set up the header and save the data pointer. Note that we set the
810 * length here. This differs from the other upResizes. */
812 head->allocLen = newLen;
814 BaseTable::data = (T*) (head + 1);
818 /* Down resize the data for len elements using Resize::downResize to determine
819 * the new length. Reads and writes allocLen. Does not read or write length. */
820 template <class T, class Resize> void SVector<T, Resize>::
823 /* If there is already no length, then there is nothing we can do. */
824 if ( BaseTable::data != 0 ) {
825 /* Get the current header. */
826 STabHead *head = ((STabHead*)BaseTable::data) - 1;
828 /* Ask the resizer what the new length will be. */
829 long newLen = Resize::downResize( head->allocLen, len );
831 /* Did the data shrink? */
832 if ( newLen < head->allocLen ) {
834 /* Simply free the data. */
839 /* Save the new allocated length. */
840 head->allocLen = newLen;
842 /* Not shrinking to size zero, realloc it to the smaller size. */
843 head = (STabHead*) realloc( head, sizeof(STabHead) +
844 sizeof(T) * newLen );
846 throw std::bad_alloc();
848 /* Save the new data ptr. */
849 BaseTable::data = (T*) (head + 1);
855 /* Allocate a new buffer for a down resize and duplication of the array. The
856 * new array will be len long and allocation size will be determined using
857 * Resize::downResize with the old array's allocLen. Does not actually copy
858 * any data. Reads and writes allocLen and writes the new len. */
859 template <class T, class Resize> void SVector<T, Resize>::
860 downResizeDup(long len)
862 /* If there is already no length, then there is nothing we can do. */
863 if ( BaseTable::data != 0 ) {
864 /* Get the current header. */
865 STabHead *head = ((STabHead*)BaseTable::data) - 1;
867 /* Ask the resizer what the new length will be. */
868 long newLen = Resize::downResize( head->allocLen, len );
870 /* Detaching from the existing head, decrement the refcount. */
873 /* Not shrinking to size zero, malloc it to the smaller size. */
874 head = (STabHead*) malloc( sizeof(STabHead) + sizeof(T) * newLen );
876 throw std::bad_alloc();
878 /* Save the new allocated length. */
880 head->allocLen = newLen;
883 /* Save the data pointer. */
884 BaseTable::data = (T*) (head + 1);
889 * \brief Free all memory used by the vector.
891 * The vector is reset to zero elements. Destructors are called on all
892 * elements in the vector. The space allocated for the vector is freed.
894 template <class T, class Resize> void SVector<T, Resize>::
897 if ( BaseTable::data != 0 ) {
898 /* Get the header and drop the refcount on the data. */
899 STabHead *head = ((STabHead*) BaseTable::data) - 1;
902 /* If the refcount just went down to zero nobody else is referencing
904 if ( head->refCount == 0 ) {
905 /* Call All destructors. */
906 T *pos = BaseTable::data;
907 for ( long i = 0; i < head->tabLen; pos++, i++ )
910 /* Free the data space. */
914 /* Clear the pointer. */
919 /* Prepare for setting the contents of the vector to some array len long.
920 * Handles reusing the existing space, detaching from a common space or
921 * growing from zero length automatically. */
922 template <class T, class Resize> void SVector<T, Resize>::
923 setAsCommon(long len)
925 if ( BaseTable::data != 0 ) {
926 /* Get the header. */
927 STabHead *head = ((STabHead*)BaseTable::data) - 1;
929 /* If the refCount is one, then we can reuse the space. Otherwise we
930 * must detach from the referenced data create new space. */
931 if ( head->refCount == 1 ) {
932 /* Call All destructors. */
933 T *pos = BaseTable::data;
934 for ( long i = 0; i < head->tabLen; pos++, i++ )
937 /* Adjust the allocated length. */
938 if ( len < head->tabLen )
940 else if ( len > head->tabLen )
943 if ( BaseTable::data != 0 ) {
944 /* Get the header again and set the length. */
945 head = ((STabHead*)BaseTable::data) - 1;
950 /* Just detach from the data. */
954 /* Make enough space. This will set the length. */
955 upResizeFromEmpty( len );
959 /* The table is currently empty. Make enough space. This will set the
961 upResizeFromEmpty( len );
966 * \brief Set the contents of the vector to be len elements exactly.
968 * The vector becomes len elements in length. Destructors are called on any
969 * existing elements in the vector. Copy constructors are used to place the
970 * new elements in the vector.
972 template <class T, class Resize> void SVector<T, Resize>::
973 setAs(const T *val, long len)
975 /* Common stuff for setting the array to len long. */
979 T *dst = BaseTable::data;
981 for ( long i = 0; i < len; i++, dst++, src++ )
987 * \brief Set the vector to len copies of item.
989 * The vector becomes len elements in length. Destructors are called on any
990 * existing elements in the vector. The element's copy constructor is used to
991 * copy the item into the vector.
993 template <class T, class Resize> void SVector<T, Resize>::
994 setAsDup(const T &item, long len)
996 /* Do the common stuff for setting the array to len long. */
999 /* Copy item in one spot at a time. */
1000 T *dst = BaseTable::data;
1001 for ( long i = 0; i < len; i++, dst++ )
1006 * \brief Set the vector to exactly len new items.
1008 * The vector becomes len elements in length. Destructors are called on any
1009 * existing elements in the vector. Default constructors are used to init the
1012 template <class T, class Resize> void SVector<T, Resize>::
1015 /* Do the common stuff for setting the array to len long. */
1018 /* Create items using default constructor. */
1019 T *dst = BaseTable::data;
1020 for ( long i = 0; i < len; i++, dst++ )
1024 /* Make space in vector for a replacement at pos of len items. Handles reusing
1025 * existing space, detaching or growing from zero space. */
1026 template <class T, class Resize> long SVector<T, Resize>::
1027 replaceCommon(long pos, long len)
1029 if ( BaseTable::data != 0 ) {
1030 /* Get the header. */
1031 STabHead *head = ((STabHead*)BaseTable::data) - 1;
1033 /* If we are given a negative position to replace at then treat it as
1034 * a position relative to the length. This doesn't have any meaning
1035 * unless the length is at least one. */
1037 pos = head->tabLen + pos;
1039 /* The end is the one past the last item that we want to write to. */
1040 long i, endPos = pos + len;
1042 if ( head->refCount == 1 ) {
1043 /* We can reuse the space. Make sure we have enough space. */
1044 if ( endPos > head->tabLen ) {
1047 /* Get the header again, whose addr may have changed after
1049 head = ((STabHead*)BaseTable::data) - 1;
1051 /* Delete any objects we need to delete. */
1052 T *item = BaseTable::data + pos;
1053 for ( i = pos; i < head->tabLen; i++, item++ )
1056 /* We are extending the vector, set the new data length. */
1057 head->tabLen = endPos;
1060 /* Delete any objects we need to delete. */
1061 T *item = BaseTable::data + pos;
1062 for ( i = pos; i < endPos; i++, item++ )
1067 /* Use endPos to calc the end of the vector. */
1068 long newLen = endPos;
1069 if ( newLen < head->tabLen )
1070 newLen = head->tabLen;
1072 /* Duplicate and grow up to endPos. This will set the length. */
1073 upResizeDup( newLen );
1075 /* Copy from src up to pos. */
1076 const T *src = (T*) (head + 1);
1077 T *dst = BaseTable::data;
1078 for ( i = 0; i < pos; i++, dst++, src++)
1081 /* Copy any items after the replace range. */
1082 for ( i += len, src += len, dst += len;
1083 i < head->tabLen; i++, dst++, src++ )
1088 /* There is no data initially, must grow from zero. This will set the
1090 upResizeFromEmpty( len );
1098 * \brief Replace len elements at position pos.
1100 * If there are existing elements at the positions to be replaced, then
1101 * destructors are called before the space is used. Copy constructors are used
1102 * to place the elements into the vector. It is allowable for the pos and
1103 * length to specify a replacement that overwrites existing elements and
1104 * creates new ones. If pos is greater than the length of the vector then
1105 * undefined behaviour results. If pos is negative, then it is treated as an
1106 * offset relative to the length of the vector.
1108 template <class T, class Resize> void SVector<T, Resize>::
1109 replace(long pos, const T *val, long len)
1111 /* Common work for replacing in the vector. */
1112 pos = replaceCommon( pos, len );
1114 /* Copy data in using copy constructor. */
1115 T *dst = BaseTable::data + pos;
1117 for ( long i = 0; i < len; i++, dst++, src++ )
1122 * \brief Replace at position pos with len copies of an item.
1124 * If there are existing elements at the positions to be replaced, then
1125 * destructors are called before the space is used. The copy constructor is
1126 * used to place the element into this vector. It is allowable for the pos and
1127 * length to specify a replacement that overwrites existing elements and
1128 * creates new ones. If pos is greater than the length of the vector then
1129 * undefined behaviour results. If pos is negative, then it is treated as an
1130 * offset relative to the length of the vector.
1132 template <class T, class Resize> void SVector<T, Resize>::
1133 replaceDup(long pos, const T &val, long len)
1135 /* Common replacement stuff. */
1136 pos = replaceCommon( pos, len );
1138 /* Copy data in using copy constructor. */
1139 T *dst = BaseTable::data + pos;
1140 for ( long i = 0; i < len; i++, dst++ )
1145 * \brief Replace at position pos with len new elements.
1147 * If there are existing elements at the positions to be replaced, then
1148 * destructors are called before the space is used. The default constructor is
1149 * used to initialize the new elements. It is allowable for the pos and length
1150 * to specify a replacement that overwrites existing elements and creates new
1151 * ones. If pos is greater than the length of the vector then undefined
1152 * behaviour results. If pos is negative, then it is treated as an offset
1153 * relative to the length of the vector.
1155 template <class T, class Resize> void SVector<T, Resize>::
1156 replaceNew(long pos, long len)
1158 /* Do the common replacement stuff. */
1159 pos = replaceCommon( pos, len );
1161 /* Copy data in using copy constructor. */
1162 T *dst = BaseTable::data + pos;
1163 for ( long i = 0; i < len; i++, dst++ )
1168 * \brief Remove len elements at position pos.
1170 * Destructor is called on all elements removed. Elements to the right of pos
1171 * are shifted len spaces to the left to take up the free space. If pos is
1172 * greater than or equal to the length of the vector then undefined behavior
1173 * results. If pos is negative then it is treated as an offset relative to the
1174 * length of the vector.
1176 template <class T, class Resize> void SVector<T, Resize>::
1177 remove(long pos, long len)
1179 /* If there is no data, we can't delete anything anyways. */
1180 if ( BaseTable::data != 0 ) {
1181 /* Get the header. */
1182 STabHead *head = ((STabHead*)BaseTable::data) - 1;
1184 /* If we are given a negative position to remove at then
1185 * treat it as a position relative to the length. */
1187 pos = head->tabLen + pos;
1189 /* The first position after the last item deleted. */
1190 long endPos = pos + len;
1192 /* The New data length. */
1193 long i, newLen = head->tabLen - len;
1195 if ( head->refCount == 1 ) {
1196 /* We are the only ones using the data. We can reuse
1197 * the existing space. */
1199 /* The place in the data we are deleting at. */
1200 T *dst = BaseTable::data + pos;
1202 /* Call Destructors. */
1203 T *item = BaseTable::data + pos;
1204 for ( i = 0; i < len; i += 1, item += 1 )
1207 /* Shift data over if necessary. */
1208 long lenToSlideOver = head->tabLen - endPos;
1209 if ( len > 0 && lenToSlideOver > 0 )
1210 memmove(BaseTable::data + pos, dst + len, sizeof(T)*lenToSlideOver);
1212 /* Shrink the data if necessary. */
1213 downResize( newLen );
1215 if ( BaseTable::data != 0 ) {
1216 /* Get the header again (because of the resize) and set the
1217 * new data length. */
1218 head = ((STabHead*)BaseTable::data) - 1;
1219 head->tabLen = newLen;
1223 /* Must detach from the common data. Just copy the non-deleted
1224 * items from the common data. */
1226 /* Duplicate and grow down to newLen. This will set the length. */
1227 downResizeDup( newLen );
1229 /* Copy over just the non-deleted parts. */
1230 const T *src = (T*) (head + 1);
1231 T *dst = BaseTable::data;
1232 for ( i = 0; i < pos; i++, dst++, src++ )
1235 /* ... and the second half. */
1236 for ( i += len, src += len; i < head->tabLen; i++, src++, dst++ )
1242 /* Shift over existing data. Handles reusing existing space, detaching or
1243 * growing from zero space. */
1244 template <class T, class Resize> long SVector<T, Resize>::
1245 insertCommon(long pos, long len)
1247 if ( BaseTable::data != 0 ) {
1248 /* Get the header. */
1249 STabHead *head = ((STabHead*)BaseTable::data) - 1;
1251 /* If we are given a negative position to insert at then treat it as a
1252 * position relative to the length. This only has meaning if there is
1255 pos = head->tabLen + pos;
1257 /* Calculate the new length. */
1258 long i, newLen = head->tabLen + len;
1260 if ( head->refCount == 1 ) {
1261 /* Up resize, we are growing. */
1264 /* Get the header again, (the addr may have changed after
1266 head = ((STabHead*)BaseTable::data) - 1;
1268 /* Shift over data at insert spot if needed. */
1269 if ( len > 0 && pos < head->tabLen ) {
1270 memmove( BaseTable::data + pos + len, BaseTable::data + pos,
1271 sizeof(T)*(head->tabLen - pos) );
1274 /* Grow the length by the len inserted. */
1275 head->tabLen += len;
1278 /* Need to detach from the existing array. Copy over the other
1279 * parts. This will set the length. */
1280 upResizeDup( newLen );
1282 /* Copy over the parts around the insert. */
1283 const T *src = (T*) (head + 1);
1284 T *dst = BaseTable::data;
1285 for ( i = 0; i < pos; i++, dst++, src++ )
1288 /* ... and the second half. */
1289 for ( dst += len; i < head->tabLen; i++, src++, dst++ )
1294 /* There is no existing data. Start from zero. This will set the
1296 upResizeFromEmpty( len );
1304 * \brief Insert len elements at position pos.
1306 * Elements in the vector from pos onward are shifted len spaces to the right.
1307 * The copy constructor is used to place the elements into this vector. If pos
1308 * is greater than the length of the vector then undefined behaviour results.
1309 * If pos is negative then it is treated as an offset relative to the length
1312 template <class T, class Resize> void SVector<T, Resize>::
1313 insert(long pos, const T *val, long len)
1315 /* Do the common insertion stuff. */
1316 pos = insertCommon( pos, len );
1318 /* Copy data in element by element. */
1319 T *dst = BaseTable::data + pos;
1321 for ( long i = 0; i < len; i++, dst++, src++ )
1326 * \brief Insert len copies of item at position pos.
1328 * Elements in the vector from pos onward are shifted len spaces to the right.
1329 * The copy constructor is used to place the element into this vector. If pos
1330 * is greater than the length of the vector then undefined behaviour results.
1331 * If pos is negative then it is treated as an offset relative to the length
1334 template <class T, class Resize> void SVector<T, Resize>::
1335 insertDup(long pos, const T &item, long len)
1337 /* Do the common insertion stuff. */
1338 pos = insertCommon( pos, len );
1340 /* Copy the data item in one at a time. */
1341 T *dst = BaseTable::data + pos;
1342 for ( long i = 0; i < len; i++, dst++ )
1348 * \brief Insert len new elements using the default constructor.
1350 * Elements in the vector from pos onward are shifted len spaces to the right.
1351 * Default constructors are used to init the new elements. If pos is off the
1352 * end of the vector then undefined behaviour results. If pos is negative then
1353 * it is treated as an offset relative to the length of the vector.
1355 template <class T, class Resize> void SVector<T, Resize>::
1356 insertNew(long pos, long len)
1358 /* Do the common insertion stuff. */
1359 pos = insertCommon( pos, len );
1361 /* Init new data with default constructors. */
1362 T *dst = BaseTable::data + pos;
1363 for ( long i = 0; i < len; i++, dst++ )
1367 /* Makes space for len items, Does not init the items in any way. If pos is
1368 * greater than the length of the vector then undefined behaviour results.
1369 * Updates the length of the vector. */
1370 template <class T, class Resize> void SVector<T, Resize>::
1371 makeRawSpaceFor(long pos, long len)
1373 if ( BaseTable::data != 0 ) {
1374 /* Get the header. */
1375 STabHead *head = ((STabHead*)BaseTable::data) - 1;
1377 /* Calculate the new length. */
1378 long i, newLen = head->tabLen + len;
1380 if ( head->refCount == 1 ) {
1381 /* Up resize, we are growing. */
1384 /* Get the header again, (the addr may have changed after
1386 head = ((STabHead*)BaseTable::data) - 1;
1388 /* Shift over data at insert spot if needed. */
1389 if ( len > 0 && pos < head->tabLen ) {
1390 memmove( BaseTable::data + pos + len, BaseTable::data + pos,
1391 sizeof(T)*(head->tabLen - pos) );
1394 /* Grow the length by the len inserted. */
1395 head->tabLen += len;
1398 /* Need to detach from the existing array. Copy over the other
1399 * parts. This will set the length. */
1400 upResizeDup( newLen );
1402 /* Copy over the parts around the insert. */
1403 const T *src = (T*) (head + 1);
1404 T *dst = BaseTable::data;
1405 for ( i = 0; i < pos; i++, dst++, src++ )
1408 /* ... and the second half. */
1409 for ( dst += len; i < head->tabLen; i++, src++, dst++ )
1414 /* There is no existing data. Start from zero. This will set the
1416 upResizeFromEmpty( len );
1421 #ifdef AAPL_NAMESPACE
1426 #endif /* _AAPL_SVECTOR_H */