253 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			253 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // vim: set sts=8 ts=2 sw=2 tw=99 et:
 | |
| //
 | |
| // Copyright (C) 2013, David Anderson and AlliedModders LLC
 | |
| // All rights reserved.
 | |
| // 
 | |
| // Redistribution and use in source and binary forms, with or without
 | |
| // modification, are permitted provided that the following conditions are met:
 | |
| // 
 | |
| //  * Redistributions of source code must retain the above copyright notice, this
 | |
| //    list of conditions and the following disclaimer.
 | |
| //  * Redistributions in binary form must reproduce the above copyright notice,
 | |
| //    this list of conditions and the following disclaimer in the documentation
 | |
| //    and/or other materials provided with the distribution.
 | |
| //  * Neither the name of AlliedModders LLC nor the names of its contributors
 | |
| //    may be used to endorse or promote products derived from this software
 | |
| //    without specific prior written permission.
 | |
| //
 | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | |
| // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 | |
| // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | |
| // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | |
| // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | |
| // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | |
| // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | |
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | |
| // POSSIBILITY OF SUCH DAMAGE.
 | |
| 
 | |
| #ifndef _INCLUDE_KEIMA_TPL_CPP_VECTOR_H_
 | |
| #define _INCLUDE_KEIMA_TPL_CPP_VECTOR_H_
 | |
| 
 | |
| #include <new>
 | |
| #include <stdlib.h>
 | |
| #include <am-allocator-policies.h>
 | |
| #include <am-utility.h>
 | |
| #include <am-moveable.h>
 | |
| 
 | |
| namespace ke {
 | |
| 
 | |
| template <typename T, typename AllocPolicy = SystemAllocatorPolicy>
 | |
| class Vector : public AllocPolicy
 | |
| {
 | |
|  public:
 | |
|   Vector(AllocPolicy = AllocPolicy())
 | |
|    : data_(NULL),
 | |
|      nitems_(0),
 | |
|      maxsize_(0)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   Vector(Moveable<Vector<T, AllocPolicy> > other) {
 | |
|     data_ = other->data_;
 | |
|     nitems_ = other->nitems_;
 | |
|     maxsize_ = other->maxsize_;
 | |
|     other->reset();
 | |
|   }
 | |
| 
 | |
|   ~Vector() {
 | |
|     zap();
 | |
|   }
 | |
| 
 | |
|   bool append(const T &item) {
 | |
|     if (!growIfNeeded(1))
 | |
|       return false;
 | |
|     new (&data_[nitems_]) T(item);
 | |
|     nitems_++;
 | |
|     return true;
 | |
|   }
 | |
|   bool append(Moveable<T> item) {
 | |
|     if (!growIfNeeded(1))
 | |
|       return false;
 | |
|     new (&data_[nitems_]) T(item);
 | |
|     nitems_++;
 | |
|     return true;
 | |
|   }
 | |
|   void infallibleAppend(const T &item) {
 | |
|     assert(growIfNeeded(1));
 | |
|     new (&data_[nitems_]) T(item);
 | |
|     nitems_++;
 | |
|   }
 | |
|   void infallibleAppend(Moveable<T> item) {
 | |
|     assert(growIfNeeded(1));
 | |
|     new (&data_[nitems_]) T(item);
 | |
|     nitems_++;
 | |
|   }
 | |
| 
 | |
|   // Shift all elements including |at| up by one, and insert |item| at the
 | |
|   // given position. If |at| is one greater than the last usable index,
 | |
|   // i.e. |at == length()|, then this is the same as append(). No other
 | |
|   // invalid indexes are allowed.
 | |
|   //
 | |
|   // This is a linear-time operation.
 | |
|   bool insert(size_t at, const T &item) {
 | |
|     if (at == length())
 | |
|       return append(item);
 | |
|     if (!moveUp(at))
 | |
|       return false;
 | |
|     new (&data_[at]) T(item);
 | |
|     return true;
 | |
|   }
 | |
|   bool insert(size_t at, Moveable<T> item) {
 | |
|     if (at == length())
 | |
|       return append(item);
 | |
|     if (!moveUp(at))
 | |
|       return false;
 | |
|     new (&data_[at]) T(item);
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   // Shift all elements at the given position down, removing the given
 | |
|   // element. This is a linear-time operation.
 | |
|   void remove(size_t at) {
 | |
|     for (size_t i = at; i < length() - 1; i++)
 | |
|       data_[i] = Moveable<T>(data_[i + 1]);
 | |
|     pop();
 | |
|   }
 | |
| 
 | |
|   T popCopy() {
 | |
|     T t = at(length() - 1);
 | |
|     pop();
 | |
|     return t;
 | |
|   }
 | |
|   void pop() {
 | |
|     assert(nitems_);
 | |
|     data_[nitems_ - 1].~T();
 | |
|     nitems_--;
 | |
|   }
 | |
|   bool empty() const {
 | |
|     return length() == 0;
 | |
|   }
 | |
|   size_t length() const {
 | |
|     return nitems_;
 | |
|   }
 | |
|   T& at(size_t i) {
 | |
|     assert(i < length());
 | |
|     return data_[i];
 | |
|   }
 | |
|   const T& at(size_t i) const {
 | |
|     assert(i < length());
 | |
|     return data_[i];
 | |
|   }
 | |
|   T& operator [](size_t i) {
 | |
|     return at(i);
 | |
|   }
 | |
|   const T& operator [](size_t i) const {
 | |
|     return at(i);
 | |
|   }
 | |
|   void clear() {
 | |
|     nitems_ = 0;
 | |
|   }
 | |
|   const T &back() const {
 | |
|     return at(length() - 1);
 | |
|   }
 | |
|   T &back() {
 | |
|     return at(length() - 1);
 | |
|   }
 | |
| 
 | |
|   T *buffer() const {
 | |
|     return data_;
 | |
|   }
 | |
| 
 | |
|   bool ensure(size_t desired) {
 | |
|     if (desired <= length())
 | |
|       return true;
 | |
| 
 | |
|     return growIfNeeded(desired - length());
 | |
|   }
 | |
| 
 | |
|   Vector &operator =(Moveable<Vector<T, AllocPolicy> > other) {
 | |
|     data_ = other->data_;
 | |
|     nitems_ = other->nitems_;
 | |
|     maxsize_ = other->maxsize_;
 | |
|     other->reset();
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   // These are disallowed because they basically violate the failure handling
 | |
|   // model for AllocPolicies and are also likely to have abysmal performance.
 | |
|   Vector(const Vector<T> &other) KE_DELETE;
 | |
|   Vector &operator =(const Vector<T> &other) KE_DELETE;
 | |
| 
 | |
|  private:
 | |
|   void zap() {
 | |
|     for (size_t i = 0; i < nitems_; i++)
 | |
|       data_[i].~T();
 | |
|     this->free(data_);
 | |
|   }
 | |
|   void reset() {
 | |
|     data_ = NULL;
 | |
|     nitems_ = 0;
 | |
|     maxsize_ = 0;
 | |
|   }
 | |
| 
 | |
|   bool moveUp(size_t at) {
 | |
|     // Note: we don't use append() here. Passing an element as a Moveable into
 | |
|     // insert() or append() can break, since the underlying storage could be
 | |
|     // reallocated, invalidating the Moveable reference. Instead, we inline
 | |
|     // the logic to append() to ensure growIfNeeded occurs before any
 | |
|     // references are taken.
 | |
|     if (!growIfNeeded(1))
 | |
|       return false;
 | |
|     new (&data_[nitems_]) T(Moveable<T>(data_[nitems_ - 1]));
 | |
|     nitems_++;
 | |
|     for (size_t i = nitems_ - 2; i > at; i--)
 | |
|       data_[i] = Moveable<T>(data_[i - 1]);
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool growIfNeeded(size_t needed)
 | |
|   {
 | |
|     if (!IsUintPtrAddSafe(nitems_, needed)) {
 | |
|       this->reportAllocationOverflow();
 | |
|       return false;
 | |
|     }
 | |
|     if (nitems_ + needed < maxsize_)
 | |
|       return true;
 | |
| 
 | |
|     size_t new_maxsize = maxsize_ ? maxsize_ : 8;
 | |
|     while (nitems_ + needed > new_maxsize) {
 | |
|       if (!IsUintPtrMultiplySafe(new_maxsize, 2)) {
 | |
|         this->reportAllocationOverflow();
 | |
|         return false;
 | |
|       }
 | |
|       new_maxsize *= 2;
 | |
|     }
 | |
| 
 | |
|     T* newdata = (T*)this->malloc(sizeof(T) * new_maxsize);
 | |
|     if (newdata == NULL)
 | |
|       return false;
 | |
|     for (size_t i = 0; i < nitems_; i++) {
 | |
|       new (&newdata[i]) T(Moveable<T>(data_[i]));
 | |
|       data_[i].~T();
 | |
|     }
 | |
|     this->free(data_);
 | |
| 
 | |
|     data_ = newdata;
 | |
|     maxsize_ = new_maxsize;
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   T* data_;
 | |
|   size_t nitems_;
 | |
|   size_t maxsize_;
 | |
| };
 | |
| 
 | |
| }
 | |
| 
 | |
| #endif /* _INCLUDE_KEIMA_TPL_CPP_VECTOR_H_ */
 | |
| 
 |