Skip to content
This repository was archived by the owner on Dec 12, 2022. It is now read-only.

Commit 7185a59

Browse files
committed
Move composite buffer methods to Buffer
Motivation: There is no reason for `compose()` to be an instance method on `BufferAllocator` since the allocator implementation should not influence how this method is implemented. Modification: Make `compose()` a static method and move it to the `Buffer` interface. Also move its companion methods `extendComposite()` and `isComposite()` to the `Buffer` interface. Result: The composite buffer methods are now in a more sensible place. Also: decided _against_ making `extendComposite()` and `isComposite()` instance methods, because the subtle behaviours of `extendComposite()` means it would behave quite differently for non-composite buffers. Also: `isComposite()` is not an instance method because it relates to the hard-coded and concrete `CompositeBuffer` implementation.
1 parent 53ba97e commit 7185a59

File tree

6 files changed

+182
-171
lines changed

6 files changed

+182
-171
lines changed

src/main/java/io/netty/buffer/api/Buffer.java

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
* To send a buffer to another thread, the buffer must not have any outstanding borrows.
6767
* That is to say, all {@linkplain #acquire() acquires} must have been paired with a {@link #close()};
6868
* all {@linkplain #slice() slices} must have been closed.
69-
* And if this buffer is a constituent of a {@linkplain BufferAllocator#compose(Deref...) composite buffer},
69+
* And if this buffer is a constituent of a {@linkplain Buffer#compose(BufferAllocator, Deref...) composite buffer},
7070
* then that composite buffer must be closed.
7171
* And if this buffer is itself a composite buffer, then it must own all of its constituent buffers.
7272
* The {@link #isOwned()} method can be used on any buffer to check if it can be sent or not.
@@ -103,6 +103,93 @@
103103
*
104104
*/
105105
public interface Buffer extends Rc<Buffer>, BufferAccessors {
106+
/**
107+
* Compose the given sequence of buffers and present them as a single buffer.
108+
* <p>
109+
* <strong>Note:</strong> The composite buffer increments the reference count on all the constituent buffers,
110+
* and holds a reference to them until the composite buffer is deallocated.
111+
* This means the constituent buffers must still have their outside-reference count decremented as normal.
112+
* If the buffers are allocated for the purpose of participating in the composite buffer,
113+
* then they should be closed as soon as the composite buffer has been created, like in this example:
114+
* <pre>{@code
115+
* try (Buffer a = allocator.allocate(size);
116+
* Buffer b = allocator.allocate(size)) {
117+
* return allocator.compose(a, b); // Reference counts for 'a' and 'b' incremented here.
118+
* } // Reference count for 'a' and 'b' decremented here; composite buffer now holds the last references.
119+
* }</pre>
120+
* <p>
121+
* {@linkplain Buffer#send() Sending} a composite buffer implies sending all of its constituent buffers.
122+
* For sending to be possible, both the composite buffer itself, and all of its constituent buffers, must be in an
123+
* {@linkplain Rc#isOwned() owned state}.
124+
* This means that the composite buffer must be the only reference to the constituent buffers.
125+
* <p>
126+
* All of the constituent buffers must have the same {@linkplain Buffer#order() byte order}.
127+
* An exception will be thrown if you attempt to compose buffers that have different byte orders,
128+
* and changing the byte order of the constituent buffers so they become inconsistent after construction,
129+
* will result in unspecified behaviour.
130+
* <p>
131+
* The read and write offsets of the constituent buffers must be arranged such that there are no "gaps" when viewed
132+
* as a single connected chunk of memory.
133+
* Specifically, there can be at most one buffer whose write offset is neither zero nor at capacity,
134+
* and all buffers prior to it must have their write offsets at capacity, and all buffers after it must have a write
135+
* offset of zero.
136+
* Likewise, there can be at most one buffer whose read offset is neither zero nor at capacity,
137+
* and all buffers prior to it must have their read offsets at capacity, and all buffers after it must have a read
138+
* offset of zero.
139+
* Furthermore, the sum of the read offsets must be less than or equal to the sum of the write offsets.
140+
* <p>
141+
* Reads and writes to the composite buffer that modifies the read or write offsets, will also modify the relevant
142+
* offsets in the constituent buffers.
143+
* <p>
144+
* It is not a requirement that the buffers have the same size.
145+
* <p>
146+
* It is not a requirement that the buffers are allocated by this allocator, but if
147+
* {@link Buffer#ensureWritable(int)} is called on the composed buffer, and the composed buffer needs to be
148+
* expanded, then this allocator instance will be used for allocation the extra memory.
149+
*
150+
* @param allocator The allocator for the composite buffer. This allocator will be used e.g. to service
151+
* {@link #ensureWritable(int)} calls.
152+
* @param bufs The buffers to compose into a single buffer view.
153+
* @return A buffer composed of, and backed by, the given buffers.
154+
* @throws IllegalArgumentException if the given buffers have an inconsistent
155+
* {@linkplain Buffer#order() byte order}.
156+
*/
157+
@SafeVarargs
158+
static Buffer compose(BufferAllocator allocator, Deref<Buffer>... bufs) {
159+
return new CompositeBuffer(allocator, bufs);
160+
}
161+
162+
/**
163+
* Extend the given composite buffer with the given extension buffer.
164+
* This works as if the extension had originally been included at the end of the list of constituent buffers when
165+
* the composite buffer was created.
166+
* The composite buffer is modified in-place.
167+
*
168+
* @see #compose(BufferAllocator, Deref...)
169+
* @param composite The composite buffer (from a prior {@link #compose(BufferAllocator, Deref...)} call) to extend
170+
* with the given extension buffer.
171+
* @param extension The buffer to extend the composite buffer with.
172+
*/
173+
static void extendComposite(Buffer composite, Buffer extension) {
174+
if (!isComposite(composite)) {
175+
throw new IllegalArgumentException(
176+
"Expected the first buffer to be a composite buffer, " +
177+
"but it is a " + composite.getClass() + " buffer: " + composite + '.');
178+
}
179+
CompositeBuffer compositeBuffer = (CompositeBuffer) composite;
180+
compositeBuffer.extendWith(extension);
181+
}
182+
183+
/**
184+
* Check if the given buffer is a {@linkplain #compose(BufferAllocator, Deref...) composite} buffer or not.
185+
* @param composite The buffer to check.
186+
* @return {@code true} if the given buffer was created with {@link #compose(BufferAllocator, Deref...)},
187+
* {@code false} otherwise.
188+
*/
189+
static boolean isComposite(Buffer composite) {
190+
return composite.getClass() == CompositeBuffer.class;
191+
}
192+
106193
/**
107194
* Change the default byte order of this buffer, and return this buffer.
108195
*

src/main/java/io/netty/buffer/api/BufferAllocator.java

Lines changed: 7 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@
2121
* Interface for {@link Buffer} allocators.
2222
*/
2323
public interface BufferAllocator extends AutoCloseable {
24+
/**
25+
* Check that the given {@code size} argument is a valid buffer size, or throw an {@link IllegalArgumentException}.
26+
*
27+
* @param size The size to check.
28+
* @throws IllegalArgumentException if the size is not possitive, or if the size is too big (over ~2 GB) for a
29+
* buffer to accomodate.
30+
*/
2431
static void checkSize(long size) {
2532
if (size < 1) {
2633
throw new IllegalArgumentException("Buffer size must be positive, but was " + size + '.');
@@ -59,89 +66,6 @@ default Buffer allocate(int size, ByteOrder order) {
5966
return allocate(size).order(order);
6067
}
6168

62-
/**
63-
* Compose the given sequence of buffers and present them as a single buffer.
64-
* <p>
65-
* <strong>Note:</strong> The composite buffer increments the reference count on all the constituent buffers,
66-
* and holds a reference to them until the composite buffer is deallocated.
67-
* This means the constituent buffers must still have their outside-reference count decremented as normal.
68-
* If the buffers are allocated for the purpose of participating in the composite buffer,
69-
* then they should be closed as soon as the composite buffer has been created, like in this example:
70-
* <pre>{@code
71-
* try (Buffer a = allocator.allocate(size);
72-
* Buffer b = allocator.allocate(size)) {
73-
* return allocator.compose(a, b); // Reference counts for 'a' and 'b' incremented here.
74-
* } // Reference count for 'a' and 'b' decremented here; composite buffer now holds the last references.
75-
* }</pre>
76-
* <p>
77-
* {@linkplain Buffer#send() Sending} a composite buffer implies sending all of its constituent buffers.
78-
* For sending to be possible, both the composite buffer itself, and all of its constituent buffers, must be in an
79-
* {@linkplain Rc#isOwned() owned state}.
80-
* This means that the composite buffer must be the only reference to the constituent buffers.
81-
* <p>
82-
* All of the constituent buffers must have the same {@linkplain Buffer#order() byte order}.
83-
* An exception will be thrown if you attempt to compose buffers that have different byte orders,
84-
* and changing the byte order of the constituent buffers so they become inconsistent after construction,
85-
* will result in unspecified behaviour.
86-
* <p>
87-
* The read and write offsets of the constituent buffers must be arranged such that there are no "gaps" when viewed
88-
* as a single connected chunk of memory.
89-
* Specifically, there can be at most one buffer whose write offset is neither zero nor at capacity,
90-
* and all buffers prior to it must have their write offsets at capacity, and all buffers after it must have a write
91-
* offset of zero.
92-
* Likewise, there can be at most one buffer whose read offset is neither zero nor at capacity,
93-
* and all buffers prior to it must have their read offsets at capacity, and all buffers after it must have a read
94-
* offset of zero.
95-
* Furthermore, the sum of the read offsets must be less than or equal to the sum of the write offsets.
96-
* <p>
97-
* Reads and writes to the composite buffer that modifies the read or write offsets, will also modify the relevant
98-
* offsets in the constituent buffers.
99-
* <p>
100-
* It is not a requirement that the buffers have the same size.
101-
* <p>
102-
* It is not a requirement that the buffers are allocated by this allocator, but if
103-
* {@link Buffer#ensureWritable(int)} is called on the composed buffer, and the composed buffer needs to be
104-
* expanded, then this allocator instance will be used for allocation the extra memory.
105-
*
106-
* @param bufs The buffers to compose into a single buffer view.
107-
* @return A buffer composed of, and backed by, the given buffers.
108-
* @throws IllegalArgumentException if the given buffers have an inconsistent
109-
* {@linkplain Buffer#order() byte order}.
110-
*/
111-
default Buffer compose(Deref<Buffer>... bufs) {
112-
return new CompositeBuffer(this, bufs);
113-
}
114-
115-
/**
116-
* Extend the given composite buffer with the given extension buffer.
117-
* This works as if the extension had originally been included at the end of the list of constituent buffers when
118-
* the composite buffer was created.
119-
* The composite buffer is modified in-place.
120-
*
121-
* @see #compose(Deref...)
122-
* @param composite The composite buffer (from a prior {@link #compose(Deref...)} call) to extend with the given
123-
* extension buffer.
124-
* @param extension The buffer to extend the composite buffer with.
125-
*/
126-
static void extend(Buffer composite, Buffer extension) {
127-
if (!isComposite(composite)) {
128-
throw new IllegalArgumentException(
129-
"Expected the first buffer to be a composite buffer, " +
130-
"but it is a " + composite.getClass() + " buffer: " + composite + '.');
131-
}
132-
CompositeBuffer buf = (CompositeBuffer) composite;
133-
buf.extendWith(extension);
134-
}
135-
136-
/**
137-
* Check if the given buffer is a {@linkplain #compose(Deref...) composite} buffer or not.
138-
* @param composite The buffer to check.
139-
* @return {@code true} if the given buffer was created with {@link #compose(Deref...)}, {@code false} otherwise.
140-
*/
141-
static boolean isComposite(Buffer composite) {
142-
return composite.getClass() == CompositeBuffer.class;
143-
}
144-
14569
/**
14670
* Close this allocator, freeing all of its internal resources. It is not specified if the allocator can still be
14771
* used after this method has been called on it.

0 commit comments

Comments
 (0)