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