Index: content/common/circular_memory_buffer.cc |
diff --git a/content/common/circular_memory_buffer.cc b/content/common/circular_memory_buffer.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..915d753580d6e14e61ae9440070b739acb895960 |
--- /dev/null |
+++ b/content/common/circular_memory_buffer.cc |
@@ -0,0 +1,186 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/common/circular_memory_buffer.h" |
+ |
+#include "base/logging.h" |
+ |
+#define MIN3(a, b, c) std::min(a, std::min(b, c)) |
tommi (sloooow) - chröme
2013/04/03 14:11:32
in the spirit of include-what-you-use I think you
Henrik Grunell
2013/04/05 11:21:08
Done. Forgot to run lint before uploading. :-)
|
+ |
+namespace content { |
+ |
+PartialCircularBuffer::PartialCircularBuffer(const uint8* buffer, |
+ size_t buffer_size) |
+ : memory_buffer_size_(buffer_size), |
+ position_(0), |
+ memory_buffer_read_(buffer), |
+ total_read_(0), |
+ memory_buffer_write_(NULL) { |
+ InitRead(); |
+} |
+ |
+PartialCircularBuffer::PartialCircularBuffer(uint8* buffer, |
+ size_t buffer_size, |
+ size_t wrap_position) |
+ : memory_buffer_size_(buffer_size), |
+ position_(0), |
+ memory_buffer_read_(NULL), |
+ total_read_(0), |
+ memory_buffer_write_(buffer) { |
+ InitWrite(wrap_position); |
+} |
+ |
+void PartialCircularBuffer::InitRead() { |
tommi (sloooow) - chröme
2013/04/03 14:11:32
Why do we need InitRead and InitWrite? Can we do
Henrik Grunell
2013/04/05 11:21:08
Not really. Moved to ctors.
|
+ DCHECK(memory_buffer_read_); |
+ DCHECK_GT(memory_buffer_size_, sizeof(header_data_)); |
+ |
+ memset(&header_data_, 0, sizeof(header_data_)); |
+ ReadHeaderData(); |
+ DCHECK_LE(header_data_.total_written, memory_buffer_size_); |
+ DCHECK_LT(header_data_.wrap_position, memory_buffer_size_); |
+ DCHECK_LT(header_data_.end_position, memory_buffer_size_); |
+ |
+ position_ = sizeof(header_data_); |
+ total_read_ = 0; |
+} |
+ |
+void PartialCircularBuffer::InitWrite(size_t wrap_position) { |
+ DCHECK(memory_buffer_write_); |
+ DCHECK_GT(memory_buffer_size_, sizeof(header_data_)); |
+ DCHECK_LT(wrap_position, memory_buffer_size_); |
+ |
+ memset(&header_data_, 0, sizeof(header_data_)); |
+ header_data_.wrap_position = wrap_position; |
+ WriteHeaderData(); |
+ position_ = sizeof(header_data_); |
+} |
+ |
+size_t PartialCircularBuffer::Read(void* buffer, size_t buffer_size) { |
+ DCHECK(memory_buffer_read_); |
+ if (total_read_ >= header_data_.total_written) |
+ return 0; |
+ |
+ uint8* buffer_uint8 = reinterpret_cast<uint8*>(buffer); |
+ size_t read = 0; |
+ |
+ // Read from beginning part. |
+ if (position_ < header_data_.wrap_position) { |
+ size_t to_marked_pos = header_data_.wrap_position - position_; |
+ size_t to_eow = header_data_.total_written - total_read_; |
+ size_t to_read = MIN3(buffer_size, to_marked_pos, to_eow); |
+ memcpy(buffer_uint8 + read, memory_buffer_read_ + position_, to_read); |
+ position_ += to_read; |
+ total_read_ += to_read; |
+ read += to_read; |
+ if (position_ == header_data_.wrap_position && |
+ header_data_.total_written + sizeof(header_data_) == |
+ memory_buffer_size_) { |
+ // We've read all the beginning part, set the position to the middle part. |
+ // (The second condition above checks if the wrapping part is filled, i.e. |
+ // writing has wrapped.) |
+ position_ = header_data_.end_position; |
+ } |
+ if (read >= buffer_size) { |
+ DCHECK(read == buffer_size); |
+ return read; |
+ } |
+ if (read >= to_eow) { |
+ DCHECK(read == to_eow); |
+ return read; |
+ } |
+ } |
+ |
+ // Read from middle part. |
+ DCHECK(position_ >= header_data_.wrap_position); |
+ if (position_ >= header_data_.end_position) { |
+ size_t remaining_buffer_size = buffer_size - read; |
+ size_t to_eof = memory_buffer_size_ - position_; |
+ size_t to_eow = header_data_.total_written - total_read_; |
+ size_t to_read = MIN3(remaining_buffer_size, to_eof, to_eow); |
+ memcpy(buffer_uint8 + read, memory_buffer_read_ + position_, to_read); |
+ position_ += to_read; |
+ total_read_ += to_read; |
+ read += to_read; |
+ if (position_ == memory_buffer_size_) { |
+ // We've read all the middle part, set position to the end part. |
+ position_ = header_data_.wrap_position; |
+ } |
+ if (read >= buffer_size) { |
+ DCHECK(read == buffer_size); |
+ return read; |
+ } |
+ if (read >= to_eow) { |
+ DCHECK(read == to_eow); |
+ return read; |
+ } |
+ } |
+ |
+ // Read from end part. |
+ DCHECK(position_ >= header_data_.wrap_position && |
+ position_ < header_data_.end_position); |
+ size_t remaining_buffer_size = buffer_size - read; |
+ size_t to_eob = header_data_.end_position - position_; |
+ size_t to_eow = header_data_.total_written - total_read_; |
+ size_t to_read = MIN3(remaining_buffer_size, to_eob, to_eow); |
+ memcpy(buffer_uint8 + read, memory_buffer_read_ + position_, to_read); |
+ position_ += to_read; |
+ total_read_ += to_read; |
+ read += to_read; |
+ DCHECK(read <= buffer_size); |
+ DCHECK(read <= to_eow); |
+ return read; |
+} |
+ |
+void PartialCircularBuffer::Write(const void* buffer, size_t buffer_size) { |
+ DCHECK(memory_buffer_write_); |
+ size_t position_before_write = position_; |
+ |
+ size_t to_eof = memory_buffer_size_ - position_; |
+ size_t to_write = std::min(buffer_size, to_eof); |
+ memcpy(memory_buffer_write_ + position_, buffer, to_write); |
+ position_ += to_write; |
+ |
+ if (position_ >= memory_buffer_size_) { |
+ DCHECK_EQ(position_, memory_buffer_size_); |
+ position_ = header_data_.wrap_position; |
+ } |
+ |
+ if (to_write < buffer_size) { |
+ size_t remainder_to_write = buffer_size - to_write; |
+ DCHECK_LT(position_, position_before_write); |
+ DCHECK_LE(position_ + remainder_to_write, position_before_write); |
+ memcpy(memory_buffer_write_ + position_, |
+ reinterpret_cast<const uint8*>(buffer) + to_write, |
+ remainder_to_write); |
+ position_ += remainder_to_write; |
+ } |
+ |
+ UpdateAndWriteHeaderData(buffer_size, position_); |
+} |
+ |
+void PartialCircularBuffer::ReadHeaderData() { |
+ const HeaderData* header = |
+ reinterpret_cast<const HeaderData*>(memory_buffer_read_); |
+ memcpy(&header_data_, header, sizeof(header_data_)); |
+} |
+ |
+void PartialCircularBuffer::WriteHeaderData() { |
+ HeaderData* header = reinterpret_cast<HeaderData*>(memory_buffer_write_); |
+ memcpy(header, &header_data_, sizeof(header_data_)); |
+} |
+ |
+void PartialCircularBuffer::UpdateAndWriteHeaderData(size_t added_length, |
tommi (sloooow) - chröme
2013/04/03 14:11:32
instead of having ReadHeaderData, WriteHeaderData
Henrik Grunell
2013/04/05 11:21:08
Indeed. Changed.
|
+ size_t new_position) { |
+ HeaderData* header = reinterpret_cast<HeaderData*>(memory_buffer_write_); |
+ memcpy(&header_data_, header, sizeof(header_data_)); |
+ |
+ size_t new_length = header_data_.total_written + added_length; |
+ if (new_length > memory_buffer_size_) |
+ new_length = memory_buffer_size_; |
+ header_data_.end_position = new_position; |
+ |
+ memcpy(header, &header_data_, sizeof(header_data_)); |
+} |
+ |
+} // namespace content |