partial_circular_buffer.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// Copyright 2013 The Chromium Authors. All rights reserved. 280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// Use of this source code is governed by a BSD-style license that can be 380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// found in the LICENSE file. 480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "chrome/common/partial_circular_buffer.h" 680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include <algorithm> 880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 9910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger#include "base/logging.h" 10910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 11910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenbergernamespace { 12910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruinline uint32 Min3(uint32 a, uint32 b, uint32 c) { 1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return std::min(a, std::min(b, c)); 15910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger} 16910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 17910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger} // namespace 18910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 19910f694aefb0b671dd8522a9afe9b6be645701c1Derek SollenbergerPartialCircularBuffer::PartialCircularBuffer(void* buffer, 20910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint32 buffer_size) 21910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger : buffer_data_(reinterpret_cast<BufferData*>(buffer)), 22910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger memory_buffer_size_(buffer_size), 23910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger data_size_(0), 24910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger position_(0), 25910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger total_read_(0) { 26910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint32 header_size = 2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru buffer_data_->data - reinterpret_cast<uint8*>(buffer_data_); 2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru data_size_ = memory_buffer_size_ - header_size; 2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 30910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger DCHECK(buffer_data_); 3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru DCHECK_GE(memory_buffer_size_, header_size); 32910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger DCHECK_LE(buffer_data_->total_written, data_size_); 33910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger DCHECK_LT(buffer_data_->wrap_position, data_size_); 34910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger DCHECK_LT(buffer_data_->end_position, data_size_); 3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruPartialCircularBuffer::PartialCircularBuffer(void* buffer, 3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint32 buffer_size, 3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint32 wrap_position, 40910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger bool append) 41910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger : buffer_data_(reinterpret_cast<BufferData*>(buffer)), 4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru memory_buffer_size_(buffer_size), 4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru data_size_(0), 44910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger position_(0), 4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru total_read_(0) { 46910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint32 header_size = 47910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger buffer_data_->data - reinterpret_cast<uint8*>(buffer_data_); 48910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger data_size_ = memory_buffer_size_ - header_size; 49910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 50910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger DCHECK(buffer_data_); 51910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger DCHECK_GE(memory_buffer_size_, header_size); 52910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 53910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (append) { 54910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger DCHECK_LT(buffer_data_->wrap_position, data_size_); 55910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger position_ = buffer_data_->end_position; 56910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } else { 57910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger DCHECK_LT(wrap_position, data_size_); 58910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger buffer_data_->total_written = 0; 59910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger buffer_data_->wrap_position = wrap_position; 60910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger buffer_data_->end_position = 0; 61910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 62910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger} 63910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 64910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenbergeruint32 PartialCircularBuffer::Read(void* buffer, uint32 buffer_size) { 65910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger DCHECK(buffer_data_); 66910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (total_read_ >= buffer_data_->total_written) 67910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger return 0; 68910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 69910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint8* buffer_uint8 = reinterpret_cast<uint8*>(buffer); 70910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint32 read = 0; 71910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 72910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // Read from beginning part. 73910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (position_ < buffer_data_->wrap_position) { 74910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint32 to_wrap_pos = buffer_data_->wrap_position - position_; 75910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint32 to_eow = buffer_data_->total_written - total_read_; 76910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint32 to_read = Min3(buffer_size, to_wrap_pos, to_eow); 77910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger memcpy(buffer_uint8, buffer_data_->data + position_, to_read); 7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru position_ += to_read; 7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 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