You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-12-01 16:38:31 +00:00
306 lines
6.4 KiB
C++
306 lines
6.4 KiB
C++
/* GRAPHITE2 LICENSING
|
|
|
|
Copyright 2011, SIL International
|
|
All rights reserved.
|
|
|
|
This library is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published
|
|
by the Free Software Foundation; either version 2.1 of License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should also have received a copy of the GNU Lesser General Public
|
|
License along with this library in the file named "LICENSE".
|
|
If not, write to the Free Software Foundation, 51 Franklin Street,
|
|
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
|
|
internet at http://www.fsf.org/licenses/lgpl.html.
|
|
|
|
Alternatively, the contents of this file may be used under the terms of the
|
|
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
|
|
License, as published by the Free Software Foundation, either version 2
|
|
of the License or (at your option) any later version.
|
|
*/
|
|
|
|
#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
|