|
66 | 66 | * To send a buffer to another thread, the buffer must not have any outstanding borrows. |
67 | 67 | * That is to say, all {@linkplain #acquire() acquires} must have been paired with a {@link #close()}; |
68 | 68 | * 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}, |
70 | 70 | * then that composite buffer must be closed. |
71 | 71 | * And if this buffer is itself a composite buffer, then it must own all of its constituent buffers. |
72 | 72 | * The {@link #isOwned()} method can be used on any buffer to check if it can be sent or not. |
|
103 | 103 | * |
104 | 104 | */ |
105 | 105 | 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 | + |
106 | 193 | /** |
107 | 194 | * Change the default byte order of this buffer, and return this buffer. |
108 | 195 | * |
|
0 commit comments