View Javadoc
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 }