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.
5 #include "net/tools/flip_server/ring_buffer.h"
6 #include "base/logging.h"
10 RingBuffer::RingBuffer(int buffer_size
)
11 : buffer_(new char[buffer_size
]),
12 buffer_size_(buffer_size
),
18 RingBuffer::~RingBuffer() {}
20 ////////////////////////////////////////////////////////////////////////////////
22 int RingBuffer::ReadableBytes() const {
26 ////////////////////////////////////////////////////////////////////////////////
28 int RingBuffer::BufferSize() const {
32 ////////////////////////////////////////////////////////////////////////////////
34 int RingBuffer::BytesFree() const {
35 return BufferSize() - ReadableBytes();
38 ////////////////////////////////////////////////////////////////////////////////
40 bool RingBuffer::Empty() const {
41 return ReadableBytes() == 0;
44 ////////////////////////////////////////////////////////////////////////////////
46 bool RingBuffer::Full() const {
47 return ReadableBytes() == BufferSize();
50 ////////////////////////////////////////////////////////////////////////////////
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
) {
59 GetWritablePtr(&wptr
, &wsize
);
60 int bytes_remaining
= size
;
61 int bytes_written
= 0;
63 while (wsize
&& bytes_remaining
) {
64 if (wsize
> bytes_remaining
) {
65 wsize
= bytes_remaining
;
67 memcpy(wptr
, bytes
+ bytes_written
, wsize
);
68 bytes_written
+= wsize
;
69 bytes_remaining
-= wsize
;
70 AdvanceWritablePtr(wsize
);
71 GetWritablePtr(&wptr
, &wsize
);
75 const char* p
= bytes
;
77 int bytes_to_write
= size
;
78 int bytes_available
= BytesFree();
79 if (bytes_available
< bytes_to_write
) {
80 bytes_to_write
= bytes_available
;
82 const char* end
= bytes
+ bytes_to_write
;
85 this->buffer_
[this->write_idx_
] = *p
;
88 if (this->write_idx_
>= this->buffer_size_
) {
92 bytes_used_
+= bytes_to_write
;
93 return bytes_to_write
;
97 ////////////////////////////////////////////////////////////////////////////////
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_
;
104 if (bytes_used_
== buffer_size_
) {
106 } else if (read_idx_
> write_idx_
) {
107 *size
= read_idx_
- write_idx_
;
109 *size
= buffer_size_
- write_idx_
;
113 ////////////////////////////////////////////////////////////////////////////////
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_
;
120 if (bytes_used_
== 0) {
122 } else if (write_idx_
> read_idx_
) {
123 *size
= write_idx_
- read_idx_
;
125 *size
= buffer_size_
- read_idx_
;
129 ////////////////////////////////////////////////////////////////////////////////
131 // returns the number of bytes read into
132 int RingBuffer::Read(char* bytes
, int size
) {
137 GetReadablePtr(&rptr
, &rsize
);
138 int bytes_remaining
= size
;
141 while (rsize
&& bytes_remaining
) {
142 if (rsize
> bytes_remaining
) {
143 rsize
= bytes_remaining
;
145 memcpy(bytes
+ bytes_read
, rptr
, rsize
);
147 bytes_remaining
-= rsize
;
148 AdvanceReadablePtr(rsize
);
149 GetReadablePtr(&rptr
, &rsize
);
154 int bytes_to_read
= size
;
155 int bytes_used
= ReadableBytes();
156 if (bytes_used
< bytes_to_read
) {
157 bytes_to_read
= bytes_used
;
159 char* end
= bytes
+ bytes_to_read
;
162 *p
= this->buffer_
[this->read_idx_
];
165 if (this->read_idx_
>= this->buffer_size_
) {
169 this->bytes_used_
-= bytes_to_read
;
170 return bytes_to_read
;
174 ////////////////////////////////////////////////////////////////////////////////
176 void RingBuffer::Clear() {
182 ////////////////////////////////////////////////////////////////////////////////
184 bool RingBuffer::Reserve(int size
) {
186 char* write_ptr
= NULL
;
188 GetWritablePtr(&write_ptr
, &write_size
);
190 if (write_size
< size
) {
191 char* read_ptr
= NULL
;
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
);
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);
214 Resize(ReadableBytes() + size
);
217 DCHECK_LE(size
, buffer_size_
- write_idx_
);
221 ////////////////////////////////////////////////////////////////////////////////
223 void RingBuffer::AdvanceReadablePtr(int amount_to_consume
) {
224 CHECK_GE(amount_to_consume
, 0);
225 if (amount_to_consume
>= bytes_used_
) {
229 read_idx_
+= amount_to_consume
;
230 read_idx_
%= buffer_size_
;
231 bytes_used_
-= amount_to_consume
;
234 ////////////////////////////////////////////////////////////////////////////////
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
;
244 ////////////////////////////////////////////////////////////////////////////////
246 void RingBuffer::Resize(int buffer_size
) {
247 CHECK_GE(buffer_size
, 0);
248 if (buffer_size
== buffer_size_
) return;
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
);
256 int bytes_written
= 0;
257 int bytes_used
= bytes_used_
;
261 GetReadablePtr(&ptr
, &size
);
262 if (size
== 0) break;
263 if (size
> buffer_size
) {
266 memcpy(new_buffer
+ bytes_written
, ptr
, size
);
267 bytes_written
+= size
;
268 AdvanceReadablePtr(size
);
270 buffer_
.reset(new_buffer
);
272 buffer_size_
= buffer_size
;
273 bytes_used_
= bytes_used
;
275 write_idx_
= bytes_used_
% buffer_size_
;