geany  1.38
About: Geany is a text editor (using GTK2) with basic features of an integrated development environment (syntax highlighting, code folding, symbol name auto-completion, ...). F: office T: editor programming GTK+ IDE
  Fossies Dox: geany-1.38.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

SplitVector.h
Go to the documentation of this file.
1// Scintilla source code edit control
2/** @file SplitVector.h
3 ** Main data structure for holding arrays that handle insertions
4 ** and deletions efficiently.
5 **/
6// Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org>
7// The License.txt file describes the conditions under which this software may be distributed.
8
9#ifndef SPLITVECTOR_H
10#define SPLITVECTOR_H
11
12namespace Scintilla {
13
14template <typename T>
16protected:
17 std::vector<T> body;
18 T empty; /// Returned as the result of out-of-bounds access.
19 ptrdiff_t lengthBody;
20 ptrdiff_t part1Length;
21 ptrdiff_t gapLength; /// invariant: gapLength == body.size() - lengthBody
22 ptrdiff_t growSize;
23
24 /// Move the gap to a particular position so that insertion and
25 /// deletion at that point will not require much copying and
26 /// hence be fast.
27 void GapTo(ptrdiff_t position) noexcept {
28 if (position != part1Length) {
29 if (position < part1Length) {
30 // Moving the gap towards start so moving elements towards end
31 std::move_backward(
32 body.data() + position,
33 body.data() + part1Length,
34 body.data() + gapLength + part1Length);
35 } else { // position > part1Length
36 // Moving the gap towards end so moving elements towards start
37 std::move(
38 body.data() + part1Length + gapLength,
39 body.data() + gapLength + position,
40 body.data() + part1Length);
41 }
43 }
44 }
45
46 /// Check that there is room in the buffer for an insertion,
47 /// reallocating if more space needed.
48 void RoomFor(ptrdiff_t insertionLength) {
49 if (gapLength <= insertionLength) {
50 while (growSize < static_cast<ptrdiff_t>(body.size() / 6))
51 growSize *= 2;
52 ReAllocate(body.size() + insertionLength + growSize);
53 }
54 }
55
56 void Init() {
57 body.clear();
58 body.shrink_to_fit();
59 lengthBody = 0;
60 part1Length = 0;
61 gapLength = 0;
62 growSize = 8;
63 }
64
65public:
66 /// Construct a split buffer.
68 }
69
70 // Deleted so SplitVector objects can not be copied.
71 SplitVector(const SplitVector &) = delete;
73 void operator=(const SplitVector &) = delete;
74 void operator=(SplitVector &&) = delete;
75
77 }
78
79 ptrdiff_t GetGrowSize() const noexcept {
80 return growSize;
81 }
82
83 void SetGrowSize(ptrdiff_t growSize_) noexcept {
84 growSize = growSize_;
85 }
86
87 /// Reallocate the storage for the buffer to be newSize and
88 /// copy existing contents to the new buffer.
89 /// Must not be used to decrease the size of the buffer.
90 void ReAllocate(ptrdiff_t newSize) {
91 if (newSize < 0)
92 throw std::runtime_error("SplitVector::ReAllocate: negative size.");
93
94 if (newSize > static_cast<ptrdiff_t>(body.size())) {
95 // Move the gap to the end
97 gapLength += newSize - static_cast<ptrdiff_t>(body.size());
98 // RoomFor implements a growth strategy but so does vector::resize so
99 // ensure vector::resize allocates exactly the amount wanted by
100 // calling reserve first.
101 body.reserve(newSize);
102 body.resize(newSize);
103 }
104 }
105
106 /// Retrieve the element at a particular position.
107 /// Retrieving positions outside the range of the buffer returns empty or 0.
108 const T& ValueAt(ptrdiff_t position) const noexcept {
109 if (position < part1Length) {
110 if (position < 0) {
111 return empty;
112 } else {
113 return body[position];
114 }
115 } else {
116 if (position >= lengthBody) {
117 return empty;
118 } else {
119 return body[gapLength + position];
120 }
121 }
122 }
123
124 /// Set the element at a particular position.
125 /// Setting positions outside the range of the buffer performs no assignment
126 /// but asserts in debug builds.
127 template <typename ParamType>
128 void SetValueAt(ptrdiff_t position, ParamType&& v) noexcept {
129 if (position < part1Length) {
131 if (position < 0) {
132 ;
133 } else {
134 body[position] = std::forward<ParamType>(v);
135 }
136 } else {
138 if (position >= lengthBody) {
139 ;
140 } else {
141 body[gapLength + position] = std::forward<ParamType>(v);
142 }
143 }
144 }
145
146 /// Retrieve the element at a particular position.
147 /// The position must be within bounds or an assertion is triggered.
148 const T &operator[](ptrdiff_t position) const noexcept {
150 if (position < part1Length) {
151 return body[position];
152 } else {
153 return body[gapLength + position];
154 }
155 }
156
157 /// Retrieve reference to the element at a particular position.
158 /// This, instead of the const variant, can be used to mutate in-place.
159 /// The position must be within bounds or an assertion is triggered.
160 T &operator[](ptrdiff_t position) noexcept {
162 if (position < part1Length) {
163 return body[position];
164 } else {
165 return body[gapLength + position];
166 }
167 }
168
169 /// Retrieve the length of the buffer.
170 ptrdiff_t Length() const noexcept {
171 return lengthBody;
172 }
173
174 /// Insert a single value into the buffer.
175 /// Inserting at positions outside the current range fails.
176 void Insert(ptrdiff_t position, T v) {
178 if ((position < 0) || (position > lengthBody)) {
179 return;
180 }
181 RoomFor(1);
183 body[part1Length] = std::move(v);
184 lengthBody++;
185 part1Length++;
186 gapLength--;
187 }
188
189 /// Insert a number of elements into the buffer setting their value.
190 /// Inserting at positions outside the current range fails.
191 void InsertValue(ptrdiff_t position, ptrdiff_t insertLength, T v) {
193 if (insertLength > 0) {
194 if ((position < 0) || (position > lengthBody)) {
195 return;
196 }
197 RoomFor(insertLength);
199 std::fill(body.data() + part1Length, body.data() + part1Length + insertLength, v);
200 lengthBody += insertLength;
201 part1Length += insertLength;
202 gapLength -= insertLength;
203 }
204 }
205
206 /// Add some new empty elements.
207 /// InsertValue is good for value objects but not for unique_ptr objects
208 /// since they can only be moved from once.
209 /// Callers can write to the returned pointer to transform inputs without copies.
210 T *InsertEmpty(ptrdiff_t position, ptrdiff_t insertLength) {
212 if (insertLength > 0) {
213 if ((position < 0) || (position > lengthBody)) {
214 return nullptr;
215 }
216 RoomFor(insertLength);
218 for (ptrdiff_t elem = part1Length; elem < part1Length + insertLength; elem++) {
219 T emptyOne = {};
220 body[elem] = std::move(emptyOne);
221 }
222 lengthBody += insertLength;
223 part1Length += insertLength;
224 gapLength -= insertLength;
225 }
226 return body.data() + position;
227 }
228
229 /// Ensure at least length elements allocated,
230 /// appending zero valued elements if needed.
231 void EnsureLength(ptrdiff_t wantedLength) {
232 if (Length() < wantedLength) {
233 InsertEmpty(Length(), wantedLength - Length());
234 }
235 }
236
237 /// Insert text into the buffer from an array.
238 void InsertFromArray(ptrdiff_t positionToInsert, const T s[], ptrdiff_t positionFrom, ptrdiff_t insertLength) {
239 PLATFORM_ASSERT((positionToInsert >= 0) && (positionToInsert <= lengthBody));
240 if (insertLength > 0) {
241 if ((positionToInsert < 0) || (positionToInsert > lengthBody)) {
242 return;
243 }
244 RoomFor(insertLength);
245 GapTo(positionToInsert);
246 std::copy(s + positionFrom, s + positionFrom + insertLength, body.data() + part1Length);
247 lengthBody += insertLength;
248 part1Length += insertLength;
249 gapLength -= insertLength;
250 }
251 }
252
253 /// Delete one element from the buffer.
254 void Delete(ptrdiff_t position) {
257 }
258
259 /// Delete a range from the buffer.
260 /// Deleting positions outside the current range fails.
261 /// Cannot be noexcept as vector::shrink_to_fit may be called and it may throw.
262 void DeleteRange(ptrdiff_t position, ptrdiff_t deleteLength) {
263 PLATFORM_ASSERT((position >= 0) && (position + deleteLength <= lengthBody));
264 if ((position < 0) || ((position + deleteLength) > lengthBody)) {
265 return;
266 }
267 if ((position == 0) && (deleteLength == lengthBody)) {
268 // Full deallocation returns storage and is faster
269 Init();
270 } else if (deleteLength > 0) {
272 lengthBody -= deleteLength;
273 gapLength += deleteLength;
274 }
275 }
276
277 /// Delete all the buffer contents.
278 void DeleteAll() {
280 }
281
282 /// Retrieve a range of elements into an array
283 void GetRange(T *buffer, ptrdiff_t position, ptrdiff_t retrieveLength) const noexcept {
284 // Split into up to 2 ranges, before and after the split then use memcpy on each.
285 ptrdiff_t range1Length = 0;
286 if (position < part1Length) {
287 const ptrdiff_t part1AfterPosition = part1Length - position;
288 range1Length = retrieveLength;
289 if (range1Length > part1AfterPosition)
290 range1Length = part1AfterPosition;
291 }
292 std::copy(body.data() + position, body.data() + position + range1Length, buffer);
293 buffer += range1Length;
294 position = position + range1Length + gapLength;
295 const ptrdiff_t range2Length = retrieveLength - range1Length;
296 std::copy(body.data() + position, body.data() + position + range2Length, buffer);
297 }
298
299 /// Compact the buffer and return a pointer to the first element.
300 /// Also ensures there is an empty element beyond logical end in case its
301 /// passed to a function expecting a NUL terminated string.
303 RoomFor(1);
305 T emptyOne = {};
306 body[lengthBody] = std::move(emptyOne);
307 return body.data();
308 }
309
310 /// Return a pointer to a range of elements, first rearranging the buffer if
311 /// needed to make that range contiguous.
312 T *RangePointer(ptrdiff_t position, ptrdiff_t rangeLength) noexcept {
313 if (position < part1Length) {
314 if ((position + rangeLength) > part1Length) {
315 // Range overlaps gap, so move gap to start of range.
317 return body.data() + position + gapLength;
318 } else {
319 return body.data() + position;
320 }
321 } else {
322 return body.data() + position + gapLength;
323 }
324 }
325
326 /// Return the position of the gap within the buffer.
327 ptrdiff_t GapPosition() const noexcept {
328 return part1Length;
329 }
330};
331
332}
333
334#endif
#define PLATFORM_ASSERT(c)
Definition: Platform.h:544
SplitVector(const SplitVector &)=delete
std::vector< T > body
Definition: SplitVector.h:17
T * InsertEmpty(ptrdiff_t position, ptrdiff_t insertLength)
Add some new empty elements.
Definition: SplitVector.h:210
T * RangePointer(ptrdiff_t position, ptrdiff_t rangeLength) noexcept
Return a pointer to a range of elements, first rearranging the buffer if needed to make that range co...
Definition: SplitVector.h:312
void EnsureLength(ptrdiff_t wantedLength)
Ensure at least length elements allocated, appending zero valued elements if needed.
Definition: SplitVector.h:231
ptrdiff_t GetGrowSize() const noexcept
Definition: SplitVector.h:79
void operator=(const SplitVector &)=delete
void InsertFromArray(ptrdiff_t positionToInsert, const T s[], ptrdiff_t positionFrom, ptrdiff_t insertLength)
Insert text into the buffer from an array.
Definition: SplitVector.h:238
void RoomFor(ptrdiff_t insertionLength)
Check that there is room in the buffer for an insertion, reallocating if more space needed.
Definition: SplitVector.h:48
SplitVector()
Construct a split buffer.
Definition: SplitVector.h:67
void DeleteAll()
Delete all the buffer contents.
Definition: SplitVector.h:278
SplitVector(SplitVector &&)=delete
void DeleteRange(ptrdiff_t position, ptrdiff_t deleteLength)
Delete a range from the buffer.
Definition: SplitVector.h:262
void GetRange(T *buffer, ptrdiff_t position, ptrdiff_t retrieveLength) const noexcept
Retrieve a range of elements into an array.
Definition: SplitVector.h:283
void Insert(ptrdiff_t position, T v)
Insert a single value into the buffer.
Definition: SplitVector.h:176
ptrdiff_t Length() const noexcept
Retrieve the length of the buffer.
Definition: SplitVector.h:170
const T & operator[](ptrdiff_t position) const noexcept
Retrieve the element at a particular position.
Definition: SplitVector.h:148
void Delete(ptrdiff_t position)
Delete one element from the buffer.
Definition: SplitVector.h:254
ptrdiff_t GapPosition() const noexcept
Return the position of the gap within the buffer.
Definition: SplitVector.h:327
T * BufferPointer()
Compact the buffer and return a pointer to the first element.
Definition: SplitVector.h:302
void SetValueAt(ptrdiff_t position, ParamType &&v) noexcept
Set the element at a particular position.
Definition: SplitVector.h:128
void InsertValue(ptrdiff_t position, ptrdiff_t insertLength, T v)
Insert a number of elements into the buffer setting their value.
Definition: SplitVector.h:191
const T & ValueAt(ptrdiff_t position) const noexcept
Retrieve the element at a particular position.
Definition: SplitVector.h:108
void GapTo(ptrdiff_t position) noexcept
Move the gap to a particular position so that insertion and deletion at that point will not require m...
Definition: SplitVector.h:27
ptrdiff_t growSize
invariant: gapLength == body.size() - lengthBody
Definition: SplitVector.h:22
void SetGrowSize(ptrdiff_t growSize_) noexcept
Definition: SplitVector.h:83
ptrdiff_t lengthBody
Returned as the result of out-of-bounds access.
Definition: SplitVector.h:19
void operator=(SplitVector &&)=delete
T & operator[](ptrdiff_t position) noexcept
Retrieve reference to the element at a particular position.
Definition: SplitVector.h:160
void ReAllocate(ptrdiff_t newSize)
Reallocate the storage for the buffer to be newSize and copy existing contents to the new buffer.
Definition: SplitVector.h:90
#define fill(Order, Group, Idx, Charset, Name)
Definition: encodings.c:62
Styling buffer using one element for each run rather than using a filled buffer.
Definition: Converter.h:9
gint position[2]
Definition: search.c:120