|
#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 |
|
|