Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(552)

Side by Side Diff: base/gap_buffer.h

Issue 3142008: Model, View and Controller for a Gap Buffer based one line text field in view... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(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_
OLDNEW
« no previous file with comments | « base/base.gypi ('k') | base/gap_buffer_unittest.cc » ('j') | base/gap_buffer_unittest.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698