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