Fix action icons in the log dialog being clipped on High-DPI displays
[TortoiseGit.git] / ext / scintilla / src / SplitVector.h
blobb0fdddd95363e77bd373c31ccb882a3aa60ebe23
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.
9 #ifndef SPLITVECTOR_H
10 #define SPLITVECTOR_H
12 #ifdef SCI_NAMESPACE
13 namespace Scintilla {
14 #endif
16 template <typename T>
17 class SplitVector {
18 protected:
19 T *body;
20 int size;
21 int lengthBody;
22 int part1Length;
23 int gapLength; /// invariant: gapLength == size - lengthBody
24 int growSize;
26 /// Move the gap to a particular position so that insertion and
27 /// deletion at that point will not require much copying and
28 /// hence be fast.
29 void GapTo(int position) {
30 if (position != part1Length) {
31 if (position < part1Length) {
32 // Moving the gap towards start so moving elements towards end
33 std::copy_backward(
34 body + position,
35 body + part1Length,
36 body + gapLength + part1Length);
37 } else { // position > part1Length
38 // Moving the gap towards end so moving elements towards start
39 std::copy(
40 body + part1Length + gapLength,
41 body + gapLength + position,
42 body + part1Length);
44 part1Length = position;
48 /// Check that there is room in the buffer for an insertion,
49 /// reallocating if more space needed.
50 void RoomFor(int insertionLength) {
51 if (gapLength <= insertionLength) {
52 while (growSize < size / 6)
53 growSize *= 2;
54 ReAllocate(size + insertionLength + growSize);
58 void Init() {
59 body = NULL;
60 growSize = 8;
61 size = 0;
62 lengthBody = 0;
63 part1Length = 0;
64 gapLength = 0;
67 public:
68 /// Construct a split buffer.
69 SplitVector() {
70 Init();
73 ~SplitVector() {
74 delete []body;
75 body = 0;
78 int GetGrowSize() const {
79 return growSize;
82 void SetGrowSize(int growSize_) {
83 growSize = growSize_;
86 /// Reallocate the storage for the buffer to be newSize and
87 /// copy exisiting contents to the new buffer.
88 /// Must not be used to decrease the size of the buffer.
89 void ReAllocate(int newSize) {
90 if (newSize < 0)
91 throw std::runtime_error("SplitVector::ReAllocate: negative size.");
93 if (newSize > size) {
94 // Move the gap to the end
95 GapTo(lengthBody);
96 T *newBody = new T[newSize];
97 if ((size != 0) && (body != 0)) {
98 std::copy(body, body + lengthBody, newBody);
99 delete []body;
101 body = newBody;
102 gapLength += newSize - size;
103 size = newSize;
107 /// Retrieve the character at a particular position.
108 /// Retrieving positions outside the range of the buffer returns 0.
109 /// The assertions here are disabled since calling code can be
110 /// simpler if out of range access works and returns 0.
111 T ValueAt(int position) const {
112 if (position < part1Length) {
113 //PLATFORM_ASSERT(position >= 0);
114 if (position < 0) {
115 return 0;
116 } else {
117 return body[position];
119 } else {
120 //PLATFORM_ASSERT(position < lengthBody);
121 if (position >= lengthBody) {
122 return 0;
123 } else {
124 return body[gapLength + position];
129 void SetValueAt(int position, T v) {
130 if (position < part1Length) {
131 PLATFORM_ASSERT(position >= 0);
132 if (position < 0) {
134 } else {
135 body[position] = v;
137 } else {
138 PLATFORM_ASSERT(position < lengthBody);
139 if (position >= lengthBody) {
141 } else {
142 body[gapLength + position] = v;
147 T &operator[](int position) const {
148 PLATFORM_ASSERT(position >= 0 && position < lengthBody);
149 if (position < part1Length) {
150 return body[position];
151 } else {
152 return body[gapLength + position];
156 /// Retrieve the length of the buffer.
157 int Length() const {
158 return lengthBody;
161 /// Insert a single value into the buffer.
162 /// Inserting at positions outside the current range fails.
163 void Insert(int position, T v) {
164 PLATFORM_ASSERT((position >= 0) && (position <= lengthBody));
165 if ((position < 0) || (position > lengthBody)) {
166 return;
168 RoomFor(1);
169 GapTo(position);
170 body[part1Length] = v;
171 lengthBody++;
172 part1Length++;
173 gapLength--;
176 /// Insert a number of elements into the buffer setting their value.
177 /// Inserting at positions outside the current range fails.
178 void InsertValue(int position, int insertLength, T v) {
179 PLATFORM_ASSERT((position >= 0) && (position <= lengthBody));
180 if (insertLength > 0) {
181 if ((position < 0) || (position > lengthBody)) {
182 return;
184 RoomFor(insertLength);
185 GapTo(position);
186 std::fill(&body[part1Length], &body[part1Length + insertLength], v);
187 lengthBody += insertLength;
188 part1Length += insertLength;
189 gapLength -= insertLength;
193 /// Ensure at least length elements allocated,
194 /// appending zero valued elements if needed.
195 void EnsureLength(int wantedLength) {
196 if (Length() < wantedLength) {
197 InsertValue(Length(), wantedLength - Length(), 0);
201 /// Insert text into the buffer from an array.
202 void InsertFromArray(int positionToInsert, const T s[], int positionFrom, int insertLength) {
203 PLATFORM_ASSERT((positionToInsert >= 0) && (positionToInsert <= lengthBody));
204 if (insertLength > 0) {
205 if ((positionToInsert < 0) || (positionToInsert > lengthBody)) {
206 return;
208 RoomFor(insertLength);
209 GapTo(positionToInsert);
210 std::copy(s + positionFrom, s + positionFrom + insertLength, body + part1Length);
211 lengthBody += insertLength;
212 part1Length += insertLength;
213 gapLength -= insertLength;
217 /// Delete one element from the buffer.
218 void Delete(int position) {
219 PLATFORM_ASSERT((position >= 0) && (position < lengthBody));
220 if ((position < 0) || (position >= lengthBody)) {
221 return;
223 DeleteRange(position, 1);
226 /// Delete a range from the buffer.
227 /// Deleting positions outside the current range fails.
228 void DeleteRange(int position, int deleteLength) {
229 PLATFORM_ASSERT((position >= 0) && (position + deleteLength <= lengthBody));
230 if ((position < 0) || ((position + deleteLength) > lengthBody)) {
231 return;
233 if ((position == 0) && (deleteLength == lengthBody)) {
234 // Full deallocation returns storage and is faster
235 delete []body;
236 Init();
237 } else if (deleteLength > 0) {
238 GapTo(position);
239 lengthBody -= deleteLength;
240 gapLength += deleteLength;
244 /// Delete all the buffer contents.
245 void DeleteAll() {
246 DeleteRange(0, lengthBody);
249 // Retrieve a range of elements into an array
250 void GetRange(T *buffer, int position, int retrieveLength) const {
251 // Split into up to 2 ranges, before and after the split then use memcpy on each.
252 int range1Length = 0;
253 if (position < part1Length) {
254 int part1AfterPosition = part1Length - position;
255 range1Length = retrieveLength;
256 if (range1Length > part1AfterPosition)
257 range1Length = part1AfterPosition;
259 std::copy(body + position, body + position + range1Length, buffer);
260 buffer += range1Length;
261 position = position + range1Length + gapLength;
262 int range2Length = retrieveLength - range1Length;
263 std::copy(body + position, body + position + range2Length, buffer);
266 T *BufferPointer() {
267 RoomFor(1);
268 GapTo(lengthBody);
269 body[lengthBody] = 0;
270 return body;
273 T *RangePointer(int position, int rangeLength) {
274 if (position < part1Length) {
275 if ((position + rangeLength) > part1Length) {
276 // Range overlaps gap, so move gap to start of range.
277 GapTo(position);
278 return body + position + gapLength;
279 } else {
280 return body + position;
282 } else {
283 return body + position + gapLength;
287 int GapPosition() const {
288 return part1Length;
292 #ifdef SCI_NAMESPACE
294 #endif
296 #endif