1 // Copyright 2013 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 #include "net/tools/balsa/simple_buffer.h" 6 #include "base/logging.h" 7 8 // Some of the following member functions are marked inlined, even though they 9 // are virtual. This may seem counter-intuitive, since virtual functions are 10 // generally not eligible for inlining. Profiling results indicate that these 11 // large amount of runtime is spent on virtual function dispatch on these 12 // simple functions. They are virtual because of the interface this class 13 // inherits from. However, it is very unlikely that anyone will sub-class 14 // SimpleBuffer and change their implementation. To get rid of this baggage, 15 // internal implementation (e.g., Write) explicitly use SimpleBuffer:: to 16 // qualify the method calls, thus disabling the virtual dispatch and enable 17 // inlining. 18 19 namespace net { 20 21 static const int kInitialSimpleBufferSize = 10; 22 23 SimpleBuffer::SimpleBuffer() 24 : storage_(new char[kInitialSimpleBufferSize]), 25 write_idx_(0), 26 read_idx_(0), 27 storage_size_(kInitialSimpleBufferSize) { 28 } 29 30 SimpleBuffer::SimpleBuffer(int size) 31 : write_idx_(0), 32 read_idx_(0), 33 storage_size_(size) { 34 // Callers may try to allocate overly large blocks, but negative sizes are 35 // obviously wrong. 36 CHECK_GE(size, 0); 37 storage_ = new char[size]; 38 } 39 40 SimpleBuffer::~SimpleBuffer() { 41 delete[] storage_; 42 } 43 44 45 //////////////////////////////////////////////////////////////////////////////// 46 47 int SimpleBuffer::ReadableBytes() const { 48 return write_idx_ - read_idx_; 49 } 50 51 //////////////////////////////////////////////////////////////////////////////// 52 53 std::string SimpleBuffer::str() const { 54 std::string s; 55 char * readable_ptr; 56 int readable_size; 57 GetReadablePtr(&readable_ptr, &readable_size); 58 s.append(readable_ptr, readable_ptr + readable_size); 59 return s; 60 } 61 62 //////////////////////////////////////////////////////////////////////////////// 63 64 int SimpleBuffer::BufferSize() const { 65 return storage_size_; 66 } 67 68 //////////////////////////////////////////////////////////////////////////////// 69 70 inline int SimpleBuffer::BytesFree() const { 71 return (storage_size_ - write_idx_); 72 } 73 74 //////////////////////////////////////////////////////////////////////////////// 75 76 bool SimpleBuffer::Empty() const { 77 return (read_idx_ == write_idx_); 78 } 79 80 //////////////////////////////////////////////////////////////////////////////// 81 82 bool SimpleBuffer::Full() const { 83 return ((write_idx_ == storage_size_) && (read_idx_ != write_idx_)); 84 } 85 86 //////////////////////////////////////////////////////////////////////////////// 87 88 // returns the number of characters written. 89 // appends up-to-'size' bytes to the simplebuffer. 90 int SimpleBuffer::Write(const char* bytes, int size) { 91 bool has_room = ((storage_size_ - write_idx_) >= size); 92 if (!has_room) { 93 (void)Reserve(size); 94 } 95 memcpy(storage_ + write_idx_, bytes, size); 96 SimpleBuffer::AdvanceWritablePtr(size); 97 return size; 98 } 99 100 //////////////////////////////////////////////////////////////////////////////// 101 102 // stores a pointer into the simple buffer in *ptr, 103 // and stores the number of characters which are allowed 104 // to be written in *size. 105 inline void SimpleBuffer::GetWritablePtr(char **ptr, int* size) const { 106 *ptr = storage_ + write_idx_; 107 *size = SimpleBuffer::BytesFree(); 108 } 109 110 //////////////////////////////////////////////////////////////////////////////// 111 112 // stores a pointer into the simple buffer in *ptr, 113 // and stores the number of characters which are allowed 114 // to be read in *size. 115 void SimpleBuffer::GetReadablePtr(char **ptr, int* size) const { 116 *ptr = storage_ + read_idx_; 117 *size = write_idx_ - read_idx_; 118 } 119 120 //////////////////////////////////////////////////////////////////////////////// 121 122 // returns the number of bytes read into 'bytes' 123 int SimpleBuffer::Read(char* bytes, int size) { 124 char * read_ptr = NULL; 125 int read_size = 0; 126 GetReadablePtr(&read_ptr, &read_size); 127 if (read_size > size) { 128 read_size = size; 129 } 130 memcpy(bytes, read_ptr, read_size); 131 AdvanceReadablePtr(read_size); 132 return read_size; 133 } 134 135 //////////////////////////////////////////////////////////////////////////////// 136 137 // removes all data from the simple buffer 138 void SimpleBuffer::Clear() { 139 read_idx_ = write_idx_ = 0; 140 } 141 142 //////////////////////////////////////////////////////////////////////////////// 143 144 // Attempts to reserve a contiguous block of buffer space by either reclaiming 145 // old data that is already read, and reallocate large storage as needed. 146 bool SimpleBuffer::Reserve(int size) { 147 if (size > 0 && BytesFree() < size) { 148 char * read_ptr = NULL; 149 int read_size = 0; 150 GetReadablePtr(&read_ptr, &read_size); 151 152 if (read_size + size <= BufferSize()) { 153 // Can reclaim space from already read bytes by shifting 154 memmove(storage_, read_ptr, read_size); 155 read_idx_ = 0; 156 write_idx_ = read_size; 157 CHECK_GE(BytesFree(), size); 158 } else { 159 // what we need is to have at least size bytes available for writing. 160 // This implies that the buffer needs to be at least size bytes + 161 // read_size bytes long. Since we want linear time extensions in the case 162 // that we're extending this thing repeatedly, we should extend to twice 163 // the current size (if that is big enough), or the size + read_size 164 // bytes, whichever is larger. 165 int new_storage_size = 2 * storage_size_; 166 if (new_storage_size < size + read_size) { 167 new_storage_size = size + read_size; 168 } 169 170 // have to extend the thing 171 char* new_storage = new char[new_storage_size]; 172 173 // copy still useful info to the new buffer. 174 memcpy(new_storage, read_ptr, read_size); 175 // reset pointers. 176 read_idx_ = 0; 177 write_idx_ = read_size; 178 delete[] storage_; 179 storage_ = new_storage; 180 storage_size_ = new_storage_size; 181 } 182 } 183 return true; 184 } 185 186 //////////////////////////////////////////////////////////////////////////////// 187 188 // removes the oldest 'amount_to_consume' characters. 189 void SimpleBuffer::AdvanceReadablePtr(int amount_to_advance) { 190 read_idx_ += amount_to_advance; 191 if (read_idx_ > storage_size_) { 192 read_idx_ = storage_size_; 193 } 194 } 195 196 //////////////////////////////////////////////////////////////////////////////// 197 198 // Moves the internal pointers around such that the 199 // amount of data specified here is expected to 200 // already be resident (as if it was Written) 201 inline void SimpleBuffer::AdvanceWritablePtr(int amount_to_advance) { 202 write_idx_ += amount_to_advance; 203 if (write_idx_ > storage_size_) { 204 write_idx_ = storage_size_; 205 } 206 } 207 208 } // namespace net 209