1 // Scintilla source code edit control
\r
2 /** @file SplitVector.h
\r
3 ** Main data structure for holding arrays that handle insertions
\r
4 ** and deletions efficiently.
\r
6 // Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org>
\r
7 // The License.txt file describes the conditions under which this software may be distributed.
\r
9 #ifndef SPLITVECTOR_H
\r
10 #define SPLITVECTOR_H
\r
12 template <typename T>
\r
19 int gapLength; /// invariant: gapLength == size - lengthBody
\r
22 /// Move the gap to a particular position so that insertion and
\r
23 /// deletion at that point will not require much copying and
\r
25 void GapTo(int position) {
\r
26 if (position != part1Length) {
\r
27 if (position < part1Length) {
\r
29 body + position + gapLength,
\r
31 sizeof(T) * (part1Length - position));
\r
32 } else { // position > part1Length
\r
35 body + part1Length + gapLength,
\r
36 sizeof(T) * (position - part1Length));
\r
38 part1Length = position;
\r
42 /// Check that there is room in the buffer for an insertion,
\r
43 /// reallocating if more space needed.
\r
44 void RoomFor(int insertionLength) {
\r
45 if (gapLength <= insertionLength) {
\r
46 if (growSize * 6 < size)
\r
48 ReAllocate(size + insertionLength + growSize);
\r
62 /// Construct a split buffer.
\r
72 int GetGrowSize() const {
\r
76 void SetGrowSize(int growSize_) {
\r
77 growSize = growSize_;
\r
80 /// Reallocate the storage for the buffer to be newSize and
\r
81 /// copy exisiting contents to the new buffer.
\r
82 /// Must not be used to decrease the size of the buffer.
\r
83 void ReAllocate(int newSize) {
\r
84 if (newSize > size) {
\r
85 // Move the gap to the end
\r
87 T *newBody = new T[newSize];
\r
88 if ((size != 0) && (body != 0)) {
\r
89 memmove(newBody, body, sizeof(T) * lengthBody);
\r
93 gapLength += newSize - size;
\r
98 /// Retrieve the character at a particular position.
\r
99 /// Retrieving positions outside the range of the buffer returns 0.
\r
100 /// The assertions here are disabled since calling code can be
\r
101 /// simpler if out of range access works and returns 0.
\r
102 T ValueAt(int position) const {
\r
103 if (position < part1Length) {
\r
104 //PLATFORM_ASSERT(position >= 0);
\r
105 if (position < 0) {
\r
108 return body[position];
\r
111 //PLATFORM_ASSERT(position < lengthBody);
\r
112 if (position >= lengthBody) {
\r
115 return body[gapLength + position];
\r
120 void SetValueAt(int position, T v) {
\r
121 if (position < part1Length) {
\r
122 PLATFORM_ASSERT(position >= 0);
\r
123 if (position < 0) {
\r
126 body[position] = v;
\r
129 PLATFORM_ASSERT(position < lengthBody);
\r
130 if (position >= lengthBody) {
\r
133 body[gapLength + position] = v;
\r
138 T& operator[](int position) const {
\r
139 PLATFORM_ASSERT(position >= 0 && position < lengthBody);
\r
140 if (position < part1Length) {
\r
141 return body[position];
\r
143 return body[gapLength + position];
\r
147 /// Retrieve the length of the buffer.
\r
148 int Length() const {
\r
152 /// Insert a single value into the buffer.
\r
153 /// Inserting at positions outside the current range fails.
\r
154 void Insert(int position, T v) {
\r
155 PLATFORM_ASSERT((position >= 0) && (position <= lengthBody));
\r
156 if ((position < 0) || (position > lengthBody)) {
\r
161 body[part1Length] = v;
\r
167 /// Insert a number of elements into the buffer setting their value.
\r
168 /// Inserting at positions outside the current range fails.
\r
169 void InsertValue(int position, int insertLength, T v) {
\r
170 PLATFORM_ASSERT((position >= 0) && (position <= lengthBody));
\r
171 if (insertLength > 0) {
\r
172 if ((position < 0) || (position > lengthBody)) {
\r
175 RoomFor(insertLength);
\r
177 for (int i = 0; i < insertLength; i++)
\r
178 body[part1Length + i] = v;
\r
179 lengthBody += insertLength;
\r
180 part1Length += insertLength;
\r
181 gapLength -= insertLength;
\r
185 /// Ensure at least length elements allocated,
\r
186 /// appending zero valued elements if needed.
\r
187 void EnsureLength(int wantedLength) {
\r
188 if (Length() < wantedLength) {
\r
189 InsertValue(Length(), wantedLength - Length(), 0);
\r
193 /// Insert text into the buffer from an array.
\r
194 void InsertFromArray(int positionToInsert, const T s[], int positionFrom, int insertLength) {
\r
195 PLATFORM_ASSERT((positionToInsert >= 0) && (positionToInsert <= lengthBody));
\r
196 if (insertLength > 0) {
\r
197 if ((positionToInsert < 0) || (positionToInsert > lengthBody)) {
\r
200 RoomFor(insertLength);
\r
201 GapTo(positionToInsert);
\r
202 memmove(body + part1Length, s + positionFrom, sizeof(T) * insertLength);
\r
203 lengthBody += insertLength;
\r
204 part1Length += insertLength;
\r
205 gapLength -= insertLength;
\r
209 /// Delete one element from the buffer.
\r
210 void Delete(int position) {
\r
211 PLATFORM_ASSERT((position >= 0) && (position < lengthBody));
\r
212 if ((position < 0) || (position >= lengthBody)) {
\r
215 DeleteRange(position, 1);
\r
218 /// Delete a range from the buffer.
\r
219 /// Deleting positions outside the current range fails.
\r
220 void DeleteRange(int position, int deleteLength) {
\r
221 PLATFORM_ASSERT((position >= 0) && (position + deleteLength <= lengthBody));
\r
222 if ((position < 0) || ((position + deleteLength) > lengthBody)) {
\r
225 if ((position == 0) && (deleteLength == lengthBody)) {
\r
226 // Full deallocation returns storage and is faster
\r
229 } else if (deleteLength > 0) {
\r
231 lengthBody -= deleteLength;
\r
232 gapLength += deleteLength;
\r
236 /// Delete all the buffer contents.
\r
238 DeleteRange(0, lengthBody);
\r
241 T* BufferPointer() {
\r
244 body[lengthBody] = 0;
\r