Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* GRAPHITE2 LICENSING |
michael@0 | 2 | |
michael@0 | 3 | Copyright 2011, SIL International |
michael@0 | 4 | All rights reserved. |
michael@0 | 5 | |
michael@0 | 6 | This library is free software; you can redistribute it and/or modify |
michael@0 | 7 | it under the terms of the GNU Lesser General Public License as published |
michael@0 | 8 | by the Free Software Foundation; either version 2.1 of License, or |
michael@0 | 9 | (at your option) any later version. |
michael@0 | 10 | |
michael@0 | 11 | This program is distributed in the hope that it will be useful, |
michael@0 | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
michael@0 | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
michael@0 | 14 | Lesser General Public License for more details. |
michael@0 | 15 | |
michael@0 | 16 | You should also have received a copy of the GNU Lesser General Public |
michael@0 | 17 | License along with this library in the file named "LICENSE". |
michael@0 | 18 | If not, write to the Free Software Foundation, 51 Franklin Street, |
michael@0 | 19 | Suite 500, Boston, MA 02110-1335, USA or visit their web page on the |
michael@0 | 20 | internet at http://www.fsf.org/licenses/lgpl.html. |
michael@0 | 21 | |
michael@0 | 22 | Alternatively, the contents of this file may be used under the terms of the |
michael@0 | 23 | Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public |
michael@0 | 24 | License, as published by the Free Software Foundation, either version 2 |
michael@0 | 25 | of the License or (at your option) any later version. |
michael@0 | 26 | */ |
michael@0 | 27 | |
michael@0 | 28 | #pragma once |
michael@0 | 29 | |
michael@0 | 30 | #include "inc/Code.h" |
michael@0 | 31 | #include "inc/Slot.h" |
michael@0 | 32 | |
michael@0 | 33 | namespace graphite2 { |
michael@0 | 34 | |
michael@0 | 35 | struct Rule { |
michael@0 | 36 | const vm::Machine::Code * constraint, |
michael@0 | 37 | * action; |
michael@0 | 38 | unsigned short sort; |
michael@0 | 39 | byte preContext; |
michael@0 | 40 | #ifndef NDEBUG |
michael@0 | 41 | uint16 rule_idx; |
michael@0 | 42 | #endif |
michael@0 | 43 | |
michael@0 | 44 | Rule() : constraint(0), action(0), sort(0), preContext(0) {} |
michael@0 | 45 | ~Rule(); |
michael@0 | 46 | |
michael@0 | 47 | CLASS_NEW_DELETE; |
michael@0 | 48 | |
michael@0 | 49 | private: |
michael@0 | 50 | Rule(const Rule &); |
michael@0 | 51 | Rule & operator = (const Rule &); |
michael@0 | 52 | }; |
michael@0 | 53 | |
michael@0 | 54 | inline Rule::~Rule() |
michael@0 | 55 | { |
michael@0 | 56 | delete constraint; |
michael@0 | 57 | delete action; |
michael@0 | 58 | } |
michael@0 | 59 | |
michael@0 | 60 | |
michael@0 | 61 | struct RuleEntry |
michael@0 | 62 | { |
michael@0 | 63 | const Rule * rule; |
michael@0 | 64 | |
michael@0 | 65 | inline |
michael@0 | 66 | bool operator < (const RuleEntry &r) const |
michael@0 | 67 | { |
michael@0 | 68 | const unsigned short lsort = rule->sort, rsort = r.rule->sort; |
michael@0 | 69 | return lsort > rsort || (lsort == rsort && rule < r.rule); |
michael@0 | 70 | } |
michael@0 | 71 | |
michael@0 | 72 | inline |
michael@0 | 73 | bool operator == (const RuleEntry &r) const |
michael@0 | 74 | { |
michael@0 | 75 | return rule == r.rule; |
michael@0 | 76 | } |
michael@0 | 77 | }; |
michael@0 | 78 | |
michael@0 | 79 | |
michael@0 | 80 | struct State |
michael@0 | 81 | { |
michael@0 | 82 | const RuleEntry * rules, |
michael@0 | 83 | * rules_end; |
michael@0 | 84 | |
michael@0 | 85 | bool empty() const; |
michael@0 | 86 | }; |
michael@0 | 87 | |
michael@0 | 88 | inline |
michael@0 | 89 | bool State::empty() const |
michael@0 | 90 | { |
michael@0 | 91 | return rules_end == rules; |
michael@0 | 92 | } |
michael@0 | 93 | |
michael@0 | 94 | |
michael@0 | 95 | class SlotMap |
michael@0 | 96 | { |
michael@0 | 97 | public: |
michael@0 | 98 | enum {MAX_SLOTS=64}; |
michael@0 | 99 | SlotMap(Segment & seg); |
michael@0 | 100 | |
michael@0 | 101 | Slot * * begin(); |
michael@0 | 102 | Slot * * end(); |
michael@0 | 103 | size_t size() const; |
michael@0 | 104 | unsigned short context() const; |
michael@0 | 105 | void reset(Slot &, unsigned short); |
michael@0 | 106 | |
michael@0 | 107 | Slot * const & operator[](int n) const; |
michael@0 | 108 | Slot * & operator [] (int); |
michael@0 | 109 | void pushSlot(Slot * const slot); |
michael@0 | 110 | void collectGarbage(); |
michael@0 | 111 | |
michael@0 | 112 | Slot * highwater() { return m_highwater; } |
michael@0 | 113 | void highwater(Slot *s) { m_highwater = s; m_highpassed = false; } |
michael@0 | 114 | bool highpassed() const { return m_highpassed; } |
michael@0 | 115 | void highpassed(bool v) { m_highpassed = v; } |
michael@0 | 116 | |
michael@0 | 117 | Segment & segment; |
michael@0 | 118 | private: |
michael@0 | 119 | Slot * m_slot_map[MAX_SLOTS+1]; |
michael@0 | 120 | unsigned short m_size; |
michael@0 | 121 | unsigned short m_precontext; |
michael@0 | 122 | Slot * m_highwater; |
michael@0 | 123 | bool m_highpassed; |
michael@0 | 124 | }; |
michael@0 | 125 | |
michael@0 | 126 | |
michael@0 | 127 | class FiniteStateMachine |
michael@0 | 128 | { |
michael@0 | 129 | public: |
michael@0 | 130 | enum {MAX_RULES=128}; |
michael@0 | 131 | |
michael@0 | 132 | private: |
michael@0 | 133 | class Rules |
michael@0 | 134 | { |
michael@0 | 135 | public: |
michael@0 | 136 | Rules(); |
michael@0 | 137 | void clear(); |
michael@0 | 138 | const RuleEntry * begin() const; |
michael@0 | 139 | const RuleEntry * end() const; |
michael@0 | 140 | size_t size() const; |
michael@0 | 141 | |
michael@0 | 142 | void accumulate_rules(const State &state); |
michael@0 | 143 | |
michael@0 | 144 | private: |
michael@0 | 145 | RuleEntry * m_begin, |
michael@0 | 146 | * m_end, |
michael@0 | 147 | m_rules[MAX_RULES*2]; |
michael@0 | 148 | }; |
michael@0 | 149 | |
michael@0 | 150 | public: |
michael@0 | 151 | FiniteStateMachine(SlotMap & map, json * logger); |
michael@0 | 152 | void reset(Slot * & slot, const short unsigned int max_pre_ctxt); |
michael@0 | 153 | |
michael@0 | 154 | Rules rules; |
michael@0 | 155 | SlotMap & slots; |
michael@0 | 156 | json * const dbgout; |
michael@0 | 157 | }; |
michael@0 | 158 | |
michael@0 | 159 | |
michael@0 | 160 | inline |
michael@0 | 161 | FiniteStateMachine::FiniteStateMachine(SlotMap& map, json * logger) |
michael@0 | 162 | : slots(map), |
michael@0 | 163 | dbgout(logger) |
michael@0 | 164 | { |
michael@0 | 165 | } |
michael@0 | 166 | |
michael@0 | 167 | inline |
michael@0 | 168 | void FiniteStateMachine::reset(Slot * & slot, const short unsigned int max_pre_ctxt) |
michael@0 | 169 | { |
michael@0 | 170 | rules.clear(); |
michael@0 | 171 | int ctxt = 0; |
michael@0 | 172 | for (; ctxt != max_pre_ctxt && slot->prev(); ++ctxt, slot = slot->prev()); |
michael@0 | 173 | slots.reset(*slot, ctxt); |
michael@0 | 174 | } |
michael@0 | 175 | |
michael@0 | 176 | inline |
michael@0 | 177 | FiniteStateMachine::Rules::Rules() |
michael@0 | 178 | : m_begin(m_rules), m_end(m_rules) |
michael@0 | 179 | { |
michael@0 | 180 | } |
michael@0 | 181 | |
michael@0 | 182 | inline |
michael@0 | 183 | void FiniteStateMachine::Rules::clear() |
michael@0 | 184 | { |
michael@0 | 185 | m_end = m_begin; |
michael@0 | 186 | } |
michael@0 | 187 | |
michael@0 | 188 | inline |
michael@0 | 189 | const RuleEntry * FiniteStateMachine::Rules::begin() const |
michael@0 | 190 | { |
michael@0 | 191 | return m_begin; |
michael@0 | 192 | } |
michael@0 | 193 | |
michael@0 | 194 | inline |
michael@0 | 195 | const RuleEntry * FiniteStateMachine::Rules::end() const |
michael@0 | 196 | { |
michael@0 | 197 | return m_end; |
michael@0 | 198 | } |
michael@0 | 199 | |
michael@0 | 200 | inline |
michael@0 | 201 | size_t FiniteStateMachine::Rules::size() const |
michael@0 | 202 | { |
michael@0 | 203 | return m_end - m_begin; |
michael@0 | 204 | } |
michael@0 | 205 | |
michael@0 | 206 | inline |
michael@0 | 207 | void FiniteStateMachine::Rules::accumulate_rules(const State &state) |
michael@0 | 208 | { |
michael@0 | 209 | // Only bother if there are rules in the State object. |
michael@0 | 210 | if (state.empty()) return; |
michael@0 | 211 | |
michael@0 | 212 | // Merge the new sorted rules list into the current sorted result set. |
michael@0 | 213 | const RuleEntry * lre = begin(), * rre = state.rules; |
michael@0 | 214 | RuleEntry * out = m_rules + (m_begin == m_rules)*MAX_RULES; |
michael@0 | 215 | const RuleEntry * const lrend = out + MAX_RULES, |
michael@0 | 216 | * const rrend = state.rules_end; |
michael@0 | 217 | m_begin = out; |
michael@0 | 218 | while (lre != end() && out != lrend) |
michael@0 | 219 | { |
michael@0 | 220 | if (*lre < *rre) *out++ = *lre++; |
michael@0 | 221 | else if (*rre < *lre) { *out++ = *rre++; } |
michael@0 | 222 | else { *out++ = *lre++; ++rre; } |
michael@0 | 223 | |
michael@0 | 224 | if (rre == rrend) |
michael@0 | 225 | { |
michael@0 | 226 | while (lre != end() && out != lrend) { *out++ = *lre++; } |
michael@0 | 227 | m_end = out; |
michael@0 | 228 | return; |
michael@0 | 229 | } |
michael@0 | 230 | } |
michael@0 | 231 | while (rre != rrend && out != lrend) { *out++ = *rre++; } |
michael@0 | 232 | m_end = out; |
michael@0 | 233 | } |
michael@0 | 234 | |
michael@0 | 235 | inline |
michael@0 | 236 | SlotMap::SlotMap(Segment & seg) |
michael@0 | 237 | : segment(seg), m_size(0), m_precontext(0), m_highwater(0), m_highpassed(false) |
michael@0 | 238 | { |
michael@0 | 239 | m_slot_map[0] = 0; |
michael@0 | 240 | } |
michael@0 | 241 | |
michael@0 | 242 | inline |
michael@0 | 243 | Slot * * SlotMap::begin() |
michael@0 | 244 | { |
michael@0 | 245 | return &m_slot_map[1]; // allow map to go 1 before slot_map when inserting |
michael@0 | 246 | // at start of segment. |
michael@0 | 247 | } |
michael@0 | 248 | |
michael@0 | 249 | inline |
michael@0 | 250 | Slot * * SlotMap::end() |
michael@0 | 251 | { |
michael@0 | 252 | return m_slot_map + m_size + 1; |
michael@0 | 253 | } |
michael@0 | 254 | |
michael@0 | 255 | inline |
michael@0 | 256 | size_t SlotMap::size() const |
michael@0 | 257 | { |
michael@0 | 258 | return m_size; |
michael@0 | 259 | } |
michael@0 | 260 | |
michael@0 | 261 | inline |
michael@0 | 262 | short unsigned int SlotMap::context() const |
michael@0 | 263 | { |
michael@0 | 264 | return m_precontext; |
michael@0 | 265 | } |
michael@0 | 266 | |
michael@0 | 267 | inline |
michael@0 | 268 | void SlotMap::reset(Slot & slot, short unsigned int ctxt) |
michael@0 | 269 | { |
michael@0 | 270 | m_size = 0; |
michael@0 | 271 | m_precontext = ctxt; |
michael@0 | 272 | *m_slot_map = slot.prev(); |
michael@0 | 273 | } |
michael@0 | 274 | |
michael@0 | 275 | inline |
michael@0 | 276 | void SlotMap::pushSlot(Slot*const slot) |
michael@0 | 277 | { |
michael@0 | 278 | m_slot_map[++m_size] = slot; |
michael@0 | 279 | } |
michael@0 | 280 | |
michael@0 | 281 | inline |
michael@0 | 282 | Slot * const & SlotMap::operator[](int n) const |
michael@0 | 283 | { |
michael@0 | 284 | return m_slot_map[n + 1]; |
michael@0 | 285 | } |
michael@0 | 286 | |
michael@0 | 287 | inline |
michael@0 | 288 | Slot * & SlotMap::operator[](int n) |
michael@0 | 289 | { |
michael@0 | 290 | return m_slot_map[n + 1]; |
michael@0 | 291 | } |
michael@0 | 292 | |
michael@0 | 293 | } // namespace graphite2 |