282 lines
5.3 KiB
C++
282 lines
5.3 KiB
C++
// SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later
|
|
// Copyright 2011, SIL International, All rights reserved.
|
|
|
|
|
|
#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)
|
|
{
|
|
// Only bother if there are rules in the State object.
|
|
if (state.empty()) return;
|
|
|
|
// Merge the new sorted rules list into the current sorted result set.
|
|
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]; // allow map to go 1 before slot_map when inserting
|
|
// at start of segment.
|
|
}
|
|
|
|
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];
|
|
}
|
|
|
|
} // namespace graphite2
|