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