blob: 2bfccdbd173a5b0019518f1d106daf41a8649be1 [file] [log] [blame]
#ifndef MARISA_GRIMOIRE_VECTOR_VECTOR_H_
#define MARISA_GRIMOIRE_VECTOR_VECTOR_H_
#include <new>
#include "marisa/grimoire/io.h"
namespace marisa {
namespace grimoire {
namespace vector {
template <typename T>
class Vector {
public:
Vector()
: buf_(), objs_(NULL), const_objs_(NULL),
size_(0), capacity_(0), fixed_(false) {}
~Vector() {
if (objs_ != NULL) {
for (std::size_t i = 0; i < size_; ++i) {
objs_[i].~T();
}
}
}
void map(Mapper &mapper) {
Vector temp;
temp.map_(mapper);
swap(temp);
}
void read(Reader &reader) {
Vector temp;
temp.read_(reader);
swap(temp);
}
void write(Writer &writer) const {
write_(writer);
}
void push_back(const T &x) {
MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR);
MARISA_DEBUG_IF(size_ == max_size(), MARISA_SIZE_ERROR);
reserve(size_ + 1);
new (&objs_[size_]) T(x);
++size_;
}
void pop_back() {
MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR);
MARISA_DEBUG_IF(size_ == 0, MARISA_STATE_ERROR);
objs_[--size_].~T();
}
// resize() assumes that T's placement new does not throw an exception.
void resize(std::size_t size) {
MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR);
reserve(size);
for (std::size_t i = size_; i < size; ++i) {
new (&objs_[i]) T;
}
for (std::size_t i = size; i < size_; ++i) {
objs_[i].~T();
}
size_ = size;
}
// resize() assumes that T's placement new does not throw an exception.
void resize(std::size_t size, const T &x) {
MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR);
reserve(size);
for (std::size_t i = size_; i < size; ++i) {
new (&objs_[i]) T(x);
}
for (std::size_t i = size; i < size_; ++i) {
objs_[i].~T();
}
size_ = size;
}
void reserve(std::size_t capacity) {
MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR);
if (capacity <= capacity_) {
return;
}
MARISA_DEBUG_IF(capacity > max_size(), MARISA_SIZE_ERROR);
std::size_t new_capacity = capacity;
if (capacity_ > (capacity / 2)) {
if (capacity_ > (max_size() / 2)) {
new_capacity = max_size();
} else {
new_capacity = capacity_ * 2;
}
}
realloc(new_capacity);
}
void shrink() {
MARISA_THROW_IF(fixed_, MARISA_STATE_ERROR);
if (size_ != capacity_) {
realloc(size_);
}
}
void fix() {
MARISA_THROW_IF(fixed_, MARISA_STATE_ERROR);
fixed_ = true;
}
const T *begin() const {
return const_objs_;
}
const T *end() const {
return const_objs_ + size_;
}
const T &operator[](std::size_t i) const {
MARISA_DEBUG_IF(i >= size_, MARISA_BOUND_ERROR);
return const_objs_[i];
}
const T &front() const {
MARISA_DEBUG_IF(size_ == 0, MARISA_STATE_ERROR);
return const_objs_[0];
}
const T &back() const {
MARISA_DEBUG_IF(size_ == 0, MARISA_STATE_ERROR);
return const_objs_[size_ - 1];
}
T *begin() {
MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR);
return objs_;
}
T *end() {
MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR);
return objs_ + size_;
}
T &operator[](std::size_t i) {
MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR);
MARISA_DEBUG_IF(i >= size_, MARISA_BOUND_ERROR);
return objs_[i];
}
T &front() {
MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR);
MARISA_DEBUG_IF(size_ == 0, MARISA_STATE_ERROR);
return objs_[0];
}
T &back() {
MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR);
MARISA_DEBUG_IF(size_ == 0, MARISA_STATE_ERROR);
return objs_[size_ - 1];
}
std::size_t size() const {
return size_;
}
std::size_t capacity() const {
return capacity_;
}
bool fixed() const {
return fixed_;
}
bool empty() const {
return size_ == 0;
}
std::size_t total_size() const {
return sizeof(T) * size_;
}
std::size_t io_size() const {
return sizeof(UInt64) + ((total_size() + 7) & ~(std::size_t)0x07);
}
void clear() {
Vector().swap(*this);
}
void swap(Vector &rhs) {
buf_.swap(rhs.buf_);
marisa::swap(objs_, rhs.objs_);
marisa::swap(const_objs_, rhs.const_objs_);
marisa::swap(size_, rhs.size_);
marisa::swap(capacity_, rhs.capacity_);
marisa::swap(fixed_, rhs.fixed_);
}
static std::size_t max_size() {
return MARISA_SIZE_MAX / sizeof(T);
}
private:
scoped_array<char> buf_;
T *objs_;
const T *const_objs_;
std::size_t size_;
std::size_t capacity_;
bool fixed_;
void map_(Mapper &mapper) {
UInt64 total_size;
mapper.map(&total_size);
MARISA_THROW_IF(total_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR);
MARISA_THROW_IF((total_size % sizeof(T)) != 0, MARISA_FORMAT_ERROR);
const std::size_t size = (std::size_t)(total_size / sizeof(T));
mapper.map(&const_objs_, size);
mapper.seek((std::size_t)((8 - (total_size % 8)) % 8));
size_ = size;
fix();
}
void read_(Reader &reader) {
UInt64 total_size;
reader.read(&total_size);
MARISA_THROW_IF(total_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR);
MARISA_THROW_IF((total_size % sizeof(T)) != 0, MARISA_FORMAT_ERROR);
const std::size_t size = (std::size_t)(total_size / sizeof(T));
resize(size);
reader.read(objs_, size);
reader.seek((std::size_t)((8 - (total_size % 8)) % 8));
}
void write_(Writer &writer) const {
writer.write((UInt64)total_size());
writer.write(const_objs_, size_);
writer.seek((8 - (total_size() % 8)) % 8);
}
// realloc() assumes that T's placement new does not throw an exception.
void realloc(std::size_t new_capacity) {
MARISA_DEBUG_IF(new_capacity > max_size(), MARISA_SIZE_ERROR);
scoped_array<char> new_buf(
new (std::nothrow) char[sizeof(T) * new_capacity]);
MARISA_DEBUG_IF(new_buf.get() == NULL, MARISA_MEMORY_ERROR);
T *new_objs = reinterpret_cast<T *>(new_buf.get());
for (std::size_t i = 0; i < size_; ++i) {
new (&new_objs[i]) T(objs_[i]);
}
for (std::size_t i = 0; i < size_; ++i) {
objs_[i].~T();
}
buf_.swap(new_buf);
objs_ = new_objs;
const_objs_ = new_objs;
capacity_ = new_capacity;
}
// Disallows copy and assignment.
Vector(const Vector &);
Vector &operator=(const Vector &);
};
} // namespace vector
} // namespace grimoire
} // namespace marisa
#endif // MARISA_GRIMOIRE_VECTOR_VECTOR_H_