1 /*
2 * Copyright 2021 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 package io.netty5.buffer.api;
17
18 import io.netty5.util.Resource;
19 import io.netty5.util.Send;
20
21 import java.nio.ByteBuffer;
22 import java.nio.charset.Charset;
23
24 /**
25 * The {@code CompositeBuffer} is a concrete {@link Buffer} implementation that make a number of other buffers appear
26 * as one. A composite buffer behaves the same as a normal, non-composite buffer in every way, so you normally don't
27 * need to handle them specially.
28 * <p>
29 * A composite buffer is constructed using one of the {@code compose} methods:
30 * <ul>
31 * <li>
32 * {@link BufferAllocator#compose(Iterable)} creates a composite buffer from the buffers that are sent to it via
33 * the passed in send objects. Since {@link Send#receive()} transfers ownership, the resulting composite buffer
34 * will have ownership, because it is guaranteed that there are no other references to its constituent buffers.
35 * </li>
36 * <li>
37 * {@link BufferAllocator#compose(Send)} creates a composite buffer with a single component.
38 * Since {@link Send#receive()} transfers ownership, the resulting composite buffer
39 * will have ownership, because it is guaranteed that there are no other references to its constituent buffer.
40 * </li>
41 * <li>
42 * {@link BufferAllocator#compose()} creates an empty, zero capacity, composite buffer. Such empty buffers may
43 * change their {@linkplain #readOnly() read-only} states when they gain their first component.
44 * </li>
45 * </ul>
46 * Composite buffers can later be extended with internally allocated components, with {@link #ensureWritable(int)},
47 * or with externally allocated buffers, using {@link #extendWith(Send)}.
48 *
49 * <h3>How buffers compose</h3>
50 *
51 * A buffer can be thought of as having three distinct regions, in order:
52 * <ol>
53 * <li>Memory that have been read.</li>
54 * <li>Memory that is readable.</li>
55 * <li>Memory that can be written to.</li>
56 * </ol>
57 *
58 * A composite buffer must present itself similarly, but may be composed of buffers where their offsets don't line up,
59 * and thus end up producing "gaps" in the composite buffer.
60 * The solution is that the composite buffer hide these gaps from view.
61 * <p>
62 * For example, if we compose two buffers that both have non-zero read-offset, then the composite buffer will get the
63 * read-offset of the first buffer, followed by a concatenation of the readable memory from both.
64 * Similarly, the write-offset of the composite buffer will come from the last buffer with a non-zero write-offset,
65 * and any writable memory prior to the last readable memory region will be hidden:
66 *
67 * <pre>
68 * First buffer Second buffer
69 * +----------------------+ +--------------------+
70 * 0| |r/o |w/o | 0| |r/o |w/o |
71 * +----+---------+-------+ +----+--------+------+
72 * \ \ \ ,____________/ ,___________/
73 * \ \ \/ /
74 * +----+---------+--------+------+
75 * 0| |r/o : |w/o | Composite buffer
76 * +------------------------------+
77 * </pre>
78 *
79 * Components in the middle can have both their end-regions hidden in the same way, so only their readable memory is
80 * included in the composite buffer.
81 * Buffers that consist entirely of memory that has already been read, or memory that is writable, can also concatenate
82 * onto those regions at the ends.
83 * The final capacity of the composite buffer, will be the sum of all the visible regions.
84 * <p>
85 * Reads and writes to the composite buffer that modifies the read or write offsets, will also modify the relevant
86 * offsets in the constituent buffers.
87 *
88 * <h3>Constituent buffer requirements</h3>
89 *
90 * The buffers that are being composed must all have the same writability.
91 * Either all components must be {@linkplain Buffer#readOnly() read-only}, or they must all be writable.
92 * <p>
93 * It is not a requirement that the buffers have the same size.
94 * <p>
95 * It is not a requirement that the buffers are allocated by this allocator, but if
96 * {@link Buffer#ensureWritable(int)} is called on the composed buffer, and the composed buffer needs to be
97 * expanded, then this allocator instance will be used for allocation the extra memory.
98 *
99 * <h3>Ownership and Send</h3>
100 *
101 * {@linkplain Resource#send() Sending} a composite buffer implies sending all of its constituent buffers.
102 * For sending to be possible, both the composite buffer itself, and all of its constituent buffers, must be in a
103 * state that permits them being sent. This should be the case by default, as it shouldn't be possible to create
104 * composite buffers that can't be sent.
105 */
106 public interface CompositeBuffer extends Buffer {
107
108 /**
109 * Create an empty composite buffer, that has no components. The buffer can be extended with components using either
110 * {@link #ensureWritable(int)} or {@link #extendWith(Send)}.
111 *
112 * @param allocator The allocator for the composite buffer. This allocator will be used e.g. to service
113 * {@link #ensureWritable(int)} calls.
114 * @return A composite buffer that has no components, and has a capacity of zero.
115 */
116 static CompositeBuffer compose(BufferAllocator allocator) {
117 return DefaultCompositeBuffer.compose(allocator);
118 }
119
120 /**
121 * Check if the given buffer is a composite buffer or not.
122 * @param composite The buffer to check.
123 * @return {@code true} if the given buffer was created with {@link BufferAllocator#compose()},
124 * {@link BufferAllocator#compose(Send)} or {@link BufferAllocator#compose(Iterable)}, {@code false} otherwise.
125 */
126 static boolean isComposite(Buffer composite) {
127 return composite instanceof CompositeBuffer;
128 }
129
130 /**
131 * Extend this composite buffer with the given extension buffer.
132 * This works as if the extension had originally been included at the end of the list of constituent buffers when
133 * the composite buffer was created.
134 * The extension buffer is added to the end of this composite buffer, which is modified in-place.
135 *
136 * @see BufferAllocator#compose(Send)
137 * @param extension The buffer to extend the composite buffer with.
138 * @return This composite buffer instance.
139 */
140 CompositeBuffer extendWith(Send<Buffer> extension);
141
142 /**
143 * Split this buffer at a component boundary that is less than or equal to the given offset.
144 * <p>
145 * This method behaves the same as {@link #split(int)}, except no components are split.
146 *
147 * @param splitOffset The maximum split offset. The real split offset will be at a component boundary that is less
148 * than or equal to this offset.
149 * @return A new buffer with independent and exclusive ownership over the bytes from the beginning to a component
150 * boundary less than or equal to the given offset of this buffer.
151 */
152 CompositeBuffer splitComponentsFloor(int splitOffset);
153
154 /**
155 * Split this buffer at a component boundary that is greater than or equal to the given offset.
156 * <p>
157 * This method behaves the same as {@link #split(int)}, except no components are split.
158 *
159 * @param splitOffset The minimum split offset. The real split offset will be at a component boundary that is
160 * greater than or equal to this offset.
161 * @return A new buffer with independent and exclusive ownership over the bytes from the beginning to a component
162 * boundary greater than or equal to the given offset of this buffer.
163 */
164 CompositeBuffer splitComponentsCeil(int splitOffset);
165
166 /**
167 * Break a composite buffer into its constituent components.
168 * <p>
169 * This "consumes" the composite buffer, leaving the composite buffer instance as if it had been closed.
170 * The buffers in the returned array are not closed, and become owned by the caller.
171 *
172 * @return An array of the constituent buffer components.
173 */
174 Buffer[] decomposeBuffer();
175
176 @Override
177 CompositeBuffer readerOffset(int offset);
178
179 @Override
180 CompositeBuffer writerOffset(int offset);
181
182 @Override
183 default CompositeBuffer skipReadableBytes(int delta) {
184 return (CompositeBuffer) Buffer.super.skipReadableBytes(delta);
185 }
186
187 @Override
188 default CompositeBuffer skipWritableBytes(int delta) {
189 return (CompositeBuffer) Buffer.super.skipWritableBytes(delta);
190 }
191
192 @Override
193 CompositeBuffer fill(byte value);
194
195 @Override
196 CompositeBuffer makeReadOnly();
197
198 @Override
199 default CompositeBuffer writeBytes(Buffer source) {
200 return (CompositeBuffer) Buffer.super.writeBytes(source);
201 }
202
203 @Override
204 default CompositeBuffer writeBytes(byte[] source) {
205 return (CompositeBuffer) Buffer.super.writeBytes(source);
206 }
207
208 @Override
209 default CompositeBuffer writeBytes(byte[] source, int srcPos, int length) {
210 return (CompositeBuffer) Buffer.super.writeBytes(source, srcPos, length);
211 }
212
213 @Override
214 default CompositeBuffer writeCharSequence(CharSequence source, Charset charset) {
215 return (CompositeBuffer) Buffer.super.writeCharSequence(source, charset);
216 }
217
218 @Override
219 default CompositeBuffer readBytes(byte[] destination, int destPos, int length) {
220 return (CompositeBuffer) Buffer.super.readBytes(destination, destPos, length);
221 }
222
223 @Override
224 default CompositeBuffer writeBoolean(boolean value) {
225 return (CompositeBuffer) Buffer.super.writeBoolean(value);
226 }
227
228 @Override
229 default CompositeBuffer setBoolean(int woff, boolean value) {
230 return (CompositeBuffer) Buffer.super.setBoolean(woff, value);
231 }
232
233 @Override
234 default CompositeBuffer writeBytes(ByteBuffer source) {
235 return (CompositeBuffer) Buffer.super.writeBytes(source);
236 }
237
238 @Override
239 default CompositeBuffer readBytes(ByteBuffer destination) {
240 return (CompositeBuffer) Buffer.super.readBytes(destination);
241 }
242
243 @Override
244 default CompositeBuffer resetOffsets() {
245 return (CompositeBuffer) Buffer.super.resetOffsets();
246 }
247
248 @Override
249 default CompositeBuffer ensureWritable(int size) {
250 return (CompositeBuffer) Buffer.super.ensureWritable(size);
251 }
252
253 @Override
254 CompositeBuffer ensureWritable(int size, int minimumGrowth, boolean allowCompaction);
255
256 @Override
257 default CompositeBuffer copy() {
258 return (CompositeBuffer) Buffer.super.copy();
259 }
260
261 @Override
262 default CompositeBuffer copy(int offset, int length) {
263 return (CompositeBuffer) Buffer.super.copy(offset, length);
264 }
265
266 @Override
267 CompositeBuffer copy(int offset, int length, boolean readOnly);
268
269 @Override
270 default CompositeBuffer split() {
271 return (CompositeBuffer) Buffer.super.split();
272 }
273
274 @Override
275 CompositeBuffer split(int splitOffset);
276
277 @Override
278 CompositeBuffer compact();
279
280 @Override
281 CompositeBuffer writeByte(byte value);
282
283 @Override
284 CompositeBuffer setByte(int woff, byte value);
285
286 @Override
287 CompositeBuffer writeUnsignedByte(int value);
288
289 @Override
290 CompositeBuffer setUnsignedByte(int woff, int value);
291
292 @Override
293 CompositeBuffer writeChar(char value);
294
295 @Override
296 CompositeBuffer setChar(int woff, char value);
297
298 @Override
299 CompositeBuffer writeShort(short value);
300
301 @Override
302 CompositeBuffer setShort(int woff, short value);
303
304 @Override
305 CompositeBuffer writeUnsignedShort(int value);
306
307 @Override
308 CompositeBuffer setUnsignedShort(int woff, int value);
309
310 @Override
311 CompositeBuffer writeMedium(int value);
312
313 @Override
314 CompositeBuffer setMedium(int woff, int value);
315
316 @Override
317 CompositeBuffer writeUnsignedMedium(int value);
318
319 @Override
320 CompositeBuffer setUnsignedMedium(int woff, int value);
321
322 @Override
323 CompositeBuffer writeInt(int value);
324
325 @Override
326 CompositeBuffer setInt(int woff, int value);
327
328 @Override
329 CompositeBuffer writeUnsignedInt(long value);
330
331 @Override
332 CompositeBuffer setUnsignedInt(int woff, long value);
333
334 @Override
335 CompositeBuffer writeFloat(float value);
336
337 @Override
338 CompositeBuffer setFloat(int woff, float value);
339
340 @Override
341 CompositeBuffer writeLong(long value);
342
343 @Override
344 CompositeBuffer setLong(int woff, long value);
345
346 @Override
347 CompositeBuffer writeDouble(double value);
348
349 @Override
350 CompositeBuffer setDouble(int woff, double value);
351
352 @Override
353 CompositeBuffer implicitCapacityLimit(int limit);
354 }