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 }