1 // Scintilla source code edit control
2 /** @file SplitVector.h
3 ** Main data structure for holding arrays that handle insertions
4 ** and deletions efficiently.
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.
23 int gapLength
; /// invariant: gapLength == size - lengthBody
26 /// Move the gap to a particular position so that insertion and
27 /// deletion at that point will not require much copying and
29 void GapTo(int position
) {
30 if (position
!= part1Length
) {
31 if (position
< part1Length
) {
32 // Moving the gap towards start so moving elements towards end
36 body
+ gapLength
+ part1Length
);
37 } else { // position > part1Length
38 // Moving the gap towards end so moving elements towards start
40 body
+ part1Length
+ gapLength
,
41 body
+ gapLength
+ position
,
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)
54 ReAllocate(size
+ insertionLength
+ growSize
);
68 /// Construct a split buffer.
78 int GetGrowSize() const {
82 void SetGrowSize(int 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
) {
91 throw std::runtime_error("SplitVector::ReAllocate: negative size.");
94 // Move the gap to the end
96 T
*newBody
= new T
[newSize
];
97 if ((size
!= 0) && (body
!= 0)) {
98 std::copy(body
, body
+ lengthBody
, newBody
);
102 gapLength
+= newSize
- size
;
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);
117 return body
[position
];
120 //PLATFORM_ASSERT(position < lengthBody);
121 if (position
>= lengthBody
) {
124 return body
[gapLength
+ position
];
129 void SetValueAt(int position
, T v
) {
130 if (position
< part1Length
) {
131 PLATFORM_ASSERT(position
>= 0);
138 PLATFORM_ASSERT(position
< lengthBody
);
139 if (position
>= lengthBody
) {
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
];
152 return body
[gapLength
+ position
];
156 /// Retrieve the length of the buffer.
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
)) {
170 body
[part1Length
] = v
;
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
)) {
184 RoomFor(insertLength
);
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
)) {
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
)) {
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
)) {
233 if ((position
== 0) && (deleteLength
== lengthBody
)) {
234 // Full deallocation returns storage and is faster
237 } else if (deleteLength
> 0) {
239 lengthBody
-= deleteLength
;
240 gapLength
+= deleteLength
;
244 /// Delete all the buffer contents.
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
);
269 body
[lengthBody
] = 0;
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.
278 return body
+ position
+ gapLength
;
280 return body
+ position
;
283 return body
+ position
+ gapLength
;
287 int GapPosition() const {