| namespace util { | |
| /** | |
| * Defines an array with fixed maximum size. | |
| * | |
| * Ever want an array of things but they don't have a default constructor or | |
| * are non-copyable? FixedArray allows constructing one at a time. | |
| */ | |
| template <class T> class FixedArray { | |
| public: | |
| /** Initialize with a given size bound but do not construct the objects. */ | |
| explicit FixedArray(std::size_t limit) { | |
| Init(limit); | |
| } | |
| /** | |
| * Constructs an instance, but does not initialize it. | |
| * | |
| * Any objects constructed in this manner must be subsequently @ref FixedArray::Init() "initialized" prior to use. | |
| * | |
| * @see FixedArray::Init() | |
| */ | |
| FixedArray() | |
| : newed_end_(NULL) | |
| , allocated_end_(NULL) | |
| {} | |
| /** | |
| * Initialize with a given size bound but do not construct the objects. | |
| * | |
| * This method is responsible for allocating memory. | |
| * Objects stored in this array will be constructed in a location within this allocated memory. | |
| */ | |
| void Init(std::size_t count) { | |
| assert(!block_.get()); | |
| block_.reset(malloc(sizeof(T) * count)); | |
| if (!block_.get()) throw std::bad_alloc(); | |
| newed_end_ = begin(); | |
| allocated_end_ = begin() + count; | |
| } | |
| /** | |
| * Constructs a copy of the provided array. | |
| * | |
| * @param from Array whose elements should be copied into this newly-constructed data structure. | |
| */ | |
| FixedArray(const FixedArray &from) { | |
| std::size_t size = from.newed_end_ - static_cast<const T*>(from.block_.get()); | |
| Init(size); | |
| for (std::size_t i = 0; i < size; ++i) { | |
| push_back(from[i]); | |
| } | |
| } | |
| /** | |
| * Frees the memory held by this object. | |
| */ | |
| ~FixedArray() { clear(); } | |
| /** Gets a pointer to the first object currently stored in this data structure. */ | |
| T *begin() { return static_cast<T*>(block_.get()); } | |
| /** Gets a const pointer to the last object currently stored in this data structure. */ | |
| const T *begin() const { return static_cast<const T*>(block_.get()); } | |
| /** Gets a pointer to the last object currently stored in this data structure. */ | |
| T *end() { return newed_end_; } | |
| /** Gets a const pointer to the last object currently stored in this data structure. */ | |
| const T *end() const { return newed_end_; } | |
| /** Gets a reference to the last object currently stored in this data structure. */ | |
| T &back() { return *(end() - 1); } | |
| /** Gets a const reference to the last object currently stored in this data structure. */ | |
| const T &back() const { return *(end() - 1); } | |
| /** Gets the number of objects currently stored in this data structure. */ | |
| std::size_t size() const { return end() - begin(); } | |
| /** Returns true if there are no objects currently stored in this data structure. */ | |
| bool empty() const { return begin() == end(); } | |
| /** | |
| * Gets a reference to the object with index i currently stored in this data structure. | |
| * | |
| * @param i Index of the object to reference | |
| */ | |
| T &operator[](std::size_t i) { | |
| assert(i < size()); | |
| return begin()[i]; | |
| } | |
| /** | |
| * Gets a const reference to the object with index i currently stored in this data structure. | |
| * | |
| * @param i Index of the object to reference | |
| */ | |
| const T &operator[](std::size_t i) const { | |
| assert(i < size()); | |
| return begin()[i]; | |
| } | |
| /** | |
| * Constructs a new object using the provided parameter, | |
| * and stores it in this data structure. | |
| * | |
| * The memory backing the constructed object is managed by this data structure. | |
| * I miss C++11 variadic templates. | |
| */ | |
| void push_back() { | |
| new (end()) T(); | |
| Constructed(); | |
| } | |
| template <class C> void push_back(const C &c) { | |
| new (end()) T(c); | |
| Constructed(); | |
| } | |
| template <class C> void push_back(C &c) { | |
| new (end()) T(c); | |
| Constructed(); | |
| } | |
| template <class C, class D> void push_back(const C &c, const D &d) { | |
| new (end()) T(c, d); | |
| Constructed(); | |
| } | |
| void pop_back() { | |
| back().~T(); | |
| --newed_end_; | |
| } | |
| /** | |
| * Removes all elements from this array. | |
| */ | |
| void clear() { | |
| while (newed_end_ != begin()) | |
| pop_back(); | |
| } | |
| protected: | |
| // Always call Constructed after successful completion of new. | |
| void Constructed() { | |
| ++newed_end_; | |
| assert(newed_end_ <= allocated_end_); | |
| } | |
| private: | |
| util::scoped_malloc block_; | |
| T *newed_end_; | |
| T *allocated_end_; | |
| }; | |
| } // namespace util | |