/* tvector.cpp May 14 1997 Chris Lacher Implementation of the class tvector History: 05/14/97: initial development 10/08/97: container protocol added 03/30/98: memory efficiency, capacity decrease capability, PushBack runtime amortized O(1) 07/30/00: nomenclature changes 08/26/00: changed <class T> to <typename T> throughout 12/05/00: subsumption of tvector.cpp 04/19/01: namespace rcl 04/19/01: index on size_t 02/10/02: changed return type of Front() and Back() to reference 12/13/02: namespace fsu 01/01/04: template the iterator "pointer arithmetic" operations 11/10/04: removed operator const T* Revised 10/8/97 as follows: 1. container class protocol added 2. design revised to lessen memory re-allocations: There are now 2 protected size_t (unsigned int) data fields: size_, capacity_ capacity_ and size_ are independent (subject to size_ <= capacity_), and reductions in size_ do not re-allocate memory When capacity_ is increased in support of Insert() operations, it it is doubled. (This results in O(n) time for n pushback operations.) A file-scope constant defaultCapacity is used to set capacity_ by the default constructor. NOTE that the implementations in this file are included into the file tvector.h, near the end of that file and inside the fsu namespace. Implementation is separated from class declaration here so that they can be released at different times. The intended use and effect is the same as if the implementations were actually in the file tvector.h. Copyright 1997 - 2007, R.C. Lacher */ namespace tvector { static const size_t defaultCapacity = 10; } //---------------------------------- // TVector<T>:: Implementations //---------------------------------- // operator overloads template <typename T> std::ostream& operator << (std::ostream& os, const TVector<T>& v) { v.Display(os); return os; } // end << template <typename T> int operator == (const TVector<T>& v1, const TVector<T>& v2) { if (v1.Size() != v2.Size()) return 0; for (size_t i = 0; i < v1.Size(); ++i) if (v1[i] != v2[i]) return 0; return 1; } template <typename T> int operator != (const TVector<T>& v1, const TVector<T>& v2) { return !(v1 == v2); } // public methods template <typename T> TVector<T>::TVector() : size_(0), capacity_(tvector::defaultCapacity), content_(0) // Construct a vector of zero size and default capacity { content_ = NewArray(capacity_); } template <typename T> TVector<T>::TVector(size_t sz) : size_(sz), capacity_(sz), content_(0) // Construct a vector of size and capacity sz { content_ = NewArray(capacity_); } template <typename T> TVector<T>::TVector(size_t sz, const T& Tval) : size_(sz), capacity_(sz), content_(0) // Construct a vector with all elements initialized to the same value { content_ = NewArray(capacity_); for (size_t i = 0; i < size_; ++i) { content_[i] = Tval; } } template <typename T> TVector<T>::TVector(const TVector<T>& source) : size_(source.size_), capacity_(source.capacity_) // copy constructor { content_ = NewArray(capacity_); for (size_t i = 0; i < size_; ++i) { content_[i] = source.content_[i]; } } template <typename T> TVector<T>::~TVector() // destructor { delete [] content_; content_ = 0; size_ = capacity_ = 0; } template <typename T> TVector<T>& TVector<T>::operator = (const TVector<T>& source) // assignment operator { if (this != &source) { // the NULL case if (source.capacity_ == 0) { if (capacity_ > 0) delete [] content_; size_ = capacity_ = 0; content_ = 0; return *this; } // set capacity if (capacity_ != source.capacity_) { if (capacity_ > 0) delete [] content_; capacity_ = source.capacity_; content_ = NewArray(capacity_); } // set size_ size_ = source.size_; // copy content for (size_t i = 0; i < size_; ++i) { content_[i] = source.content_[i]; } } // end if return *this; } // end assignment operator = template <typename T> TVector<T>& TVector<T>::operator += (const TVector<T>& V) { if (V.Empty()) return *this; size_t i, s(Size()); if (!SetSize(s + V.Size())) { std::cerr << "** TVector error: cannot expand vector in operator +=()\n"; return *this; } for (i = 0; i < V.Size(); ++i) content_[i + s] = V[i]; return *this; } template <typename T> T& TVector<T>::operator [] (size_t i) // element operator { if (i >= size_) { std::cerr << "** TVector<T> Error: vector index out of range!\n"; if (i >= capacity_) exit(EXIT_FAILURE); } return content_[i]; } template <typename T> const T& TVector<T>::operator [] (size_t i) const // element operator { if (i >= size_) { std::cerr << "** TVector<T> Error: vector index out of range!\n"; if (i >= capacity_) exit(EXIT_FAILURE); } return content_[i]; } template <typename T> int TVector<T>::SetCapacity(size_t newcapacity) // Reserve more (or less) space for vector growth; // this is where memory is allocated. Note that this is // an expensive operation and should be used judiciuosly. // SetCapacity() is called by SetSize() only when increased capacity // is required. If the client needs to reduce capacity, a call must be // made specifically to SetCapacity. { if (newcapacity == 0) { delete [] content_; content_ = 0; size_ = capacity_ = 0; return 1; } if (newcapacity != capacity_) { T* newcontent = NewArray(newcapacity); if (newcontent == 0) return 0; if (size_ > newcapacity) size_ = newcapacity; for (size_t i = 0; i < size_; ++i) { newcontent[i] = content_[i]; } capacity_ = newcapacity; delete [] content_; content_ = newcontent; } return 1; } // end SetCapacity() template <typename T> int TVector<T>::SetSize(size_t newsize) // (re)set size { if (newsize > capacity_) if (!SetCapacity(newsize)) return 0; size_ = newsize; return 1; } template <typename T> int TVector<T>::SetSize(size_t newsize, const T& Tval) // (re)set size_ with extra elements initialized to the same value { size_t i, oldsize = size_; if (!SetSize(newsize)) return 0; for (i = oldsize; i < newsize; ++i) { content_[i] = Tval; } return 1; } template <typename T> size_t TVector<T>::Capacity() const // return capacity of vector (current memory reserved) { return capacity_; } // Container class protocol implementation template <typename T> int TVector<T>::Empty() const { return size_ == 0; } template <typename T> size_t TVector<T>::Size() const { return size_; } /* template <typename T> TVector<T>::operator const T* () const // auto conversion of vector to array { return content_; } */ template <typename T> int TVector<T>::PushBack(const T& Tval) // grow by doubling capacity { if (size_ >= capacity_) { if (capacity_ == 0) { if (!SetCapacity(1)) return 0; } else if (!SetCapacity(2 * capacity_)) return 0; } content_[size_] = Tval; ++size_; return 1; } template <typename T> int TVector<T>::PopBack() { if (size_ == 0) return 0; --size_; return 1; } template <typename T> void TVector<T>::Clear() { SetSize(0); } template <typename T> T& TVector<T>::Front() { if (size_ == 0) { std::cerr << "** TVector error: invalid Front() called on empty vector\n"; exit (EXIT_FAILURE); } return content_[0]; } template <typename T> const T& TVector<T>::Front() const { if (size_ == 0) { std::cerr << "** TVector error: invalid Front() called on empty vector\n"; exit (EXIT_FAILURE); } return content_[0]; } template <typename T> T& TVector<T>::Back() { if (size_ == 0) { std::cerr << "** TVector error: invalid Back() called on empty vector\n"; exit (EXIT_FAILURE); } return content_[size_ - 1]; } template <typename T> const T& TVector<T>::Back() const { if (size_ == 0) { std::cerr << "** TVector error: invalid Back() called on empty vector\n"; exit (EXIT_FAILURE); } return content_[size_ - 1]; } // Iterator support template <typename T> TVectorIterator<T> TVector<T>::Begin () const { Iterator I(*this); return I; } template <typename T> TVectorIterator<T> TVector<T>::End() const { Iterator I (*this); I.Tptr_ += size_; return I; } template <typename T> TVectorIterator<T> TVector<T>::rBegin() const { Iterator I(*this); I.Tptr_ += size_ - 1; return I; } template <typename T> TVectorIterator<T> TVector<T>::rEnd() const { Iterator I(*this); return --I; } template <typename T> void TVector<T>::Display(std::ostream& os, char ofc) const { size_t i; if (ofc == '\0') for (i = 0; i < size_; ++i) os << content_[i]; else for (i = 0; i < size_; ++i) os << content_[i] << ofc; } // end Display() template <typename T> void TVector<T>::Dump(std::ostream& os) const { size_t i; for (i = 0; i < capacity_; ++i) { if (i < 10) os << " content_[" << i << "] == " << content_[i]; else if (i < 100) os << " content_[" << i << "] == " << content_[i]; else if (i < 1000) os << " content_[" << i << "] == " << content_[i]; else if (i < 10000) os << " content_[" << i << "] == " << content_[i]; else os << "content_[" << i << "] == " << content_[i]; if (i == 0) os << " <- begin"; if (i == size_) os << " <- end"; os << '\n'; } i = capacity_; if (i < 10) os << " content_[" << i << "] == <undefined>"; else if (i < 100) os << " content_[" << i << "] == <undefined>"; else if (i < 1000) os << " content_[" << i << "] == <undefined>"; else if (i < 10000) os << " content_[" << i << "] == <undefined>"; else os << "content_[" << i << "] == <undefined>"; if (i == size_) os << " <- end"; os << '\n'; } // end Dump() // protected template <typename T> T* TVector<T>::NewArray(size_t newcapacity) // safe memory allocator { T* Tptr; if (newcapacity > 0) { Tptr = new T [newcapacity]; if (Tptr == 0) { std::cerr << "** TVector error: unable to allocate memory for array!\n"; exit (EXIT_FAILURE); } } else { Tptr = 0; } return Tptr; } //----------------------------------------- // TVectorIterator<T>:: Implementations //----------------------------------------- template <typename T> TVectorIterator<T>::TVectorIterator () : Tptr_(0) {} template <typename T> TVectorIterator<T>::TVectorIterator (const TVector<T>& V) : Tptr_(V.content_) {} template <typename T> TVectorIterator<T>::TVectorIterator (const Iterator& I) : Tptr_(I.Tptr_) {} template <typename T> void TVectorIterator<T>::Initialize (const TVector<T>& V) { Tptr_ = V.content_; } template <typename T> void TVectorIterator<T>::rInitialize (const TVector<T>& V) { Tptr_ = V.content_ + V.size_ - 1; } template <typename T> T& TVectorIterator<T>::Retrieve () { if (Tptr_ == 0) { std::cerr << "** TVectorIterator error: invalid Retrieve()\n"; exit (EXIT_FAILURE); } return *Tptr_; } template <typename T> const T& TVectorIterator<T>::Retrieve () const { if (Tptr_ == 0) { std::cerr << "** TVectorIterator error: invalid Retrieve()\n"; exit (EXIT_FAILURE); } return *Tptr_; } template <typename T> int TVectorIterator<T>::Valid () const { return Tptr_ != 0; } template <typename T> int TVectorIterator<T>::operator == (const Iterator& I2) const { return Tptr_ == I2.Tptr_; } template <typename T> int TVectorIterator<T>::operator != (const Iterator& I2) const { return !(*this == I2); } template <typename T> T& TVectorIterator<T>::operator * () { if (!Valid()) { std::cerr << "** TVectorIterator error: invalid dereference\n"; exit (EXIT_FAILURE); } return *Tptr_; } template <typename T> const T& TVectorIterator<T>::operator * () const { if (!Valid()) { std::cerr << "** TVectorIterator error: invalid dereference\n"; exit (EXIT_FAILURE); } return *Tptr_; } template <typename T> T& TVectorIterator<T>::operator [] (size_t i) { if (!Valid()) { std::cerr << "** TVectorIterator error: invalid dereference\n"; exit (EXIT_FAILURE); } return *(Tptr_ + i); } template <typename T> const T& TVectorIterator<T>::operator [] (size_t i) const { if (!Valid()) { std::cerr << "** TVectorIterator error: invalid dereference\n"; exit (EXIT_FAILURE); } return *(Tptr_ + i); } template <typename T> TVectorIterator<T>& TVectorIterator<T>::operator = (const Iterator & I) { Tptr_ = I.Tptr_; return *this; } template <typename T> TVectorIterator<T>& TVectorIterator<T>::operator ++ () { ++Tptr_; return *this; } template <typename T> TVectorIterator<T> TVectorIterator<T>::operator ++ (int) { Iterator I(*this); operator ++(); return I; } template <typename T> TVectorIterator<T>& TVectorIterator<T>::operator -- () { --Tptr_; return *this; } template <typename T> TVectorIterator<T> TVectorIterator<T>::operator -- (int) { Iterator I(*this); operator --(); return I; } template <typename T> long TVectorIterator<T>::operator - (const TVectorIterator<T> & I2) const { return Tptr_ - I2.Tptr_; } template <typename T> template <typename N> TVectorIterator<T> TVectorIterator<T>::operator + (N n) const { Iterator I1 = *this; I1.Tptr_ += n; return I1; } template <typename T> template <typename N> TVectorIterator<T>& TVectorIterator<T>::operator += (N n) { Tptr_ += n; return *this; } template <typename T> template <typename N> TVectorIterator<T>& TVectorIterator<T>::operator -= (N n) { Tptr_ -= n; return *this; }