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.
5 #include "net/tools/flip_server/ring_buffer.h"
6 #include "base/logging.h"
10 RingBuffer::RingBuffer(int buffer_size)
11 : buffer_(new char[buffer_size]),
12 buffer_size_(buffer_size),
17 RingBuffer::~RingBuffer() {}
19 int RingBuffer::ReadableBytes() const { return bytes_used_; }
21 int RingBuffer::BufferSize() const { return buffer_size_; }
23 int RingBuffer::BytesFree() const { return BufferSize() - ReadableBytes(); }
25 bool RingBuffer::Empty() const { return ReadableBytes() == 0; }
27 bool RingBuffer::Full() const { return ReadableBytes() == BufferSize(); }
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) {
36 GetWritablePtr(&wptr, &wsize);
37 int bytes_remaining = size;
38 int bytes_written = 0;
40 while (wsize && bytes_remaining) {
41 if (wsize > bytes_remaining) {
42 wsize = bytes_remaining;
44 memcpy(wptr, bytes + bytes_written, wsize);
45 bytes_written += wsize;
46 bytes_remaining -= wsize;
47 AdvanceWritablePtr(wsize);
48 GetWritablePtr(&wptr, &wsize);
52 const char* p = bytes;
54 int bytes_to_write = size;
55 int bytes_available = BytesFree();
56 if (bytes_available < bytes_to_write) {
57 bytes_to_write = bytes_available;
59 const char* end = bytes + bytes_to_write;
62 this->buffer_[this->write_idx_] = *p;
65 if (this->write_idx_ >= this->buffer_size_) {
69 bytes_used_ += bytes_to_write;
70 return bytes_to_write;
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_;
79 if (bytes_used_ == buffer_size_) {
81 } else if (read_idx_ > write_idx_) {
82 *size = read_idx_ - write_idx_;
84 *size = buffer_size_ - write_idx_;
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_;
93 if (bytes_used_ == 0) {
95 } else if (write_idx_ > read_idx_) {
96 *size = write_idx_ - read_idx_;
98 *size = buffer_size_ - read_idx_;
102 // returns the number of bytes read into
103 int RingBuffer::Read(char* bytes, int size) {
108 GetReadablePtr(&rptr, &rsize);
109 int bytes_remaining = size;
112 while (rsize && bytes_remaining) {
113 if (rsize > bytes_remaining) {
114 rsize = bytes_remaining;
116 memcpy(bytes + bytes_read, rptr, rsize);
118 bytes_remaining -= rsize;
119 AdvanceReadablePtr(rsize);
120 GetReadablePtr(&rptr, &rsize);
125 int bytes_to_read = size;
126 int bytes_used = ReadableBytes();
127 if (bytes_used < bytes_to_read) {
128 bytes_to_read = bytes_used;
130 char* end = bytes + bytes_to_read;
133 *p = this->buffer_[this->read_idx_];
136 if (this->read_idx_ >= this->buffer_size_) {
140 this->bytes_used_ -= bytes_to_read;
141 return bytes_to_read;
145 void RingBuffer::Clear() {
151 bool RingBuffer::Reserve(int size) {
153 char* write_ptr = NULL;
155 GetWritablePtr(&write_ptr, &write_size);
157 if (write_size < size) {
158 char* read_ptr = NULL;
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);
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);
181 Resize(ReadableBytes() + size);
184 DCHECK_LE(size, buffer_size_ - write_idx_);
188 void RingBuffer::AdvanceReadablePtr(int amount_to_consume) {
189 CHECK_GE(amount_to_consume, 0);
190 if (amount_to_consume >= bytes_used_) {
194 read_idx_ += amount_to_consume;
195 read_idx_ %= buffer_size_;
196 bytes_used_ -= amount_to_consume;
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;
207 void RingBuffer::Resize(int buffer_size) {
208 CHECK_GE(buffer_size, 0);
209 if (buffer_size == buffer_size_)
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);
218 int bytes_written = 0;
219 int bytes_used = bytes_used_;
223 GetReadablePtr(&ptr, &size);
226 if (size > buffer_size) {
229 memcpy(new_buffer + bytes_written, ptr, size);
230 bytes_written += size;
231 AdvanceReadablePtr(size);
233 buffer_.reset(new_buffer);
235 buffer_size_ = buffer_size;
236 bytes_used_ = bytes_used;
238 write_idx_ = bytes_used_ % buffer_size_;