Home | History | Annotate | Download | only in flip_server
      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