simple_buffer.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1// Copyright 2013 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/balsa/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
19namespace net {
20
21static const int kInitialSimpleBufferSize = 10;
22
23SimpleBuffer::SimpleBuffer()
24  : storage_(new char[kInitialSimpleBufferSize]),
25    write_idx_(0),
26    read_idx_(0),
27    storage_size_(kInitialSimpleBufferSize) {
28}
29
30SimpleBuffer::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
40SimpleBuffer::~SimpleBuffer() {
41  delete[] storage_;
42}
43
44
45////////////////////////////////////////////////////////////////////////////////
46
47int SimpleBuffer::ReadableBytes() const {
48  return write_idx_ - read_idx_;
49}
50
51////////////////////////////////////////////////////////////////////////////////
52
53std::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
64int SimpleBuffer::BufferSize() const {
65  return storage_size_;
66}
67
68////////////////////////////////////////////////////////////////////////////////
69
70inline int SimpleBuffer::BytesFree() const {
71  return (storage_size_ - write_idx_);
72}
73
74////////////////////////////////////////////////////////////////////////////////
75
76bool SimpleBuffer::Empty() const {
77  return (read_idx_ == write_idx_);
78}
79
80////////////////////////////////////////////////////////////////////////////////
81
82bool 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.
90int 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.
105inline 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.
115void 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'
123int 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
138void 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.
146bool 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.
189void 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)
201inline 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