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.buffer.api.internal.Statics;
19 import io.netty5.buffer.api.pool.PooledBufferAllocator;
20 import io.netty5.util.SafeCloseable;
21 import io.netty5.util.Send;
22
23 import java.nio.ByteBuffer;
24 import java.nio.charset.Charset;
25 import java.util.Collections;
26 import java.util.function.Supplier;
27
28 /**
29 * Interface for allocating {@link Buffer}s.
30 */
31 public interface BufferAllocator extends SafeCloseable {
32 /**
33 * Produces a {@link BufferAllocator} that allocates unpooled, on-heap buffers.
34 * On-heap buffers have a {@code byte[]} internally, and their
35 * {@linkplain ReadableComponent#readableNativeAddress() readable} and
36 * {@linkplain WritableComponent#writableNativeAddress() writable} native addresses are zero.
37 * <p>
38 * The concrete {@link Buffer} implementation is chosen by {@link MemoryManager#instance()}.
39 * <p>
40 * <strong>Note:</strong> This method always creates a new allocator instance.
41 * To get a shared and cached allocator instance, use the {@link DefaultBufferAllocators#onHeapAllocator()}
42 * method instead.
43 *
44 * @return A non-pooling allocator of on-heap buffers
45 */
46 static BufferAllocator onHeapUnpooled() {
47 return new ManagedBufferAllocator(MemoryManager.instance(), false);
48 }
49
50 /**
51 * Produces a {@link BufferAllocator} that allocates unpooled, off-heap buffers.
52 * Off-heap buffers a native memory pointer internally, which can be obtained from their
53 * {@linkplain ReadableComponent#readableNativeAddress() readable} and
54 * {@linkplain WritableComponent#writableNativeAddress() writable} native address methods.
55 * <p>
56 * The concrete {@link Buffer} implementation is chosen by {@link MemoryManager#instance()}.
57 * <p>
58 * <strong>Note:</strong> This method always creates a new allocator instance.
59 * To get a shared and cached allocator instance, use the {@link DefaultBufferAllocators#offHeapAllocator()}
60 * method instead.
61 *
62 * @return A non-pooling allocator of on-heap buffers
63 */
64 static BufferAllocator offHeapUnpooled() {
65 return new ManagedBufferAllocator(MemoryManager.instance(), true);
66 }
67
68 /**
69 * Produces a pooling {@link BufferAllocator} that allocates and recycles on-heap buffers.
70 * On-heap buffers have a {@code byte[]} internally, and their
71 * {@linkplain ReadableComponent#readableNativeAddress() readable} and
72 * {@linkplain WritableComponent#writableNativeAddress() writable} native addresses are zero.
73 * <p>
74 * The concrete {@link Buffer} implementation is chosen by {@link MemoryManager#instance()}.
75 * <p>
76 * <strong>Note:</strong> This method always creates a new allocator instance.
77 * To get a shared and cached allocator instance, use the {@link DefaultBufferAllocators#onHeapAllocator()}
78 * method instead.
79 *
80 * @return A pooling allocator of on-heap buffers
81 */
82 static BufferAllocator onHeapPooled() {
83 return new PooledBufferAllocator(MemoryManager.instance(), false);
84 }
85
86 /**
87 * Produces a pooling {@link BufferAllocator} that allocates and recycles off-heap buffers.
88 * Off-heap buffers a native memory pointer internally, which can be obtained from their
89 * {@linkplain ReadableComponent#readableNativeAddress() readable} and
90 * {@linkplain WritableComponent#writableNativeAddress() writable} native address methods.
91 * <p>
92 * The concrete {@link Buffer} implementation is chosen by {@link MemoryManager#instance()}.
93 * <p>
94 * <strong>Note:</strong> This method always creates a new allocator instance.
95 * To get a shared and cached allocator instance, use the {@link DefaultBufferAllocators#offHeapAllocator()}
96 * method instead.
97 *
98 * @return A pooling allocator of on-heap buffers
99 */
100 static BufferAllocator offHeapPooled() {
101 return new PooledBufferAllocator(MemoryManager.instance(), true);
102 }
103
104 /**
105 * Determine if this allocator is pooling and reusing its allocated memory.
106 *
107 * @return {@code true} if this allocator is pooling and reusing its memory, {@code false} otherwise.
108 */
109 boolean isPooling();
110
111 /**
112 * Get the {@link AllocationType} from this allocator.
113 * This would typically be one of the {@link StandardAllocationTypes}.
114 *
115 * @return The type of allocations performed by this allocator.
116 */
117 AllocationType getAllocationType();
118
119 /**
120 * Allocate a {@link Buffer} of the given size in bytes. This method may throw an {@link OutOfMemoryError} if there
121 * is not enough free memory available to allocate a {@link Buffer} of the requested size.
122 * <p>
123 * The buffer will use big endian byte order.
124 *
125 * @param size The size of {@link Buffer} to allocate.
126 * @return The newly allocated {@link Buffer}.
127 * @throws IllegalStateException if this allocator has been {@linkplain #close() closed}.
128 */
129 Buffer allocate(int size);
130
131 /**
132 * Compose the send of a buffer and present them as a single buffer.
133 * <p>
134 * When a composite buffer is closed, all of its constituent component buffers are closed as well.
135 * <p>
136 * See the class documentation for more information on how buffers compose, and what is required of the given
137 * buffers for composition to be allowed.
138 *
139 * @param send The sent buffer to compose into a single buffer view.
140 * @return A buffer composed of, and backed by, the given buffers.
141 * @throws IllegalStateException if one of the sends have already been received. The remaining buffers and sends
142 * will be closed and discarded, respectively.
143 */
144 default CompositeBuffer compose(Send<Buffer> send) {
145 return DefaultCompositeBuffer.compose(this, Collections.singleton(send));
146 }
147
148 /**
149 * Compose the given sequence of sends of buffers and present them as a single buffer.
150 * <p>
151 * When a composite buffer is closed, all of its constituent component buffers are closed as well.
152 * <p>
153 * See the class documentation for more information on how buffers compose, and what is required of the given
154 * buffers for composition to be allowed.
155 *
156 * @param sends The sent buffers to compose into a single buffer view.
157 * @return A buffer composed of, and backed by, the given buffers.
158 * @throws IllegalStateException if one of the sends have already been received. The remaining buffers and sends
159 * will be closed and discarded, respectively.
160 */
161 default CompositeBuffer compose(Iterable<Send<Buffer>> sends) {
162 return DefaultCompositeBuffer.compose(this, sends);
163 }
164
165 /**
166 * Create an empty composite buffer, that has no components. The buffer can be extended with components using either
167 * {@link CompositeBuffer#ensureWritable(int)} or {@link CompositeBuffer#extendWith(Send)}.
168 * @return A composite buffer that has no components, and has a capacity of zero.
169 */
170 default CompositeBuffer compose() {
171 return DefaultCompositeBuffer.compose(this);
172 }
173
174 /**
175 * Create a supplier of "constant" {@linkplain Buffer Buffers} from this allocator, that all have the given
176 * byte contents. The buffer has the same capacity as the byte array length, and its write offset is placed at the
177 * end, and its read offset is at the beginning, such that the entire buffer contents are readable.
178 * <p>
179 * The buffers produced by the supplier will each have their own independent life-cycle, and closing them will
180 * make them {@linkplain Buffer#isAccessible() inaccessible}, just like normally allocated buffers.
181 * <p>
182 * The buffers produced are "constants", in the sense that they are {@linkplain Buffer#readOnly() read-only}.
183 * <p>
184 * It can generally be expected, but is not guaranteed, that the returned supplier is more resource efficient than
185 * allocating and copying memory with other available APIs. In such optimised implementations, the underlying memory
186 * baking the buffers will be shared among all the buffers produced by the supplier.
187 * <p>
188 * The primary use case for this API, is when you need to repeatedly produce buffers with the same contents, and
189 * you perhaps wish to keep a {@code static final} field with these contents. The supplier-based API enforces
190 * that each usage get their own distinct buffer instance. Each of these instances cannot interfere with each other,
191 * so bugs like closing, or modifying the contents, of a shared buffer cannot occur.
192 *
193 * @param bytes The byte contents of the buffers produced by the returned supplier.
194 * @return A supplier of read-only buffers with the given contents.
195 * @throws IllegalStateException if this allocator has been {@linkplain #close() closed}, but any supplier obtained
196 * prior to closing the allocator will continue to work.
197 */
198 Supplier<Buffer> constBufferSupplier(byte[] bytes);
199
200 /**
201 * Allocate a {@link Buffer} with the same size and contents of the given byte array.
202 * The allocated buffer is <em>NOT</em> backed by the given byte array, and changes to the contents of either
203 * will not be reflected in the other.
204 * This may throw an {@link OutOfMemoryError} if there is not enough free memory available to allocate a
205 * {@link Buffer} of the requested size.
206 * <p>
207 * The allocated buffer will use big endian byte order.
208 *
209 * @param bytes The byte array that determines the size and contents of the new buffer.
210 * @return The newly allocated {@link Buffer}.
211 * @throws IllegalStateException if this allocator has been {@linkplain #close() closed}.
212 */
213 default Buffer copyOf(byte[] bytes) {
214 return allocate(bytes.length).writeBytes(bytes);
215 }
216
217 /**
218 * Allocate a {@link Buffer} with the same size and contents of the given {@link String},
219 * when interpreted as a sequence of bytes with the given {@link Charset}.
220 * This may throw an {@link OutOfMemoryError} if there is not enough free memory available to allocate a
221 * {@link Buffer} of the requested size.
222 * <p>
223 * The allocated buffer will use big endian byte order.
224 *
225 * @param str The {@link String} that determines the size and contents of the new buffer.
226 * @param charset The {@link Charset} that determines how to turn the string into a sequence of bytes.
227 * @return The newly allocated {@link Buffer}.
228 * @throws IllegalStateException if this allocator has been {@linkplain #close() closed}.
229 */
230 default Buffer copyOf(String str, Charset charset) {
231 byte[] bytes = str.getBytes(charset);
232 return allocate(bytes.length).writeBytes(bytes);
233 }
234
235 /**
236 * Allocate a {@link Buffer} with the same size and contents, as the contents of the given {@link ByteBuffer}.
237 * The allocated buffer is <em>NOT</em> backed by the give byte buffer, and changes to the contents of either
238 * will not be reflected in the other.
239 * The position and limit of the given byte buffer defines the region of contents that will be copied.
240 * The position and limit are not modified by this method.
241 * This may throw an {@link OutOfMemoryError} if there is not enough free memory available to allocate a
242 * {@link Buffer} of the requested size.
243 * <p>
244 * The allocated buffer will use big endian byte order, regardless of the byte order of the given buffer.
245 * The contents of the byte buffer will be copied without regard to the byte order, as if the bytes are copied
246 * one at a time.
247 *
248 * @param buffer The byte buffer, whose contents determine the capacity and contents of the allocated buffer.
249 * @return The newly allocated {@link Buffer}.
250 * @throws IllegalStateException if this allocator has been {@linkplain #close() closed}.
251 */
252 default Buffer copyOf(ByteBuffer buffer) {
253 if (!buffer.hasRemaining()) {
254 return allocate(0);
255 }
256 int bytesToCopy = buffer.remaining();
257 final Buffer copy = allocate(bytesToCopy);
258 final ByteBuffer duplicate = buffer.duplicate();
259 copy.forEachWritable(0, (i, component) -> {
260 ByteBuffer dest = component.writableBuffer();
261 int length = Math.min(dest.capacity(), duplicate.remaining());
262 Statics.bbput(dest, 0, duplicate, duplicate.position(), length);
263 duplicate.position(length + duplicate.position());
264 return true;
265 });
266 copy.skipWritableBytes(bytesToCopy);
267 return copy;
268 }
269
270 /**
271 * Close this allocator, freeing all of its internal resources.
272 * <p>
273 * Existing (currently in-use) allocated buffers will not be impacted by calling this method.
274 * If this is a pooling or caching allocator, then existing buffers will be immediately freed when they are closed,
275 * instead of being pooled or cached.
276 * <p>
277 * The allocator can no longer be used to allocate more buffers after calling this method.
278 * Attempting to allocate from a closed allocator will cause {@link IllegalStateException}s to be thrown.
279 */
280 @Override
281 void close();
282 }