Chromium Code Reviews
|
| 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 |