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.
5 #include "chrome/common/partial_circular_buffer.h"
9 #include "base/logging.h"
13 inline uint32
Min3(uint32 a
, uint32 b
, uint32 c
) {
14 return std::min(a
, std::min(b
, c
));
19 PartialCircularBuffer::PartialCircularBuffer(void* buffer
,
21 : buffer_data_(reinterpret_cast<BufferData
*>(buffer
)),
22 memory_buffer_size_(buffer_size
),
27 buffer_data_
->data
- reinterpret_cast<uint8
*>(buffer_data_
);
28 data_size_
= memory_buffer_size_
- header_size
;
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_
);
37 PartialCircularBuffer::PartialCircularBuffer(void* buffer
,
41 : buffer_data_(reinterpret_cast<BufferData
*>(buffer
)),
42 memory_buffer_size_(buffer_size
),
47 buffer_data_
->data
- reinterpret_cast<uint8
*>(buffer_data_
);
48 data_size_
= memory_buffer_size_
- header_size
;
51 DCHECK_GE(memory_buffer_size_
, header_size
);
54 DCHECK_LT(buffer_data_
->wrap_position
, data_size_
);
55 position_
= buffer_data_
->end_position
;
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;
64 uint32
PartialCircularBuffer::Read(void* buffer
, uint32 buffer_size
) {
66 if (total_read_
>= buffer_data_
->total_written
)
69 uint8
* buffer_uint8
= reinterpret_cast<uint8
*>(buffer
);
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
);
79 total_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
;
88 if (read
>= buffer_size
) {
89 DCHECK_EQ(read
, buffer_size
);
93 DCHECK_EQ(read
, to_eow
);
94 DCHECK_EQ(total_read_
, buffer_data_
->total_written
);
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
;
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
;
114 if (read
>= buffer_size
) {
115 DCHECK_EQ(read
, buffer_size
);
118 if (total_read_
>= buffer_data_
->total_written
) {
119 DCHECK_EQ(total_read_
, buffer_data_
->total_written
);
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
;
135 DCHECK_LE(read
, buffer_size
);
136 DCHECK_LE(total_read_
, buffer_data_
->total_written
);
140 void PartialCircularBuffer::Write(const void* buffer
, uint32 buffer_size
) {
141 DCHECK(buffer_data_
);
142 const uint8
* input
= static_cast<const uint8
*>(buffer
);
143 uint32 wrap_position
= buffer_data_
->wrap_position
;
144 uint32 cycle_size
= data_size_
- wrap_position
;
146 // First write the non-wrapping part.
147 if (position_
< wrap_position
) {
148 uint32 space_left
= wrap_position
- position_
;
149 uint32 write_size
= std::min(buffer_size
, space_left
);
150 DoWrite(input
, write_size
);
152 buffer_size
-= write_size
;
155 // Skip the part that would overlap.
156 if (buffer_size
> cycle_size
) {
157 uint32 skip
= buffer_size
- cycle_size
;
160 position_
= wrap_position
+ (position_
- wrap_position
+ skip
) % cycle_size
;
163 // Finally write the wrapping part.
164 DoWrite(input
, buffer_size
);
167 void PartialCircularBuffer::DoWrite(const uint8
* input
, uint32 input_size
) {
168 DCHECK_LT(position_
, data_size_
);
169 buffer_data_
->total_written
=
170 std::min(buffer_data_
->total_written
+ input_size
, data_size_
);
172 // Write() skips any overlapping part, so this loop will run at most twice.
173 while (input_size
> 0) {
174 uint32 space_left
= data_size_
- position_
;
175 uint32 write_size
= std::min(input_size
, space_left
);
176 memcpy(buffer_data_
->data
+ position_
, input
, write_size
);
178 input_size
-= write_size
;
179 position_
+= write_size
;
180 if (position_
>= data_size_
) {
181 DCHECK_EQ(position_
, data_size_
);
182 position_
= buffer_data_
->wrap_position
;
186 buffer_data_
->end_position
= position_
;