- add sources.
[platform/framework/web/crosswalk.git] / src / net / tools / flip_server / ring_buffer.cc
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
18 RingBuffer::~RingBuffer() {}
19
20 ////////////////////////////////////////////////////////////////////////////////
21
22 int RingBuffer::ReadableBytes() const {
23   return bytes_used_;
24 }
25
26 ////////////////////////////////////////////////////////////////////////////////
27
28 int RingBuffer::BufferSize() const {
29   return buffer_size_;
30 }
31
32 ////////////////////////////////////////////////////////////////////////////////
33
34 int RingBuffer::BytesFree() const {
35   return BufferSize() - ReadableBytes();
36 }
37
38 ////////////////////////////////////////////////////////////////////////////////
39
40 bool RingBuffer::Empty() const {
41   return ReadableBytes() == 0;
42 }
43
44 ////////////////////////////////////////////////////////////////////////////////
45
46 bool RingBuffer::Full() const {
47   return ReadableBytes() == BufferSize();
48 }
49
50 ////////////////////////////////////////////////////////////////////////////////
51
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) {
55   CHECK_GE(size, 0);
56 #if 1
57   char* wptr;
58   int wsize;
59   GetWritablePtr(&wptr, &wsize);
60   int bytes_remaining = size;
61   int bytes_written = 0;
62
63   while (wsize && bytes_remaining) {
64     if (wsize > bytes_remaining) {
65       wsize = bytes_remaining;
66     }
67     memcpy(wptr, bytes + bytes_written, wsize);
68     bytes_written += wsize;
69     bytes_remaining -= wsize;
70     AdvanceWritablePtr(wsize);
71     GetWritablePtr(&wptr, &wsize);
72   }
73   return bytes_written;
74 #else
75   const char* p = bytes;
76
77   int bytes_to_write = size;
78   int bytes_available = BytesFree();
79   if (bytes_available < bytes_to_write) {
80     bytes_to_write = bytes_available;
81   }
82   const char* end = bytes + bytes_to_write;
83
84   while (p != end) {
85     this->buffer_[this->write_idx_] = *p;
86     ++p;
87     ++this->write_idx_;
88     if (this->write_idx_ >= this->buffer_size_) {
89       this->write_idx_ = 0;
90     }
91   }
92   bytes_used_ += bytes_to_write;
93   return bytes_to_write;
94 #endif
95 }
96
97 ////////////////////////////////////////////////////////////////////////////////
98
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_;
103
104   if (bytes_used_ == buffer_size_) {
105     *size = 0;
106   } else if (read_idx_ > write_idx_) {
107     *size = read_idx_ - write_idx_;
108   } else {
109     *size = buffer_size_ - write_idx_;
110   }
111 }
112
113 ////////////////////////////////////////////////////////////////////////////////
114
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_;
119
120   if (bytes_used_ == 0) {
121     *size = 0;
122   } else if (write_idx_ > read_idx_) {
123     *size = write_idx_ - read_idx_;
124   } else {
125     *size = buffer_size_ - read_idx_;
126   }
127 }
128
129 ////////////////////////////////////////////////////////////////////////////////
130
131 // returns the number of bytes read into
132 int RingBuffer::Read(char* bytes, int size) {
133   CHECK_GE(size, 0);
134 #if 1
135   char* rptr;
136   int rsize;
137   GetReadablePtr(&rptr, &rsize);
138   int bytes_remaining = size;
139   int bytes_read = 0;
140
141   while (rsize && bytes_remaining) {
142     if (rsize > bytes_remaining) {
143       rsize = bytes_remaining;
144     }
145     memcpy(bytes + bytes_read, rptr, rsize);
146     bytes_read += rsize;
147     bytes_remaining -= rsize;
148     AdvanceReadablePtr(rsize);
149     GetReadablePtr(&rptr, &rsize);
150   }
151   return bytes_read;
152 #else
153   char* p = bytes;
154   int bytes_to_read = size;
155   int bytes_used = ReadableBytes();
156   if (bytes_used < bytes_to_read) {
157     bytes_to_read = bytes_used;
158   }
159   char* end = bytes + bytes_to_read;
160
161   while (p != end) {
162     *p = this->buffer_[this->read_idx_];
163     ++p;
164     ++this->read_idx_;
165     if (this->read_idx_ >= this->buffer_size_) {
166       this->read_idx_ = 0;
167     }
168   }
169   this->bytes_used_ -= bytes_to_read;
170   return bytes_to_read;
171 #endif
172 }
173
174 ////////////////////////////////////////////////////////////////////////////////
175
176 void RingBuffer::Clear() {
177   bytes_used_ = 0;
178   write_idx_ = 0;
179   read_idx_ = 0;
180 }
181
182 ////////////////////////////////////////////////////////////////////////////////
183
184 bool RingBuffer::Reserve(int size) {
185   DCHECK(size > 0);
186   char* write_ptr = NULL;
187   int write_size = 0;
188   GetWritablePtr(&write_ptr, &write_size);
189
190   if (write_size < size) {
191     char* read_ptr = NULL;
192     int read_size = 0;
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);
205         read_idx_ = 0;
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);
210         read_idx_ = 0;
211         write_idx_ = 0;
212       }
213     } else {
214       Resize(ReadableBytes() + size);
215     }
216   }
217   DCHECK_LE(size, buffer_size_ - write_idx_);
218   return true;
219 }
220
221 ////////////////////////////////////////////////////////////////////////////////
222
223 void RingBuffer::AdvanceReadablePtr(int amount_to_consume) {
224   CHECK_GE(amount_to_consume, 0);
225   if (amount_to_consume >= bytes_used_) {
226     Clear();
227     return;
228   }
229   read_idx_ += amount_to_consume;
230   read_idx_ %= buffer_size_;
231   bytes_used_ -= amount_to_consume;
232 }
233
234 ////////////////////////////////////////////////////////////////////////////////
235
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;
242 }
243
244 ////////////////////////////////////////////////////////////////////////////////
245
246 void RingBuffer::Resize(int buffer_size) {
247   CHECK_GE(buffer_size, 0);
248   if (buffer_size == buffer_size_) return;
249
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);
254   }
255
256   int bytes_written = 0;
257   int bytes_used = bytes_used_;
258   while (true) {
259     int size;
260     char* ptr;
261     GetReadablePtr(&ptr, &size);
262     if (size == 0) break;
263     if (size > buffer_size) {
264       size = buffer_size;
265     }
266     memcpy(new_buffer + bytes_written, ptr, size);
267     bytes_written += size;
268     AdvanceReadablePtr(size);
269   }
270   buffer_.reset(new_buffer);
271
272   buffer_size_ = buffer_size;
273   bytes_used_ = bytes_used;
274   read_idx_ = 0;
275   write_idx_ = bytes_used_ % buffer_size_;
276 }
277
278 }  // namespace net
279