- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / common / partial_circular_buffer.cc
1 // Copyright 2013 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 "chrome/common/partial_circular_buffer.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10
11 namespace {
12
13 inline uint32 Min3(uint32 a, uint32 b, uint32 c) {
14   return std::min(a, std::min(b, c));
15 }
16
17 }  // namespace
18
19 PartialCircularBuffer::PartialCircularBuffer(void* buffer,
20                                              uint32 buffer_size)
21     : buffer_data_(reinterpret_cast<BufferData*>(buffer)),
22       memory_buffer_size_(buffer_size),
23       data_size_(0),
24       position_(0),
25       total_read_(0) {
26   uint32 header_size =
27       buffer_data_->data - reinterpret_cast<uint8*>(buffer_data_);
28   data_size_ = memory_buffer_size_ - header_size;
29
30   DCHECK(buffer_data_);
31   DCHECK_GE(memory_buffer_size_, header_size);
32   DCHECK_LE(buffer_data_->total_written, data_size_);
33   DCHECK_LT(buffer_data_->wrap_position, data_size_);
34   DCHECK_LT(buffer_data_->end_position, data_size_);
35 }
36
37 PartialCircularBuffer::PartialCircularBuffer(void* buffer,
38                                              uint32 buffer_size,
39                                              uint32 wrap_position,
40                                              bool append)
41     : buffer_data_(reinterpret_cast<BufferData*>(buffer)),
42       memory_buffer_size_(buffer_size),
43       data_size_(0),
44       position_(0),
45       total_read_(0) {
46   uint32 header_size =
47       buffer_data_->data - reinterpret_cast<uint8*>(buffer_data_);
48   data_size_ = memory_buffer_size_ - header_size;
49
50   DCHECK(buffer_data_);
51   DCHECK_GE(memory_buffer_size_, header_size);
52
53   if (append) {
54     DCHECK_LT(buffer_data_->wrap_position, data_size_);
55     position_ = buffer_data_->end_position;
56   } else {
57     DCHECK_LT(wrap_position, data_size_);
58     buffer_data_->total_written = 0;
59     buffer_data_->wrap_position = wrap_position;
60     buffer_data_->end_position = 0;
61   }
62 }
63
64 uint32 PartialCircularBuffer::Read(void* buffer, uint32 buffer_size) {
65   DCHECK(buffer_data_);
66   if (total_read_ >= buffer_data_->total_written)
67     return 0;
68
69   uint8* buffer_uint8 = reinterpret_cast<uint8*>(buffer);
70   uint32 read = 0;
71
72   // Read from beginning part.
73   if (position_ < buffer_data_->wrap_position) {
74     uint32 to_wrap_pos = buffer_data_->wrap_position - position_;
75     uint32 to_eow = buffer_data_->total_written - total_read_;
76     uint32 to_read = Min3(buffer_size, to_wrap_pos, to_eow);
77     memcpy(buffer_uint8, buffer_data_->data + position_, to_read);
78     position_ += to_read;
79     total_read_ += to_read;
80     read += to_read;
81     if (position_ == buffer_data_->wrap_position &&
82         buffer_data_->total_written == data_size_) {
83       // We've read all the beginning part, set the position to the middle part.
84       // (The second condition above checks if the wrapping part is filled, i.e.
85       // writing has wrapped.)
86       position_ = buffer_data_->end_position;
87     }
88     if (read >= buffer_size) {
89       DCHECK_EQ(read, buffer_size);
90       return read;
91     }
92     if (read >= to_eow) {
93       DCHECK_EQ(read, to_eow);
94       DCHECK_EQ(total_read_, buffer_data_->total_written);
95       return read;
96     }
97   }
98
99   // Read from middle part.
100   DCHECK_GE(position_, buffer_data_->wrap_position);
101   if (position_ >= buffer_data_->end_position) {
102     uint32 remaining_buffer_size = buffer_size - read;
103     uint32 to_eof = data_size_ - position_;
104     uint32 to_eow = buffer_data_->total_written - total_read_;
105     uint32 to_read = Min3(remaining_buffer_size, to_eof, to_eow);
106     memcpy(buffer_uint8 + read, buffer_data_->data + position_, to_read);
107     position_ += to_read;
108     total_read_ += to_read;
109     read += to_read;
110     if (position_ == data_size_) {
111       // We've read all the middle part, set position to the end part.
112       position_ = buffer_data_->wrap_position;
113     }
114     if (read >= buffer_size) {
115       DCHECK_EQ(read, buffer_size);
116       return read;
117     }
118     if (total_read_ >= buffer_data_->total_written) {
119       DCHECK_EQ(total_read_, buffer_data_->total_written);
120       return read;
121     }
122   }
123
124   // Read from end part.
125   DCHECK_GE(position_, buffer_data_->wrap_position);
126   DCHECK_LT(position_, buffer_data_->end_position);
127   uint32 remaining_buffer_size = buffer_size - read;
128   uint32 to_eob = buffer_data_->end_position - position_;
129   uint32 to_eow = buffer_data_->total_written - total_read_;
130   uint32 to_read = Min3(remaining_buffer_size, to_eob, to_eow);
131   memcpy(buffer_uint8 + read, buffer_data_->data + position_, to_read);
132   position_ += to_read;
133   total_read_ += to_read;
134   read += to_read;
135   DCHECK_LE(read, buffer_size);
136   DCHECK_LE(total_read_, buffer_data_->total_written);
137   return read;
138 }
139
140 void PartialCircularBuffer::Write(const void* buffer, uint32 buffer_size) {
141   DCHECK(buffer_data_);
142   uint32 position_before_write = position_;
143
144   uint32 to_eof = data_size_ - position_;
145   uint32 to_write = std::min(buffer_size, to_eof);
146   DoWrite(buffer_data_->data + position_, buffer, to_write);
147   if (position_ >= data_size_) {
148     DCHECK_EQ(position_, data_size_);
149     position_ = buffer_data_->wrap_position;
150   }
151
152   if (to_write < buffer_size) {
153     uint32 remainder_to_write = buffer_size - to_write;
154     DCHECK_LT(position_, position_before_write);
155     DCHECK_LE(position_ + remainder_to_write, position_before_write);
156     DoWrite(buffer_data_->data + position_,
157             reinterpret_cast<const uint8*>(buffer) + to_write,
158             remainder_to_write);
159   }
160 }
161
162 void PartialCircularBuffer::DoWrite(void* dest, const void* src, uint32 num) {
163   memcpy(dest, src, num);
164   position_ += num;
165   buffer_data_->total_written =
166       std::min(buffer_data_->total_written + num, data_size_);
167   buffer_data_->end_position = position_;
168 }