diff options
Diffstat (limited to 'net/tools/flip_server/ring_buffer.cc')
-rw-r--r-- | net/tools/flip_server/ring_buffer.cc | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/net/tools/flip_server/ring_buffer.cc b/net/tools/flip_server/ring_buffer.cc new file mode 100644 index 0000000..9f702a0 --- /dev/null +++ b/net/tools/flip_server/ring_buffer.cc @@ -0,0 +1,265 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/tools/flip_server/ring_buffer.h" +#include "base/logging.h" + +namespace gfe2 { + +RingBuffer::RingBuffer(int buffer_size) + : buffer_(new char[buffer_size]), + buffer_size_(buffer_size), + bytes_used_(0), + read_idx_(0), + write_idx_(0) { +} + +//////////////////////////////////////////////////////////////////////////////// + +int RingBuffer::ReadableBytes() const { + return bytes_used_; +} + +//////////////////////////////////////////////////////////////////////////////// + +int RingBuffer::BufferSize() const { + return buffer_size_; +} + +//////////////////////////////////////////////////////////////////////////////// + +int RingBuffer::BytesFree() const { + return BufferSize() - ReadableBytes(); +} + +//////////////////////////////////////////////////////////////////////////////// + +// Returns the number of characters written. +// Appends up-to-'size' bytes to the ringbuffer. +int RingBuffer::Write(const char* bytes, int size) { + CHECK_GE(size, 0); +#if 1 + char* wptr; + int wsize; + GetWritablePtr(&wptr, &wsize); + int bytes_remaining = size; + int bytes_written = 0; + + while (wsize && bytes_remaining) { + if (wsize > bytes_remaining) { + wsize = bytes_remaining; + } + memcpy(wptr, bytes + bytes_written, wsize); + bytes_written += wsize; + bytes_remaining -= wsize; + AdvanceWritablePtr(wsize); + GetWritablePtr(&wptr, &wsize); + } + return bytes_written; +#else + const char* p = bytes; + + int bytes_to_write = size; + int bytes_available = BytesFree(); + if (bytes_available < bytes_to_write) { + bytes_to_write = bytes_available; + } + const char* end = bytes + bytes_to_write; + + while (p != end) { + this->buffer_[this->write_idx_] = *p; + ++p; + ++this->write_idx_; + if (this->write_idx_ >= this->buffer_size_) { + this->write_idx_ = 0; + } + } + bytes_used_ += bytes_to_write; + return bytes_to_write; +#endif +} + +//////////////////////////////////////////////////////////////////////////////// + +// Sets *ptr to the beginning of writable memory, and sets *size to the size +// available for writing using this pointer. +void RingBuffer::GetWritablePtr(char** ptr, int* size) const { + *ptr = buffer_.get() + write_idx_; + + if (bytes_used_ == buffer_size_) { + *size = 0; + } else if (read_idx_ > write_idx_) { + *size = read_idx_ - write_idx_; + } else { + *size = buffer_size_ - write_idx_; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// Sets *ptr to the beginning of readable memory, and sets *size to the size +// available for reading using this pointer. +void RingBuffer::GetReadablePtr(char** ptr, int* size) const { + *ptr = buffer_.get() + read_idx_; + + if (bytes_used_ == 0) { + *size = 0; + } else if (write_idx_ > read_idx_) { + *size = write_idx_ - read_idx_; + } else { + *size = buffer_size_ - read_idx_; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// returns the number of bytes read into +int RingBuffer::Read(char* bytes, int size) { + CHECK_GE(size, 0); +#if 1 + char* rptr; + int rsize; + GetReadablePtr(&rptr, &rsize); + int bytes_remaining = size; + int bytes_read = 0; + + while (rsize && bytes_remaining) { + if (rsize > bytes_remaining) { + rsize = bytes_remaining; + } + memcpy(bytes + bytes_read, rptr, rsize); + bytes_read += rsize; + bytes_remaining -= rsize; + AdvanceReadablePtr(rsize); + GetReadablePtr(&rptr, &rsize); + } + return bytes_read; +#else + char* p = bytes; + int bytes_to_read = size; + int bytes_used = ReadableBytes(); + if (bytes_used < bytes_to_read) { + bytes_to_read = bytes_used; + } + char* end = bytes + bytes_to_read; + + while (p != end) { + *p = this->buffer_[this->read_idx_]; + ++p; + ++this->read_idx_; + if (this->read_idx_ >= this->buffer_size_) { + this->read_idx_ = 0; + } + } + this->bytes_used_ -= bytes_to_read; + return bytes_to_read; +#endif +} + +//////////////////////////////////////////////////////////////////////////////// + +void RingBuffer::Clear() { + bytes_used_ = 0; + write_idx_ = 0; + read_idx_ = 0; +} + +//////////////////////////////////////////////////////////////////////////////// + +bool RingBuffer::Reserve(int size) { + DCHECK(size > 0); + char* write_ptr = NULL; + int write_size = 0; + GetWritablePtr(&write_ptr, &write_size); + + if (write_size < size) { + char* read_ptr = NULL; + int read_size = 0; + GetReadablePtr(&read_ptr, &read_size); + if (size <= BytesFree()) { + // The fact that the total Free size is big enough but writable size is + // not means that the writeable region is broken into two pieces: only + // possible if the read_idx < write_idx. If write_idx < read_idx, then + // the writeable region must be contiguous: [write_idx, read_idx). There + // is no work to be done for the latter. + DCHECK(read_idx_ <= write_idx_); + DCHECK(read_size == ReadableBytes()); + if (read_idx_ < write_idx_) { + // Writeable area fragmented, consolidate it. + memmove(buffer_.get(), read_ptr, read_size); + read_idx_ = 0; + write_idx_ = read_size; + } else if (read_idx_ == write_idx_) { + // No unconsumed data in the buffer, simply reset the indexes. + DCHECK(ReadableBytes() == 0); + read_idx_ = 0; + write_idx_ = 0; + } + } else { + Resize(ReadableBytes() + size); + } + } + DCHECK_LE(size, buffer_size_ - write_idx_); + return true; +} + +//////////////////////////////////////////////////////////////////////////////// + +void RingBuffer::AdvanceReadablePtr(int amount_to_consume) { + CHECK_GE(amount_to_consume, 0); + if (amount_to_consume >= bytes_used_) { + Clear(); + return; + } + read_idx_ += amount_to_consume; + read_idx_ %= buffer_size_; + bytes_used_ -= amount_to_consume; +} + +//////////////////////////////////////////////////////////////////////////////// + +void RingBuffer::AdvanceWritablePtr(int amount_to_produce) { + CHECK_GE(amount_to_produce, 0); + CHECK_LE(amount_to_produce, BytesFree()); + write_idx_ += amount_to_produce; + write_idx_ %= buffer_size_; + bytes_used_ += amount_to_produce; +} + +//////////////////////////////////////////////////////////////////////////////// + +void RingBuffer::Resize(int buffer_size) { + CHECK_GE(buffer_size, 0); + if (buffer_size == buffer_size_) return; + + char* new_buffer = new char[buffer_size]; + if (buffer_size < bytes_used_) { + // consume the oldest data. + AdvanceReadablePtr(bytes_used_ - buffer_size); + } + + int bytes_written = 0; + int bytes_used = bytes_used_; + while (true) { + int size; + char* ptr; + GetReadablePtr(&ptr, &size); + if (size == 0) break; + if (size > buffer_size) { + size = buffer_size; + } + memcpy(new_buffer + bytes_written, ptr, size); + bytes_written += size; + AdvanceReadablePtr(size); + } + buffer_.reset(new_buffer); + + buffer_size_ = buffer_size; + bytes_used_ = bytes_used; + read_idx_ = 0; + write_idx_ = bytes_used_ % buffer_size_; +} + +} // namespace gfe2 + |