Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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. | |
| 4 | |
| 5 #include <functional> | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "net/base/io_buffer.h" | |
| 9 #include "remoting/base/compound_buffer.h" | |
| 10 | |
| 11 namespace remoting { | |
| 12 | |
| 13 CompoundBuffer::DataChunk::DataChunk( | |
| 14 net::IOBuffer* buffer, const char* data_start, int data_size) | |
| 15 : buffer(buffer), | |
| 16 data_start(data_start), | |
| 17 data_size(data_size) { | |
| 18 } | |
| 19 | |
| 20 CompoundBuffer::CompoundBuffer() | |
| 21 : total_bytes_(0), | |
| 22 current_buffer_(0), | |
| 23 current_buffer_position_(0), | |
| 24 position_(0), | |
| 25 last_returned_size_(0) { | |
| 26 } | |
| 27 | |
| 28 CompoundBuffer::~CompoundBuffer() { | |
| 29 } | |
| 30 | |
| 31 void CompoundBuffer::Clear() { | |
| 32 buffers_.clear(); | |
| 33 total_bytes_ = 0; | |
| 34 position_ = 0; | |
| 35 last_returned_size_ = 0; | |
| 36 current_buffer_ = 0; | |
| 37 current_buffer_position_ = 0; | |
| 38 } | |
| 39 | |
| 40 | |
|
awong
2010/11/12 02:40:06
remove extra newline
Sergey Ulanov
2010/11/13 04:43:39
Done.
| |
| 41 void CompoundBuffer::Append(net::IOBuffer* buffer, | |
| 42 const char* data, int data_size) { | |
| 43 // A weak check that the |data| is within |buffer|. | |
| 44 DCHECK_GE(data, buffer->data()); | |
| 45 DCHECK_GT(data_size, 0); | |
| 46 | |
| 47 DCHECK_EQ(position_, 0); // Haven't started reading. | |
|
awong
2010/11/12 02:40:06
So the API contract is that once you start reading
Sergey Ulanov
2010/11/13 04:43:39
Done.
| |
| 48 | |
| 49 buffers_.push_back(DataChunk(buffer, data, data_size)); | |
| 50 total_bytes_ += data_size; | |
| 51 } | |
| 52 | |
| 53 void CompoundBuffer::Append(net::IOBuffer* buffer, int data_size) { | |
| 54 Append(buffer, buffer->data(), data_size); | |
| 55 } | |
| 56 | |
| 57 void CompoundBuffer::Prepend(net::IOBuffer* buffer, | |
| 58 const char* data, int data_size) { | |
| 59 // A weak check that the |data| is within |buffer|. | |
| 60 DCHECK_GE(data, buffer->data()); | |
|
awong
2010/11/12 02:40:06
Same comments as earlier.
Also, should there be a
Sergey Ulanov
2010/11/13 04:43:39
Added locked() returns true if content is locked.
| |
| 61 DCHECK_GT(data_size, 0); | |
| 62 | |
| 63 DCHECK_EQ(position_, 0); // Haven't started reading. | |
| 64 | |
| 65 buffers_.push_front(DataChunk(buffer, data, data_size)); | |
| 66 total_bytes_ += data_size; | |
| 67 } | |
| 68 | |
| 69 void CompoundBuffer::Prepend(net::IOBuffer* buffer, int data_size) { | |
| 70 Prepend(buffer, buffer->data(), data_size); | |
| 71 } | |
| 72 | |
| 73 void CompoundBuffer::CopyAndAppend(const char* data, int data_size) { | |
| 74 net::IOBuffer* buffer = new net::IOBuffer(data_size); | |
| 75 memcpy(buffer->data(), data, data_size); | |
| 76 Append(buffer, buffer->data(), data_size); | |
| 77 } | |
| 78 | |
| 79 void CompoundBuffer::CopyAndPrepend(const char* data, int data_size) { | |
| 80 net::IOBuffer* buffer = new net::IOBuffer(data_size); | |
| 81 memcpy(buffer->data(), data, data_size); | |
| 82 Prepend(buffer, buffer->data(), data_size); | |
| 83 } | |
| 84 | |
| 85 net::IOBufferWithSize* CompoundBuffer::Assemble() const { | |
| 86 net::IOBufferWithSize* result = new net::IOBufferWithSize(total_bytes_); | |
|
awong
2010/11/12 02:40:06
Are these things refcounted?
Sergey Ulanov
2010/11/13 04:43:39
Yes, but we just create it, and then the caller wi
| |
| 87 Assemble(result->data(), total_bytes_); | |
| 88 return result; | |
| 89 } | |
| 90 | |
| 91 void CompoundBuffer::Assemble(char* data, int data_size) const { | |
| 92 char* pos = data; | |
| 93 for (DataChunkList::const_iterator it = buffers_.begin(); | |
| 94 it != buffers_.end(); ++it) { | |
| 95 CHECK_LE(pos + it->data_size, data + data_size); | |
| 96 memcpy(pos, it->data_start, it->data_size); | |
| 97 pos += it->data_size; | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 void CompoundBuffer::CopyFrom(const CompoundBuffer& source, | |
| 102 int start, int end) { | |
| 103 // Check that 0 <= |start| <= |end| <= |total_bytes_|. | |
| 104 DCHECK_LE(0, start); | |
| 105 DCHECK_LE(start, end); | |
| 106 DCHECK_LE(end, source.total_bytes()); | |
| 107 | |
| 108 Clear(); | |
| 109 | |
| 110 if (end == start) { | |
| 111 return; | |
| 112 } | |
| 113 | |
| 114 // Iterate over chunks in the |source| and add those that we need. | |
| 115 int pos = 0; | |
| 116 for (DataChunkList::const_iterator it = source.buffers_.begin(); | |
| 117 it != source.buffers_.end(); ++it) { | |
| 118 | |
| 119 // Add data from the current chunk only if it is in the specified interval. | |
| 120 if (pos + it->data_size > start && pos < end) { | |
| 121 int relative_start = std::max(0, start - pos); | |
| 122 int relative_end = std::min(it->data_size, end - pos); | |
| 123 DCHECK_LE(0, relative_start); | |
| 124 DCHECK_LT(relative_start, relative_end); | |
| 125 DCHECK_LE(relative_end, it->data_size); | |
| 126 Append(it->buffer.get(), it->data_start + relative_start, | |
| 127 relative_end - relative_start); | |
| 128 } | |
| 129 | |
| 130 pos += it->data_size; | |
| 131 if (pos >= end) { | |
| 132 // We've got all the data we need. | |
| 133 break; | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 DCHECK_EQ(total_bytes_, end - start); | |
| 138 } | |
| 139 | |
| 140 bool CompoundBuffer::Next(const void** data, int* size) { | |
| 141 if (current_buffer_ < buffers_.size()) { | |
| 142 // Reply with the number of bytes remaining in the current buffer. | |
| 143 const DataChunk& buffer = buffers_[current_buffer_]; | |
| 144 int read_size = buffer.data_size - current_buffer_position_; | |
| 145 *data = buffer.data_start + current_buffer_position_; | |
| 146 *size = read_size; | |
| 147 | |
| 148 // Adjust position. | |
| 149 ++current_buffer_; | |
| 150 current_buffer_position_ = 0; | |
| 151 position_ += read_size; | |
| 152 | |
| 153 last_returned_size_ = read_size; | |
| 154 return true; | |
| 155 } | |
| 156 | |
| 157 DCHECK_EQ(position_, total_bytes_); | |
| 158 | |
| 159 // We've reached the end of the stream. So reset |last_returned_size_| | |
| 160 // to zero to prevent any backup request. | |
| 161 // This is the same as in ArrayInputStream. | |
| 162 // See google/protobuf/io/zero_copy_stream_impl_lite.cc. | |
| 163 last_returned_size_ = 0; | |
| 164 return false; | |
| 165 } | |
| 166 | |
| 167 void CompoundBuffer::BackUp(int count) { | |
| 168 DCHECK_LE(count, last_returned_size_); | |
| 169 DCHECK_GT(current_buffer_, 0u); | |
| 170 | |
| 171 // Rewind one buffer and rewind data offset by |count| bytes. | |
| 172 --current_buffer_; | |
| 173 const DataChunk& buffer = buffers_[current_buffer_]; | |
| 174 current_buffer_position_ = buffer.data_size - count; | |
| 175 position_ -= count; | |
| 176 DCHECK_GE(position_, 0); | |
| 177 | |
| 178 // Prevent additional backups. | |
| 179 last_returned_size_ = 0; | |
| 180 } | |
| 181 | |
| 182 bool CompoundBuffer::Skip(int count) { | |
| 183 DCHECK_GE(count, 0); | |
| 184 last_returned_size_ = 0; | |
| 185 | |
| 186 while (count > 0 && current_buffer_ < buffers_.size()) { | |
| 187 const DataChunk& buffer = buffers_[current_buffer_]; | |
| 188 int read = std::min(count, buffer.data_size - current_buffer_position_); | |
| 189 | |
| 190 // Advance the current buffer offset and position. | |
| 191 current_buffer_position_ += read; | |
| 192 position_ += read; | |
| 193 count -= read; | |
| 194 | |
| 195 // If the current buffer is fully read, then advance to the next buffer. | |
| 196 if (current_buffer_position_ == buffer.data_size) { | |
| 197 ++current_buffer_; | |
| 198 current_buffer_position_ = 0; | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 return count == 0; | |
| 203 } | |
| 204 | |
| 205 int64 CompoundBuffer::ByteCount() const { | |
| 206 return position_; | |
| 207 } | |
| 208 | |
| 209 } // namespace remoting | |
| OLD | NEW |