1 // Copyright (c) 2009 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/flip_server/ring_buffer.h" 6 #include "base/logging.h" 7 8 namespace net { 9 10 RingBuffer::RingBuffer(int buffer_size) 11 : buffer_(new char[buffer_size]), 12 buffer_size_(buffer_size), 13 bytes_used_(0), 14 read_idx_(0), 15 write_idx_(0) { 16 } 17 18 //////////////////////////////////////////////////////////////////////////////// 19 20 int RingBuffer::ReadableBytes() const { 21 return bytes_used_; 22 } 23 24 //////////////////////////////////////////////////////////////////////////////// 25 26 int RingBuffer::BufferSize() const { 27 return buffer_size_; 28 } 29 30 //////////////////////////////////////////////////////////////////////////////// 31 32 int RingBuffer::BytesFree() const { 33 return BufferSize() - ReadableBytes(); 34 } 35 36 //////////////////////////////////////////////////////////////////////////////// 37 38 // Returns the number of characters written. 39 // Appends up-to-'size' bytes to the ringbuffer. 40 int RingBuffer::Write(const char* bytes, int size) { 41 CHECK_GE(size, 0); 42 #if 1 43 char* wptr; 44 int wsize; 45 GetWritablePtr(&wptr, &wsize); 46 int bytes_remaining = size; 47 int bytes_written = 0; 48 49 while (wsize && bytes_remaining) { 50 if (wsize > bytes_remaining) { 51 wsize = bytes_remaining; 52 } 53 memcpy(wptr, bytes + bytes_written, wsize); 54 bytes_written += wsize; 55 bytes_remaining -= wsize; 56 AdvanceWritablePtr(wsize); 57 GetWritablePtr(&wptr, &wsize); 58 } 59 return bytes_written; 60 #else 61 const char* p = bytes; 62 63 int bytes_to_write = size; 64 int bytes_available = BytesFree(); 65 if (bytes_available < bytes_to_write) { 66 bytes_to_write = bytes_available; 67 } 68 const char* end = bytes + bytes_to_write; 69 70 while (p != end) { 71 this->buffer_[this->write_idx_] = *p; 72 ++p; 73 ++this->write_idx_; 74 if (this->write_idx_ >= this->buffer_size_) { 75 this->write_idx_ = 0; 76 } 77 } 78 bytes_used_ += bytes_to_write; 79 return bytes_to_write; 80 #endif 81 } 82 83 //////////////////////////////////////////////////////////////////////////////// 84 85 // Sets *ptr to the beginning of writable memory, and sets *size to the size 86 // available for writing using this pointer. 87 void RingBuffer::GetWritablePtr(char** ptr, int* size) const { 88 *ptr = buffer_.get() + write_idx_; 89 90 if (bytes_used_ == buffer_size_) { 91 *size = 0; 92 } else if (read_idx_ > write_idx_) { 93 *size = read_idx_ - write_idx_; 94 } else { 95 *size = buffer_size_ - write_idx_; 96 } 97 } 98 99 //////////////////////////////////////////////////////////////////////////////// 100 101 // Sets *ptr to the beginning of readable memory, and sets *size to the size 102 // available for reading using this pointer. 103 void RingBuffer::GetReadablePtr(char** ptr, int* size) const { 104 *ptr = buffer_.get() + read_idx_; 105 106 if (bytes_used_ == 0) { 107 *size = 0; 108 } else if (write_idx_ > read_idx_) { 109 *size = write_idx_ - read_idx_; 110 } else { 111 *size = buffer_size_ - read_idx_; 112 } 113 } 114 115 //////////////////////////////////////////////////////////////////////////////// 116 117 // returns the number of bytes read into 118 int RingBuffer::Read(char* bytes, int size) { 119 CHECK_GE(size, 0); 120 #if 1 121 char* rptr; 122 int rsize; 123 GetReadablePtr(&rptr, &rsize); 124 int bytes_remaining = size; 125 int bytes_read = 0; 126 127 while (rsize && bytes_remaining) { 128 if (rsize > bytes_remaining) { 129 rsize = bytes_remaining; 130 } 131 memcpy(bytes + bytes_read, rptr, rsize); 132 bytes_read += rsize; 133 bytes_remaining -= rsize; 134 AdvanceReadablePtr(rsize); 135 GetReadablePtr(&rptr, &rsize); 136 } 137 return bytes_read; 138 #else 139 char* p = bytes; 140 int bytes_to_read = size; 141 int bytes_used = ReadableBytes(); 142 if (bytes_used < bytes_to_read) { 143 bytes_to_read = bytes_used; 144 } 145 char* end = bytes + bytes_to_read; 146 147 while (p != end) { 148 *p = this->buffer_[this->read_idx_]; 149 ++p; 150 ++this->read_idx_; 151 if (this->read_idx_ >= this->buffer_size_) { 152 this->read_idx_ = 0; 153 } 154 } 155 this->bytes_used_ -= bytes_to_read; 156 return bytes_to_read; 157 #endif 158 } 159 160 //////////////////////////////////////////////////////////////////////////////// 161 162 void RingBuffer::Clear() { 163 bytes_used_ = 0; 164 write_idx_ = 0; 165 read_idx_ = 0; 166 } 167 168 //////////////////////////////////////////////////////////////////////////////// 169 170 bool RingBuffer::Reserve(int size) { 171 DCHECK(size > 0); 172 char* write_ptr = NULL; 173 int write_size = 0; 174 GetWritablePtr(&write_ptr, &write_size); 175 176 if (write_size < size) { 177 char* read_ptr = NULL; 178 int read_size = 0; 179 GetReadablePtr(&read_ptr, &read_size); 180 if (size <= BytesFree()) { 181 // The fact that the total Free size is big enough but writable size is 182 // not means that the writeable region is broken into two pieces: only 183 // possible if the read_idx < write_idx. If write_idx < read_idx, then 184 // the writeable region must be contiguous: [write_idx, read_idx). There 185 // is no work to be done for the latter. 186 DCHECK(read_idx_ <= write_idx_); 187 DCHECK(read_size == ReadableBytes()); 188 if (read_idx_ < write_idx_) { 189 // Writeable area fragmented, consolidate it. 190 memmove(buffer_.get(), read_ptr, read_size); 191 read_idx_ = 0; 192 write_idx_ = read_size; 193 } else if (read_idx_ == write_idx_) { 194 // No unconsumed data in the buffer, simply reset the indexes. 195 DCHECK(ReadableBytes() == 0); 196 read_idx_ = 0; 197 write_idx_ = 0; 198 } 199 } else { 200 Resize(ReadableBytes() + size); 201 } 202 } 203 DCHECK_LE(size, buffer_size_ - write_idx_); 204 return true; 205 } 206 207 //////////////////////////////////////////////////////////////////////////////// 208 209 void RingBuffer::AdvanceReadablePtr(int amount_to_consume) { 210 CHECK_GE(amount_to_consume, 0); 211 if (amount_to_consume >= bytes_used_) { 212 Clear(); 213 return; 214 } 215 read_idx_ += amount_to_consume; 216 read_idx_ %= buffer_size_; 217 bytes_used_ -= amount_to_consume; 218 } 219 220 //////////////////////////////////////////////////////////////////////////////// 221 222 void RingBuffer::AdvanceWritablePtr(int amount_to_produce) { 223 CHECK_GE(amount_to_produce, 0); 224 CHECK_LE(amount_to_produce, BytesFree()); 225 write_idx_ += amount_to_produce; 226 write_idx_ %= buffer_size_; 227 bytes_used_ += amount_to_produce; 228 } 229 230 //////////////////////////////////////////////////////////////////////////////// 231 232 void RingBuffer::Resize(int buffer_size) { 233 CHECK_GE(buffer_size, 0); 234 if (buffer_size == buffer_size_) return; 235 236 char* new_buffer = new char[buffer_size]; 237 if (buffer_size < bytes_used_) { 238 // consume the oldest data. 239 AdvanceReadablePtr(bytes_used_ - buffer_size); 240 } 241 242 int bytes_written = 0; 243 int bytes_used = bytes_used_; 244 while (true) { 245 int size; 246 char* ptr; 247 GetReadablePtr(&ptr, &size); 248 if (size == 0) break; 249 if (size > buffer_size) { 250 size = buffer_size; 251 } 252 memcpy(new_buffer + bytes_written, ptr, size); 253 bytes_written += size; 254 AdvanceReadablePtr(size); 255 } 256 buffer_.reset(new_buffer); 257 258 buffer_size_ = buffer_size; 259 bytes_used_ = bytes_used; 260 read_idx_ = 0; 261 write_idx_ = bytes_used_ % buffer_size_; 262 } 263 264 } // namespace net 265 266