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 | |
10 | namespace graphite2 { |
11 | |
12 | struct 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 | |
26 | private: |
27 | Rule(const Rule &); |
28 | Rule & operator = (const Rule &); |
29 | }; |
30 | |
31 | inline |
32 | Rule::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 | |
44 | struct 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 | |
63 | struct State |
64 | { |
65 | const RuleEntry * rules, |
66 | * rules_end; |
67 | |
68 | bool empty() const; |
69 | }; |
70 | |
71 | inline |
72 | bool State::empty() const |
73 | { |
74 | return rules_end == rules; |
75 | } |
76 | |
77 | |
78 | class SlotMap |
79 | { |
80 | public: |
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; |
104 | private: |
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 | |
115 | class FiniteStateMachine |
116 | { |
117 | public: |
118 | enum {MAX_RULES=128}; |
119 | |
120 | private: |
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 | |
138 | public: |
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 | |
148 | inline |
149 | FiniteStateMachine::FiniteStateMachine(SlotMap& map, json * logger) |
150 | : slots(map), |
151 | dbgout(logger) |
152 | { |
153 | } |
154 | |
155 | inline |
156 | void 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 | |
164 | inline |
165 | FiniteStateMachine::Rules::Rules() |
166 | : m_begin(m_rules), m_end(m_rules) |
167 | { |
168 | } |
169 | |
170 | inline |
171 | void FiniteStateMachine::Rules::clear() |
172 | { |
173 | m_end = m_begin; |
174 | } |
175 | |
176 | inline |
177 | const RuleEntry * FiniteStateMachine::Rules::begin() const |
178 | { |
179 | return m_begin; |
180 | } |
181 | |
182 | inline |
183 | const RuleEntry * FiniteStateMachine::Rules::end() const |
184 | { |
185 | return m_end; |
186 | } |
187 | |
188 | inline |
189 | size_t FiniteStateMachine::Rules::size() const |
190 | { |
191 | return m_end - m_begin; |
192 | } |
193 | |
194 | inline |
195 | void 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 | |
223 | inline |
224 | SlotMap::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 | |
231 | inline |
232 | Slot * * 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 | |
238 | inline |
239 | Slot * * SlotMap::end() |
240 | { |
241 | return m_slot_map + m_size + 1; |
242 | } |
243 | |
244 | inline |
245 | size_t SlotMap::size() const |
246 | { |
247 | return m_size; |
248 | } |
249 | |
250 | inline |
251 | short unsigned int SlotMap::context() const |
252 | { |
253 | return m_precontext; |
254 | } |
255 | |
256 | inline |
257 | void 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 | |
264 | inline |
265 | void SlotMap::pushSlot(Slot*const slot) |
266 | { |
267 | m_slot_map[++m_size] = slot; |
268 | } |
269 | |
270 | inline |
271 | Slot * const & SlotMap::operator[](int n) const |
272 | { |
273 | return m_slot_map[n + 1]; |
274 | } |
275 | |
276 | inline |
277 | Slot * & SlotMap::operator[](int n) |
278 | { |
279 | return m_slot_map[n + 1]; |
280 | } |
281 | |
282 | } // namespace graphite2 |
283 | |