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/simple_buffer.h"
      6 #include "base/logging.h"
      7 
      8 // Some of the following member functions are marked inlined, even though they
      9 // are virtual. This may seem counter-intuitive, since virtual functions are
     10 // generally not eligible for inlining. Profiling results indicate that these
     11 // large amount of runtime is spent on virtual function dispatch on these
     12 // simple functions. They are virtual because of the interface this class
     13 // inherits from. However, it is very unlikely that anyone will sub-class
     14 // SimpleBuffer and change their implementation. To get rid of this baggage,
     15 // internal implementation (e.g., Write) explicitly use SimpleBuffer:: to
     16 // qualify the method calls, thus disabling the virtual dispatch and enable
     17 // inlining.
     18 
     19 namespace net {
     20 
     21 static const int kInitialSimpleBufferSize = 10;
     22 
     23 SimpleBuffer::SimpleBuffer()
     24   : storage_(new char[kInitialSimpleBufferSize]),
     25     write_idx_(0),
     26     read_idx_(0),
     27     storage_size_(kInitialSimpleBufferSize) {
     28 }
     29 
     30 SimpleBuffer::SimpleBuffer(int size)
     31   : write_idx_(0),
     32     read_idx_(0),
     33     storage_size_(size) {
     34   // Callers may try to allocate overly large blocks, but negative sizes are
     35   // obviously wrong.
     36   CHECK_GE(size, 0);
     37   storage_ = new char[size];
     38 }
     39 
     40 SimpleBuffer::~SimpleBuffer() {
     41   delete[] storage_;
     42 }
     43 
     44 
     45 ////////////////////////////////////////////////////////////////////////////////
     46 
     47 int SimpleBuffer::ReadableBytes() const {
     48   return write_idx_ - read_idx_;
     49 }
     50 
     51 ////////////////////////////////////////////////////////////////////////////////
     52 
     53 std::string SimpleBuffer::str() const {
     54   std::string s;
     55   char * readable_ptr;
     56   int readable_size;
     57   GetReadablePtr(&readable_ptr, &readable_size);
     58   s.append(readable_ptr, readable_ptr + readable_size);
     59   return s;
     60 }
     61 
     62 ////////////////////////////////////////////////////////////////////////////////
     63 
     64 int SimpleBuffer::BufferSize() const {
     65   return storage_size_;
     66 }
     67 
     68 ////////////////////////////////////////////////////////////////////////////////
     69 
     70 inline int SimpleBuffer::BytesFree() const {
     71   return (storage_size_ - write_idx_);
     72 }
     73 
     74 ////////////////////////////////////////////////////////////////////////////////
     75 
     76 bool SimpleBuffer::Empty() const {
     77   return (read_idx_ == write_idx_);
     78 }
     79 
     80 ////////////////////////////////////////////////////////////////////////////////
     81 
     82 bool SimpleBuffer::Full() const {
     83   return ((write_idx_ == storage_size_) && (read_idx_ != write_idx_));
     84 }
     85 
     86 ////////////////////////////////////////////////////////////////////////////////
     87 
     88 // returns the number of characters written.
     89 // appends up-to-'size' bytes to the simplebuffer.
     90 int SimpleBuffer::Write(const char* bytes, int size) {
     91   bool has_room = ((storage_size_ - write_idx_) >= size);
     92   if (!has_room) {
     93     (void)Reserve(size);
     94   }
     95   memcpy(storage_ + write_idx_, bytes, size);
     96   SimpleBuffer::AdvanceWritablePtr(size);
     97   return size;
     98 }
     99 
    100 ////////////////////////////////////////////////////////////////////////////////
    101 
    102 // stores a pointer into the simple buffer in *ptr,
    103 // and stores the number of characters which are allowed
    104 // to be written in *size.
    105 inline void SimpleBuffer::GetWritablePtr(char **ptr, int* size) const {
    106   *ptr = storage_ + write_idx_;
    107   *size = SimpleBuffer::BytesFree();
    108 }
    109 
    110 ////////////////////////////////////////////////////////////////////////////////
    111 
    112 // stores a pointer into the simple buffer in *ptr,
    113 // and stores the number of characters which are allowed
    114 // to be read in *size.
    115 void SimpleBuffer::GetReadablePtr(char **ptr, int* size) const {
    116   *ptr = storage_ + read_idx_;
    117   *size = write_idx_ - read_idx_;
    118 }
    119 
    120 ////////////////////////////////////////////////////////////////////////////////
    121 
    122 // returns the number of bytes read into 'bytes'
    123 int SimpleBuffer::Read(char* bytes, int size) {
    124   char * read_ptr = NULL;
    125   int read_size = 0;
    126   GetReadablePtr(&read_ptr, &read_size);
    127   if (read_size > size) {
    128     read_size = size;
    129   }
    130   memcpy(bytes, read_ptr, read_size);
    131   AdvanceReadablePtr(read_size);
    132   return read_size;
    133 }
    134 
    135 ////////////////////////////////////////////////////////////////////////////////
    136 
    137 // removes all data from the simple buffer
    138 void SimpleBuffer::Clear() {
    139   read_idx_ = write_idx_ = 0;
    140 }
    141 
    142 ////////////////////////////////////////////////////////////////////////////////
    143 
    144 // Attempts to reserve a contiguous block of buffer space by either reclaiming
    145 // old data that is already read, and reallocate large storage as needed.
    146 bool SimpleBuffer::Reserve(int size) {
    147   if (size > 0 && BytesFree() < size) {
    148     char * read_ptr = NULL;
    149     int read_size = 0;
    150     GetReadablePtr(&read_ptr, &read_size);
    151 
    152     if (read_size + size <= BufferSize()) {
    153       // Can reclaim space from already read bytes by shifting
    154       memmove(storage_, read_ptr, read_size);
    155       read_idx_ = 0;
    156       write_idx_ = read_size;
    157       CHECK_GE(BytesFree(), size);
    158     } else {
    159       // what we need is to have at least size bytes available for writing.
    160       // This implies that the buffer needs to be at least size bytes +
    161       // read_size bytes long. Since we want linear time extensions in the case
    162       // that we're extending this thing repeatedly, we should extend to twice
    163       // the current size (if that is big enough), or the size + read_size
    164       // bytes, whichever is larger.
    165       int new_storage_size = 2 * storage_size_;
    166       if (new_storage_size < size + read_size) {
    167         new_storage_size = size + read_size;
    168       }
    169 
    170       // have to extend the thing
    171       char* new_storage = new char[new_storage_size];
    172 
    173       // copy still useful info to the new buffer.
    174       memcpy(new_storage, read_ptr, read_size);
    175       // reset pointers.
    176       read_idx_ = 0;
    177       write_idx_ = read_size;
    178       delete[] storage_;
    179       storage_ = new_storage;
    180       storage_size_ = new_storage_size;
    181     }
    182   }
    183   return true;
    184 }
    185 
    186 ////////////////////////////////////////////////////////////////////////////////
    187 
    188 // removes the oldest 'amount_to_consume' characters.
    189 void SimpleBuffer::AdvanceReadablePtr(int amount_to_advance) {
    190   read_idx_ += amount_to_advance;
    191   if (read_idx_ > storage_size_) {
    192     read_idx_ = storage_size_;
    193   }
    194 }
    195 
    196 ////////////////////////////////////////////////////////////////////////////////
    197 
    198 // Moves the internal pointers around such that the
    199 // amount of data specified here is expected to
    200 // already be resident (as if it was Written)
    201 inline void SimpleBuffer::AdvanceWritablePtr(int amount_to_advance) {
    202   write_idx_ += amount_to_advance;
    203   if (write_idx_ > storage_size_) {
    204     write_idx_ = storage_size_;
    205   }
    206 }
    207 
    208 }  // namespace net
    209