1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/partial_circular_buffer.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <algorithm>
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/logging.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)inline uint32 Min3(uint32 a, uint32 b, uint32 c) {
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return std::min(a, std::min(b, c));
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)PartialCircularBuffer::PartialCircularBuffer(void* buffer,
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                             uint32 buffer_size)
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : buffer_data_(reinterpret_cast<BufferData*>(buffer)),
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      memory_buffer_size_(buffer_size),
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      data_size_(0),
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      position_(0),
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      total_read_(0) {
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint32 header_size =
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      buffer_data_->data - reinterpret_cast<uint8*>(buffer_data_);
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  data_size_ = memory_buffer_size_ - header_size;
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(buffer_data_);
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(memory_buffer_size_, header_size);
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LE(buffer_data_->total_written, data_size_);
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LT(buffer_data_->wrap_position, data_size_);
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LT(buffer_data_->end_position, data_size_);
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)PartialCircularBuffer::PartialCircularBuffer(void* buffer,
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                             uint32 buffer_size,
397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                             uint32 wrap_position,
407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                             bool append)
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : buffer_data_(reinterpret_cast<BufferData*>(buffer)),
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      memory_buffer_size_(buffer_size),
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      data_size_(0),
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      position_(0),
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      total_read_(0) {
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint32 header_size =
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      buffer_data_->data - reinterpret_cast<uint8*>(buffer_data_);
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  data_size_ = memory_buffer_size_ - header_size;
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(buffer_data_);
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(memory_buffer_size_, header_size);
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (append) {
547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK_LT(buffer_data_->wrap_position, data_size_);
557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    position_ = buffer_data_->end_position;
567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  } else {
577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK_LT(wrap_position, data_size_);
587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    buffer_data_->total_written = 0;
597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    buffer_data_->wrap_position = wrap_position;
607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    buffer_data_->end_position = 0;
617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)uint32 PartialCircularBuffer::Read(void* buffer, uint32 buffer_size) {
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(buffer_data_);
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (total_read_ >= buffer_data_->total_written)
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return 0;
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint8* buffer_uint8 = reinterpret_cast<uint8*>(buffer);
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint32 read = 0;
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Read from beginning part.
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (position_ < buffer_data_->wrap_position) {
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    uint32 to_wrap_pos = buffer_data_->wrap_position - position_;
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    uint32 to_eow = buffer_data_->total_written - total_read_;
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    uint32 to_read = Min3(buffer_size, to_wrap_pos, to_eow);
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    memcpy(buffer_uint8, buffer_data_->data + position_, to_read);
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    position_ += to_read;
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    total_read_ += to_read;
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    read += to_read;
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (position_ == buffer_data_->wrap_position &&
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        buffer_data_->total_written == data_size_) {
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // We've read all the beginning part, set the position to the middle part.
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // (The second condition above checks if the wrapping part is filled, i.e.
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // writing has wrapped.)
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      position_ = buffer_data_->end_position;
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (read >= buffer_size) {
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      DCHECK_EQ(read, buffer_size);
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return read;
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (read >= to_eow) {
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      DCHECK_EQ(read, to_eow);
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      DCHECK_EQ(total_read_, buffer_data_->total_written);
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return read;
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Read from middle part.
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(position_, buffer_data_->wrap_position);
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (position_ >= buffer_data_->end_position) {
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    uint32 remaining_buffer_size = buffer_size - read;
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    uint32 to_eof = data_size_ - position_;
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    uint32 to_eow = buffer_data_->total_written - total_read_;
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    uint32 to_read = Min3(remaining_buffer_size, to_eof, to_eow);
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    memcpy(buffer_uint8 + read, buffer_data_->data + position_, to_read);
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    position_ += to_read;
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    total_read_ += to_read;
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    read += to_read;
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (position_ == data_size_) {
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // We've read all the middle part, set position to the end part.
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      position_ = buffer_data_->wrap_position;
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (read >= buffer_size) {
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      DCHECK_EQ(read, buffer_size);
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return read;
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (total_read_ >= buffer_data_->total_written) {
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      DCHECK_EQ(total_read_, buffer_data_->total_written);
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return read;
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Read from end part.
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(position_, buffer_data_->wrap_position);
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LT(position_, buffer_data_->end_position);
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint32 remaining_buffer_size = buffer_size - read;
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint32 to_eob = buffer_data_->end_position - position_;
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint32 to_eow = buffer_data_->total_written - total_read_;
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint32 to_read = Min3(remaining_buffer_size, to_eob, to_eow);
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  memcpy(buffer_uint8 + read, buffer_data_->data + position_, to_read);
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  position_ += to_read;
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  total_read_ += to_read;
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  read += to_read;
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LE(read, buffer_size);
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LE(total_read_, buffer_data_->total_written);
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return read;
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void PartialCircularBuffer::Write(const void* buffer, uint32 buffer_size) {
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(buffer_data_);
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint32 position_before_write = position_;
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint32 to_eof = data_size_ - position_;
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint32 to_write = std::min(buffer_size, to_eof);
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DoWrite(buffer_data_->data + position_, buffer, to_write);
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (position_ >= data_size_) {
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_EQ(position_, data_size_);
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    position_ = buffer_data_->wrap_position;
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (to_write < buffer_size) {
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    uint32 remainder_to_write = buffer_size - to_write;
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_LT(position_, position_before_write);
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_LE(position_ + remainder_to_write, position_before_write);
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DoWrite(buffer_data_->data + position_,
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            reinterpret_cast<const uint8*>(buffer) + to_write,
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            remainder_to_write);
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void PartialCircularBuffer::DoWrite(void* dest, const void* src, uint32 num) {
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  memcpy(dest, src, num);
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  position_ += num;
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  buffer_data_->total_written =
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      std::min(buffer_data_->total_written + num, data_size_);
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  buffer_data_->end_position = position_;
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
169