// Copyright (c) 2013 Austin T. Clements. All rights reserved. // Use of this source code is governed by an MIT license // that can be found in the LICENSE file. #ifndef _DWARFPP_SMALL_VECTOR_HH_ #define _DWARFPP_SMALL_VECTOR_HH_ DWARFPP_BEGIN_NAMESPACE /** * A vector-like class that only heap allocates above a specified * size. */ template class small_vector { public: typedef T value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef size_t size_type; small_vector() : base((T*)buf), end(base), cap((T*)&buf[sizeof(T[Min])]) { } small_vector(const small_vector &o) : base((T*)buf), end(base), cap((T*)&buf[sizeof(T[Min])]) { *this = o; } small_vector(small_vector &&o) : base((T*)buf), end(base), cap((T*)&buf[sizeof(T[Min])]) { if ((char*)o.base == o.buf) { // Elements are inline; have to copy them base = (T*)buf; end = base; cap = (T*)&buf[sizeof(T[Min])]; *this = o; o.clear(); } else { // Elements are external; swap pointers base = o.base; end = o.end; cap = o.cap; o.base = (T*)o.buf; o.end = o.base; o.cap = (T*)&o.buf[sizeof(T[Min])]; } } ~small_vector() { clear(); if ((char*)base != buf) delete[] (char*)base; } small_vector &operator=(const small_vector &o) { size_type osize = o.size(); clear(); reserve(osize); for (size_type i = 0; i < osize; i++) new (&base[i]) T(o[i]); end = base + osize; return *this; } size_type size() const { return end - base; } bool empty() const { return base == end; } void reserve(size_type n) { if (n <= (size_type)(cap - base)) return; size_type target = cap - base; if (target == 0) target = 1; while (target < n) target <<= 1; char *newbuf = new char[sizeof(T[target])]; T *src = base, *dest = (T*)newbuf; for (; src < end; src++, dest++) { new(dest) T(*src); dest->~T(); } if ((char*)base != buf) delete[] (char*)base; base = (T*)newbuf; end = dest; cap = base + target; } reference operator[](size_type n) { return base[n]; } const_reference operator[](size_type n) const { return base[n]; } reference at(size_type n) { return base[n]; } const_reference at(size_type n) const { return base[n]; } /** * "Reverse at". revat(0) is equivalent to back(). revat(1) * is the element before back. Etc. */ reference revat(size_type n) { return *(end - 1 - n); } const_reference revat(size_type n) const { return *(end - 1 - n); } reference front() { return base[0]; } const_reference front() const { return base[0]; } reference back() { return *(end-1); } const_reference back() const { return *(end-1); } void push_back(const T& x) { reserve(size() + 1); new (end) T(x); end++; } void push_back(T&& x) { reserve(size() + 1); new (end) T(std::move(x)); end++; } void pop_back() { end--; end->~T(); } void clear() { for (T* p = base; p < end; ++p) p->~T(); end = base; } private: char buf[sizeof(T[Min])]; T *base, *end, *cap; }; DWARFPP_END_NAMESPACE #endif