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 11namespace { 12 13inline uint32 Min3(uint32 a, uint32 b, uint32 c) { 14 return std::min(a, std::min(b, c)); 15} 16 17} // namespace 18 19PartialCircularBuffer::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 37PartialCircularBuffer::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 64uint32 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 140void 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 162void 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} 169