xref: /MusicPlayer2/scintilla/src/RunStyles.cxx (revision 8af74909132ed5e696cb05b6689ae4baf14c1c96)
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