| #ifndef UTIL_FIXED_ARRAY_H |
| #define UTIL_FIXED_ARRAY_H |
|
|
| #include "scoped.hh" |
|
|
| #include <cstddef> |
|
|
| #include <cassert> |
| #include <cstdlib> |
|
|
| namespace util { |
|
|
| |
| |
| |
| |
| |
| |
| template <class T> class FixedArray { |
| public: |
| |
| explicit FixedArray(std::size_t limit) { |
| Init(limit); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| FixedArray() |
| : newed_end_(NULL) |
| #ifndef NDEBUG |
| , allocated_end_(NULL) |
| #endif |
| {} |
|
|
| |
| |
| |
| |
| |
| |
| 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(); |
| #ifndef NDEBUG |
| allocated_end_ = begin() + count; |
| #endif |
| } |
|
|
| |
| |
| |
| |
| |
| 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]); |
| } |
| } |
|
|
| |
| |
| |
| ~FixedArray() { clear(); } |
|
|
| #if __cplusplus >= 201103L |
| FixedArray(FixedArray &&from) |
| : block_(std::move(from.block_)), |
| newed_end_(from.newed_end_) |
| # ifndef NDEBUG |
| , allocated_end_(from.allocated_end_) |
| # endif |
| { |
| from.newed_end_ = NULL; |
| # ifndef NDEBUG |
| from.allocated_end_ = NULL; |
| # endif |
| } |
| #endif |
|
|
| |
| T *begin() { return static_cast<T*>(block_.get()); } |
|
|
| |
| const T *begin() const { return static_cast<const T*>(block_.get()); } |
|
|
| |
| T *end() { return newed_end_; } |
|
|
| |
| const T *end() const { return newed_end_; } |
|
|
| |
| T &back() { return *(end() - 1); } |
|
|
| |
| const T &back() const { return *(end() - 1); } |
|
|
| |
| std::size_t size() const { return end() - begin(); } |
|
|
| |
| bool empty() const { return begin() == end(); } |
|
|
| |
| |
| |
| |
| |
| T &operator[](std::size_t i) { |
| assert(i < size()); |
| return begin()[i]; |
| } |
|
|
| |
| |
| |
| |
| |
| const T &operator[](std::size_t i) const { |
| assert(i < size()); |
| return begin()[i]; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| #if __cplusplus >= 201103L |
| template <typename... Construct> T *emplace_back(Construct&&... construct) { |
| T *ret = end(); |
| new (end()) T(construct...); |
| Constructed(); |
| return ret; |
| } |
| template <typename... Construct> T *push_back(Construct&&... construct) { |
| T *ret = end(); |
| new (end()) T(construct...); |
| Constructed(); |
| return ret; |
| } |
| #else |
| 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(); |
| } |
| #endif |
|
|
| void pop_back() { |
| back().~T(); |
| --newed_end_; |
| } |
|
|
| |
| |
| |
| void clear() { |
| while (newed_end_ != begin()) |
| pop_back(); |
| } |
|
|
| protected: |
| |
| void Constructed() { |
| ++newed_end_; |
| #ifndef NDEBUG |
| assert(newed_end_ <= allocated_end_); |
| #endif |
| } |
|
|
| private: |
| util::scoped_malloc block_; |
|
|
| T *newed_end_; |
|
|
| #ifndef NDEBUG |
| T *allocated_end_; |
| #endif |
| }; |
|
|
| } |
|
|
| #endif |
|
|