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