|
|
|
|
|
|
|
|
|
|
|
#pragma once |
|
|
|
|
|
#include <cstdlib> |
|
|
#include <memory> |
|
|
#include <vector> |
|
|
#include <unordered_map> |
|
|
#include <list> |
|
|
|
|
|
typedef int32_t token_t; |
|
|
|
|
|
class Prefix; |
|
|
|
|
|
|
|
|
|
|
|
class Prefix |
|
|
{ |
|
|
public: |
|
|
token_t Token; |
|
|
Prefix *Parent; |
|
|
|
|
|
Prefix(token_t token = 0 , Prefix *parent = nullptr) |
|
|
: Token(token), Parent(parent) |
|
|
{} |
|
|
|
|
|
std::vector<token_t> ToList() const; |
|
|
|
|
|
size_t size() const; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
template<typename T> |
|
|
void hash_combine(size_t & seed, T const& v) |
|
|
{ |
|
|
seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); |
|
|
} |
|
|
|
|
|
|
|
|
namespace std { |
|
|
template<> |
|
|
struct hash<Prefix*> |
|
|
{ |
|
|
size_t operator()(const Prefix *p) const noexcept |
|
|
{ |
|
|
size_t seed = 0; |
|
|
|
|
|
while (p) { |
|
|
if (p->Token != 0) { |
|
|
hash_combine(seed, p->Token); |
|
|
} |
|
|
p = p->Parent; |
|
|
} |
|
|
return seed; |
|
|
} |
|
|
}; |
|
|
|
|
|
template<> |
|
|
struct hash<tuple<Prefix*, token_t>> |
|
|
{ |
|
|
size_t operator()(const tuple<Prefix*, token_t> &t) const noexcept |
|
|
{ |
|
|
size_t seed = 0; |
|
|
hash_combine(seed, get<0>(t)); |
|
|
hash_combine(seed, get<1>(t)); |
|
|
return seed; |
|
|
} |
|
|
}; |
|
|
|
|
|
template<> |
|
|
struct equal_to<Prefix*> |
|
|
{ |
|
|
bool operator()(const Prefix *a, const Prefix *b) const noexcept |
|
|
{ |
|
|
while (a != nullptr && b != nullptr) { |
|
|
if (a->Token != b->Token) { |
|
|
return false; |
|
|
} |
|
|
a = a->Parent; |
|
|
b = b->Parent; |
|
|
} |
|
|
|
|
|
return a == b; |
|
|
} |
|
|
}; |
|
|
} |
|
|
|
|
|
inline size_t Prefix::size() const |
|
|
{ |
|
|
size_t ret = 0; |
|
|
auto p = this; |
|
|
while (p != nullptr) { |
|
|
ret += 1; |
|
|
p = p->Parent; |
|
|
} |
|
|
return ret; |
|
|
} |
|
|
|
|
|
|
|
|
class PrefixAllocator |
|
|
{ |
|
|
public: |
|
|
PrefixAllocator() = default; |
|
|
~PrefixAllocator(); |
|
|
|
|
|
template<typename ...Args> |
|
|
Prefix *GetPrefix(Args&& ...ctorArgs); |
|
|
|
|
|
private: |
|
|
void AllocateNextBuffer(); |
|
|
|
|
|
std::list<Prefix*> m_buffers; |
|
|
size_t m_allocSize = 0; |
|
|
size_t m_currOff = 0; |
|
|
}; |
|
|
|
|
|
inline PrefixAllocator::~PrefixAllocator() |
|
|
{ |
|
|
for (auto p : m_buffers) { |
|
|
|
|
|
|
|
|
|
|
|
free(p); |
|
|
} |
|
|
} |
|
|
|
|
|
inline void PrefixAllocator::AllocateNextBuffer() |
|
|
{ |
|
|
size_t nextSize = m_allocSize == 0 ? 1000 : 2 * m_allocSize; |
|
|
|
|
|
|
|
|
|
|
|
auto pBuff = reinterpret_cast<Prefix*>(malloc(sizeof(Prefix) * nextSize)); |
|
|
|
|
|
m_buffers.push_back(pBuff); |
|
|
|
|
|
m_allocSize = nextSize; |
|
|
m_currOff = 0; |
|
|
} |
|
|
|
|
|
template<typename ...Args> |
|
|
Prefix *PrefixAllocator::GetPrefix(Args&& ...ctorArgs) |
|
|
{ |
|
|
if (m_currOff == m_allocSize) { |
|
|
AllocateNextBuffer(); |
|
|
} |
|
|
|
|
|
auto buff = m_buffers.back() + m_currOff; |
|
|
|
|
|
auto ret = new (buff) Prefix(std::forward<Args>(ctorArgs)...); |
|
|
|
|
|
++m_currOff; |
|
|
|
|
|
return ret; |
|
|
} |
|
|
|