xref: /MusicPlayer2/scintilla/src/Partitioning.h (revision 8af74909132ed5e696cb05b6689ae4baf14c1c96)
1*8af74909SZhong Yang // Scintilla source code edit control
2*8af74909SZhong Yang /** @file Partitioning.h
3*8af74909SZhong Yang  ** Data structure used to partition an interval. Used for holding line start/end positions.
4*8af74909SZhong Yang  **/
5*8af74909SZhong Yang // Copyright 1998-2007 by Neil Hodgson <[email protected]>
6*8af74909SZhong Yang // The License.txt file describes the conditions under which this software may be distributed.
7*8af74909SZhong Yang 
8*8af74909SZhong Yang #ifndef PARTITIONING_H
9*8af74909SZhong Yang #define PARTITIONING_H
10*8af74909SZhong Yang 
11*8af74909SZhong Yang namespace Scintilla {
12*8af74909SZhong Yang 
13*8af74909SZhong Yang /// A split vector of integers with a method for adding a value to all elements
14*8af74909SZhong Yang /// in a range.
15*8af74909SZhong Yang /// Used by the Partitioning class.
16*8af74909SZhong Yang 
17*8af74909SZhong Yang template <typename T>
18*8af74909SZhong Yang class SplitVectorWithRangeAdd : public SplitVector<T> {
19*8af74909SZhong Yang public:
SplitVectorWithRangeAdd(ptrdiff_t growSize_)20*8af74909SZhong Yang 	explicit SplitVectorWithRangeAdd(ptrdiff_t growSize_) {
21*8af74909SZhong Yang 		this->SetGrowSize(growSize_);
22*8af74909SZhong Yang 		this->ReAllocate(growSize_);
23*8af74909SZhong Yang 	}
24*8af74909SZhong Yang 	// Deleted so SplitVectorWithRangeAdd objects can not be copied.
25*8af74909SZhong Yang 	SplitVectorWithRangeAdd(const SplitVectorWithRangeAdd &) = delete;
26*8af74909SZhong Yang 	SplitVectorWithRangeAdd(SplitVectorWithRangeAdd &&) = delete;
27*8af74909SZhong Yang 	void operator=(const SplitVectorWithRangeAdd &) = delete;
28*8af74909SZhong Yang 	void operator=(SplitVectorWithRangeAdd &&) = delete;
~SplitVectorWithRangeAdd()29*8af74909SZhong Yang 	~SplitVectorWithRangeAdd() {
30*8af74909SZhong Yang 	}
RangeAddDelta(ptrdiff_t start,ptrdiff_t end,T delta)31*8af74909SZhong Yang 	void RangeAddDelta(ptrdiff_t start, ptrdiff_t end, T delta) noexcept {
32*8af74909SZhong Yang 		// end is 1 past end, so end-start is number of elements to change
33*8af74909SZhong Yang 		ptrdiff_t i = 0;
34*8af74909SZhong Yang 		const ptrdiff_t rangeLength = end - start;
35*8af74909SZhong Yang 		ptrdiff_t range1Length = rangeLength;
36*8af74909SZhong Yang 		const ptrdiff_t part1Left = this->part1Length - start;
37*8af74909SZhong Yang 		if (range1Length > part1Left)
38*8af74909SZhong Yang 			range1Length = part1Left;
39*8af74909SZhong Yang 		while (i < range1Length) {
40*8af74909SZhong Yang 			this->body[start++] += delta;
41*8af74909SZhong Yang 			i++;
42*8af74909SZhong Yang 		}
43*8af74909SZhong Yang 		start += this->gapLength;
44*8af74909SZhong Yang 		while (i < rangeLength) {
45*8af74909SZhong Yang 			this->body[start++] += delta;
46*8af74909SZhong Yang 			i++;
47*8af74909SZhong Yang 		}
48*8af74909SZhong Yang 	}
49*8af74909SZhong Yang };
50*8af74909SZhong Yang 
51*8af74909SZhong Yang /// Divide an interval into multiple partitions.
52*8af74909SZhong Yang /// Useful for breaking a document down into sections such as lines.
53*8af74909SZhong Yang /// A 0 length interval has a single 0 length partition, numbered 0
54*8af74909SZhong Yang /// If interval not 0 length then each partition non-zero length
55*8af74909SZhong Yang /// When needed, positions after the interval are considered part of the last partition
56*8af74909SZhong Yang /// but the end of the last partition can be found with PositionFromPartition(last+1).
57*8af74909SZhong Yang 
58*8af74909SZhong Yang template <typename T>
59*8af74909SZhong Yang class Partitioning {
60*8af74909SZhong Yang private:
61*8af74909SZhong Yang 	// To avoid calculating all the partition positions whenever any text is inserted
62*8af74909SZhong Yang 	// there may be a step somewhere in the list.
63*8af74909SZhong Yang 	T stepPartition;
64*8af74909SZhong Yang 	T stepLength;
65*8af74909SZhong Yang 	std::unique_ptr<SplitVectorWithRangeAdd<T>> body;
66*8af74909SZhong Yang 
67*8af74909SZhong Yang 	// Move step forward
ApplyStep(T partitionUpTo)68*8af74909SZhong Yang 	void ApplyStep(T partitionUpTo) noexcept {
69*8af74909SZhong Yang 		if (stepLength != 0) {
70*8af74909SZhong Yang 			body->RangeAddDelta(stepPartition+1, partitionUpTo + 1, stepLength);
71*8af74909SZhong Yang 		}
72*8af74909SZhong Yang 		stepPartition = partitionUpTo;
73*8af74909SZhong Yang 		if (stepPartition >= body->Length()-1) {
74*8af74909SZhong Yang 			stepPartition = Partitions();
75*8af74909SZhong Yang 			stepLength = 0;
76*8af74909SZhong Yang 		}
77*8af74909SZhong Yang 	}
78*8af74909SZhong Yang 
79*8af74909SZhong Yang 	// Move step backward
BackStep(T partitionDownTo)80*8af74909SZhong Yang 	void BackStep(T partitionDownTo) noexcept {
81*8af74909SZhong Yang 		if (stepLength != 0) {
82*8af74909SZhong Yang 			body->RangeAddDelta(partitionDownTo+1, stepPartition+1, -stepLength);
83*8af74909SZhong Yang 		}
84*8af74909SZhong Yang 		stepPartition = partitionDownTo;
85*8af74909SZhong Yang 	}
86*8af74909SZhong Yang 
Allocate(ptrdiff_t growSize)87*8af74909SZhong Yang 	void Allocate(ptrdiff_t growSize) {
88*8af74909SZhong Yang 		body = std::make_unique<SplitVectorWithRangeAdd<T>>(growSize);
89*8af74909SZhong Yang 		stepPartition = 0;
90*8af74909SZhong Yang 		stepLength = 0;
91*8af74909SZhong Yang 		body->Insert(0, 0);	// This value stays 0 for ever
92*8af74909SZhong Yang 		body->Insert(1, 0);	// This is the end of the first partition and will be the start of the second
93*8af74909SZhong Yang 	}
94*8af74909SZhong Yang 
95*8af74909SZhong Yang public:
Partitioning(int growSize)96*8af74909SZhong Yang 	explicit Partitioning(int growSize) : stepPartition(0), stepLength(0) {
97*8af74909SZhong Yang 		Allocate(growSize);
98*8af74909SZhong Yang 	}
99*8af74909SZhong Yang 
100*8af74909SZhong Yang 	// Deleted so Partitioning objects can not be copied.
101*8af74909SZhong Yang 	Partitioning(const Partitioning &) = delete;
102*8af74909SZhong Yang 	Partitioning(Partitioning &&) = delete;
103*8af74909SZhong Yang 	void operator=(const Partitioning &) = delete;
104*8af74909SZhong Yang 	void operator=(Partitioning &&) = delete;
105*8af74909SZhong Yang 
~Partitioning()106*8af74909SZhong Yang 	~Partitioning() {
107*8af74909SZhong Yang 	}
108*8af74909SZhong Yang 
Partitions()109*8af74909SZhong Yang 	T Partitions() const noexcept {
110*8af74909SZhong Yang 		return static_cast<T>(body->Length())-1;
111*8af74909SZhong Yang 	}
112*8af74909SZhong Yang 
Length()113*8af74909SZhong Yang 	T Length() const noexcept {
114*8af74909SZhong Yang 		return PositionFromPartition(Partitions());
115*8af74909SZhong Yang 	}
116*8af74909SZhong Yang 
InsertPartition(T partition,T pos)117*8af74909SZhong Yang 	void InsertPartition(T partition, T pos) {
118*8af74909SZhong Yang 		if (stepPartition < partition) {
119*8af74909SZhong Yang 			ApplyStep(partition);
120*8af74909SZhong Yang 		}
121*8af74909SZhong Yang 		body->Insert(partition, pos);
122*8af74909SZhong Yang 		stepPartition++;
123*8af74909SZhong Yang 	}
124*8af74909SZhong Yang 
InsertPartitions(T partition,const T * positions,size_t length)125*8af74909SZhong Yang 	void InsertPartitions(T partition, const T *positions, size_t length) {
126*8af74909SZhong Yang 		if (stepPartition < partition) {
127*8af74909SZhong Yang 			ApplyStep(partition);
128*8af74909SZhong Yang 		}
129*8af74909SZhong Yang 		body->InsertFromArray(partition, positions, 0, length);
130*8af74909SZhong Yang 		stepPartition += static_cast<T>(length);
131*8af74909SZhong Yang 	}
132*8af74909SZhong Yang 
InsertPartitionsWithCast(T partition,const ptrdiff_t * positions,size_t length)133*8af74909SZhong Yang 	void InsertPartitionsWithCast(T partition, const ptrdiff_t *positions, size_t length) {
134*8af74909SZhong Yang 		// Used for 64-bit builds when T is 32-bits
135*8af74909SZhong Yang 		if (stepPartition < partition) {
136*8af74909SZhong Yang 			ApplyStep(partition);
137*8af74909SZhong Yang 		}
138*8af74909SZhong Yang 		T *pInsertion = body->InsertEmpty(partition, length);
139*8af74909SZhong Yang 		for (size_t i = 0; i < length; i++) {
140*8af74909SZhong Yang 			pInsertion[i] = static_cast<T>(positions[i]);
141*8af74909SZhong Yang 		}
142*8af74909SZhong Yang 		stepPartition += static_cast<T>(length);
143*8af74909SZhong Yang 	}
144*8af74909SZhong Yang 
SetPartitionStartPosition(T partition,T pos)145*8af74909SZhong Yang 	void SetPartitionStartPosition(T partition, T pos) noexcept {
146*8af74909SZhong Yang 		ApplyStep(partition+1);
147*8af74909SZhong Yang 		if ((partition < 0) || (partition > body->Length())) {
148*8af74909SZhong Yang 			return;
149*8af74909SZhong Yang 		}
150*8af74909SZhong Yang 		body->SetValueAt(partition, pos);
151*8af74909SZhong Yang 	}
152*8af74909SZhong Yang 
InsertText(T partitionInsert,T delta)153*8af74909SZhong Yang 	void InsertText(T partitionInsert, T delta) noexcept {
154*8af74909SZhong Yang 		// Point all the partitions after the insertion point further along in the buffer
155*8af74909SZhong Yang 		if (stepLength != 0) {
156*8af74909SZhong Yang 			if (partitionInsert >= stepPartition) {
157*8af74909SZhong Yang 				// Fill in up to the new insertion point
158*8af74909SZhong Yang 				ApplyStep(partitionInsert);
159*8af74909SZhong Yang 				stepLength += delta;
160*8af74909SZhong Yang 			} else if (partitionInsert >= (stepPartition - body->Length() / 10)) {
161*8af74909SZhong Yang 				// Close to step but before so move step back
162*8af74909SZhong Yang 				BackStep(partitionInsert);
163*8af74909SZhong Yang 				stepLength += delta;
164*8af74909SZhong Yang 			} else {
165*8af74909SZhong Yang 				ApplyStep(Partitions());
166*8af74909SZhong Yang 				stepPartition = partitionInsert;
167*8af74909SZhong Yang 				stepLength = delta;
168*8af74909SZhong Yang 			}
169*8af74909SZhong Yang 		} else {
170*8af74909SZhong Yang 			stepPartition = partitionInsert;
171*8af74909SZhong Yang 			stepLength = delta;
172*8af74909SZhong Yang 		}
173*8af74909SZhong Yang 	}
174*8af74909SZhong Yang 
RemovePartition(T partition)175*8af74909SZhong Yang 	void RemovePartition(T partition) {
176*8af74909SZhong Yang 		if (partition > stepPartition) {
177*8af74909SZhong Yang 			ApplyStep(partition);
178*8af74909SZhong Yang 			stepPartition--;
179*8af74909SZhong Yang 		} else {
180*8af74909SZhong Yang 			stepPartition--;
181*8af74909SZhong Yang 		}
182*8af74909SZhong Yang 		body->Delete(partition);
183*8af74909SZhong Yang 	}
184*8af74909SZhong Yang 
PositionFromPartition(T partition)185*8af74909SZhong Yang 	T PositionFromPartition(T partition) const noexcept {
186*8af74909SZhong Yang 		PLATFORM_ASSERT(partition >= 0);
187*8af74909SZhong Yang 		PLATFORM_ASSERT(partition < body->Length());
188*8af74909SZhong Yang 		const ptrdiff_t lengthBody = body->Length();
189*8af74909SZhong Yang 		if ((partition < 0) || (partition >= lengthBody)) {
190*8af74909SZhong Yang 			return 0;
191*8af74909SZhong Yang 		}
192*8af74909SZhong Yang 		T pos = body->ValueAt(partition);
193*8af74909SZhong Yang 		if (partition > stepPartition)
194*8af74909SZhong Yang 			pos += stepLength;
195*8af74909SZhong Yang 		return pos;
196*8af74909SZhong Yang 	}
197*8af74909SZhong Yang 
198*8af74909SZhong Yang 	/// Return value in range [0 .. Partitions() - 1] even for arguments outside interval
PartitionFromPosition(T pos)199*8af74909SZhong Yang 	T PartitionFromPosition(T pos) const noexcept {
200*8af74909SZhong Yang 		if (body->Length() <= 1)
201*8af74909SZhong Yang 			return 0;
202*8af74909SZhong Yang 		if (pos >= (PositionFromPartition(Partitions())))
203*8af74909SZhong Yang 			return Partitions() - 1;
204*8af74909SZhong Yang 		T lower = 0;
205*8af74909SZhong Yang 		T upper = Partitions();
206*8af74909SZhong Yang 		do {
207*8af74909SZhong Yang 			const T middle = (upper + lower + 1) / 2; 	// Round high
208*8af74909SZhong Yang 			T posMiddle = body->ValueAt(middle);
209*8af74909SZhong Yang 			if (middle > stepPartition)
210*8af74909SZhong Yang 				posMiddle += stepLength;
211*8af74909SZhong Yang 			if (pos < posMiddle) {
212*8af74909SZhong Yang 				upper = middle - 1;
213*8af74909SZhong Yang 			} else {
214*8af74909SZhong Yang 				lower = middle;
215*8af74909SZhong Yang 			}
216*8af74909SZhong Yang 		} while (lower < upper);
217*8af74909SZhong Yang 		return lower;
218*8af74909SZhong Yang 	}
219*8af74909SZhong Yang 
DeleteAll()220*8af74909SZhong Yang 	void DeleteAll() {
221*8af74909SZhong Yang 		Allocate(body->GetGrowSize());
222*8af74909SZhong Yang 	}
223*8af74909SZhong Yang 
Check()224*8af74909SZhong Yang 	void Check() const {
225*8af74909SZhong Yang #ifdef CHECK_CORRECTNESS
226*8af74909SZhong Yang 		if (Length() < 0) {
227*8af74909SZhong Yang 			throw std::runtime_error("Partitioning: Length can not be negative.");
228*8af74909SZhong Yang 		}
229*8af74909SZhong Yang 		if (Partitions() < 1) {
230*8af74909SZhong Yang 			throw std::runtime_error("Partitioning: Must always have 1 or more partitions.");
231*8af74909SZhong Yang 		}
232*8af74909SZhong Yang 		if (Length() == 0) {
233*8af74909SZhong Yang 			if ((PositionFromPartition(0) != 0) || (PositionFromPartition(1) != 0)) {
234*8af74909SZhong Yang 				throw std::runtime_error("Partitioning: Invalid empty partitioning.");
235*8af74909SZhong Yang 			}
236*8af74909SZhong Yang 		} else {
237*8af74909SZhong Yang 			// Positions should be a strictly ascending sequence
238*8af74909SZhong Yang 			for (T i = 0; i < Partitions(); i++) {
239*8af74909SZhong Yang 				const T pos = PositionFromPartition(i);
240*8af74909SZhong Yang 				const T posNext = PositionFromPartition(i+1);
241*8af74909SZhong Yang 				if (pos > posNext) {
242*8af74909SZhong Yang 					throw std::runtime_error("Partitioning: Negative partition.");
243*8af74909SZhong Yang 				} else if (pos == posNext) {
244*8af74909SZhong Yang 					throw std::runtime_error("Partitioning: Empty partition.");
245*8af74909SZhong Yang 				}
246*8af74909SZhong Yang 			}
247*8af74909SZhong Yang 		}
248*8af74909SZhong Yang #endif
249*8af74909SZhong Yang 	}
250*8af74909SZhong Yang 
251*8af74909SZhong Yang };
252*8af74909SZhong Yang 
253*8af74909SZhong Yang 
254*8af74909SZhong Yang }
255*8af74909SZhong Yang 
256*8af74909SZhong Yang #endif
257