xref: /MusicPlayer2/scintilla/src/SparseVector.h (revision 8af74909132ed5e696cb05b6689ae4baf14c1c96)
1*8af74909SZhong Yang // Scintilla source code edit control
2*8af74909SZhong Yang /** @file SparseVector.h
3*8af74909SZhong Yang  ** Hold data sparsely associated with elements in a range.
4*8af74909SZhong Yang  **/
5*8af74909SZhong Yang // Copyright 2016 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 SPARSEVECTOR_H
9*8af74909SZhong Yang #define SPARSEVECTOR_H
10*8af74909SZhong Yang 
11*8af74909SZhong Yang namespace Scintilla {
12*8af74909SZhong Yang 
13*8af74909SZhong Yang // SparseVector is similar to RunStyles but is more efficient for cases where values occur
14*8af74909SZhong Yang // for one position instead of over a range of positions.
15*8af74909SZhong Yang // There are always elements at the start and end, so the element type should have
16*8af74909SZhong Yang // a reasonable empty value that will cause no problems.
17*8af74909SZhong Yang // The element type should have a noexcept default constructor as that allows methods to
18*8af74909SZhong Yang // be noexcept.
19*8af74909SZhong Yang template <typename T>
20*8af74909SZhong Yang class SparseVector {
21*8af74909SZhong Yang private:
22*8af74909SZhong Yang 	std::unique_ptr<Partitioning<Sci::Position>> starts;
23*8af74909SZhong Yang 	std::unique_ptr<SplitVector<T>> values;
24*8af74909SZhong Yang 	T empty;	// Return from ValueAt when no element at a position.
ClearValue(Sci::Position partition)25*8af74909SZhong Yang 	void ClearValue(Sci::Position partition) noexcept {
26*8af74909SZhong Yang 		values->SetValueAt(partition, T());
27*8af74909SZhong Yang 	}
28*8af74909SZhong Yang public:
SparseVector()29*8af74909SZhong Yang 	SparseVector() : empty() {
30*8af74909SZhong Yang 		starts = std::make_unique<Partitioning<Sci::Position>>(8);
31*8af74909SZhong Yang 		values = std::make_unique<SplitVector<T>>();
32*8af74909SZhong Yang 		values->InsertEmpty(0, 2);
33*8af74909SZhong Yang 	}
34*8af74909SZhong Yang 	// Deleted so SparseVector objects can not be copied.
35*8af74909SZhong Yang 	SparseVector(const SparseVector &) = delete;
36*8af74909SZhong Yang 	SparseVector(SparseVector &&) = delete;
37*8af74909SZhong Yang 	void operator=(const SparseVector &) = delete;
38*8af74909SZhong Yang 	void operator=(SparseVector &&) = delete;
~SparseVector()39*8af74909SZhong Yang 	~SparseVector() {
40*8af74909SZhong Yang 		starts.reset();
41*8af74909SZhong Yang 		// starts dead here but not used by ClearValue.
42*8af74909SZhong Yang 		for (Sci::Position part = 0; part < values->Length(); part++) {
43*8af74909SZhong Yang 			ClearValue(part);
44*8af74909SZhong Yang 		}
45*8af74909SZhong Yang 		values.reset();
46*8af74909SZhong Yang 	}
Length()47*8af74909SZhong Yang 	Sci::Position Length() const noexcept {
48*8af74909SZhong Yang 		return starts->Length();
49*8af74909SZhong Yang 	}
Elements()50*8af74909SZhong Yang 	Sci::Position Elements() const noexcept {
51*8af74909SZhong Yang 		return starts->Partitions();
52*8af74909SZhong Yang 	}
PositionOfElement(Sci::Position element)53*8af74909SZhong Yang 	Sci::Position PositionOfElement(Sci::Position element) const noexcept {
54*8af74909SZhong Yang 		return starts->PositionFromPartition(element);
55*8af74909SZhong Yang 	}
ElementFromPosition(Sci::Position position)56*8af74909SZhong Yang 	Sci::Position ElementFromPosition(Sci::Position position) const noexcept {
57*8af74909SZhong Yang 		if (position < Length()) {
58*8af74909SZhong Yang 			return starts->PartitionFromPosition(position);
59*8af74909SZhong Yang 		} else {
60*8af74909SZhong Yang 			return starts->Partitions();
61*8af74909SZhong Yang 		}
62*8af74909SZhong Yang 	}
ValueAt(Sci::Position position)63*8af74909SZhong Yang 	const T& ValueAt(Sci::Position position) const noexcept {
64*8af74909SZhong Yang 		assert(position <= Length());
65*8af74909SZhong Yang 		const Sci::Position partition = ElementFromPosition(position);
66*8af74909SZhong Yang 		const Sci::Position startPartition = starts->PositionFromPartition(partition);
67*8af74909SZhong Yang 		if (startPartition == position) {
68*8af74909SZhong Yang 			return values->ValueAt(partition);
69*8af74909SZhong Yang 		} else {
70*8af74909SZhong Yang 			return empty;
71*8af74909SZhong Yang 		}
72*8af74909SZhong Yang 	}
73*8af74909SZhong Yang 	template <typename ParamType>
SetValueAt(Sci::Position position,ParamType && value)74*8af74909SZhong Yang 	void SetValueAt(Sci::Position position, ParamType &&value) {
75*8af74909SZhong Yang 		assert(position <= Length());
76*8af74909SZhong Yang 		const Sci::Position partition = ElementFromPosition(position);
77*8af74909SZhong Yang 		const Sci::Position startPartition = starts->PositionFromPartition(partition);
78*8af74909SZhong Yang 		if (value == T()) {
79*8af74909SZhong Yang 			// Setting the empty value is equivalent to deleting the position
80*8af74909SZhong Yang 			if (position == 0) {
81*8af74909SZhong Yang 				ClearValue(partition);
82*8af74909SZhong Yang 			} else if (position == startPartition) {
83*8af74909SZhong Yang 				// Currently an element at this position, so remove
84*8af74909SZhong Yang 				ClearValue(partition);
85*8af74909SZhong Yang 				starts->RemovePartition(partition);
86*8af74909SZhong Yang 				values->Delete(partition);
87*8af74909SZhong Yang 			}
88*8af74909SZhong Yang 			// Else element remains empty
89*8af74909SZhong Yang 		} else {
90*8af74909SZhong Yang 			if (position == startPartition) {
91*8af74909SZhong Yang 				// Already a value at this position, so replace
92*8af74909SZhong Yang 				ClearValue(partition);
93*8af74909SZhong Yang 				values->SetValueAt(partition, std::forward<ParamType>(value));
94*8af74909SZhong Yang 			} else {
95*8af74909SZhong Yang 				// Insert a new element
96*8af74909SZhong Yang 				starts->InsertPartition(partition + 1, position);
97*8af74909SZhong Yang 				values->Insert(partition + 1, std::forward<ParamType>(value));
98*8af74909SZhong Yang 			}
99*8af74909SZhong Yang 		}
100*8af74909SZhong Yang 	}
InsertSpace(Sci::Position position,Sci::Position insertLength)101*8af74909SZhong Yang 	void InsertSpace(Sci::Position position, Sci::Position insertLength) {
102*8af74909SZhong Yang 		assert(position <= Length());
103*8af74909SZhong Yang 		const Sci::Position partition = starts->PartitionFromPosition(position);
104*8af74909SZhong Yang 		const Sci::Position startPartition = starts->PositionFromPartition(partition);
105*8af74909SZhong Yang 		if (startPartition == position) {
106*8af74909SZhong Yang 			const bool positionOccupied = values->ValueAt(partition) != T();
107*8af74909SZhong Yang 			// Inserting at start of run so make previous longer
108*8af74909SZhong Yang 			if (partition == 0) {
109*8af74909SZhong Yang 				// Inserting at start of document so ensure start empty
110*8af74909SZhong Yang 				if (positionOccupied) {
111*8af74909SZhong Yang 					starts->InsertPartition(1, 0);
112*8af74909SZhong Yang 					values->InsertEmpty(0, 1);
113*8af74909SZhong Yang 				}
114*8af74909SZhong Yang 				starts->InsertText(partition, insertLength);
115*8af74909SZhong Yang 			} else {
116*8af74909SZhong Yang 				if (positionOccupied) {
117*8af74909SZhong Yang 					starts->InsertText(partition - 1, insertLength);
118*8af74909SZhong Yang 				} else {
119*8af74909SZhong Yang 					// Insert at end of run so do not extend style
120*8af74909SZhong Yang 					starts->InsertText(partition, insertLength);
121*8af74909SZhong Yang 				}
122*8af74909SZhong Yang 			}
123*8af74909SZhong Yang 		} else {
124*8af74909SZhong Yang 			starts->InsertText(partition, insertLength);
125*8af74909SZhong Yang 		}
126*8af74909SZhong Yang 	}
DeletePosition(Sci::Position position)127*8af74909SZhong Yang 	void DeletePosition(Sci::Position position) {
128*8af74909SZhong Yang 		assert(position < Length());
129*8af74909SZhong Yang 		Sci::Position partition = starts->PartitionFromPosition(position);
130*8af74909SZhong Yang 		const Sci::Position startPartition = starts->PositionFromPartition(partition);
131*8af74909SZhong Yang 		if (startPartition == position) {
132*8af74909SZhong Yang 			if (partition == 0) {
133*8af74909SZhong Yang 				ClearValue(0);
134*8af74909SZhong Yang 				if (starts->PositionFromPartition(1) == 1) {
135*8af74909SZhong Yang 					// Removing all space of first partition, so remove next partition
136*8af74909SZhong Yang 					// and move value if not last
137*8af74909SZhong Yang 					if (Elements() > 1) {
138*8af74909SZhong Yang 						starts->RemovePartition(partition + 1);
139*8af74909SZhong Yang 						values->Delete(partition);
140*8af74909SZhong Yang 					}
141*8af74909SZhong Yang 				}
142*8af74909SZhong Yang 			} else if (partition == starts->Partitions()) {
143*8af74909SZhong Yang 				// This should not be possible
144*8af74909SZhong Yang 				ClearValue(partition);
145*8af74909SZhong Yang 				throw std::runtime_error("SparseVector: deleting end partition.");
146*8af74909SZhong Yang 			} else {
147*8af74909SZhong Yang 				ClearValue(partition);
148*8af74909SZhong Yang 				starts->RemovePartition(partition);
149*8af74909SZhong Yang 				values->Delete(partition);
150*8af74909SZhong Yang 				// Its the previous partition now that gets smaller
151*8af74909SZhong Yang 				partition--;
152*8af74909SZhong Yang 			}
153*8af74909SZhong Yang 		}
154*8af74909SZhong Yang 		starts->InsertText(partition, -1);
155*8af74909SZhong Yang 		Check();
156*8af74909SZhong Yang 	}
DeleteRange(Sci::Position position,Sci::Position deleteLength)157*8af74909SZhong Yang 	void DeleteRange(Sci::Position position, Sci::Position deleteLength) {
158*8af74909SZhong Yang 		// For now, delete elements in range - may want to leave value at start
159*8af74909SZhong Yang 		// or combine onto position.
160*8af74909SZhong Yang 		if (position > Length() || (deleteLength == 0)) {
161*8af74909SZhong Yang 			return;
162*8af74909SZhong Yang 		}
163*8af74909SZhong Yang 		const Sci::Position positionEnd = position + deleteLength;
164*8af74909SZhong Yang 		assert(positionEnd <= Length());
165*8af74909SZhong Yang 		if (position == 0) {
166*8af74909SZhong Yang 			// Remove all partitions in range, moving values to start
167*8af74909SZhong Yang 			while ((Elements() > 1) && (starts->PositionFromPartition(1) <= deleteLength)) {
168*8af74909SZhong Yang 				starts->RemovePartition(1);
169*8af74909SZhong Yang 				values->Delete(0);
170*8af74909SZhong Yang 			}
171*8af74909SZhong Yang 			starts->InsertText(0, -deleteLength);
172*8af74909SZhong Yang 			if (Length() == 0) {
173*8af74909SZhong Yang 				ClearValue(0);
174*8af74909SZhong Yang 			}
175*8af74909SZhong Yang 		} else {
176*8af74909SZhong Yang 			const Sci::Position partition = starts->PartitionFromPosition(position);
177*8af74909SZhong Yang 			const bool atPartitionStart = position == starts->PositionFromPartition(partition);
178*8af74909SZhong Yang 			const Sci::Position partitionDelete = partition + (atPartitionStart ? 0 : 1);
179*8af74909SZhong Yang 			assert(partitionDelete > 0);
180*8af74909SZhong Yang 			for (;;) {
181*8af74909SZhong Yang 				const Sci::Position positionAtIndex = starts->PositionFromPartition(partitionDelete);
182*8af74909SZhong Yang 				assert(position <= positionAtIndex);
183*8af74909SZhong Yang 				if (positionAtIndex >= positionEnd) {
184*8af74909SZhong Yang 					break;
185*8af74909SZhong Yang 				}
186*8af74909SZhong Yang 				assert(partitionDelete <= Elements());
187*8af74909SZhong Yang 				starts->RemovePartition(partitionDelete);
188*8af74909SZhong Yang 				values->Delete(partitionDelete);
189*8af74909SZhong Yang 			}
190*8af74909SZhong Yang 			starts->InsertText(partition - (atPartitionStart ? 1 : 0), -deleteLength);
191*8af74909SZhong Yang 		}
192*8af74909SZhong Yang 		Check();
193*8af74909SZhong Yang 	}
IndexAfter(Sci::Position position)194*8af74909SZhong Yang 	Sci::Position IndexAfter(Sci::Position position) const noexcept {
195*8af74909SZhong Yang 		assert(position < Length());
196*8af74909SZhong Yang 		if (position < 0)
197*8af74909SZhong Yang 			return 0;
198*8af74909SZhong Yang 		const Sci::Position partition = starts->PartitionFromPosition(position);
199*8af74909SZhong Yang 		return partition + 1;
200*8af74909SZhong Yang 	}
Check()201*8af74909SZhong Yang 	void Check() const {
202*8af74909SZhong Yang #ifdef CHECK_CORRECTNESS
203*8af74909SZhong Yang 		starts->Check();
204*8af74909SZhong Yang 		if (starts->Partitions() != values->Length() - 1) {
205*8af74909SZhong Yang 			throw std::runtime_error("SparseVector: Partitions and values different lengths.");
206*8af74909SZhong Yang 		}
207*8af74909SZhong Yang #endif
208*8af74909SZhong Yang 	}
209*8af74909SZhong Yang };
210*8af74909SZhong Yang 
211*8af74909SZhong Yang }
212*8af74909SZhong Yang 
213*8af74909SZhong Yang #endif
214