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 |