Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / common / partial_circular_buffer.cc
blob6e3e017e991f080a87f980f091a6b03b13230c83
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"
7 #include <algorithm>
9 #include "base/logging.h"
11 namespace {
13 inline uint32 Min3(uint32 a, uint32 b, uint32 c) {
14 return std::min(a, std::min(b, c));
17 } // namespace
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;
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_);
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;
50 DCHECK(buffer_data_);
51 DCHECK_GE(memory_buffer_size_, header_size);
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;
64 uint32 PartialCircularBuffer::Read(void* buffer, uint32 buffer_size) {
65 DCHECK(buffer_data_);
66 if (total_read_ >= buffer_data_->total_written)
67 return 0;
69 uint8* buffer_uint8 = reinterpret_cast<uint8*>(buffer);
70 uint32 read = 0;
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;
88 if (read >= buffer_size) {
89 DCHECK_EQ(read, buffer_size);
90 return read;
92 if (read >= to_eow) {
93 DCHECK_EQ(read, to_eow);
94 DCHECK_EQ(total_read_, buffer_data_->total_written);
95 return read;
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;
114 if (read >= buffer_size) {
115 DCHECK_EQ(read, buffer_size);
116 return read;
118 if (total_read_ >= buffer_data_->total_written) {
119 DCHECK_EQ(total_read_, buffer_data_->total_written);
120 return read;
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;
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);
151 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;
158 input += skip;
159 buffer_size -= skip;
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);
177 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_;