|
OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // This class implements a standard GapBuffer | |
sky
2010/08/31 23:19:47
Put the comment above the class name.
varunjain
2010/11/18 03:45:57
Done.
| |
6 // (http://en.wikipedia.org/wiki/Gap_buffer) | |
7 | |
8 #ifndef BASE_GAP_BUFFER_H_ | |
9 #define BASE_GAP_BUFFER_H_ | |
10 #pragma once | |
11 | |
12 #include <stdio.h> | |
13 | |
14 #include <string> | |
sky
2010/08/31 23:19:47
Do you need this include?
varunjain
2010/11/18 03:45:57
Done.
| |
15 #include <vector> | |
16 #include "base/basictypes.h" | |
sky
2010/08/31 23:19:47
newline between 15 and 16.
varunjain
2010/11/18 03:45:57
Done.
| |
17 #include "base/logging.h" | |
18 #include "base/scoped_ptr.h" | |
19 | |
20 namespace base { | |
21 | |
22 template<class T> | |
sky
2010/08/31 23:19:47
Is it really worth parameterizing the type? At som
varunjain
2010/11/18 03:45:57
my intention was exactly to avoid changes to this
| |
23 class GapBuffer { | |
24 public: | |
25 | |
sky
2010/08/31 23:19:47
no newline here.
varunjain
2010/11/18 03:45:57
Done.
| |
26 // Constructor. The initial size of the buffer can be specified in the | |
27 // argument (defaults to 10). | |
28 explicit GapBuffer(int size) | |
29 : kMinResizeAmount(10) { | |
30 if (size < kMinResizeAmount) { | |
31 size = kMinResizeAmount; | |
32 } | |
33 | |
34 buffer_.reset(new T[size]); | |
35 if (buffer_.get()) { | |
sky
2010/08/31 23:19:47
We don't do checks like this. OOM triggers a crash
varunjain
2010/11/18 03:45:57
Done.
| |
36 buffer_size_ = size; | |
37 gap_start_ = 0; | |
38 gap_end_ = buffer_size_; | |
39 } else { | |
40 LOG(INFO) << ">>error creating gap buffer\n"; | |
41 } | |
42 } | |
43 | |
44 // Constructor. Initializes the gap buffer with values from the input buffer. | |
45 GapBuffer(const T* buffer, int buffer_size) | |
46 : kMinResizeAmount(10) { | |
47 buffer_size_ = buffer_size + kMinResizeAmount; | |
48 buffer_.reset(new T[buffer_size_]); | |
49 if (buffer_.get()) { | |
sky
2010/08/31 23:19:47
Same comment as on line 35.
varunjain
2010/11/18 03:45:57
Done.
| |
50 gap_start_ = buffer_size; | |
51 gap_end_ = buffer_size_; | |
52 memmove(buffer_.get(), buffer, sizeof(T) * buffer_size); | |
53 } else { | |
54 LOG(INFO) << ">>error creating gap buffer\n"; | |
55 } | |
56 } | |
57 | |
58 // Moves the Gap left by "count" positions (until it hits the start of the | |
59 // buffer). The gap size remains constant. Contents from the start of the gap | |
60 // are moved to the end. | |
61 void MoveGapLeft(int count) { | |
sky
2010/08/31 23:19:47
Do we really need all these MoveGapFoo methods? Ca
varunjain
2010/11/18 03:45:57
Since gap buffers are really only used in text edi
| |
62 if (buffer_.get() && gap_start_ > 0) { | |
sky
2010/08/31 23:19:47
Don't check buffer_.get() at all in this class.
varunjain
2010/11/18 03:45:57
Done.
| |
63 int new_gap_start = (gap_start_ >= count)? gap_start_ - count : 0; | |
64 int num_elements = gap_start_ - new_gap_start; | |
65 memmove(buffer_.get() + gap_end_ - num_elements, | |
66 buffer_.get() + new_gap_start, sizeof(T) * num_elements); | |
67 gap_start_ = new_gap_start; | |
68 gap_end_ -= num_elements; | |
69 } | |
70 } | |
71 | |
72 // Moves the Gap right by "count" positions (until it hits the end of the | |
73 // buffer). The gap size remains constant. Contents from the end of the gap | |
74 // are moved to the start. | |
75 void MoveGapRight(int count) { | |
76 if (buffer_.get() && gap_end_ < buffer_size_) { | |
77 int new_gap_end = (gap_end_ + count > buffer_size_)? buffer_size_ | |
78 : gap_end_ + count; | |
79 int num_elements = new_gap_end - gap_end_; | |
80 memmove(buffer_.get() + gap_start_, buffer_.get() + gap_end_, | |
81 sizeof(T) * num_elements); | |
82 gap_start_ += num_elements; | |
83 gap_end_ = new_gap_end; | |
84 } | |
85 } | |
86 | |
87 // Moves the Gap to the left until its just after the first occurrence of | |
88 // "object". If object is not found it moves the gap all the way to the | |
89 // beginning of the buffer. | |
90 void MoveGapLeftTo(T object) { | |
91 if (buffer_.get()) { | |
92 for (; gap_start_ > 0 && buffer_[gap_start_ - 1] != object;) { | |
93 MoveGapLeftByOne(); | |
94 } | |
95 } | |
96 } | |
97 | |
98 // Moves the Gap to the right until its just after the first occurrence of | |
99 // "object". If object is not found it moves the gap all the way to the end | |
100 // of the buffer. | |
101 void MoveGapRightTo(T object) { | |
102 if (buffer_.get()) { | |
103 for (; gap_end_ < buffer_size_ && buffer_[gap_end_] != object;) { | |
104 MoveGapRightByOne(); | |
105 } | |
106 // Move one more space to get after the occurrence on "object". | |
107 MoveGapRight(1); | |
108 } | |
109 } | |
110 | |
111 // Inserts one element in the gap at the beginning. Gap size decreases by one. | |
112 // If gap is full, it resizes the buffer_ to create gap and then inserts. | |
113 void InsertAtGapStart(T object) { | |
114 if (buffer_.get()) { | |
115 if (gap_start_ < gap_end_) { | |
116 buffer_.get()[gap_start_] = object; | |
sky
2010/08/31 23:19:47
buffer_[gap_start]
varunjain
2010/11/18 03:45:57
Done.
| |
117 gap_start_++; | |
118 } else { | |
119 ResizeBuffer(); | |
120 InsertAtGapStart(object); | |
121 } | |
122 } | |
123 } | |
124 | |
125 // Removes an element from the beginning of the gap increasing the gap size | |
126 // by one (unless the gap is already at the beginning of the buffer). Returns | |
127 // the element removed. | |
128 T RemoveFromGapStart() { | |
129 if (buffer_.get() && gap_start_ > 0) { | |
130 gap_start_--; | |
131 return buffer_[gap_start_]; | |
132 } else { | |
133 return NULL; | |
134 } | |
135 } | |
136 | |
137 // Removes an element from the end of the gap increasing the gap size | |
138 // by one (unless the gap is already at the end of the buffer). Returns the | |
139 // element removed. | |
140 T RemoveFromGapEnd() { | |
141 if (buffer_.get() && gap_end_ < buffer_size_) { | |
142 gap_end_++; | |
143 return buffer_[gap_end_ - 1]; | |
144 } else { | |
145 return NULL; | |
146 } | |
147 } | |
148 | |
149 // Replaces the part of the buffer from "start" (inclusive) upto "end" with | |
150 // "replacement". Resizes the gap appropriately. <start-end> should not | |
151 // overlap with the gap. | |
152 // FIXME: implement this. | |
153 void Replace(int start, int end, T replacement) { } | |
154 | |
155 // Gets the contents of the buffer (removing the gap) in vector "contents". | |
156 void GetContents(std::vector<T>* contents) { | |
157 (*contents).clear(); | |
sky
2010/08/31 23:19:47
contents->
varunjain
2010/11/18 03:45:57
Done.
| |
158 int size = GetCurrentSize(); | |
159 if (buffer_.get() && size) { | |
160 int i, j; | |
161 for (i = 0; i < gap_start_; i++) { | |
162 (*contents).push_back(buffer_[i]); | |
163 } | |
164 for (j = gap_end_; j < buffer_size_; j++, i++) { | |
165 (*contents).push_back(buffer_[j]); | |
166 } | |
167 } | |
168 } | |
169 | |
170 // Gets the current number of elements in the buffer. | |
171 int GetCurrentSize() { | |
172 return buffer_.get()? buffer_size_ - (gap_end_ - gap_start_) : 0; | |
173 } | |
174 | |
175 // Gets the size of the underlying buffer. | |
176 int GetBufferSize() { | |
sky
2010/08/31 23:19:47
Is there a case where someone cares about GetBuffe
varunjain
2010/11/18 03:45:57
Done.
| |
177 return buffer_.get()? buffer_size_ : 0; | |
178 } | |
179 | |
180 // Gets the gap_start_ index (essentially the current cursor position). | |
181 int GetGapStart() { | |
182 return buffer_.get()? gap_start_ : 0; | |
183 } | |
184 | |
185 private: | |
186 // Increases the size of the buffer by 10% of current size. Unsafe.. assumes | |
187 // that the buffer is already allocated. Should not be invoked for | |
188 // un-initialized buffer. | |
189 // FIXME: explore more efficient resizing. | |
190 void ResizeBuffer() { | |
191 int size_increment = (buffer_size_ / 10.0 < kMinResizeAmount)? | |
192 kMinResizeAmount : buffer_size_ / 10.0; | |
193 int new_size = buffer_size_ + size_increment; | |
194 T* new_buffer = new T[new_size]; | |
195 int i; | |
196 for (i = 0; i < gap_start_; i++) { | |
sky
2010/08/31 23:19:47
How come you don't memmove these two blocks?
varunjain
2010/11/18 03:45:57
Done.
| |
197 new_buffer[i] = buffer_[i]; | |
198 } | |
199 for (i = 0; i < buffer_size_ - gap_end_; i++) { | |
200 new_buffer[new_size - i - 1] = buffer_[buffer_size_ - i - 1]; | |
201 } | |
202 gap_end_ = new_size - i; | |
203 buffer_size_ = new_size; | |
204 buffer_.reset(new_buffer); | |
205 } | |
206 | |
207 // Internal helper function. Should not be used on its own as it doesnot do | |
208 // any sanity checks. Use MoveGapLeft() or MoveGapLeftTo() instead. | |
209 void MoveGapLeftByOne() { | |
210 gap_start_--; | |
211 gap_end_--; | |
212 buffer_.get()[gap_end_] = buffer_[gap_start_]; | |
213 } | |
214 | |
215 // Internal helper function. Should not be used on its own as it doesnot do | |
216 // any sanity checks. Use MoveGapRight() or MoveGapRightTo() instead. | |
217 void MoveGapRightByOne() { | |
218 buffer_.get()[gap_start_] = buffer_[gap_end_]; | |
219 gap_start_++; | |
220 gap_end_++; | |
221 } | |
222 | |
223 scoped_array<T> buffer_; | |
224 int buffer_size_; | |
225 int gap_start_; | |
226 int gap_end_; | |
227 | |
228 // In case of resizing the buffer, we will increase the length at least by | |
229 // kMinResizeAmount to avoid frequent resizing. | |
230 const int kMinResizeAmount; | |
sky
2010/08/31 23:19:47
This should be static.
varunjain
2010/11/18 03:45:57
Done.
| |
231 }; | |
sky
2010/08/31 23:19:47
DISALLOW_COPY_AND_ASSIGN
varunjain
2010/11/18 03:45:57
Done.
| |
232 | |
233 } // namespace | |
234 | |
235 #endif // BASE_GAP_BUFFER_H_ | |
OLD | NEW |