1*8af74909SZhong Yang /** @file RunStyles.cxx
2*8af74909SZhong Yang ** Data structure used to store sparse styles.
3*8af74909SZhong Yang **/
4*8af74909SZhong Yang // Copyright 1998-2007 by Neil Hodgson <[email protected]>
5*8af74909SZhong Yang // The License.txt file describes the conditions under which this software may be distributed.
6*8af74909SZhong Yang
7*8af74909SZhong Yang #include <cstddef>
8*8af74909SZhong Yang #include <cstdlib>
9*8af74909SZhong Yang #include <cstdint>
10*8af74909SZhong Yang #include <cstring>
11*8af74909SZhong Yang #include <cstdio>
12*8af74909SZhong Yang #include <cstdarg>
13*8af74909SZhong Yang #include <climits>
14*8af74909SZhong Yang
15*8af74909SZhong Yang #include <stdexcept>
16*8af74909SZhong Yang #include <string_view>
17*8af74909SZhong Yang #include <vector>
18*8af74909SZhong Yang #include <algorithm>
19*8af74909SZhong Yang #include <memory>
20*8af74909SZhong Yang
21*8af74909SZhong Yang #include "Platform.h"
22*8af74909SZhong Yang
23*8af74909SZhong Yang #include "Scintilla.h"
24*8af74909SZhong Yang #include "Position.h"
25*8af74909SZhong Yang #include "SplitVector.h"
26*8af74909SZhong Yang #include "Partitioning.h"
27*8af74909SZhong Yang #include "RunStyles.h"
28*8af74909SZhong Yang
29*8af74909SZhong Yang using namespace Scintilla;
30*8af74909SZhong Yang
31*8af74909SZhong Yang // Find the first run at a position
32*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
RunFromPosition(DISTANCE position) const33*8af74909SZhong Yang DISTANCE RunStyles<DISTANCE, STYLE>::RunFromPosition(DISTANCE position) const noexcept {
34*8af74909SZhong Yang DISTANCE run = starts->PartitionFromPosition(position);
35*8af74909SZhong Yang // Go to first element with this position
36*8af74909SZhong Yang while ((run > 0) && (position == starts->PositionFromPartition(run-1))) {
37*8af74909SZhong Yang run--;
38*8af74909SZhong Yang }
39*8af74909SZhong Yang return run;
40*8af74909SZhong Yang }
41*8af74909SZhong Yang
42*8af74909SZhong Yang // If there is no run boundary at position, insert one continuing style.
43*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
SplitRun(DISTANCE position)44*8af74909SZhong Yang DISTANCE RunStyles<DISTANCE, STYLE>::SplitRun(DISTANCE position) {
45*8af74909SZhong Yang DISTANCE run = RunFromPosition(position);
46*8af74909SZhong Yang const DISTANCE posRun = starts->PositionFromPartition(run);
47*8af74909SZhong Yang if (posRun < position) {
48*8af74909SZhong Yang STYLE runStyle = ValueAt(position);
49*8af74909SZhong Yang run++;
50*8af74909SZhong Yang starts->InsertPartition(run, position);
51*8af74909SZhong Yang styles->InsertValue(run, 1, runStyle);
52*8af74909SZhong Yang }
53*8af74909SZhong Yang return run;
54*8af74909SZhong Yang }
55*8af74909SZhong Yang
56*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
RemoveRun(DISTANCE run)57*8af74909SZhong Yang void RunStyles<DISTANCE, STYLE>::RemoveRun(DISTANCE run) {
58*8af74909SZhong Yang starts->RemovePartition(run);
59*8af74909SZhong Yang styles->DeleteRange(run, 1);
60*8af74909SZhong Yang }
61*8af74909SZhong Yang
62*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
RemoveRunIfEmpty(DISTANCE run)63*8af74909SZhong Yang void RunStyles<DISTANCE, STYLE>::RemoveRunIfEmpty(DISTANCE run) {
64*8af74909SZhong Yang if ((run < starts->Partitions()) && (starts->Partitions() > 1)) {
65*8af74909SZhong Yang if (starts->PositionFromPartition(run) == starts->PositionFromPartition(run+1)) {
66*8af74909SZhong Yang RemoveRun(run);
67*8af74909SZhong Yang }
68*8af74909SZhong Yang }
69*8af74909SZhong Yang }
70*8af74909SZhong Yang
71*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
RemoveRunIfSameAsPrevious(DISTANCE run)72*8af74909SZhong Yang void RunStyles<DISTANCE, STYLE>::RemoveRunIfSameAsPrevious(DISTANCE run) {
73*8af74909SZhong Yang if ((run > 0) && (run < starts->Partitions())) {
74*8af74909SZhong Yang if (styles->ValueAt(run-1) == styles->ValueAt(run)) {
75*8af74909SZhong Yang RemoveRun(run);
76*8af74909SZhong Yang }
77*8af74909SZhong Yang }
78*8af74909SZhong Yang }
79*8af74909SZhong Yang
80*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
RunStyles()81*8af74909SZhong Yang RunStyles<DISTANCE, STYLE>::RunStyles() {
82*8af74909SZhong Yang starts = std::make_unique<Partitioning<DISTANCE>>(8);
83*8af74909SZhong Yang styles = std::make_unique<SplitVector<STYLE>>();
84*8af74909SZhong Yang styles->InsertValue(0, 2, 0);
85*8af74909SZhong Yang }
86*8af74909SZhong Yang
87*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
~RunStyles()88*8af74909SZhong Yang RunStyles<DISTANCE, STYLE>::~RunStyles() {
89*8af74909SZhong Yang }
90*8af74909SZhong Yang
91*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
Length() const92*8af74909SZhong Yang DISTANCE RunStyles<DISTANCE, STYLE>::Length() const noexcept {
93*8af74909SZhong Yang return starts->PositionFromPartition(starts->Partitions());
94*8af74909SZhong Yang }
95*8af74909SZhong Yang
96*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
ValueAt(DISTANCE position) const97*8af74909SZhong Yang STYLE RunStyles<DISTANCE, STYLE>::ValueAt(DISTANCE position) const noexcept {
98*8af74909SZhong Yang return styles->ValueAt(starts->PartitionFromPosition(position));
99*8af74909SZhong Yang }
100*8af74909SZhong Yang
101*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
FindNextChange(DISTANCE position,DISTANCE end) const102*8af74909SZhong Yang DISTANCE RunStyles<DISTANCE, STYLE>::FindNextChange(DISTANCE position, DISTANCE end) const noexcept {
103*8af74909SZhong Yang const DISTANCE run = starts->PartitionFromPosition(position);
104*8af74909SZhong Yang if (run < starts->Partitions()) {
105*8af74909SZhong Yang const DISTANCE runChange = starts->PositionFromPartition(run);
106*8af74909SZhong Yang if (runChange > position)
107*8af74909SZhong Yang return runChange;
108*8af74909SZhong Yang const DISTANCE nextChange = starts->PositionFromPartition(run + 1);
109*8af74909SZhong Yang if (nextChange > position) {
110*8af74909SZhong Yang return nextChange;
111*8af74909SZhong Yang } else if (position < end) {
112*8af74909SZhong Yang return end;
113*8af74909SZhong Yang } else {
114*8af74909SZhong Yang return end + 1;
115*8af74909SZhong Yang }
116*8af74909SZhong Yang } else {
117*8af74909SZhong Yang return end + 1;
118*8af74909SZhong Yang }
119*8af74909SZhong Yang }
120*8af74909SZhong Yang
121*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
StartRun(DISTANCE position) const122*8af74909SZhong Yang DISTANCE RunStyles<DISTANCE, STYLE>::StartRun(DISTANCE position) const noexcept {
123*8af74909SZhong Yang return starts->PositionFromPartition(starts->PartitionFromPosition(position));
124*8af74909SZhong Yang }
125*8af74909SZhong Yang
126*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
EndRun(DISTANCE position) const127*8af74909SZhong Yang DISTANCE RunStyles<DISTANCE, STYLE>::EndRun(DISTANCE position) const noexcept {
128*8af74909SZhong Yang return starts->PositionFromPartition(starts->PartitionFromPosition(position) + 1);
129*8af74909SZhong Yang }
130*8af74909SZhong Yang
131*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
FillRange(DISTANCE position,STYLE value,DISTANCE fillLength)132*8af74909SZhong Yang FillResult<DISTANCE> RunStyles<DISTANCE, STYLE>::FillRange(DISTANCE position, STYLE value, DISTANCE fillLength) {
133*8af74909SZhong Yang const FillResult<DISTANCE> resultNoChange{false, position, fillLength};
134*8af74909SZhong Yang if (fillLength <= 0) {
135*8af74909SZhong Yang return resultNoChange;
136*8af74909SZhong Yang }
137*8af74909SZhong Yang DISTANCE end = position + fillLength;
138*8af74909SZhong Yang if (end > Length()) {
139*8af74909SZhong Yang return resultNoChange;
140*8af74909SZhong Yang }
141*8af74909SZhong Yang DISTANCE runEnd = RunFromPosition(end);
142*8af74909SZhong Yang if (styles->ValueAt(runEnd) == value) {
143*8af74909SZhong Yang // End already has value so trim range.
144*8af74909SZhong Yang end = starts->PositionFromPartition(runEnd);
145*8af74909SZhong Yang if (position >= end) {
146*8af74909SZhong Yang // Whole range is already same as value so no action
147*8af74909SZhong Yang return resultNoChange;
148*8af74909SZhong Yang }
149*8af74909SZhong Yang fillLength = end - position;
150*8af74909SZhong Yang } else {
151*8af74909SZhong Yang runEnd = SplitRun(end);
152*8af74909SZhong Yang }
153*8af74909SZhong Yang DISTANCE runStart = RunFromPosition(position);
154*8af74909SZhong Yang if (styles->ValueAt(runStart) == value) {
155*8af74909SZhong Yang // Start is in expected value so trim range.
156*8af74909SZhong Yang runStart++;
157*8af74909SZhong Yang position = starts->PositionFromPartition(runStart);
158*8af74909SZhong Yang fillLength = end - position;
159*8af74909SZhong Yang } else {
160*8af74909SZhong Yang if (starts->PositionFromPartition(runStart) < position) {
161*8af74909SZhong Yang runStart = SplitRun(position);
162*8af74909SZhong Yang runEnd++;
163*8af74909SZhong Yang }
164*8af74909SZhong Yang }
165*8af74909SZhong Yang if (runStart < runEnd) {
166*8af74909SZhong Yang const FillResult<DISTANCE> result{ true, position, fillLength };
167*8af74909SZhong Yang styles->SetValueAt(runStart, value);
168*8af74909SZhong Yang // Remove each old run over the range
169*8af74909SZhong Yang for (DISTANCE run=runStart+1; run<runEnd; run++) {
170*8af74909SZhong Yang RemoveRun(runStart+1);
171*8af74909SZhong Yang }
172*8af74909SZhong Yang runEnd = RunFromPosition(end);
173*8af74909SZhong Yang RemoveRunIfSameAsPrevious(runEnd);
174*8af74909SZhong Yang RemoveRunIfSameAsPrevious(runStart);
175*8af74909SZhong Yang runEnd = RunFromPosition(end);
176*8af74909SZhong Yang RemoveRunIfEmpty(runEnd);
177*8af74909SZhong Yang return result;
178*8af74909SZhong Yang } else {
179*8af74909SZhong Yang return resultNoChange;
180*8af74909SZhong Yang }
181*8af74909SZhong Yang }
182*8af74909SZhong Yang
183*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
SetValueAt(DISTANCE position,STYLE value)184*8af74909SZhong Yang void RunStyles<DISTANCE, STYLE>::SetValueAt(DISTANCE position, STYLE value) {
185*8af74909SZhong Yang FillRange(position, value, 1);
186*8af74909SZhong Yang }
187*8af74909SZhong Yang
188*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
InsertSpace(DISTANCE position,DISTANCE insertLength)189*8af74909SZhong Yang void RunStyles<DISTANCE, STYLE>::InsertSpace(DISTANCE position, DISTANCE insertLength) {
190*8af74909SZhong Yang DISTANCE runStart = RunFromPosition(position);
191*8af74909SZhong Yang if (starts->PositionFromPartition(runStart) == position) {
192*8af74909SZhong Yang STYLE runStyle = ValueAt(position);
193*8af74909SZhong Yang // Inserting at start of run so make previous longer
194*8af74909SZhong Yang if (runStart == 0) {
195*8af74909SZhong Yang // Inserting at start of document so ensure 0
196*8af74909SZhong Yang if (runStyle) {
197*8af74909SZhong Yang styles->SetValueAt(0, STYLE());
198*8af74909SZhong Yang starts->InsertPartition(1, 0);
199*8af74909SZhong Yang styles->InsertValue(1, 1, runStyle);
200*8af74909SZhong Yang starts->InsertText(0, insertLength);
201*8af74909SZhong Yang } else {
202*8af74909SZhong Yang starts->InsertText(runStart, insertLength);
203*8af74909SZhong Yang }
204*8af74909SZhong Yang } else {
205*8af74909SZhong Yang if (runStyle) {
206*8af74909SZhong Yang starts->InsertText(runStart-1, insertLength);
207*8af74909SZhong Yang } else {
208*8af74909SZhong Yang // Insert at end of run so do not extend style
209*8af74909SZhong Yang starts->InsertText(runStart, insertLength);
210*8af74909SZhong Yang }
211*8af74909SZhong Yang }
212*8af74909SZhong Yang } else {
213*8af74909SZhong Yang starts->InsertText(runStart, insertLength);
214*8af74909SZhong Yang }
215*8af74909SZhong Yang }
216*8af74909SZhong Yang
217*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
DeleteAll()218*8af74909SZhong Yang void RunStyles<DISTANCE, STYLE>::DeleteAll() {
219*8af74909SZhong Yang starts = std::make_unique<Partitioning<DISTANCE>>(8);
220*8af74909SZhong Yang styles = std::make_unique<SplitVector<STYLE>>();
221*8af74909SZhong Yang styles->InsertValue(0, 2, 0);
222*8af74909SZhong Yang }
223*8af74909SZhong Yang
224*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
DeleteRange(DISTANCE position,DISTANCE deleteLength)225*8af74909SZhong Yang void RunStyles<DISTANCE, STYLE>::DeleteRange(DISTANCE position, DISTANCE deleteLength) {
226*8af74909SZhong Yang DISTANCE end = position + deleteLength;
227*8af74909SZhong Yang DISTANCE runStart = RunFromPosition(position);
228*8af74909SZhong Yang DISTANCE runEnd = RunFromPosition(end);
229*8af74909SZhong Yang if (runStart == runEnd) {
230*8af74909SZhong Yang // Deleting from inside one run
231*8af74909SZhong Yang starts->InsertText(runStart, -deleteLength);
232*8af74909SZhong Yang RemoveRunIfEmpty(runStart);
233*8af74909SZhong Yang } else {
234*8af74909SZhong Yang runStart = SplitRun(position);
235*8af74909SZhong Yang runEnd = SplitRun(end);
236*8af74909SZhong Yang starts->InsertText(runStart, -deleteLength);
237*8af74909SZhong Yang // Remove each old run over the range
238*8af74909SZhong Yang for (DISTANCE run=runStart; run<runEnd; run++) {
239*8af74909SZhong Yang RemoveRun(runStart);
240*8af74909SZhong Yang }
241*8af74909SZhong Yang RemoveRunIfEmpty(runStart);
242*8af74909SZhong Yang RemoveRunIfSameAsPrevious(runStart);
243*8af74909SZhong Yang }
244*8af74909SZhong Yang }
245*8af74909SZhong Yang
246*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
Runs() const247*8af74909SZhong Yang DISTANCE RunStyles<DISTANCE, STYLE>::Runs() const noexcept {
248*8af74909SZhong Yang return starts->Partitions();
249*8af74909SZhong Yang }
250*8af74909SZhong Yang
251*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
AllSame() const252*8af74909SZhong Yang bool RunStyles<DISTANCE, STYLE>::AllSame() const noexcept {
253*8af74909SZhong Yang for (DISTANCE run = 1; run < starts->Partitions(); run++) {
254*8af74909SZhong Yang if (styles->ValueAt(run) != styles->ValueAt(run - 1))
255*8af74909SZhong Yang return false;
256*8af74909SZhong Yang }
257*8af74909SZhong Yang return true;
258*8af74909SZhong Yang }
259*8af74909SZhong Yang
260*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
AllSameAs(STYLE value) const261*8af74909SZhong Yang bool RunStyles<DISTANCE, STYLE>::AllSameAs(STYLE value) const noexcept {
262*8af74909SZhong Yang return AllSame() && (styles->ValueAt(0) == value);
263*8af74909SZhong Yang }
264*8af74909SZhong Yang
265*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
Find(STYLE value,DISTANCE start) const266*8af74909SZhong Yang DISTANCE RunStyles<DISTANCE, STYLE>::Find(STYLE value, DISTANCE start) const noexcept {
267*8af74909SZhong Yang if (start < Length()) {
268*8af74909SZhong Yang DISTANCE run = start ? RunFromPosition(start) : 0;
269*8af74909SZhong Yang if (styles->ValueAt(run) == value)
270*8af74909SZhong Yang return start;
271*8af74909SZhong Yang run++;
272*8af74909SZhong Yang while (run < starts->Partitions()) {
273*8af74909SZhong Yang if (styles->ValueAt(run) == value)
274*8af74909SZhong Yang return starts->PositionFromPartition(run);
275*8af74909SZhong Yang run++;
276*8af74909SZhong Yang }
277*8af74909SZhong Yang }
278*8af74909SZhong Yang return -1;
279*8af74909SZhong Yang }
280*8af74909SZhong Yang
281*8af74909SZhong Yang template <typename DISTANCE, typename STYLE>
Check() const282*8af74909SZhong Yang void RunStyles<DISTANCE, STYLE>::Check() const {
283*8af74909SZhong Yang if (Length() < 0) {
284*8af74909SZhong Yang throw std::runtime_error("RunStyles: Length can not be negative.");
285*8af74909SZhong Yang }
286*8af74909SZhong Yang if (starts->Partitions() < 1) {
287*8af74909SZhong Yang throw std::runtime_error("RunStyles: Must always have 1 or more partitions.");
288*8af74909SZhong Yang }
289*8af74909SZhong Yang if (starts->Partitions() != styles->Length()-1) {
290*8af74909SZhong Yang throw std::runtime_error("RunStyles: Partitions and styles different lengths.");
291*8af74909SZhong Yang }
292*8af74909SZhong Yang DISTANCE start=0;
293*8af74909SZhong Yang while (start < Length()) {
294*8af74909SZhong Yang const DISTANCE end = EndRun(start);
295*8af74909SZhong Yang if (start >= end) {
296*8af74909SZhong Yang throw std::runtime_error("RunStyles: Partition is 0 length.");
297*8af74909SZhong Yang }
298*8af74909SZhong Yang start = end;
299*8af74909SZhong Yang }
300*8af74909SZhong Yang if (styles->ValueAt(styles->Length()-1) != 0) {
301*8af74909SZhong Yang throw std::runtime_error("RunStyles: Unused style at end changed.");
302*8af74909SZhong Yang }
303*8af74909SZhong Yang for (ptrdiff_t j=1; j<styles->Length()-1; j++) {
304*8af74909SZhong Yang if (styles->ValueAt(j) == styles->ValueAt(j-1)) {
305*8af74909SZhong Yang throw std::runtime_error("RunStyles: Style of a partition same as previous.");
306*8af74909SZhong Yang }
307*8af74909SZhong Yang }
308*8af74909SZhong Yang }
309*8af74909SZhong Yang
310*8af74909SZhong Yang template class Scintilla::RunStyles<int, int>;
311*8af74909SZhong Yang template class Scintilla::RunStyles<int, char>;
312*8af74909SZhong Yang #if (PTRDIFF_MAX != INT_MAX) || PLAT_HAIKU
313*8af74909SZhong Yang template class Scintilla::RunStyles<ptrdiff_t, int>;
314*8af74909SZhong Yang template class Scintilla::RunStyles<ptrdiff_t, char>;
315*8af74909SZhong Yang #endif
316