#pragma once
#include "inc/Code.h"
#include "inc/Slot.h"
namespace graphite2 {
struct Rule {
const vm::Machine::Code * constraint,
* action;
unsigned short sort;
byte preContext;
#ifndef NDEBUG
uint16 rule_idx;
#endif
Rule();
~Rule() {}
CLASS_NEW_DELETE;
private:
Rule(const Rule &);
Rule & operator = (const Rule &);
};
inline
Rule::Rule()
: constraint(0),
action(0),
sort(0),
preContext(0)
{
#ifndef NDEBUG
rule_idx = 0;
#endif
}
struct RuleEntry
{
const Rule * rule;
inline
bool operator < (const RuleEntry &r) const
{
const unsigned short lsort = rule->sort, rsort = r.rule->sort;
return lsort > rsort || (lsort == rsort && rule < r.rule);
}
inline
bool operator == (const RuleEntry &r) const
{
return rule == r.rule;
}
};
struct State
{
const RuleEntry * rules,
* rules_end;
bool empty() const;
};
inline
bool State::empty() const
{
return rules_end == rules;
}
class SlotMap
{
public:
enum {MAX_SLOTS=64};
SlotMap(Segment & seg, uint8 direction, size_t maxSize);
Slot * * begin();
Slot * * end();
size_t size() const;
unsigned short context() const;
void reset(Slot &, unsigned short);
Slot * const & operator[](int n) const;
Slot * & operator [] (int);
void pushSlot(Slot * const slot);
void collectGarbage(Slot *& aSlot);
Slot * highwater() { return m_highwater; }
void highwater(Slot *s) { m_highwater = s; m_highpassed = false; }
bool highpassed() const { return m_highpassed; }
void highpassed(bool v) { m_highpassed = v; }
uint8 dir() const { return m_dir; }
int decMax() { return --m_maxSize; }
Segment & segment;
private:
Slot * m_slot_map[MAX_SLOTS+1];
unsigned short m_size;
unsigned short m_precontext;
Slot * m_highwater;
int m_maxSize;
uint8 m_dir;
bool m_highpassed;
};
class FiniteStateMachine
{
public:
enum {MAX_RULES=128};
private:
class Rules
{
public:
Rules();
void clear();
const RuleEntry * begin() const;
const RuleEntry * end() const;
size_t size() const;
void accumulate_rules(const State &state);
private:
RuleEntry * m_begin,
* m_end,
m_rules[MAX_RULES*2];
};
public:
FiniteStateMachine(SlotMap & map, json * logger);
void reset(Slot * & slot, const short unsigned int max_pre_ctxt);
Rules rules;
SlotMap & slots;
json * const dbgout;
};
inline
FiniteStateMachine::FiniteStateMachine(SlotMap& map, json * logger)
: slots(map),
dbgout(logger)
{
}
inline
void FiniteStateMachine::reset(Slot * & slot, const short unsigned int max_pre_ctxt)
{
rules.clear();
int ctxt = 0;
for (; ctxt != max_pre_ctxt && slot->prev(); ++ctxt, slot = slot->prev());
slots.reset(*slot, ctxt);
}
inline
FiniteStateMachine::Rules::Rules()
: m_begin(m_rules), m_end(m_rules)
{
}
inline
void FiniteStateMachine::Rules::clear()
{
m_end = m_begin;
}
inline
const RuleEntry * FiniteStateMachine::Rules::begin() const
{
return m_begin;
}
inline
const RuleEntry * FiniteStateMachine::Rules::end() const
{
return m_end;
}
inline
size_t FiniteStateMachine::Rules::size() const
{
return m_end - m_begin;
}
inline
void FiniteStateMachine::Rules::accumulate_rules(const State &state)
{
if (state.empty()) return;
const RuleEntry * lre = begin(), * rre = state.rules;
RuleEntry * out = m_rules + (m_begin == m_rules)*MAX_RULES;
const RuleEntry * const lrend = out + MAX_RULES,
* const rrend = state.rules_end;
m_begin = out;
while (lre != end() && out != lrend)
{
if (*lre < *rre) *out++ = *lre++;
else if (*rre < *lre) { *out++ = *rre++; }
else { *out++ = *lre++; ++rre; }
if (rre == rrend)
{
while (lre != end() && out != lrend) { *out++ = *lre++; }
m_end = out;
return;
}
}
while (rre != rrend && out != lrend) { *out++ = *rre++; }
m_end = out;
}
inline
SlotMap::SlotMap(Segment & seg, uint8 direction, size_t maxSize)
: segment(seg), m_size(0), m_precontext(0), m_highwater(0),
m_maxSize(int(maxSize)), m_dir(direction), m_highpassed(false)
{
m_slot_map[0] = 0;
}
inline
Slot * * SlotMap::begin()
{
return &m_slot_map[1];
}
inline
Slot * * SlotMap::end()
{
return m_slot_map + m_size + 1;
}
inline
size_t SlotMap::size() const
{
return m_size;
}
inline
short unsigned int SlotMap::context() const
{
return m_precontext;
}
inline
void SlotMap::reset(Slot & slot, short unsigned int ctxt)
{
m_size = 0;
m_precontext = ctxt;
*m_slot_map = slot.prev();
}
inline
void SlotMap::pushSlot(Slot*const slot)
{
m_slot_map[++m_size] = slot;
}
inline
Slot * const & SlotMap::operator[](int n) const
{
return m_slot_map[n + 1];
}
inline
Slot * & SlotMap::operator[](int n)
{
return m_slot_map[n + 1];
}
}