summaryrefslogtreecommitdiff
path: root/chromium/net/tools/flip_server/simple_buffer.cc
blob: d94153b29ec9000d1f1caedf9ec46fccaf85175b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/tools/flip_server/simple_buffer.h"
#include "base/logging.h"

// Some of the following member functions are marked inlined, even though they
// are virtual. This may seem counter-intuitive, since virtual functions are
// generally not eligible for inlining. Profiling results indicate that these
// large amount of runtime is spent on virtual function dispatch on these
// simple functions. They are virtual because of the interface this class
// inherits from. However, it is very unlikely that anyone will sub-class
// SimpleBuffer and change their implementation. To get rid of this baggage,
// internal implementation (e.g., Write) explicitly use SimpleBuffer:: to
// qualify the method calls, thus disabling the virtual dispatch and enable
// inlining.

namespace net {

static const int kInitialSimpleBufferSize = 10;

SimpleBuffer::SimpleBuffer()
  : storage_(new char[kInitialSimpleBufferSize]),
    write_idx_(0),
    read_idx_(0),
    storage_size_(kInitialSimpleBufferSize) {
}

SimpleBuffer::SimpleBuffer(int size)
  : write_idx_(0),
    read_idx_(0),
    storage_size_(size) {
  // Callers may try to allocate overly large blocks, but negative sizes are
  // obviously wrong.
  CHECK_GE(size, 0);
  storage_ = new char[size];
}

SimpleBuffer::~SimpleBuffer() {
  delete[] storage_;
}


////////////////////////////////////////////////////////////////////////////////

int SimpleBuffer::ReadableBytes() const {
  return write_idx_ - read_idx_;
}

////////////////////////////////////////////////////////////////////////////////

std::string SimpleBuffer::str() const {
  std::string s;
  char * readable_ptr;
  int readable_size;
  GetReadablePtr(&readable_ptr, &readable_size);
  s.append(readable_ptr, readable_ptr + readable_size);
  return s;
}

////////////////////////////////////////////////////////////////////////////////

int SimpleBuffer::BufferSize() const {
  return storage_size_;
}

////////////////////////////////////////////////////////////////////////////////

inline int SimpleBuffer::BytesFree() const {
  return (storage_size_ - write_idx_);
}

////////////////////////////////////////////////////////////////////////////////

bool SimpleBuffer::Empty() const {
  return (read_idx_ == write_idx_);
}

////////////////////////////////////////////////////////////////////////////////

bool SimpleBuffer::Full() const {
  return ((write_idx_ == storage_size_) && (read_idx_ != write_idx_));
}

////////////////////////////////////////////////////////////////////////////////

// returns the number of characters written.
// appends up-to-'size' bytes to the simplebuffer.
int SimpleBuffer::Write(const char* bytes, int size) {
  bool has_room = ((storage_size_ - write_idx_) >= size);
  if (!has_room) {
    (void)Reserve(size);
  }
  memcpy(storage_ + write_idx_, bytes, size);
  SimpleBuffer::AdvanceWritablePtr(size);
  return size;
}

////////////////////////////////////////////////////////////////////////////////

// stores a pointer into the simple buffer in *ptr,
// and stores the number of characters which are allowed
// to be written in *size.
inline void SimpleBuffer::GetWritablePtr(char **ptr, int* size) const {
  *ptr = storage_ + write_idx_;
  *size = SimpleBuffer::BytesFree();
}

////////////////////////////////////////////////////////////////////////////////

// stores a pointer into the simple buffer in *ptr,
// and stores the number of characters which are allowed
// to be read in *size.
void SimpleBuffer::GetReadablePtr(char **ptr, int* size) const {
  *ptr = storage_ + read_idx_;
  *size = write_idx_ - read_idx_;
}

////////////////////////////////////////////////////////////////////////////////

// returns the number of bytes read into 'bytes'
int SimpleBuffer::Read(char* bytes, int size) {
  char * read_ptr = NULL;
  int read_size = 0;
  GetReadablePtr(&read_ptr, &read_size);
  if (read_size > size) {
    read_size = size;
  }
  memcpy(bytes, read_ptr, read_size);
  AdvanceReadablePtr(read_size);
  return read_size;
}

////////////////////////////////////////////////////////////////////////////////

// removes all data from the simple buffer
void SimpleBuffer::Clear() {
  read_idx_ = write_idx_ = 0;
}

////////////////////////////////////////////////////////////////////////////////

// Attempts to reserve a contiguous block of buffer space by either reclaiming
// old data that is already read, and reallocate large storage as needed.
bool SimpleBuffer::Reserve(int size) {
  if (size > 0 && BytesFree() < size) {
    char * read_ptr = NULL;
    int read_size = 0;
    GetReadablePtr(&read_ptr, &read_size);

    if (read_size + size <= BufferSize()) {
      // Can reclaim space from already read bytes by shifting
      memmove(storage_, read_ptr, read_size);
      read_idx_ = 0;
      write_idx_ = read_size;
      CHECK_GE(BytesFree(), size);
    } else {
      // what we need is to have at least size bytes available for writing.
      // This implies that the buffer needs to be at least size bytes +
      // read_size bytes long. Since we want linear time extensions in the case
      // that we're extending this thing repeatedly, we should extend to twice
      // the current size (if that is big enough), or the size + read_size
      // bytes, whichever is larger.
      int new_storage_size = 2 * storage_size_;
      if (new_storage_size < size + read_size) {
        new_storage_size = size + read_size;
      }

      // have to extend the thing
      char* new_storage = new char[new_storage_size];

      // copy still useful info to the new buffer.
      memcpy(new_storage, read_ptr, read_size);
      // reset pointers.
      read_idx_ = 0;
      write_idx_ = read_size;
      delete[] storage_;
      storage_ = new_storage;
      storage_size_ = new_storage_size;
    }
  }
  return true;
}

////////////////////////////////////////////////////////////////////////////////

// removes the oldest 'amount_to_consume' characters.
void SimpleBuffer::AdvanceReadablePtr(int amount_to_advance) {
  read_idx_ += amount_to_advance;
  if (read_idx_ > storage_size_) {
    read_idx_ = storage_size_;
  }
}

////////////////////////////////////////////////////////////////////////////////

// Moves the internal pointers around such that the
// amount of data specified here is expected to
// already be resident (as if it was Written)
inline void SimpleBuffer::AdvanceWritablePtr(int amount_to_advance) {
  write_idx_ += amount_to_advance;
  if (write_idx_ > storage_size_) {
    write_idx_ = storage_size_;
  }
}

}  // namespace net