ring_buffer.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
178901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch// Copyright (c) 2009 The Chromium Authors. All rights reserved. 278901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 378901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch// found in the LICENSE file. 478901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch 578901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch#include "net/tools/flip_server/ring_buffer.h" 678901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch#include "base/logging.h" 778901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch 878901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdochnamespace net { 978901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch 1078901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben MurdochRingBuffer::RingBuffer(int buffer_size) 1178901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch : buffer_(new char[buffer_size]), 1278901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch buffer_size_(buffer_size), 1378901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch bytes_used_(0), 1478901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch read_idx_(0), 1578901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch write_idx_(0) {} 1678901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch 1778901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben MurdochRingBuffer::~RingBuffer() {} 1878901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch 1978901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdochint RingBuffer::ReadableBytes() const { return bytes_used_; } 2078901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch 2178901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdochint RingBuffer::BufferSize() const { return buffer_size_; } 2278901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch 2378901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdochint RingBuffer::BytesFree() const { return BufferSize() - ReadableBytes(); } 2478901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch 2578901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdochbool RingBuffer::Empty() const { return ReadableBytes() == 0; } 2678901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch 2778901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdochbool RingBuffer::Full() const { return ReadableBytes() == BufferSize(); } 2878901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch 2978901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch// Returns the number of characters written. 3078901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch// Appends up-to-'size' bytes to the ringbuffer. 3178901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdochint RingBuffer::Write(const char* bytes, int size) { 3278901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch CHECK_GE(size, 0); 3378901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch#if 1 3478901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch char* wptr; 3578901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch int wsize; 3678901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch GetWritablePtr(&wptr, &wsize); 3778901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch int bytes_remaining = size; 3878901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch int bytes_written = 0; 3978901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch 4078901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch while (wsize && bytes_remaining) { 4178901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch if (wsize > bytes_remaining) { 4278901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch wsize = bytes_remaining; 4378901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch } 4478901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch memcpy(wptr, bytes + bytes_written, wsize); 4578901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch bytes_written += wsize; 4678901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch bytes_remaining -= wsize; 4778901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch AdvanceWritablePtr(wsize); 4878901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch GetWritablePtr(&wptr, &wsize); 4978901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch } 5078901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch return bytes_written; 5178901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch#else 5278901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch const char* p = bytes; 5378901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch 5478901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch int bytes_to_write = size; 5578901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch int bytes_available = BytesFree(); 5678901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch if (bytes_available < bytes_to_write) { 5778901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch bytes_to_write = bytes_available; 5878901d17b47ef1f8d6d0a89eaf37f9523ba1de85Ben Murdoch } 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. 76void 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. 90void 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 103int 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 145void RingBuffer::Clear() { 146 bytes_used_ = 0; 147 write_idx_ = 0; 148 read_idx_ = 0; 149} 150 151bool 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 188void 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 199void 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 207void 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