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

Side by Side Diff: base/gap_buffer.h

Issue 5158004: Generic Gap Buffer data structure (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: addressed comments Created 10 years, 1 month 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
« no previous file with comments | « base/base.gypi ('k') | base/gap_buffer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 #ifndef BASE_GAP_BUFFER_H_
6 #define BASE_GAP_BUFFER_H_
7 #pragma once
8
9 #include <vector>
10
11 #include "base/basictypes.h"
12 #include "base/logging.h"
13 #include "base/scoped_ptr.h"
14
15 namespace base {
16
17 ////////////////////////////////////////////////////////////////////////////////
18 //
19 // This class implements a standard GapBuffer
20 // (http://en.wikipedia.org/wiki/Gap_buffer)
21 //
22 ////////////////////////////////////////////////////////////////////////////////
23 template<class T>
24 class GapBuffer {
25 public:
26 // Constructor. The initial size of the buffer can be specified in the
27 // argument (defaults to 10).
28 explicit GapBuffer(int size) {
29 if (size < kMinResizeAmount) {
30 size = kMinResizeAmount;
31 }
32
33 buffer_.reset(new T[size]);
34 buffer_size_ = size;
35 gap_start_ = 0;
36 gap_end_ = buffer_size_;
37 }
38
39 // Constructor. Initializes the gap buffer with values from the input buffer.
40 GapBuffer(const T* buffer, int buffer_size) {
41 buffer_size_ = buffer_size + kMinResizeAmount;
42 buffer_.reset(new T[buffer_size_]);
43 gap_start_ = buffer_size;
44 gap_end_ = buffer_size_;
45 memmove(buffer_.get(), buffer, sizeof(T) * buffer_size);
46 }
47
48 // Moves the Gap left by "count" positions (until it hits the start of the
49 // buffer). The gap size remains constant. Contents from the start of the gap
50 // are moved to the end.
51 void MoveGapLeft(int count) {
52 if (buffer_.get() && gap_start_ > 0) {
53 int new_gap_start = (gap_start_ >= count)? gap_start_ - count : 0;
54 int num_elements = gap_start_ - new_gap_start;
55 memmove(buffer_.get() + gap_end_ - num_elements,
56 buffer_.get() + new_gap_start, sizeof(T) * num_elements);
57 gap_start_ = new_gap_start;
58 gap_end_ -= num_elements;
59 }
60 }
61
62 // Moves the Gap right by "count" positions (until it hits the end of the
63 // buffer). The gap size remains constant. Contents from the end of the gap
64 // are moved to the start.
65 void MoveGapRight(int count) {
66 if (gap_end_ < buffer_size_) {
67 int new_gap_end = (gap_end_ + count > buffer_size_)? buffer_size_
68 : gap_end_ + count;
69 int num_elements = new_gap_end - gap_end_;
70 memmove(buffer_.get() + gap_start_, buffer_.get() + gap_end_,
71 sizeof(T) * num_elements);
72 gap_start_ += num_elements;
73 gap_end_ = new_gap_end;
74 }
75 }
76
77 // Moves the Gap to the left until its just after the first occurrence of
78 // "object". If object is not found it moves the gap all the way to the
79 // beginning of the buffer.
80 void MoveGapLeftTo(T object) {
81 for (; gap_start_ > 0 && buffer_[gap_start_ - 1] != object;) {
82 MoveGapLeftByOne();
83 }
84 }
85
86 // Moves the Gap to the right until its just after the first occurrence of
87 // "object". If object is not found it moves the gap all the way to the end
88 // of the buffer.
89 void MoveGapRightTo(T object) {
90 for (; gap_end_ < buffer_size_ && buffer_[gap_end_] != object;) {
91 MoveGapRightByOne();
92 }
93 // Move one more space to get after the occurrence on "object".
94 MoveGapRight(1);
95 }
96
97 // Inserts one element in the gap at the beginning. Gap size decreases by one.
98 // If gap is full, it resizes the buffer_ to create gap and then inserts.
99 void InsertAtGapStart(T object) {
100 if (gap_start_ < gap_end_) {
101 buffer_[gap_start_] = object;
102 gap_start_++;
103 } else {
104 ResizeBuffer();
105 InsertAtGapStart(object);
106 }
107 }
108
109 // Removes an element from the beginning of the gap increasing the gap size
110 // by one (unless the gap is already at the beginning of the buffer). Returns
111 // a pointer to the element removed.
112 const T* RemoveFromGapStart() {
113 if (gap_start_ > 0) {
114 gap_start_--;
115 return buffer_.get() + gap_start_;
116 } else {
117 return NULL;
118 }
119 }
120
121 // Removes an element from the end of the gap increasing the gap size
122 // by one (unless the gap is already at the end of the buffer). Returns a
123 // pointer to the element removed.
124 const T* RemoveFromGapEnd() {
125 if (gap_end_ < buffer_size_) {
126 gap_end_++;
127 return buffer_.get() + gap_end_ - 1;
128 } else {
129 return NULL;
130 }
131 }
132
133 // Replaces the part of the buffer from "start" (inclusive) upto "end" with
134 // "replacement". Resizes the gap appropriately. <start-end> should not
135 // overlap with the gap.
136 // FIXME: implement this.
137 void Replace(int start, int end, T replacement) {
138 NOTIMPLEMENTED();
139 }
140
141 // Gets the contents of the buffer (removing the gap) in vector "contents".
142 void GetContents(std::vector<T>* contents) {
143 contents->clear();
144 int size = GetCurrentSize();
145 if (size) {
146 int i, j;
147 for (i = 0; i < gap_start_; i++) {
148 (*contents).push_back(buffer_[i]);
149 }
150 for (j = gap_end_; j < buffer_size_; j++, i++) {
151 (*contents).push_back(buffer_[j]);
152 }
153 }
154 }
155
156 // Gets the current number of elements in the buffer.
157 int GetCurrentSize() {
158 return buffer_size_ - (gap_end_ - gap_start_);
159 }
160
161 // Gets the size of the underlying buffer.
162 int GetBufferSize() {
163 return buffer_size_;
164 }
165
166 // Gets the gap_start_ index (essentially the current cursor position).
167 int GetGapStart() {
168 return gap_start_;
169 }
170
171 private:
172 // Increases the size of the buffer by 10% of current size. Unsafe.. assumes
173 // that the buffer is already allocated. Should not be invoked for
174 // un-initialized buffer.
175 // FIXME: explore more efficient resizing.
176 void ResizeBuffer() {
177 int size_increment = (buffer_size_ / 10.0 < kMinResizeAmount)?
178 kMinResizeAmount : buffer_size_ / 10.0;
179 int new_size = buffer_size_ + size_increment;
180 T* new_buffer = new T[new_size];
181 memmove(new_buffer, buffer_.get(), sizeof(T) * gap_start_);
182 memmove(new_buffer + gap_start_ + new_size, buffer_.get() + gap_end_,
183 sizeof(T) * (buffer_size_ - gap_end_));
184 gap_end_ = new_size - (buffer_size_ - gap_end_);
185 buffer_size_ = new_size;
186 buffer_.reset(new_buffer);
187 }
188
189 // Internal helper function. Should not be used on its own as it doesnot do
190 // any sanity checks. Use MoveGapLeft() or MoveGapLeftTo() instead.
191 void MoveGapLeftByOne() {
192 gap_start_--;
193 gap_end_--;
194 buffer_[gap_end_] = buffer_[gap_start_];
195 }
196
197 // Internal helper function. Should not be used on its own as it doesnot do
198 // any sanity checks. Use MoveGapRight() or MoveGapRightTo() instead.
199 void MoveGapRightByOne() {
200 buffer_[gap_start_] = buffer_[gap_end_];
201 gap_start_++;
202 gap_end_++;
203 }
204
205 scoped_array<T> buffer_;
206 int buffer_size_;
207 int gap_start_;
208 int gap_end_;
209
210 // In case of resizing the buffer, we will increase the length at least by
211 // kMinResizeAmount to avoid frequent resizing.
212 static const int kMinResizeAmount = 10;
213
214 DISALLOW_COPY_AND_ASSIGN(GapBuffer);
215 };
216
217 } // namespace base
218
219 #endif // BASE_GAP_BUFFER_H_
OLDNEW
« no previous file with comments | « base/base.gypi ('k') | base/gap_buffer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698