//======================================================================== // // GooVector.h // // This file is licensed under the GPLv2 or later // // Copyright 2010 David Benjamin // Copyright 2010 Albert Astals Cid // //======================================================================== #ifndef GOO_GOOVECTOR_H #define GOO_GOOVECTOR_H #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include // vector implementations need placement-new #include #include /* Mostly STL-compatible vector class. Should correctly call constructors and * destructors, but does not carefully handle alignment requirements. */ template class GooVector { public: /* various STL-compatible typedefs */ typedef T value_type; typedef T* pointer; typedef T& reference; typedef const T& const_reference; typedef size_t size_type; typedef int difference_type; typedef T* iterator; typedef const T* const_iterator; // TODO: reverse_iterator, if we feel like it GooVector() : m_data(NULL), m_capacity(0), m_size(0) {} explicit GooVector(size_type n) : m_data(NULL), m_capacity(0), m_size(0) { resize(n); } explicit GooVector(size_type n, const T& t) : m_data(NULL), m_capacity(0), m_size(0) { resize(n, t); } explicit GooVector(const GooVector& gv) : m_data(NULL), m_capacity(0), m_size(0) { reserve(gv.size()); for (size_type i = 0; i < m_size; i++) { push_back(gv[i]); } } ~GooVector() { clear(); } iterator begin() { return m_data; } const_iterator begin() const { return m_data; } iterator end() { return m_data + m_size; } const_iterator end() const { return m_data + m_size; } size_type size() const { return m_size; } size_type capacity() const { return m_capacity; } bool empty() const { return m_size == 0; } reference operator[] (size_type n) { return m_data[n]; } const_reference operator[] (size_type n) const { return m_data[n]; } reference at(size_type n) { assert(n < m_size); return m_data[n]; } const_reference at(size_type n) const { assert(n < m_size); return m_data[n]; } reference front() { assert(!empty()); return m_data[0]; } const_reference front() const { assert(!empty()); return m_data[0]; } reference back() { assert(!empty()); return m_data[m_size-1]; } const_reference back() const { assert(!empty()); return m_data[m_size-1]; } void push_back(const T& v) { reserve(m_size + 1); place_new(m_data + m_size, v); m_size++; } void pop_back() { assert(!empty()); m_size--; destruct(m_data + m_size); } void clear() { for (size_t i = 0; i < m_size; i++) { destruct(m_data + i); } m_size = 0; free(m_data); m_data = NULL; m_capacity = 0; } void reserve(size_type cap) { if (m_capacity >= cap) return; // make sure we always at least double if (m_capacity*2 > cap) cap = m_capacity*2; resize_internal(cap); } void resize(size_type n) { resize(n, T()); } void resize(size_type n, const T& t) { reserve(n); while (m_size < n) push_back(t); while (m_size > n) pop_back(); } private: T *m_data; size_type m_capacity; size_type m_size; inline void destruct(T *obj) { obj->~T(); } inline void place_new(T *loc, const T& v) { new (loc) T(v); } inline void resize_internal(size_type new_cap) { assert(new_cap >= m_capacity); // To be correct with ctors and dtors, we do not use realloc and friends. // A more efficient implementation would specialize for POD types and just // realloc() or something. Meh, if we care, we ought to use just STL's T *new_data = (T*) malloc(sizeof(T) * new_cap); assert(new_data); // Move over old data if (m_data) { for (size_type i = 0; i < m_size; i++) { place_new(new_data + i, m_data[i]); destruct(m_data + i); } free(m_data); } // And set the new values m_data = new_data; m_capacity = new_cap; } }; #endif