1 | // Scintilla source code edit control |
2 | /** @file SparseState.h |
3 | ** Hold lexer state that may change rarely. |
4 | ** This is often per-line state such as whether a particular type of section has been entered. |
5 | ** A state continues until it is changed. |
6 | **/ |
7 | // Copyright 2011 by Neil Hodgson <neilh@scintilla.org> |
8 | // The License.txt file describes the conditions under which this software may be distributed. |
9 | |
10 | #ifndef SPARSESTATE_H |
11 | #define SPARSESTATE_H |
12 | |
13 | namespace Lexilla { |
14 | |
15 | template <typename T> |
16 | class SparseState { |
17 | struct State { |
18 | Sci_Position position; |
19 | T value; |
20 | constexpr State(Sci_Position position_, T value_) noexcept : position(position_), value(value_) { |
21 | } |
22 | inline bool operator<(const State &other) const noexcept { |
23 | return position < other.position; |
24 | } |
25 | inline bool operator==(const State &other) const noexcept { |
26 | return (position == other.position) && (value == other.value); |
27 | } |
28 | }; |
29 | Sci_Position positionFirst; |
30 | typedef std::vector<State> stateVector; |
31 | stateVector states; |
32 | |
33 | typename stateVector::iterator Find(Sci_Position position) { |
34 | const State searchValue(position, T()); |
35 | return std::lower_bound(states.begin(), states.end(), searchValue); |
36 | } |
37 | |
38 | public: |
39 | explicit SparseState(Sci_Position positionFirst_=-1) { |
40 | positionFirst = positionFirst_; |
41 | } |
42 | void Set(Sci_Position position, T value) { |
43 | Delete(position); |
44 | if (states.empty() || (value != states[states.size()-1].value)) { |
45 | states.push_back(State(position, value)); |
46 | } |
47 | } |
48 | T ValueAt(Sci_Position position) { |
49 | if (states.empty()) |
50 | return T(); |
51 | if (position < states[0].position) |
52 | return T(); |
53 | typename stateVector::iterator low = Find(position); |
54 | if (low == states.end()) { |
55 | return states[states.size()-1].value; |
56 | } else { |
57 | if (low->position > position) { |
58 | --low; |
59 | } |
60 | return low->value; |
61 | } |
62 | } |
63 | bool Delete(Sci_Position position) { |
64 | typename stateVector::iterator low = Find(position); |
65 | if (low != states.end()) { |
66 | states.erase(low, states.end()); |
67 | return true; |
68 | } |
69 | return false; |
70 | } |
71 | size_t size() const { |
72 | return states.size(); |
73 | } |
74 | |
75 | // Returns true if Merge caused a significant change |
76 | bool Merge(const SparseState<T> &other, Sci_Position ignoreAfter) { |
77 | // Changes caused beyond ignoreAfter are not significant |
78 | Delete(ignoreAfter+1); |
79 | |
80 | bool different = true; |
81 | bool changed = false; |
82 | typename stateVector::iterator low = Find(other.positionFirst); |
83 | if (static_cast<size_t>(states.end() - low) == other.states.size()) { |
84 | // Same number in other as after positionFirst in this |
85 | different = !std::equal(low, states.end(), other.states.begin()); |
86 | } |
87 | if (different) { |
88 | if (low != states.end()) { |
89 | states.erase(low, states.end()); |
90 | changed = true; |
91 | } |
92 | typename stateVector::const_iterator startOther = other.states.begin(); |
93 | if (!states.empty() && !other.states.empty() && states.back().value == startOther->value) |
94 | ++startOther; |
95 | if (startOther != other.states.end()) { |
96 | states.insert(states.end(), startOther, other.states.end()); |
97 | changed = true; |
98 | } |
99 | } |
100 | return changed; |
101 | } |
102 | }; |
103 | |
104 | } |
105 | |
106 | #endif |
107 | |