blob: eeae719e27c093e74d5b2224e80ed03cf8b63ca4 [file] [log] [blame]
#ifndef MARISA_GRIMOIRE_VECTOR_FLAT_VECTOR_H_
#define MARISA_GRIMOIRE_VECTOR_FLAT_VECTOR_H_
#include "marisa/grimoire/vector/vector.h"
namespace marisa {
namespace grimoire {
namespace vector {
class FlatVector {
public:
#if MARISA_WORD_SIZE == 64
typedef UInt64 Unit;
#else // MARISA_WORD_SIZE == 64
typedef UInt32 Unit;
#endif // MARISA_WORD_SIZE == 64
FlatVector() : units_(), value_size_(0), mask_(0), size_(0) {}
void build(const Vector<UInt32> &values) {
FlatVector temp;
temp.build_(values);
swap(temp);
}
void map(Mapper &mapper) {
FlatVector temp;
temp.map_(mapper);
swap(temp);
}
void read(Reader &reader) {
FlatVector temp;
temp.read_(reader);
swap(temp);
}
void write(Writer &writer) const {
write_(writer);
}
UInt32 operator[](std::size_t i) const {
MARISA_DEBUG_IF(i >= size_, MARISA_BOUND_ERROR);
const std::size_t pos = i * value_size_;
const std::size_t unit_id = pos / MARISA_WORD_SIZE;
const std::size_t unit_offset = pos % MARISA_WORD_SIZE;
if ((unit_offset + value_size_) <= MARISA_WORD_SIZE) {
return (UInt32)(units_[unit_id] >> unit_offset) & mask_;
} else {
return (UInt32)((units_[unit_id] >> unit_offset)
| (units_[unit_id + 1] << (MARISA_WORD_SIZE - unit_offset))) & mask_;
}
}
std::size_t value_size() const {
return value_size_;
}
UInt32 mask() const {
return mask_;
}
bool empty() const {
return size_ == 0;
}
std::size_t size() const {
return size_;
}
std::size_t total_size() const {
return units_.total_size();
}
std::size_t io_size() const {
return units_.io_size() + (sizeof(UInt32) * 2) + sizeof(UInt64);
}
void clear() {
FlatVector().swap(*this);
}
void swap(FlatVector &rhs) {
units_.swap(rhs.units_);
marisa::swap(value_size_, rhs.value_size_);
marisa::swap(mask_, rhs.mask_);
marisa::swap(size_, rhs.size_);
}
private:
Vector<Unit> units_;
std::size_t value_size_;
UInt32 mask_;
std::size_t size_;
void build_(const Vector<UInt32> &values) {
UInt32 max_value = 0;
for (std::size_t i = 0; i < values.size(); ++i) {
if (values[i] > max_value) {
max_value = values[i];
}
}
std::size_t value_size = 0;
while (max_value != 0) {
++value_size;
max_value >>= 1;
}
std::size_t num_units = values.empty() ? 0 : (64 / MARISA_WORD_SIZE);
if (value_size != 0) {
num_units = (std::size_t)(
(((UInt64)value_size * values.size()) + (MARISA_WORD_SIZE - 1))
/ MARISA_WORD_SIZE);
num_units += num_units % (64 / MARISA_WORD_SIZE);
}
units_.resize(num_units);
if (num_units > 0) {
units_.back() = 0;
}
value_size_ = value_size;
if (value_size != 0) {
mask_ = MARISA_UINT32_MAX >> (32 - value_size);
}
size_ = values.size();
for (std::size_t i = 0; i < values.size(); ++i) {
set(i, values[i]);
}
}
void map_(Mapper &mapper) {
units_.map(mapper);
{
UInt32 temp_value_size;
mapper.map(&temp_value_size);
MARISA_THROW_IF(temp_value_size > 32, MARISA_FORMAT_ERROR);
value_size_ = temp_value_size;
}
{
UInt32 temp_mask;
mapper.map(&temp_mask);
mask_ = temp_mask;
}
{
UInt64 temp_size;
mapper.map(&temp_size);
MARISA_THROW_IF(temp_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR);
size_ = (std::size_t)temp_size;
}
}
void read_(Reader &reader) {
units_.read(reader);
{
UInt32 temp_value_size;
reader.read(&temp_value_size);
MARISA_THROW_IF(temp_value_size > 32, MARISA_FORMAT_ERROR);
value_size_ = temp_value_size;
}
{
UInt32 temp_mask;
reader.read(&temp_mask);
mask_ = temp_mask;
}
{
UInt64 temp_size;
reader.read(&temp_size);
MARISA_THROW_IF(temp_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR);
size_ = (std::size_t)temp_size;
}
}
void write_(Writer &writer) const {
units_.write(writer);
writer.write((UInt32)value_size_);
writer.write((UInt32)mask_);
writer.write((UInt64)size_);
}
void set(std::size_t i, UInt32 value) {
MARISA_DEBUG_IF(i >= size_, MARISA_BOUND_ERROR);
MARISA_DEBUG_IF(value > mask_, MARISA_RANGE_ERROR);
const std::size_t pos = i * value_size_;
const std::size_t unit_id = pos / MARISA_WORD_SIZE;
const std::size_t unit_offset = pos % MARISA_WORD_SIZE;
units_[unit_id] &= ~((Unit)mask_ << unit_offset);
units_[unit_id] |= (Unit)(value & mask_) << unit_offset;
if ((unit_offset + value_size_) > MARISA_WORD_SIZE) {
units_[unit_id + 1] &=
~((Unit)mask_ >> (MARISA_WORD_SIZE - unit_offset));
units_[unit_id + 1] |=
(Unit)(value & mask_) >> (MARISA_WORD_SIZE - unit_offset);
}
}
// Disallows copy and assignment.
FlatVector(const FlatVector &);
FlatVector &operator=(const FlatVector &);
};
} // namespace vector
} // namespace grimoire
} // namespace marisa
#endif // MARISA_GRIMOIRE_VECTOR_FLAT_VECTOR_H_