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 uint32 position_before_write
= position_
;
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
;
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
,
162 void PartialCircularBuffer::DoWrite(void* dest
, const void* src
, uint32 num
) {
163 memcpy(dest
, src
, num
);
165 buffer_data_
->total_written
=
166 std::min(buffer_data_
->total_written
+ num
, data_size_
);
167 buffer_data_
->end_position
= position_
;