OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "net/tools/flip_server/ring_buffer.h" | |
6 #include "base/logging.h" | |
7 | |
8 namespace net { | |
9 | |
10 RingBuffer::RingBuffer(int buffer_size) | |
11 : buffer_(new char[buffer_size]), | |
12 buffer_size_(buffer_size), | |
13 bytes_used_(0), | |
14 read_idx_(0), | |
15 write_idx_(0) {} | |
16 | |
17 RingBuffer::~RingBuffer() {} | |
18 | |
19 int RingBuffer::ReadableBytes() const { return bytes_used_; } | |
20 | |
21 int RingBuffer::BufferSize() const { return buffer_size_; } | |
22 | |
23 int RingBuffer::BytesFree() const { return BufferSize() - ReadableBytes(); } | |
24 | |
25 bool RingBuffer::Empty() const { return ReadableBytes() == 0; } | |
26 | |
27 bool RingBuffer::Full() const { return ReadableBytes() == BufferSize(); } | |
28 | |
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) { | |
32 CHECK_GE(size, 0); | |
33 #if 1 | |
34 char* wptr; | |
35 int wsize; | |
36 GetWritablePtr(&wptr, &wsize); | |
37 int bytes_remaining = size; | |
38 int bytes_written = 0; | |
39 | |
40 while (wsize && bytes_remaining) { | |
41 if (wsize > bytes_remaining) { | |
42 wsize = bytes_remaining; | |
43 } | |
44 memcpy(wptr, bytes + bytes_written, wsize); | |
45 bytes_written += wsize; | |
46 bytes_remaining -= wsize; | |
47 AdvanceWritablePtr(wsize); | |
48 GetWritablePtr(&wptr, &wsize); | |
49 } | |
50 return bytes_written; | |
51 #else | |
52 const char* p = bytes; | |
53 | |
54 int bytes_to_write = size; | |
55 int bytes_available = BytesFree(); | |
56 if (bytes_available < bytes_to_write) { | |
57 bytes_to_write = bytes_available; | |
58 } | |
59 const char* end = bytes + bytes_to_write; | |
60 | |
61 while (p != end) { | |
62 this->buffer_[this->write_idx_] = *p; | |
63 ++p; | |
64 ++this->write_idx_; | |
65 if (this->write_idx_ >= this->buffer_size_) { | |
66 this->write_idx_ = 0; | |
67 } | |
68 } | |
69 bytes_used_ += bytes_to_write; | |
70 return bytes_to_write; | |
71 #endif | |
72 } | |
73 | |
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_; | |
78 | |
79 if (bytes_used_ == buffer_size_) { | |
80 *size = 0; | |
81 } else if (read_idx_ > write_idx_) { | |
82 *size = read_idx_ - write_idx_; | |
83 } else { | |
84 *size = buffer_size_ - write_idx_; | |
85 } | |
86 } | |
87 | |
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_; | |
92 | |
93 if (bytes_used_ == 0) { | |
94 *size = 0; | |
95 } else if (write_idx_ > read_idx_) { | |
96 *size = write_idx_ - read_idx_; | |
97 } else { | |
98 *size = buffer_size_ - read_idx_; | |
99 } | |
100 } | |
101 | |
102 // returns the number of bytes read into | |
103 int RingBuffer::Read(char* bytes, int size) { | |
104 CHECK_GE(size, 0); | |
105 #if 1 | |
106 char* rptr; | |
107 int rsize; | |
108 GetReadablePtr(&rptr, &rsize); | |
109 int bytes_remaining = size; | |
110 int bytes_read = 0; | |
111 | |
112 while (rsize && bytes_remaining) { | |
113 if (rsize > bytes_remaining) { | |
114 rsize = bytes_remaining; | |
115 } | |
116 memcpy(bytes + bytes_read, rptr, rsize); | |
117 bytes_read += rsize; | |
118 bytes_remaining -= rsize; | |
119 AdvanceReadablePtr(rsize); | |
120 GetReadablePtr(&rptr, &rsize); | |
121 } | |
122 return bytes_read; | |
123 #else | |
124 char* p = bytes; | |
125 int bytes_to_read = size; | |
126 int bytes_used = ReadableBytes(); | |
127 if (bytes_used < bytes_to_read) { | |
128 bytes_to_read = bytes_used; | |
129 } | |
130 char* end = bytes + bytes_to_read; | |
131 | |
132 while (p != end) { | |
133 *p = this->buffer_[this->read_idx_]; | |
134 ++p; | |
135 ++this->read_idx_; | |
136 if (this->read_idx_ >= this->buffer_size_) { | |
137 this->read_idx_ = 0; | |
138 } | |
139 } | |
140 this->bytes_used_ -= bytes_to_read; | |
141 return bytes_to_read; | |
142 #endif | |
143 } | |
144 | |
145 void RingBuffer::Clear() { | |
146 bytes_used_ = 0; | |
147 write_idx_ = 0; | |
148 read_idx_ = 0; | |
149 } | |
150 | |
151 bool RingBuffer::Reserve(int size) { | |
152 DCHECK_GT(size, 0); | |
153 char* write_ptr = NULL; | |
154 int write_size = 0; | |
155 GetWritablePtr(&write_ptr, &write_size); | |
156 | |
157 if (write_size < size) { | |
158 char* read_ptr = NULL; | |
159 int read_size = 0; | |
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); | |
172 read_idx_ = 0; | |
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); | |
177 read_idx_ = 0; | |
178 write_idx_ = 0; | |
179 } | |
180 } else { | |
181 Resize(ReadableBytes() + size); | |
182 } | |
183 } | |
184 DCHECK_LE(size, buffer_size_ - write_idx_); | |
185 return true; | |
186 } | |
187 | |
188 void RingBuffer::AdvanceReadablePtr(int amount_to_consume) { | |
189 CHECK_GE(amount_to_consume, 0); | |
190 if (amount_to_consume >= bytes_used_) { | |
191 Clear(); | |
192 return; | |
193 } | |
194 read_idx_ += amount_to_consume; | |
195 read_idx_ %= buffer_size_; | |
196 bytes_used_ -= amount_to_consume; | |
197 } | |
198 | |
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; | |
205 } | |
206 | |
207 void RingBuffer::Resize(int buffer_size) { | |
208 CHECK_GE(buffer_size, 0); | |
209 if (buffer_size == buffer_size_) | |
210 return; | |
211 | |
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); | |
216 } | |
217 | |
218 int bytes_written = 0; | |
219 int bytes_used = bytes_used_; | |
220 while (true) { | |
221 int size; | |
222 char* ptr; | |
223 GetReadablePtr(&ptr, &size); | |
224 if (size == 0) | |
225 break; | |
226 if (size > buffer_size) { | |
227 size = buffer_size; | |
228 } | |
229 memcpy(new_buffer + bytes_written, ptr, size); | |
230 bytes_written += size; | |
231 AdvanceReadablePtr(size); | |
232 } | |
233 buffer_.reset(new_buffer); | |
234 | |
235 buffer_size_ = buffer_size; | |
236 bytes_used_ = bytes_used; | |
237 read_idx_ = 0; | |
238 write_idx_ = bytes_used_ % buffer_size_; | |
239 } | |
240 | |
241 } // namespace net | |
OLD | NEW |