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
),
17 RingBuffer::~RingBuffer() {}
19 int RingBuffer::ReadableBytes() const { return bytes_used_
; }
21 int RingBuffer::BufferSize() const { return buffer_size_
; }
23 int RingBuffer::BytesFree() const { return BufferSize() - ReadableBytes(); }
25 bool RingBuffer::Empty() const { return ReadableBytes() == 0; }
27 bool RingBuffer::Full() const { return ReadableBytes() == BufferSize(); }
29 // Returns the number of characters written.
30 // Appends up-to-'size' bytes to the ringbuffer.
31 int RingBuffer::Write(const char* bytes
, int size
) {
36 GetWritablePtr(&wptr
, &wsize
);
37 int bytes_remaining
= size
;
38 int bytes_written
= 0;
40 while (wsize
&& bytes_remaining
) {
41 if (wsize
> bytes_remaining
) {
42 wsize
= bytes_remaining
;
44 memcpy(wptr
, bytes
+ bytes_written
, wsize
);
45 bytes_written
+= wsize
;
46 bytes_remaining
-= wsize
;
47 AdvanceWritablePtr(wsize
);
48 GetWritablePtr(&wptr
, &wsize
);
52 const char* p
= bytes
;
54 int bytes_to_write
= size
;
55 int bytes_available
= BytesFree();
56 if (bytes_available
< bytes_to_write
) {
57 bytes_to_write
= bytes_available
;
59 const char* end
= bytes
+ bytes_to_write
;
62 this->buffer_
[this->write_idx_
] = *p
;
65 if (this->write_idx_
>= this->buffer_size_
) {
69 bytes_used_
+= bytes_to_write
;
70 return bytes_to_write
;
74 // Sets *ptr to the beginning of writable memory, and sets *size to the size
75 // available for writing using this pointer.
76 void RingBuffer::GetWritablePtr(char** ptr
, int* size
) const {
77 *ptr
= buffer_
.get() + write_idx_
;
79 if (bytes_used_
== buffer_size_
) {
81 } else if (read_idx_
> write_idx_
) {
82 *size
= read_idx_
- write_idx_
;
84 *size
= buffer_size_
- write_idx_
;
88 // Sets *ptr to the beginning of readable memory, and sets *size to the size
89 // available for reading using this pointer.
90 void RingBuffer::GetReadablePtr(char** ptr
, int* size
) const {
91 *ptr
= buffer_
.get() + read_idx_
;
93 if (bytes_used_
== 0) {
95 } else if (write_idx_
> read_idx_
) {
96 *size
= write_idx_
- read_idx_
;
98 *size
= buffer_size_
- read_idx_
;
102 // returns the number of bytes read into
103 int RingBuffer::Read(char* bytes
, int size
) {
108 GetReadablePtr(&rptr
, &rsize
);
109 int bytes_remaining
= size
;
112 while (rsize
&& bytes_remaining
) {
113 if (rsize
> bytes_remaining
) {
114 rsize
= bytes_remaining
;
116 memcpy(bytes
+ bytes_read
, rptr
, rsize
);
118 bytes_remaining
-= rsize
;
119 AdvanceReadablePtr(rsize
);
120 GetReadablePtr(&rptr
, &rsize
);
125 int bytes_to_read
= size
;
126 int bytes_used
= ReadableBytes();
127 if (bytes_used
< bytes_to_read
) {
128 bytes_to_read
= bytes_used
;
130 char* end
= bytes
+ bytes_to_read
;
133 *p
= this->buffer_
[this->read_idx_
];
136 if (this->read_idx_
>= this->buffer_size_
) {
140 this->bytes_used_
-= bytes_to_read
;
141 return bytes_to_read
;
145 void RingBuffer::Clear() {
151 bool RingBuffer::Reserve(int size
) {
153 char* write_ptr
= NULL
;
155 GetWritablePtr(&write_ptr
, &write_size
);
157 if (write_size
< size
) {
158 char* read_ptr
= NULL
;
160 GetReadablePtr(&read_ptr
, &read_size
);
161 if (size
<= BytesFree()) {
162 // The fact that the total Free size is big enough but writable size is
163 // not means that the writeable region is broken into two pieces: only
164 // possible if the read_idx < write_idx. If write_idx < read_idx, then
165 // the writeable region must be contiguous: [write_idx, read_idx). There
166 // is no work to be done for the latter.
167 DCHECK_LE(read_idx_
, write_idx_
);
168 DCHECK_EQ(read_size
, ReadableBytes());
169 if (read_idx_
< write_idx_
) {
170 // Writeable area fragmented, consolidate it.
171 memmove(buffer_
.get(), read_ptr
, read_size
);
173 write_idx_
= read_size
;
174 } else if (read_idx_
== write_idx_
) {
175 // No unconsumed data in the buffer, simply reset the indexes.
176 DCHECK_EQ(ReadableBytes(), 0);
181 Resize(ReadableBytes() + size
);
184 DCHECK_LE(size
, buffer_size_
- write_idx_
);
188 void RingBuffer::AdvanceReadablePtr(int amount_to_consume
) {
189 CHECK_GE(amount_to_consume
, 0);
190 if (amount_to_consume
>= bytes_used_
) {
194 read_idx_
+= amount_to_consume
;
195 read_idx_
%= buffer_size_
;
196 bytes_used_
-= amount_to_consume
;
199 void RingBuffer::AdvanceWritablePtr(int amount_to_produce
) {
200 CHECK_GE(amount_to_produce
, 0);
201 CHECK_LE(amount_to_produce
, BytesFree());
202 write_idx_
+= amount_to_produce
;
203 write_idx_
%= buffer_size_
;
204 bytes_used_
+= amount_to_produce
;
207 void RingBuffer::Resize(int buffer_size
) {
208 CHECK_GE(buffer_size
, 0);
209 if (buffer_size
== buffer_size_
)
212 char* new_buffer
= new char[buffer_size
];
213 if (buffer_size
< bytes_used_
) {
214 // consume the oldest data.
215 AdvanceReadablePtr(bytes_used_
- buffer_size
);
218 int bytes_written
= 0;
219 int bytes_used
= bytes_used_
;
223 GetReadablePtr(&ptr
, &size
);
226 if (size
> buffer_size
) {
229 memcpy(new_buffer
+ bytes_written
, ptr
, size
);
230 bytes_written
+= size
;
231 AdvanceReadablePtr(size
);
233 buffer_
.reset(new_buffer
);
235 buffer_size_
= buffer_size
;
236 bytes_used_
= bytes_used
;
238 write_idx_
= bytes_used_
% buffer_size_
;