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