Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / remoting / base / compound_buffer.cc
blob79b4d32818b9f65127ab93bcc59768c084f9640f
1 // Copyright (c) 2010 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 <functional>
7 #include "base/logging.h"
8 #include "net/base/io_buffer.h"
9 #include "remoting/base/compound_buffer.h"
11 namespace remoting {
13 CompoundBuffer::DataChunk::DataChunk(
14 net::IOBuffer* buffer_value, const char* start_value, int size_value)
15 : buffer(buffer_value),
16 start(start_value),
17 size(size_value) {
20 CompoundBuffer::DataChunk::~DataChunk() {}
22 CompoundBuffer::CompoundBuffer()
23 : total_bytes_(0),
24 locked_(false) {
27 CompoundBuffer::~CompoundBuffer() {
30 void CompoundBuffer::Clear() {
31 CHECK(!locked_);
32 chunks_.clear();
33 total_bytes_ = 0;
36 void CompoundBuffer::Append(net::IOBuffer* buffer,
37 const char* start, int size) {
38 // A weak check that the |start| is within |buffer|.
39 DCHECK_GE(start, buffer->data());
40 DCHECK_GT(size, 0);
42 CHECK(!locked_);
44 chunks_.push_back(DataChunk(buffer, start, size));
45 total_bytes_ += size;
48 void CompoundBuffer::Append(net::IOBuffer* buffer, int size) {
49 Append(buffer, buffer->data(), size);
52 void CompoundBuffer::Append(const CompoundBuffer& buffer) {
53 for (DataChunkList::const_iterator it = buffer.chunks_.begin();
54 it != buffer.chunks_.end(); ++it) {
55 Append(it->buffer.get(), it->start, it->size);
59 void CompoundBuffer::Prepend(net::IOBuffer* buffer,
60 const char* start, int size) {
61 // A weak check that the |start| is within |buffer|.
62 DCHECK_GE(start, buffer->data());
63 DCHECK_GT(size, 0);
65 CHECK(!locked_);
67 chunks_.push_front(DataChunk(buffer, start, size));
68 total_bytes_ += size;
71 void CompoundBuffer::Prepend(net::IOBuffer* buffer, int size) {
72 Prepend(buffer, buffer->data(), size);
75 void CompoundBuffer::Prepend(const CompoundBuffer& buffer) {
76 for (DataChunkList::const_iterator it = buffer.chunks_.begin();
77 it != buffer.chunks_.end(); ++it) {
78 Prepend(it->buffer.get(), it->start, it->size);
81 void CompoundBuffer::AppendCopyOf(const char* data, int size) {
82 net::IOBuffer* buffer = new net::IOBuffer(size);
83 memcpy(buffer->data(), data, size);
84 Append(buffer, size);
87 void CompoundBuffer::PrependCopyOf(const char* data, int size) {
88 net::IOBuffer* buffer = new net::IOBuffer(size);
89 memcpy(buffer->data(), data, size);
90 Prepend(buffer, size);
93 void CompoundBuffer::CropFront(int bytes) {
94 CHECK(!locked_);
96 if (total_bytes_ <= bytes) {
97 Clear();
98 return;
101 total_bytes_ -= bytes;
102 while (!chunks_.empty() && chunks_.front().size <= bytes) {
103 bytes -= chunks_.front().size;
104 chunks_.pop_front();
106 if (!chunks_.empty() && bytes > 0) {
107 chunks_.front().start += bytes;
108 chunks_.front().size -= bytes;
109 DCHECK_GT(chunks_.front().size, 0);
110 bytes = 0;
112 DCHECK_EQ(bytes, 0);
115 void CompoundBuffer::CropBack(int bytes) {
116 CHECK(!locked_);
118 if (total_bytes_ <= bytes) {
119 Clear();
120 return;
123 total_bytes_ -= bytes;
124 while (!chunks_.empty() && chunks_.back().size <= bytes) {
125 bytes -= chunks_.back().size;
126 chunks_.pop_back();
128 if (!chunks_.empty() && bytes > 0) {
129 chunks_.back().size -= bytes;
130 DCHECK_GT(chunks_.back().size, 0);
131 bytes = 0;
133 DCHECK_EQ(bytes, 0);
136 void CompoundBuffer::Lock() {
137 locked_ = true;
140 net::IOBufferWithSize* CompoundBuffer::ToIOBufferWithSize() const {
141 net::IOBufferWithSize* result = new net::IOBufferWithSize(total_bytes_);
142 CopyTo(result->data(), total_bytes_);
143 return result;
146 void CompoundBuffer::CopyTo(char* data, int size) const {
147 char* pos = data;
148 for (DataChunkList::const_iterator it = chunks_.begin();
149 it != chunks_.end(); ++it) {
150 CHECK_LE(pos + it->size, data + size);
151 memcpy(pos, it->start, it->size);
152 pos += it->size;
156 void CompoundBuffer::CopyFrom(const CompoundBuffer& source,
157 int start, int end) {
158 // Check that 0 <= |start| <= |end| <= |total_bytes_|.
159 DCHECK_LE(0, start);
160 DCHECK_LE(start, end);
161 DCHECK_LE(end, source.total_bytes());
163 Clear();
165 if (end == start) {
166 return;
169 // Iterate over chunks in the |source| and add those that we need.
170 int pos = 0;
171 for (DataChunkList::const_iterator it = source.chunks_.begin();
172 it != source.chunks_.end(); ++it) {
174 // Add data from the current chunk only if it is in the specified interval.
175 if (pos + it->size > start && pos < end) {
176 int relative_start = std::max(0, start - pos);
177 int relative_end = std::min(it->size, end - pos);
178 DCHECK_LE(0, relative_start);
179 DCHECK_LT(relative_start, relative_end);
180 DCHECK_LE(relative_end, it->size);
181 Append(it->buffer.get(), it->start + relative_start,
182 relative_end - relative_start);
185 pos += it->size;
186 if (pos >= end) {
187 // We've got all the data we need.
188 break;
192 DCHECK_EQ(total_bytes_, end - start);
195 CompoundBufferInputStream::CompoundBufferInputStream(
196 const CompoundBuffer* buffer)
197 : buffer_(buffer),
198 current_chunk_(0),
199 current_chunk_position_(0),
200 position_(0),
201 last_returned_size_(0) {
202 DCHECK(buffer_->locked());
205 CompoundBufferInputStream::~CompoundBufferInputStream() {
208 bool CompoundBufferInputStream::Next(const void** data, int* size) {
209 if (current_chunk_ < buffer_->chunks_.size()) {
210 // Reply with the number of bytes remaining in the current buffer.
211 const CompoundBuffer::DataChunk& chunk = buffer_->chunks_[current_chunk_];
212 int read_size = chunk.size - current_chunk_position_;
213 *data = chunk.start + current_chunk_position_;
214 *size = read_size;
216 // Adjust position.
217 ++current_chunk_;
218 current_chunk_position_ = 0;
219 position_ += read_size;
221 last_returned_size_ = read_size;
222 return true;
225 DCHECK_EQ(position_, buffer_->total_bytes());
227 // We've reached the end of the stream. So reset |last_returned_size_|
228 // to zero to prevent any backup request.
229 // This is the same as in ArrayInputStream.
230 // See google/protobuf/io/zero_copy_stream_impl_lite.cc.
231 last_returned_size_ = 0;
232 return false;
235 void CompoundBufferInputStream::BackUp(int count) {
236 DCHECK_LE(count, last_returned_size_);
237 DCHECK_GT(current_chunk_, 0u);
239 // Rewind one buffer and rewind data offset by |count| bytes.
240 --current_chunk_;
241 const CompoundBuffer::DataChunk& chunk = buffer_->chunks_[current_chunk_];
242 current_chunk_position_ = chunk.size - count;
243 position_ -= count;
244 DCHECK_GE(position_, 0);
246 // Prevent additional backups.
247 last_returned_size_ = 0;
250 bool CompoundBufferInputStream::Skip(int count) {
251 DCHECK_GE(count, 0);
252 last_returned_size_ = 0;
254 while (count > 0 && current_chunk_ < buffer_->chunks_.size()) {
255 const CompoundBuffer::DataChunk& chunk = buffer_->chunks_[current_chunk_];
256 int read = std::min(count, chunk.size - current_chunk_position_);
258 // Advance the current buffer offset and position.
259 current_chunk_position_ += read;
260 position_ += read;
261 count -= read;
263 // If the current buffer is fully read, then advance to the next buffer.
264 if (current_chunk_position_ == chunk.size) {
265 ++current_chunk_;
266 current_chunk_position_ = 0;
270 return count == 0;
273 int64 CompoundBufferInputStream::ByteCount() const {
274 return position_;
277 } // namespace remoting