Upstream version 11.40.277.0
[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 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