1// SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later
2// Copyright 2011, SIL International, All rights reserved.
3
4
5#pragma once
6
7#include "inc/Code.h"
8#include "inc/Slot.h"
9
10namespace graphite2 {
11
12struct Rule {
13 const vm::Machine::Code * constraint,
14 * action;
15 unsigned short sort;
16 byte preContext;
17#ifndef NDEBUG
18 uint16 rule_idx;
19#endif
20
21 Rule();
22 ~Rule() {}
23
24 CLASS_NEW_DELETE;
25
26private:
27 Rule(const Rule &);
28 Rule & operator = (const Rule &);
29};
30
31inline
32Rule::Rule()
33: constraint(0),
34 action(0),
35 sort(0),
36 preContext(0)
37{
38#ifndef NDEBUG
39 rule_idx = 0;
40#endif
41}
42
43
44struct RuleEntry
45{
46 const Rule * rule;
47
48 inline
49 bool operator < (const RuleEntry &r) const
50 {
51 const unsigned short lsort = rule->sort, rsort = r.rule->sort;
52 return lsort > rsort || (lsort == rsort && rule < r.rule);
53 }
54
55 inline
56 bool operator == (const RuleEntry &r) const
57 {
58 return rule == r.rule;
59 }
60};
61
62
63struct State
64{
65 const RuleEntry * rules,
66 * rules_end;
67
68 bool empty() const;
69};
70
71inline
72bool State::empty() const
73{
74 return rules_end == rules;
75}
76
77
78class SlotMap
79{
80public:
81 enum {MAX_SLOTS=64};
82 SlotMap(Segment & seg, uint8 direction, size_t maxSize);
83
84 Slot * * begin();
85 Slot * * end();
86 size_t size() const;
87 unsigned short context() const;
88 void reset(Slot &, unsigned short);
89
90 Slot * const & operator[](int n) const;
91 Slot * & operator [] (int);
92 void pushSlot(Slot * const slot);
93 void collectGarbage(Slot *& aSlot);
94
95 Slot * highwater() { return m_highwater; }
96 void highwater(Slot *s) { m_highwater = s; m_highpassed = false; }
97 bool highpassed() const { return m_highpassed; }
98 void highpassed(bool v) { m_highpassed = v; }
99
100 uint8 dir() const { return m_dir; }
101 int decMax() { return --m_maxSize; }
102
103 Segment & segment;
104private:
105 Slot * m_slot_map[MAX_SLOTS+1];
106 unsigned short m_size;
107 unsigned short m_precontext;
108 Slot * m_highwater;
109 int m_maxSize;
110 uint8 m_dir;
111 bool m_highpassed;
112};
113
114
115class FiniteStateMachine
116{
117public:
118 enum {MAX_RULES=128};
119
120private:
121 class Rules
122 {
123 public:
124 Rules();
125 void clear();
126 const RuleEntry * begin() const;
127 const RuleEntry * end() const;
128 size_t size() const;
129
130 void accumulate_rules(const State &state);
131
132 private:
133 RuleEntry * m_begin,
134 * m_end,
135 m_rules[MAX_RULES*2];
136 };
137
138public:
139 FiniteStateMachine(SlotMap & map, json * logger);
140 void reset(Slot * & slot, const short unsigned int max_pre_ctxt);
141
142 Rules rules;
143 SlotMap & slots;
144 json * const dbgout;
145};
146
147
148inline
149FiniteStateMachine::FiniteStateMachine(SlotMap& map, json * logger)
150: slots(map),
151 dbgout(logger)
152{
153}
154
155inline
156void FiniteStateMachine::reset(Slot * & slot, const short unsigned int max_pre_ctxt)
157{
158 rules.clear();
159 int ctxt = 0;
160 for (; ctxt != max_pre_ctxt && slot->prev(); ++ctxt, slot = slot->prev());
161 slots.reset(*slot, ctxt);
162}
163
164inline
165FiniteStateMachine::Rules::Rules()
166 : m_begin(m_rules), m_end(m_rules)
167{
168}
169
170inline
171void FiniteStateMachine::Rules::clear()
172{
173 m_end = m_begin;
174}
175
176inline
177const RuleEntry * FiniteStateMachine::Rules::begin() const
178{
179 return m_begin;
180}
181
182inline
183const RuleEntry * FiniteStateMachine::Rules::end() const
184{
185 return m_end;
186}
187
188inline
189size_t FiniteStateMachine::Rules::size() const
190{
191 return m_end - m_begin;
192}
193
194inline
195void FiniteStateMachine::Rules::accumulate_rules(const State &state)
196{
197 // Only bother if there are rules in the State object.
198 if (state.empty()) return;
199
200 // Merge the new sorted rules list into the current sorted result set.
201 const RuleEntry * lre = begin(), * rre = state.rules;
202 RuleEntry * out = m_rules + (m_begin == m_rules)*MAX_RULES;
203 const RuleEntry * const lrend = out + MAX_RULES,
204 * const rrend = state.rules_end;
205 m_begin = out;
206 while (lre != end() && out != lrend)
207 {
208 if (*lre < *rre) *out++ = *lre++;
209 else if (*rre < *lre) { *out++ = *rre++; }
210 else { *out++ = *lre++; ++rre; }
211
212 if (rre == rrend)
213 {
214 while (lre != end() && out != lrend) { *out++ = *lre++; }
215 m_end = out;
216 return;
217 }
218 }
219 while (rre != rrend && out != lrend) { *out++ = *rre++; }
220 m_end = out;
221}
222
223inline
224SlotMap::SlotMap(Segment & seg, uint8 direction, size_t maxSize)
225: segment(seg), m_size(0), m_precontext(0), m_highwater(0),
226 m_maxSize(int(maxSize)), m_dir(direction), m_highpassed(false)
227{
228 m_slot_map[0] = 0;
229}
230
231inline
232Slot * * SlotMap::begin()
233{
234 return &m_slot_map[1]; // allow map to go 1 before slot_map when inserting
235 // at start of segment.
236}
237
238inline
239Slot * * SlotMap::end()
240{
241 return m_slot_map + m_size + 1;
242}
243
244inline
245size_t SlotMap::size() const
246{
247 return m_size;
248}
249
250inline
251short unsigned int SlotMap::context() const
252{
253 return m_precontext;
254}
255
256inline
257void SlotMap::reset(Slot & slot, short unsigned int ctxt)
258{
259 m_size = 0;
260 m_precontext = ctxt;
261 *m_slot_map = slot.prev();
262}
263
264inline
265void SlotMap::pushSlot(Slot*const slot)
266{
267 m_slot_map[++m_size] = slot;
268}
269
270inline
271Slot * const & SlotMap::operator[](int n) const
272{
273 return m_slot_map[n + 1];
274}
275
276inline
277Slot * & SlotMap::operator[](int n)
278{
279 return m_slot_map[n + 1];
280}
281
282} // namespace graphite2
283