14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/tools/balsa/simple_buffer.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Some of the following member functions are marked inlined, even though they
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// are virtual. This may seem counter-intuitive, since virtual functions are
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// generally not eligible for inlining. Profiling results indicate that these
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// large amount of runtime is spent on virtual function dispatch on these
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// simple functions. They are virtual because of the interface this class
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// inherits from. However, it is very unlikely that anyone will sub-class
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SimpleBuffer and change their implementation. To get rid of this baggage,
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// internal implementation (e.g., Write) explicitly use SimpleBuffer:: to
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// qualify the method calls, thus disabling the virtual dispatch and enable
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// inlining.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kInitialSimpleBufferSize = 10;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SimpleBuffer::SimpleBuffer()
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  : storage_(new char[kInitialSimpleBufferSize]),
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    write_idx_(0),
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    read_idx_(0),
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    storage_size_(kInitialSimpleBufferSize) {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SimpleBuffer::SimpleBuffer(int size)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  : write_idx_(0),
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    read_idx_(0),
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    storage_size_(size) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Callers may try to allocate overly large blocks, but negative sizes are
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // obviously wrong.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_GE(size, 0);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  storage_ = new char[size];
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SimpleBuffer::~SimpleBuffer() {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete[] storage_;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SimpleBuffer::ReadableBytes() const {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return write_idx_ - read_idx_;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string SimpleBuffer::str() const {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string s;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char * readable_ptr;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int readable_size;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetReadablePtr(&readable_ptr, &readable_size);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  s.append(readable_ptr, readable_ptr + readable_size);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return s;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SimpleBuffer::BufferSize() const {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return storage_size_;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline int SimpleBuffer::BytesFree() const {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (storage_size_ - write_idx_);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SimpleBuffer::Empty() const {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (read_idx_ == write_idx_);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SimpleBuffer::Full() const {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ((write_idx_ == storage_size_) && (read_idx_ != write_idx_));
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// returns the number of characters written.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// appends up-to-'size' bytes to the simplebuffer.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SimpleBuffer::Write(const char* bytes, int size) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_room = ((storage_size_ - write_idx_) >= size);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!has_room) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (void)Reserve(size);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(storage_ + write_idx_, bytes, size);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SimpleBuffer::AdvanceWritablePtr(size);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return size;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// stores a pointer into the simple buffer in *ptr,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and stores the number of characters which are allowed
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to be written in *size.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void SimpleBuffer::GetWritablePtr(char **ptr, int* size) const {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ptr = storage_ + write_idx_;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *size = SimpleBuffer::BytesFree();
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// stores a pointer into the simple buffer in *ptr,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and stores the number of characters which are allowed
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to be read in *size.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SimpleBuffer::GetReadablePtr(char **ptr, int* size) const {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ptr = storage_ + read_idx_;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *size = write_idx_ - read_idx_;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// returns the number of bytes read into 'bytes'
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SimpleBuffer::Read(char* bytes, int size) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char * read_ptr = NULL;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int read_size = 0;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetReadablePtr(&read_ptr, &read_size);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (read_size > size) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    read_size = size;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(bytes, read_ptr, read_size);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AdvanceReadablePtr(read_size);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return read_size;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// removes all data from the simple buffer
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SimpleBuffer::Clear() {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  read_idx_ = write_idx_ = 0;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Attempts to reserve a contiguous block of buffer space by either reclaiming
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// old data that is already read, and reallocate large storage as needed.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SimpleBuffer::Reserve(int size) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (size > 0 && BytesFree() < size) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char * read_ptr = NULL;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int read_size = 0;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetReadablePtr(&read_ptr, &read_size);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (read_size + size <= BufferSize()) {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Can reclaim space from already read bytes by shifting
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memmove(storage_, read_ptr, read_size);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      read_idx_ = 0;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      write_idx_ = read_size;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CHECK_GE(BytesFree(), size);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // what we need is to have at least size bytes available for writing.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This implies that the buffer needs to be at least size bytes +
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // read_size bytes long. Since we want linear time extensions in the case
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // that we're extending this thing repeatedly, we should extend to twice
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the current size (if that is big enough), or the size + read_size
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // bytes, whichever is larger.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int new_storage_size = 2 * storage_size_;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (new_storage_size < size + read_size) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_storage_size = size + read_size;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // have to extend the thing
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      char* new_storage = new char[new_storage_size];
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // copy still useful info to the new buffer.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memcpy(new_storage, read_ptr, read_size);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // reset pointers.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      read_idx_ = 0;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      write_idx_ = read_size;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete[] storage_;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      storage_ = new_storage;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      storage_size_ = new_storage_size;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// removes the oldest 'amount_to_consume' characters.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SimpleBuffer::AdvanceReadablePtr(int amount_to_advance) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  read_idx_ += amount_to_advance;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (read_idx_ > storage_size_) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    read_idx_ = storage_size_;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Moves the internal pointers around such that the
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// amount of data specified here is expected to
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// already be resident (as if it was Written)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void SimpleBuffer::AdvanceWritablePtr(int amount_to_advance) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  write_idx_ += amount_to_advance;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (write_idx_ > storage_size_) {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    write_idx_ = storage_size_;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
209