#include <algorithm>
#include <functional>
#include <utility>
#include "tail.h"
namespace marisa_alpha {
Tail::Tail() : buf_() {}
void Tail::build(const Vector<String> &keys,
Vector<UInt32> *offsets, int mode) {
switch (mode) {
case MARISA_ALPHA_BINARY_TAIL: {
build_binary_tail(keys, offsets);
return;
}
case MARISA_ALPHA_TEXT_TAIL: {
if (!build_text_tail(keys, offsets)) {
build_binary_tail(keys, offsets);
}
return;
}
default: {
MARISA_ALPHA_THROW(MARISA_ALPHA_PARAM_ERROR);
}
}
}
void Tail::mmap(Mapper *mapper, const char *filename,
long offset, int whence) {
if (mapper == NULL) {
MARISA_ALPHA_THROW(MARISA_ALPHA_PARAM_ERROR);
}
Mapper temp_mapper;
temp_mapper.open(filename, offset, whence);
map(temp_mapper);
temp_mapper.swap(mapper);
}
void Tail::map(const void *ptr, std::size_t size) {
Mapper mapper(ptr, size);
map(mapper);
}
void Tail::map(Mapper &mapper) {
Tail temp;
temp.buf_.map(mapper);
temp.swap(this);
}
void Tail::load(const char *filename, long offset, int whence) {
Reader reader;
reader.open(filename, offset, whence);
read(reader);
}
void Tail::fread(::FILE *file) {
Reader reader(file);
read(reader);
}
void Tail::read(int fd) {
Reader reader(fd);
read(reader);
}
void Tail::read(std::istream &stream) {
Reader reader(&stream);
read(reader);
}
void Tail::read(Reader &reader) {
Tail temp;
temp.buf_.read(reader);
temp.swap(this);
}
void Tail::save(const char *filename, bool trunc_flag,
long offset, int whence) const {
Writer writer;
writer.open(filename, trunc_flag, offset, whence);
write(writer);
}
void Tail::fwrite(::FILE *file) const {
Writer writer(file);
write(writer);
}
void Tail::write(int fd) const {
Writer writer(fd);
write(writer);
}
void Tail::write(std::ostream &stream) const {
Writer writer(&stream);
write(writer);
}
void Tail::write(Writer &writer) const {
buf_.write(writer);
}
void Tail::clear() {
Tail().swap(this);
}
void Tail::swap(Tail *rhs) {
buf_.swap(&rhs->buf_);
}
void Tail::build_binary_tail(const Vector<String> &keys,
Vector<UInt32> *offsets) {
if (keys.empty()) {
build_empty_tail(offsets);
return;
}
Vector<UInt8> buf;
buf.push_back('\0');
Vector<UInt32> temp_offsets;
temp_offsets.resize(keys.size() + 1);
for (std::size_t i = 0; i < keys.size(); ++i) {
temp_offsets[i] = (UInt32)buf.size();
for (std::size_t j = 0; j < keys[i].length(); ++j) {
buf.push_back(keys[i][j]);
}
}
temp_offsets.back() = (UInt32)buf.size();
buf.shrink();
if (offsets != NULL) {
temp_offsets.swap(offsets);
}
buf_.swap(&buf);
}
bool Tail::build_text_tail(const Vector<String> &keys,
Vector<UInt32> *offsets) {
if (keys.empty()) {
build_empty_tail(offsets);
return true;
}
typedef std::pair<RString, UInt32> KeyIdPair;
Vector<KeyIdPair> pairs;
pairs.resize(keys.size());
for (std::size_t i = 0; i < keys.size(); ++i) {
for (std::size_t j = 0; j < keys[i].length(); ++j) {
if (keys[i][j] == '\0') {
return false;
}
}
pairs[i].first = RString(keys[i]);
pairs[i].second = (UInt32)i;
}
std::sort(pairs.begin(), pairs.end(), std::greater<KeyIdPair>());
Vector<UInt8> buf;
buf.push_back('T');
Vector<UInt32> temp_offsets;
temp_offsets.resize(pairs.size(), 1);
const KeyIdPair dummy_key;
const KeyIdPair *last = &dummy_key;
for (std::size_t i = 0; i < pairs.size(); ++i) {
const KeyIdPair &cur = pairs[i];
std::size_t match = 0;
while ((match < cur.first.length()) && (match < last->first.length()) &&
last->first[match] == cur.first[match]) {
++match;
}
if ((match == cur.first.length()) && (last->first.length() != 0)) {
temp_offsets[cur.second] = (UInt32)(temp_offsets[last->second]
+ (last->first.length() - match));
} else {
temp_offsets[cur.second] = (UInt32)buf.size();
for (std::size_t j = 1; j <= cur.first.length(); ++j) {
buf.push_back(cur.first[cur.first.length() - j]);
}
buf.push_back('\0');
}
last = &cur;
}
buf.shrink();
if (offsets != NULL) {
temp_offsets.swap(offsets);
}
buf_.swap(&buf);
return true;
}
void Tail::build_empty_tail(Vector<UInt32> *offsets) {
buf_.clear();
if (offsets != NULL) {
offsets->clear();
}
}
} // namespace marisa_alpha