- * A buffer is a sequential stretch of memory with a certain capacity, an offset for writing, and an offset for reading.
- *
- *
- * This carves the buffer into three regions, as demonstrated by this diagram:
- *
- * Splitting a buffer is useful for when you want to hand over a region of a buffer to some other,
- * perhaps unknown, piece of code, and relinquish your ownership of that buffer region in the process.
- * Examples include aggregating messages into an accumulator buffer, and sending messages down the pipeline for
- * further processing, as split buffer regions, once their data has been received in its entirety.
- *
- * If you instead wish to temporarily share a region of a buffer, you will have to pass offset and length along with the
- * buffer, or you will have to make a copy of the region.
- *
- *
, BufferAccessors {
- /**
- * Change the default byte order of this buffer, and return this buffer.
- *
- * @param order The new default byte order, used by accessor methods that don't use an explicit byte order.
- * @return This buffer instance.
- */
- Buffer order(ByteOrder order);
-
- /**
- * The default byte order of this buffer.
- * @return The default byte order of this buffer.
- */
- ByteOrder order();
-
- /**
- * The capacity of this buffer, that is, the maximum number of bytes it can contain.
- *
- * @return The capacity in bytes.
- */
- int capacity();
-
- /**
- * Get the current reader offset. The next read will happen from this byte offset into the buffer.
- *
- * @return The current reader offset.
- */
- int readerOffset();
-
- /**
- * Set the reader offset. Make the next read happen from the given offset into the buffer.
- *
- * @param offset The reader offset to set.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException if the specified {@code offset} is less than zero or greater than the current
- * {@link #writerOffset()}.
- */
- Buffer readerOffset(int offset);
-
- /**
- * Get the current writer offset. The next write will happen at this byte offset into the byffer.
- *
- * @return The current writer offset.
- */
- int writerOffset();
-
- /**
- * Set the writer offset. Make the next write happen at the given offset.
- *
- * @param offset The writer offset to set.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException if the specified {@code offset} is less than the current
- * {@link #readerOffset()} or greater than {@link #capacity()}.
- * @throws BufferClosedException if this buffer is closed.
- * @throws BufferReadOnlyException if this buffer is {@linkplain #readOnly() read-only}.
- */
- Buffer writerOffset(int offset);
-
- /**
- * Returns the number of readable bytes which is equal to {@code (writerOffset() - readerOffset())}.
- */
- default int readableBytes() {
- return writerOffset() - readerOffset();
- }
-
- /**
- * Returns the number of writable bytes which is equal to {@code (capacity() - writerOffset())}.
- */
- default int writableBytes() {
- return capacity() - writerOffset();
- }
-
- /**
- * Fill the buffer with the given byte value. This method does not respect the {@link #readerOffset()} or {@link
- * #writerOffset()}, but copies the full capacity of the buffer. The {@link #readerOffset()} and {@link
- * #writerOffset()} are not modified.
- *
- * @param value The byte value to write at every position in the buffer.
- * @return This Buffer.
- * @throws BufferReadOnlyException if this buffer is {@linkplain #readOnly() read-only}.
- */
- Buffer fill(byte value);
-
- /**
- * Give the native memory address backing this buffer, or return 0 if this buffer has no native memory address.
- * @return The native memory address, if any, otherwise 0.
- */
- long nativeAddress();
-
- /**
- * Make this buffer read-only.
- * This is irreversible.
- *
- * @return this buffer.
- */
- Buffer makeReadOnly();
-
- /**
- * Query if this buffer is read-only or not.
- *
- * @return {@code true} if this buffer is read-only, {@code false} otherwise.
- */
- boolean readOnly();
-
- /**
- * Copies the given length of data from this buffer into the given destination array, beginning at the given source
- * position in this buffer, and the given destination position in the destination array.
- *
- * This method does not read or modify the {@linkplain #writerOffset() write offset} or the
- * {@linkplain #readerOffset() read offset}.
- *
- * @param srcPos The byte offset into this buffer wherefrom the copying should start; the byte at this offset in
- * this buffer will be copied to the {@code destPos} index in the {@code dest} array.
- * @param dest The destination byte array.
- * @param destPos The index into the {@code dest} array wherefrom the copying should start.
- * @param length The number of bytes to copy.
- * @throws NullPointerException if the destination array is null.
- * @throws IndexOutOfBoundsException if the source or destination positions, or the length, are negative,
- * or if the resulting end positions reaches beyond the end of either this buffer, or the destination array.
- */
- void copyInto(int srcPos, byte[] dest, int destPos, int length);
-
- /**
- * Copies the given length of data from this buffer into the given destination byte buffer, beginning at the given
- * source position in this buffer, and the given destination position in the destination byte buffer.
- *
- * This method does not read or modify the {@linkplain #writerOffset() write offset} or the
- * {@linkplain #readerOffset() read offset}, nor is the position of the destination buffer changed.
- *
- * The position and limit of the destination byte buffer are also ignored, and do not influence {@code destPos}
- * or {@code length}.
- *
- * @param srcPos The byte offset into this buffer wherefrom the copying should start; the byte at this offset in
- * this buffer will be copied to the {@code destPos} index in the {@code dest} array.
- * @param dest The destination byte buffer.
- * @param destPos The index into the {@code dest} array wherefrom the copying should start.
- * @param length The number of bytes to copy.
- * @throws NullPointerException if the destination array is null.
- * @throws IndexOutOfBoundsException if the source or destination positions, or the length, are negative,
- * or if the resulting end positions reaches beyond the end of either this buffer, or the destination array.
- */
- void copyInto(int srcPos, ByteBuffer dest, int destPos, int length);
-
- /**
- * Copies the given length of data from this buffer into the given destination buffer, beginning at the given
- * source position in this buffer, and the given destination position in the destination buffer.
- *
- * This method does not read or modify the {@linkplain #writerOffset() write offset} or the
- * {@linkplain #readerOffset() read offset} on this buffer, nor on the destination buffer.
- *
- * The read and write offsets of the destination buffer are also ignored, and do not influence {@code destPos}
- * or {@code length}.
- *
- * @param srcPos The byte offset into this buffer wherefrom the copying should start; the byte at this offset in
- * this buffer will be copied to the {@code destPos} index in the {@code dest} array.
- * @param dest The destination buffer.
- * @param destPos The index into the {@code dest} array wherefrom the copying should start.
- * @param length The number of bytes to copy.
- * @throws NullPointerException if the destination array is null.
- * @throws IndexOutOfBoundsException if the source or destination positions, or the length, are negative,
- * or if the resulting end positions reaches beyond the end of either this buffer, or the destination array.
- */
- void copyInto(int srcPos, Buffer dest, int destPos, int length);
-
- /**
- * Write into this buffer, all the readable bytes from the given buffer.
- * This updates the {@linkplain #writerOffset() write offset} of this buffer, and the
- * {@linkplain #readerOffset() reader offset} of the given buffer.
- *
- * @param source The buffer to read from.
- * @return This buffer.
- */
- default Buffer writeBytes(Buffer source) {
- int size = source.readableBytes();
- int woff = writerOffset();
- writerOffset(woff + size);
- source.copyInto(source.readerOffset(), this, woff, size);
- source.readerOffset(source.readerOffset() + size);
- return this;
- }
-
- /**
- * Write into this buffer, all the bytes from the given byte array.
- * This updates the {@linkplain #writerOffset() write offset} of this buffer by the length of the array.
- *
- * @param source The byte array to read from.
- * @return This buffer.
- */
- default Buffer writeBytes(byte[] source) {
- int size = source.length;
- int woff = writerOffset();
- writerOffset(woff + size);
- for (int i = 0; i < size; i++) {
- setByte(woff + i, source[i]);
- }
- return this;
- }
-
- /**
- * Resets the {@linkplain #readerOffset() read offset} and the {@linkplain #writerOffset() write offset} on this
- * buffer to their initial values.
- */
- default Buffer reset() {
- readerOffset(0);
- writerOffset(0);
- return this;
- }
-
- /**
- * Open a cursor to iterate the readable bytes of this buffer. The {@linkplain #readerOffset() reader offset} and
- * {@linkplain #writerOffset() witer offset} are not modified by the cursor.
- *
- * Care should be taken to ensure that the buffer's lifetime extends beyond the cursor and the iteration, and that
- * the {@linkplain #readerOffset() reader offset} and {@linkplain #writerOffset() writer offset} are not modified
- * while the iteration takes place. Otherwise, unpredictable behaviour might result.
- *
- * @return A {@link ByteCursor} for iterating the readable bytes of this buffer.
- */
- ByteCursor openCursor();
-
- /**
- * Open a cursor to iterate the given number bytes of this buffer, starting at the given offset.
- * The {@linkplain #readerOffset() reader offset} and {@linkplain #writerOffset() witer offset} are not modified by
- * the cursor.
- *
- * Care should be taken to ensure that the buffer's lifetime extends beyond the cursor and the iteration, and that
- * the {@linkplain #readerOffset() reader offset} and {@linkplain #writerOffset() writer offset} are not modified
- * while the iteration takes place. Otherwise, unpredictable behaviour might result.
- *
- * @param fromOffset The offset into the buffer where iteration should start.
- * The first byte read from the iterator will be the byte at this offset.
- * @param length The number of bytes to iterate.
- * @return A {@link ByteCursor} for the given stretch of bytes of this buffer.
- * @throws IllegalArgumentException if the length is negative, or if the region given by the {@code fromOffset} and
- * the {@code length} reaches outside the bounds of this buffer.
- */
- ByteCursor openCursor(int fromOffset, int length);
-
- /**
- * Open a cursor to iterate the readable bytes of this buffer, in reverse.
- * The {@linkplain #readerOffset() reader offset} and {@linkplain #writerOffset() witer offset} are not modified by
- * the cursor.
- *
- * Care should be taken to ensure that the buffer's lifetime extends beyond the cursor and the iteration, and that
- * the {@linkplain #readerOffset() reader offset} and {@linkplain #writerOffset() writer offset} are not modified
- * while the iteration takes place. Otherwise, unpredictable behaviour might result.
- *
- * @return A {@link ByteCursor} for the readable bytes of this buffer.
- */
- default ByteCursor openReverseCursor() {
- int woff = writerOffset();
- return openReverseCursor(woff == 0? 0 : woff - 1, readableBytes());
- }
-
- /**
- * Open a cursor to iterate the given number bytes of this buffer, in reverse, starting at the given offset.
- * The {@linkplain #readerOffset() reader offset} and {@linkplain #writerOffset() witer offset} are not modified by
- * the cursor.
- *
- * Care should be taken to ensure that the buffer's lifetime extends beyond the cursor and the iteration, and that
- * the {@linkplain #readerOffset() reader offset} and {@linkplain #writerOffset() writer offset} are not modified
- * while the iteration takes place. Otherwise, unpredictable behaviour might result.
- *
- * @param fromOffset The offset into the buffer where iteration should start.
- * The first byte read from the iterator will be the byte at this offset.
- * @param length The number of bytes to iterate.
- * @return A {@link ByteCursor} for the given stretch of bytes of this buffer.
- * @throws IllegalArgumentException if the length is negative, or if the region given by the {@code fromOffset} and
- * the {@code length} reaches outside the bounds of this buffer.
- */
- ByteCursor openReverseCursor(int fromOffset, int length);
-
- /**
- * Ensure that this buffer has {@linkplain #writableBytes() available space for writing} the given number of
- * bytes.
- * If this buffer already has the necessary space, then this method returns immediately.
- * If this buffer does not already have the necessary space, then it will be expanded using the
- * {@link BufferAllocator} the buffer was created with.
- * This method is the same as calling {@link #ensureWritable(int, int, boolean)} where {@code allowCompaction} is
- * {@code false}.
- *
- * @param size The requested number of bytes of space that should be available for writing.
- * @throws IllegalStateException if this buffer is in a bad state.
- * @throws BufferClosedException if this buffer is closed.
- * @throws BufferReadOnlyException if this buffer is {@linkplain #readOnly() read-only}.
- */
- default void ensureWritable(int size) {
- ensureWritable(size, 1, true);
- }
-
- /**
- * Ensure that this buffer has {@linkplain #writableBytes() available space for writing} the given number of
- * bytes.
- * If this buffer already has the necessary space, then this method returns immediately.
- * If this buffer does not already have the necessary space, then space will be made available in one or all of
- * the following available ways:
- *
- *
- * -
- * If {@code allowCompaction} is {@code true}, and sum of the read and writable bytes would be enough to
- * satisfy the request, and it (depending on the buffer implementation) seems faster and easier to compact
- * the existing buffer rather than allocation a new buffer, then the requested bytes will be made available
- * that way. The compaction will not necessarily work the same way as the {@link #compact()} method, as the
- * implementation may be able to make the requested bytes available with less effort than is strictly
- * mandated by the {@link #compact()} method.
- *
- * -
- * Regardless of the value of the {@code allowCompaction}, the implementation may make more space available
- * by just allocating more or larger buffers. This allocation would use the same {@link BufferAllocator}
- * that this buffer was created with.
- *
- * -
- * If {@code allowCompaction} is {@code true}, then the implementation may choose to do a combination of
- * compaction and allocation.
- *
- *
- *
- * @param size The requested number of bytes of space that should be available for writing.
- * @param minimumGrowth The minimum number of bytes to grow by. If it is determined that memory should be allocated
- * and copied, make sure that the new memory allocation is bigger than the old one by at least
- * this many bytes. This way, the buffer can grow by more than what is immediately necessary,
- * thus amortising the costs of allocating and copying.
- * @param allowCompaction {@code true} if the method is allowed to modify the
- * {@linkplain #readerOffset() reader offset} and
- * {@linkplain #writerOffset() writer offset}, otherwise {@code false}.
- * @throws BufferReadOnlyException if this buffer is {@linkplain #readOnly() read-only}.
- * @throws IllegalArgumentException if {@code size} or {@code minimumGrowth} are negative.
- * @throws IllegalStateException if this buffer is in a bad state.
- */
- void ensureWritable(int size, int minimumGrowth, boolean allowCompaction);
-
- /**
- * Returns a copy of this buffer's readable bytes.
- * Modifying the content of the returned buffer will not affect this buffers contents.
- * The two buffers will maintain separate offsets. This method is identical to
- * {@code buf.copy(buf.readerOffset(), buf.readableBytes())}.
- * This method does not modify {@link #readerOffset()} or {@link #writerOffset()} of this buffer.
- *
- * The copy is created with a {@linkplain #writerOffset() write offset} equal to the length of the copied data,
- * so that the entire contents of the copy is ready to be read.
- *
- * @return A new buffer instance, with independent {@link #readerOffset()} and {@link #writerOffset()},
- * that contains a copy of the readable region of this buffer.
- */
- default Buffer copy() {
- int offset = readerOffset();
- int length = readableBytes();
- return copy(offset, length);
- }
-
- /**
- * Returns a copy of the given region of this buffer.
- * Modifying the content of the returned buffer will not affect this buffers contents.
- * The two buffers will maintain separate offsets.
- * This method does not modify {@link #readerOffset()} or {@link #writerOffset()} of this buffer.
- *
- * The copy is created with a {@linkplain #writerOffset() write offset} equal to the length of the copy,
- * so that the entire contents of the copy is ready to be read.
- *
- * @return A new buffer instance, with independent {@link #readerOffset()} and {@link #writerOffset()},
- * that contains a copy of the given region of this buffer.
- */
- Buffer copy(int offset, int length);
-
- /**
- * Split the buffer into two, at the {@linkplain #writerOffset() write offset} position.
- *
- * The region of this buffer that contain the read and readable bytes, will be captured and returned in a new
- * buffer, that will hold its own ownership of that region. This allows the returned buffer to be independently
- * {@linkplain #send() sent} to other threads.
- *
- * The returned buffer will adopt the {@link #readerOffset()} of this buffer, and have its {@link #writerOffset()}
- * and {@link #capacity()} both set to the equal to the write-offset of this buffer.
- *
- * The memory region in the returned buffer will become inaccessible through this buffer. This buffer will have its
- * capacity reduced by the capacity of the returned buffer, and the read and write offsets of this buffer will both
- * become zero, even though their position in memory remain unchanged.
- *
- * Effectively, the following transformation takes place:
- *
{@code
- * This buffer:
- * +------------------------------------------+
- * 0| |r/o |w/o |cap
- * +---+---------------------+----------------+
- * / / / \ \
- * / / / \ \
- * / / / \ \
- * / / / \ \
- * / / / \ \
- * +---+---------------------+ +---------------+
- * | |r/o |w/o & cap |r/o & w/o |cap
- * +---+---------------------+ +---------------+
- * Returned buffer. This buffer.
- * }
- * When the buffers are in this state, both of the split parts retain an atomic reference count on the
- * underlying memory. This means that shared underlying memory will not be deallocated or returned to a pool, until
- * all the split parts have been closed.
- *
- * Composite buffers have it a little easier, in that at most only one of the constituent buffers will actually be
- * split. If the split point lands perfectly between two constituent buffers, then a composite buffer can
- * simply split its internal array in two.
- *
- * Split buffers support all operations that normal buffers do, including {@link #ensureWritable(int)}.
- *
- * See the Splitting buffers section for details.
- *
- * @return A new buffer with independent and exclusive ownership over the read and readable bytes from this buffer.
- */
- default Buffer split() {
- return split(writerOffset());
- }
-
- /**
- * Split the buffer into two, at the given {@code splitOffset}.
- *
- * The region of this buffer that precede the {@code splitOffset}, will be captured and returned in a new
- * buffer, that will hold its own ownership of that region. This allows the returned buffer to be independently
- * {@linkplain #send() sent} to other threads.
- *
- * The returned buffer will adopt the {@link #readerOffset()} and {@link #writerOffset()} of this buffer,
- * but truncated to fit within the capacity dictated by the {@code splitOffset}.
- *
- * The memory region in the returned buffer will become inaccessible through this buffer. If the
- * {@link #readerOffset()} or {@link #writerOffset()} of this buffer lie prior to the {@code splitOffset},
- * then those offsets will be moved forward, so they land on offset 0 after the split.
- *
- * Effectively, the following transformation takes place:
- *
{@code
- * This buffer:
- * +--------------------------------+
- * 0| |splitOffset |cap
- * +---------------+----------------+
- * / / \ \
- * / / \ \
- * / / \ \
- * / / \ \
- * / / \ \
- * +---------------+ +---------------+
- * | |cap | |cap
- * +---------------+ +---------------+
- * Returned buffer. This buffer.
- * }
- * When the buffers are in this state, both of the split parts retain an atomic reference count on the
- * underlying memory. This means that shared underlying memory will not be deallocated or returned to a pool, until
- * all the split parts have been closed.
- *
- * Composite buffers have it a little easier, in that at most only one of the constituent buffers will actually be
- * split. If the split point lands perfectly between two constituent buffers, then a composite buffer can
- * simply split its internal array in two.
- *
- * Split buffers support all operations that normal buffers do, including {@link #ensureWritable(int)}.
- *
- * See the Splitting buffers section for details.
- *
- * @return A new buffer with independent and exclusive ownership over the bytes from the beginning to the given
- * offset of this buffer.
- */
- Buffer split(int splitOffset);
-
- /**
- * Discards the read bytes, and moves the buffer contents to the beginning of the buffer.
- *
- * @throws BufferReadOnlyException if this buffer is {@linkplain #readOnly() read-only}.
- * @throws IllegalStateException if this buffer is in a bad state.
- */
- void compact();
-
- /**
- * Get the number of "components" in this buffer. For composite buffers, this is the number of transitive
- * constituent buffers, while non-composite buffers only have one component.
- *
- * @return The number of components in this buffer.
- */
- int countComponents();
-
- /**
- * Get the number of "components" in this buffer, that are readable. These are the components that would be
- * processed by {@link #forEachReadable(int, ReadableComponentProcessor)}. For composite buffers, this is the
- * number of transitive constituent buffers that are readable, while non-composite buffers only have at most one
- * readable component.
- *
- * The number of readable components may be less than the {@link #countComponents() component count}, if not all of
- * them have readable data.
- *
- * @return The number of readable components in this buffer.
- */
- int countReadableComponents();
-
- /**
- * Get the number of "components" in this buffer, that are writable. These are the components that would be
- * processed by {@link #forEachWritable(int, WritableComponentProcessor)}. For composite buffers, this is the
- * number of transitive constituent buffers that are writable, while non-composite buffers only have at most one
- * writable component.
- *
- * The number of writable components may be less than the {@link #countComponents() component count}, if not all of
- * them have space for writing.
- *
- * @return The number of writable components in this buffer.
- */
- int countWritableComponents();
-
- /**
- * Process all readable components of this buffer, and return the number of components processed.
- *
- * The given {@linkplain ReadableComponentProcessor processor} is called for each readable component in this buffer,
- * and passed a component index, for the given component in the iteration, and a {@link ReadableComponent} object
- * for accessing the data within the given component.
- *
- * The component index is specific to the particular invokation of this method. The first call to the consumer will
- * be passed the given initial index, and the next call will be passed the initial index plus one, and so on.
- *
- * The {@linkplain ReadableComponentProcessor component processor} may stop the iteration at any time by returning
- * {@code false}.
- * This will cause the number of components processed to be returned as a negative number (to signal early return),
- * and the number of components processed may then be less than the
- * {@linkplain #countReadableComponents() readable component count}.
- *
- * Note that the {@link ReadableComponent} instance passed to the consumer could be reused for
- * multiple calls, so the data must be extracted from the component in the context of the iteration.
- *
- * The {@link ByteBuffer} instances obtained from the component, share lifetime with that internal component.
- * This means they can be accessed as long as the internal memory store remain unchanged. Methods that may cause
- * such changes are {@link #split(int)}, {@link #split()}, {@link #compact()}, {@link #ensureWritable(int)},
- * {@link #ensureWritable(int, int, boolean)}, and {@link #send()}.
- *
- * The best way to ensure this doesn't cause any trouble, is to use the buffers directly as part of the iteration,
- * or immediately after the iteration while we are still in the scope of the method that triggered the iteration.
- *
- * Note that the arrays, memory addresses, and byte buffers exposed as components by this method,
- * should not be used for changing the buffer contents. Doing so may cause undefined behaviour.
- *
- * Changes to position and limit of the byte buffers exposed via the processed components, are not reflected back to
- * this buffer instance.
- *
- * @param initialIndex The initial index of the iteration, and the index that will be passed to the first call to
- * the {@linkplain ReadableComponentProcessor#process(int, ReadableComponent) processor}.
- * @param processor The processor that will be used to process the buffer components.
- * @return The number of readable components processed, as a positive number of all readable components were
- * processed, or as a negative number if the iteration was stopped because
- * {@link ReadableComponentProcessor#process(int, ReadableComponent)} returned {@code false}.
- * In any case, the number of components processed may be less than {@link #countComponents()}.
- */
- int forEachReadable(int initialIndex, ReadableComponentProcessor processor) throws E;
-
- /**
- * Process all writable components of this buffer, and return the number of components processed.
- *
- * The given {@linkplain WritableComponentProcessor processor} is called for each writable component in this buffer,
- * and passed a component index, for the given component in the iteration, and a {@link WritableComponent} object
- * for accessing the data within the given component.
- *
- * The component index is specific to the particular invokation of this method. The first call to the consumer will
- * be passed the given initial index, and the next call will be passed the initial index plus one, and so on.
- *
- * The {@link WritableComponentProcessor component processor} may stop the iteration at any time by returning
- * {@code false}.
- * This will cause the number of components processed to be returned as a negative number (to signal early return),
- * and the number of components processed may then be less than the
- * {@linkplain #countReadableComponents() readable component count}.
- *
- * Note that the {@link WritableComponent} instance passed to the consumer could be reused for
- * multiple calls, so the data must be extracted from the component in the context of the iteration.
- *
- * The {@link ByteBuffer} instances obtained from the component, share lifetime with that internal component.
- * This means they can be accessed as long as the internal memory store remain unchanged. Methods that may cause
- * such changes are {@link #split(int)}, {@link #split()}, {@link #compact()}, {@link #ensureWritable(int)},
- * {@link #ensureWritable(int, int, boolean)}, and {@link #send()}.
- *
- * The best way to ensure this doesn't cause any trouble, is to use the buffers directly as part of the iteration,
- * or immediately after the iteration while we are still in the scope of the method that triggered the iteration.
- *
- * Changes to position and limit of the byte buffers exposed via the processed components, are not reflected back to
- * this buffer instance.
- *
- * @param initialIndex The initial index of the iteration, and the index that will be passed to the first call to
- * the {@linkplain WritableComponentProcessor#process(int, WritableComponent) processor}.
- * @param processor The processor that will be used to process the buffer components.
- * @return The number of writable components processed, as a positive number of all writable components were
- * processed, or as a negative number if the iteration was stopped because
- * {@link WritableComponentProcessor#process(int, WritableComponent)} returned {@code false}.
- * In any case, the number of components processed may be less than {@link #countComponents()}.
- */
- int forEachWritable(int initialIndex, WritableComponentProcessor processor) throws E;
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/BufferAccessors.java b/buffer-api/src/main/java/io/netty/buffer/api/BufferAccessors.java
deleted file mode 100644
index 2ff30fe..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/BufferAccessors.java
+++ /dev/null
@@ -1,614 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-/**
- * This interface is just the primitive data accessor methods that {@link Buffer} exposes.
- * It can be useful if you only need the data access methods, and perhaps wish to decorate or modify their behaviour.
- * Usually, you'd use the {@link Buffer} interface directly, since this lets you properly control the buffer reference
- * count.
- */
-public interface BufferAccessors {
- //
- /**
- * Get the byte value at the current {@link Buffer#readerOffset()},
- * and increases the reader offset by {@link Byte#BYTES}.
- * The value is read using a two's complement 8-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @return The byte value at the current reader offset.
- * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Byte#BYTES}.
- */
- byte readByte();
-
- /**
- * Get the byte value at the given reader offset.
- * The {@link Buffer#readerOffset()} is not modified.
- * The value is read using a two's complement 8-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param roff The read offset, an absolute offset into this buffer, to read from.
- * @return The byte value at the given offset.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Byte#BYTES}.
- */
- byte getByte(int roff);
-
- /**
- * Get the unsigned byte value at the current {@link Buffer#readerOffset()},
- * and increases the reader offset by {@link Byte#BYTES}.
- * The value is read using an unsigned two's complement 8-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @return The unsigned byte value at the current reader offset.
- * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Byte#BYTES}.
- */
- int readUnsignedByte();
-
- /**
- * Get the unsigned byte value at the given reader offset.
- * The {@link Buffer#readerOffset()} is not modified.
- * The value is read using an unsigned two's complement 8-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param roff The read offset, an absolute offset into this buffer, to read from.
- * @return The unsigned byte value at the given offset.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Byte#BYTES}.
- */
- int getUnsignedByte(int roff);
-
- /**
- * Set the given byte value at the current {@link Buffer#writerOffset()},
- * and increase the writer offset by {@link Byte#BYTES}.
- * The value is written using a two's complement 8-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param value The byte value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Byte#BYTES}.
- */
- Buffer writeByte(byte value);
-
- /**
- * Set the given byte value at the given write offset. The {@link Buffer#writerOffset()} is not modified.
- * The value is written using a two's complement 8-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param woff The write offset, an absolute offset into this buffer to write to.
- * @param value The byte value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Byte#BYTES}.
- */
- Buffer setByte(int woff, byte value);
-
- /**
- * Set the given unsigned byte value at the current {@link Buffer#writerOffset()},
- * and increase the writer offset by {@link Byte#BYTES}.
- * The value is written using an unsigned two's complement 8-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param value The int value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Byte#BYTES}.
- */
- Buffer writeUnsignedByte(int value);
-
- /**
- * Set the given unsigned byte value at the given write offset. The {@link Buffer#writerOffset()} is not modified.
- * The value is written using an unsigned two's complement 8-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param woff The write offset, an absolute offset into this buffer to write to.
- * @param value The int value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Byte#BYTES}.
- */
- Buffer setUnsignedByte(int woff, int value);
-
- /**
- * Get the char value at the current {@link Buffer#readerOffset()},
- * and increases the reader offset by 2.
- * The value is read using a 2-byte UTF-16 encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @return The char value at the current reader offset.
- * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than 2.
- */
- char readChar();
-
- /**
- * Get the char value at the given reader offset.
- * The {@link Buffer#readerOffset()} is not modified.
- * The value is read using a 2-byte UTF-16 encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param roff The read offset, an absolute offset into this buffer, to read from.
- * @return The char value at the given offset.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus 2.
- */
- char getChar(int roff);
-
- /**
- * Set the given char value at the current {@link Buffer#writerOffset()},
- * and increase the writer offset by 2.
- * The value is written using a 2-byte UTF-16 encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param value The char value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than 2.
- */
- Buffer writeChar(char value);
-
- /**
- * Set the given char value at the given write offset. The {@link Buffer#writerOffset()} is not modified.
- * The value is written using a 2-byte UTF-16 encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param woff The write offset, an absolute offset into this buffer to write to.
- * @param value The char value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus 2.
- */
- Buffer setChar(int woff, char value);
-
- /**
- * Get the short value at the current {@link Buffer#readerOffset()},
- * and increases the reader offset by {@link Short#BYTES}.
- * The value is read using a two's complement 16-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @return The short value at the current reader offset.
- * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Short#BYTES}.
- */
- short readShort();
-
- /**
- * Get the short value at the given reader offset.
- * The {@link Buffer#readerOffset()} is not modified.
- * The value is read using a two's complement 16-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param roff The read offset, an absolute offset into this buffer, to read from.
- * @return The short value at the given offset.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Short#BYTES}.
- */
- short getShort(int roff);
-
- /**
- * Get the unsigned short value at the current {@link Buffer#readerOffset()},
- * and increases the reader offset by {@link Short#BYTES}.
- * The value is read using an unsigned two's complement 16-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @return The unsigned short value at the current reader offset.
- * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Short#BYTES}.
- */
- int readUnsignedShort();
-
- /**
- * Get the unsigned short value at the given reader offset.
- * The {@link Buffer#readerOffset()} is not modified.
- * The value is read using an unsigned two's complement 16-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param roff The read offset, an absolute offset into this buffer, to read from.
- * @return The unsigned short value at the given offset.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Short#BYTES}.
- */
- int getUnsignedShort(int roff);
-
- /**
- * Set the given short value at the current {@link Buffer#writerOffset()},
- * and increase the writer offset by {@link Short#BYTES}.
- * The value is written using a two's complement 16-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param value The short value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Short#BYTES}.
- */
- Buffer writeShort(short value);
-
- /**
- * Set the given short value at the given write offset. The {@link Buffer#writerOffset()} is not modified.
- * The value is written using a two's complement 16-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param woff The write offset, an absolute offset into this buffer to write to.
- * @param value The short value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Short#BYTES}.
- */
- Buffer setShort(int woff, short value);
-
- /**
- * Set the given unsigned short value at the current {@link Buffer#writerOffset()},
- * and increase the writer offset by {@link Short#BYTES}.
- * The value is written using an unsigned two's complement 16-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param value The int value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Short#BYTES}.
- */
- Buffer writeUnsignedShort(int value);
-
- /**
- * Set the given unsigned short value at the given write offset. The {@link Buffer#writerOffset()} is not modified.
- * The value is written using an unsigned two's complement 16-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param woff The write offset, an absolute offset into this buffer to write to.
- * @param value The int value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Short#BYTES}.
- */
- Buffer setUnsignedShort(int woff, int value);
-
- /**
- * Get the int value at the current {@link Buffer#readerOffset()},
- * and increases the reader offset by 3.
- * The value is read using a two's complement 24-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @return The int value at the current reader offset.
- * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than 3.
- */
- int readMedium();
-
- /**
- * Get the int value at the given reader offset.
- * The {@link Buffer#readerOffset()} is not modified.
- * The value is read using a two's complement 24-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param roff The read offset, an absolute offset into this buffer, to read from.
- * @return The int value at the given offset.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus 3.
- */
- int getMedium(int roff);
-
- /**
- * Get the unsigned int value at the current {@link Buffer#readerOffset()},
- * and increases the reader offset by 3.
- * The value is read using an unsigned two's complement 24-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @return The unsigned int value at the current reader offset.
- * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than 3.
- */
- int readUnsignedMedium();
-
- /**
- * Get the unsigned int value at the given reader offset.
- * The {@link Buffer#readerOffset()} is not modified.
- * The value is read using an unsigned two's complement 24-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param roff The read offset, an absolute offset into this buffer, to read from.
- * @return The unsigned int value at the given offset.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus 3.
- */
- int getUnsignedMedium(int roff);
-
- /**
- * Set the given int value at the current {@link Buffer#writerOffset()},
- * and increase the writer offset by 3.
- * The value is written using a two's complement 24-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param value The int value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than 3.
- */
- Buffer writeMedium(int value);
-
- /**
- * Set the given int value at the given write offset. The {@link Buffer#writerOffset()} is not modified.
- * The value is written using a two's complement 24-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param woff The write offset, an absolute offset into this buffer to write to.
- * @param value The int value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus 3.
- */
- Buffer setMedium(int woff, int value);
-
- /**
- * Set the given unsigned int value at the current {@link Buffer#writerOffset()},
- * and increase the writer offset by 3.
- * The value is written using an unsigned two's complement 24-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param value The int value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than 3.
- */
- Buffer writeUnsignedMedium(int value);
-
- /**
- * Set the given unsigned int value at the given write offset. The {@link Buffer#writerOffset()} is not modified.
- * The value is written using an unsigned two's complement 24-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param woff The write offset, an absolute offset into this buffer to write to.
- * @param value The int value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus 3.
- */
- Buffer setUnsignedMedium(int woff, int value);
-
- /**
- * Get the int value at the current {@link Buffer#readerOffset()},
- * and increases the reader offset by {@link Integer#BYTES}.
- * The value is read using a two's complement 32-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @return The int value at the current reader offset.
- * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Integer#BYTES}.
- */
- int readInt();
-
- /**
- * Get the int value at the given reader offset.
- * The {@link Buffer#readerOffset()} is not modified.
- * The value is read using a two's complement 32-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param roff The read offset, an absolute offset into this buffer, to read from.
- * @return The int value at the given offset.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Integer#BYTES}.
- */
- int getInt(int roff);
-
- /**
- * Get the unsigned int value at the current {@link Buffer#readerOffset()},
- * and increases the reader offset by {@link Integer#BYTES}.
- * The value is read using an unsigned two's complement 32-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @return The unsigned int value at the current reader offset.
- * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Integer#BYTES}.
- */
- long readUnsignedInt();
-
- /**
- * Get the unsigned int value at the given reader offset.
- * The {@link Buffer#readerOffset()} is not modified.
- * The value is read using an unsigned two's complement 32-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param roff The read offset, an absolute offset into this buffer, to read from.
- * @return The unsigned int value at the given offset.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Integer#BYTES}.
- */
- long getUnsignedInt(int roff);
-
- /**
- * Set the given int value at the current {@link Buffer#writerOffset()},
- * and increase the writer offset by {@link Integer#BYTES}.
- * The value is written using a two's complement 32-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param value The int value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Integer#BYTES}.
- */
- Buffer writeInt(int value);
-
- /**
- * Set the given int value at the given write offset. The {@link Buffer#writerOffset()} is not modified.
- * The value is written using a two's complement 32-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param woff The write offset, an absolute offset into this buffer to write to.
- * @param value The int value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Integer#BYTES}.
- */
- Buffer setInt(int woff, int value);
-
- /**
- * Set the given unsigned int value at the current {@link Buffer#writerOffset()},
- * and increase the writer offset by {@link Integer#BYTES}.
- * The value is written using an unsigned two's complement 32-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param value The long value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Integer#BYTES}.
- */
- Buffer writeUnsignedInt(long value);
-
- /**
- * Set the given unsigned int value at the given write offset. The {@link Buffer#writerOffset()} is not modified.
- * The value is written using an unsigned two's complement 32-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param woff The write offset, an absolute offset into this buffer to write to.
- * @param value The long value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Integer#BYTES}.
- */
- Buffer setUnsignedInt(int woff, long value);
-
- /**
- * Get the float value at the current {@link Buffer#readerOffset()},
- * and increases the reader offset by {@link Float#BYTES}.
- * The value is read using a 32-bit IEEE floating point encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @return The float value at the current reader offset.
- * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Float#BYTES}.
- */
- float readFloat();
-
- /**
- * Get the float value at the given reader offset.
- * The {@link Buffer#readerOffset()} is not modified.
- * The value is read using a 32-bit IEEE floating point encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param roff The read offset, an absolute offset into this buffer, to read from.
- * @return The float value at the given offset.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Float#BYTES}.
- */
- float getFloat(int roff);
-
- /**
- * Set the given float value at the current {@link Buffer#writerOffset()},
- * and increase the writer offset by {@link Float#BYTES}.
- * The value is written using a 32-bit IEEE floating point encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param value The float value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Float#BYTES}.
- */
- Buffer writeFloat(float value);
-
- /**
- * Set the given float value at the given write offset. The {@link Buffer#writerOffset()} is not modified.
- * The value is written using a 32-bit IEEE floating point encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param woff The write offset, an absolute offset into this buffer to write to.
- * @param value The float value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Float#BYTES}.
- */
- Buffer setFloat(int woff, float value);
-
- /**
- * Get the long value at the current {@link Buffer#readerOffset()},
- * and increases the reader offset by {@link Long#BYTES}.
- * The value is read using a two's complement 64-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @return The long value at the current reader offset.
- * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Long#BYTES}.
- */
- long readLong();
-
- /**
- * Get the long value at the given reader offset.
- * The {@link Buffer#readerOffset()} is not modified.
- * The value is read using a two's complement 64-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param roff The read offset, an absolute offset into this buffer, to read from.
- * @return The long value at the given offset.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Long#BYTES}.
- */
- long getLong(int roff);
-
- /**
- * Set the given long value at the current {@link Buffer#writerOffset()},
- * and increase the writer offset by {@link Long#BYTES}.
- * The value is written using a two's complement 64-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param value The long value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Long#BYTES}.
- */
- Buffer writeLong(long value);
-
- /**
- * Set the given long value at the given write offset. The {@link Buffer#writerOffset()} is not modified.
- * The value is written using a two's complement 64-bit encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param woff The write offset, an absolute offset into this buffer to write to.
- * @param value The long value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Long#BYTES}.
- */
- Buffer setLong(int woff, long value);
-
- /**
- * Get the double value at the current {@link Buffer#readerOffset()},
- * and increases the reader offset by {@link Double#BYTES}.
- * The value is read using a 64-bit IEEE floating point encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @return The double value at the current reader offset.
- * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Double#BYTES}.
- */
- double readDouble();
-
- /**
- * Get the double value at the given reader offset.
- * The {@link Buffer#readerOffset()} is not modified.
- * The value is read using a 64-bit IEEE floating point encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param roff The read offset, an absolute offset into this buffer, to read from.
- * @return The double value at the given offset.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Double#BYTES}.
- */
- double getDouble(int roff);
-
- /**
- * Set the given double value at the current {@link Buffer#writerOffset()},
- * and increase the writer offset by {@link Double#BYTES}.
- * The value is written using a 64-bit IEEE floating point encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param value The double value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Double#BYTES}.
- */
- Buffer writeDouble(double value);
-
- /**
- * Set the given double value at the given write offset. The {@link Buffer#writerOffset()} is not modified.
- * The value is written using a 64-bit IEEE floating point encoding,
- * with the {@link Buffer#order() configured} default byte order.
- *
- * @param woff The write offset, an absolute offset into this buffer to write to.
- * @param value The double value to write.
- * @return This Buffer.
- * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or
- * greater than {@link Buffer#capacity()} minus {@link Double#BYTES}.
- */
- Buffer setDouble(int woff, double value);
- //
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/BufferAllocator.java b/buffer-api/src/main/java/io/netty/buffer/api/BufferAllocator.java
deleted file mode 100644
index 16e847b..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/BufferAllocator.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-import io.netty.buffer.api.pool.PooledBufferAllocator;
-
-import java.nio.ByteOrder;
-import java.util.function.Supplier;
-
-/**
- * Interface for {@link Buffer} allocators.
- */
-public interface BufferAllocator extends AutoCloseable {
- /**
- * Check that the given {@code size} argument is a valid buffer size, or throw an {@link IllegalArgumentException}.
- *
- * @param size The size to check.
- * @throws IllegalArgumentException if the size is not positive, or if the size is too big (over ~2 GB) for a
- * buffer to accommodate.
- */
- static void checkSize(long size) {
- if (size < 1) {
- throw new IllegalArgumentException("Buffer size must be positive, but was " + size + '.');
- }
- // We use max array size because on-heap buffers will be backed by byte-arrays.
- int maxArraySize = Integer.MAX_VALUE - 8;
- if (size > maxArraySize) {
- throw new IllegalArgumentException(
- "Buffer size cannot be greater than " + maxArraySize + ", but was " + size + '.');
- }
- }
-
- /**
- * Allocate a {@link Buffer} of the given size in bytes. This method may throw an {@link OutOfMemoryError} if there
- * is not enough free memory available to allocate a {@link Buffer} of the requested size.
- *
- * The buffer will use the current platform native byte order by default, for accessor methods that don't have an
- * explicit byte order.
- *
- * @param size The size of {@link Buffer} to allocate.
- * @return The newly allocated {@link Buffer}.
- */
- Buffer allocate(int size);
-
- /**
- * Allocate a {@link Buffer} of the given size in bytes. This method may throw an {@link OutOfMemoryError} if there
- * is not enough free memory available to allocate a {@link Buffer} of the requested size.
- *
- * The buffer will use the given byte order by default.
- *
- * @param size The size of {@link Buffer} to allocate.
- * @param order The default byte order used by the accessor methods that don't have an explicit byte order.
- * @return The newly allocated {@link Buffer}.
- */
- default Buffer allocate(int size, ByteOrder order) {
- return allocate(size).order(order);
- }
-
- /**
- * Create a supplier of "constant" {@linkplain Buffer Buffers} from this allocator, that all have the given
- * byte contents. The buffer has the same capacity as the byte array length, and its write offset is placed at the
- * end, and its read offset is at the beginning, such that the entire buffer contents are readable.
- *
- * The buffers produced by the supplier will each have their own independent life-cycle, and closing them will
- * make them {@linkplain Buffer#isAccessible() inaccessible}, just like normally allocated buffers.
- *
- * The buffers produced are "constants", in the sense that they are {@linkplain Buffer#readOnly() read-only}.
- *
- * It can generally be expected, but is not guaranteed, that the returned supplier is more resource efficient than
- * allocating and copying memory with other available APIs. In such optimised implementations, the underlying memory
- * baking the buffers will be shared among all the buffers produced by the supplier.
- *
- * The primary use case for this API, is when you need to repeatedly produce buffers with the same contents, and
- * you perhaps wish to keep a {@code static final} field with these contents. This use case has previously been
- * solved by allocating a read-only buffer with the given contents, and then slicing or duplicating it on every use.
- * This approach had several problems. For instance, if you forget to slice, the offsets of the buffer can change
- * in unexpected ways, since the same buffer instance is shared and accessed from many places. The buffer could also
- * be deallocated, making the data inaccessible. The supplier-based API solves all of these problems, by enforcing
- * that each usage get their own distinct buffer instance.
- *
- * @param bytes The byte contents of the buffers produced by the returned supplier.
- * @return A supplier of read-only buffers with the given contents.
- */
- default Supplier constBufferSupplier(byte[] bytes) {
- byte[] safeCopy = bytes.clone(); // Prevent modifying the bytes after creating the supplier.
- return () -> allocate(bytes.length).writeBytes(safeCopy).makeReadOnly();
- }
-
- /**
- * Close this allocator, freeing all of its internal resources.
- *
- * Existing (currently in-use) allocated buffers will not be impacted by calling this method.
- * If this is a pooling or caching allocator, then existing buffers will be immediately freed when they are closed,
- * instead of being pooled or cached.
- *
- * The allocator can still be used to allocate more buffers after calling this method.
- * However, if this is a pooling or caching allocator, then the pooling and caching functionality will be
- * effectively disabled after calling this method.
- *
- * If this allocator does not perform any pooling or caching, then calling this method likely has no effect.
- */
- @Override
- default void close() {
- }
-
- static BufferAllocator heap() {
- return new ManagedBufferAllocator(MemoryManagers.getManagers().getHeapMemoryManager());
- }
-
- static BufferAllocator direct() {
- return new ManagedBufferAllocator(MemoryManagers.getManagers().getNativeMemoryManager());
- }
-
- static BufferAllocator pooledHeap() {
- return new PooledBufferAllocator(MemoryManagers.getManagers().getHeapMemoryManager());
- }
-
- static BufferAllocator pooledDirect() {
- return new PooledBufferAllocator(MemoryManagers.getManagers().getNativeMemoryManager());
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/BufferClosedException.java b/buffer-api/src/main/java/io/netty/buffer/api/BufferClosedException.java
deleted file mode 100644
index a47058e..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/BufferClosedException.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-/**
- * An exception thrown when an operation is attempted on a {@link Buffer} when it has been closed.
- */
-public final class BufferClosedException extends UnsupportedOperationException {
- private static final long serialVersionUID = 85913332711192868L;
-
- public BufferClosedException(final String message) {
- super(message);
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/BufferHolder.java b/buffer-api/src/main/java/io/netty/buffer/api/BufferHolder.java
deleted file mode 100644
index 751f43a..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/BufferHolder.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-import io.netty.buffer.api.internal.ResourceSupport;
-import io.netty.buffer.api.internal.Statics;
-
-import java.lang.invoke.VarHandle;
-import java.util.Objects;
-
-import static java.lang.invoke.MethodHandles.lookup;
-
-/**
- * The {@link BufferHolder} is an abstract class that simplifies the implementation of objects that themselves contain
- * a {@link Buffer} instance.
- *
- * The {@link BufferHolder} can only hold on to a single buffer, so objects and classes that need to hold on to multiple
- * buffers will have to do their implementation from scratch, though they can use the code of the {@link BufferHolder}
- * as inspiration.
- *
- * If you just want an object that is a reference to a buffer, then the {@link BufferRef} can be used for that purpose.
- * If you have an advanced use case where you wish to implement {@link Resource}, and tightly control lifetimes, then
- * {@link ResourceSupport} can be of help.
- *
- * @param The concrete {@link BufferHolder} type.
- */
-public abstract class BufferHolder> implements Resource {
- private static final VarHandle BUF = Statics.findVarHandle(lookup(), BufferHolder.class, "buf", Buffer.class);
- private Buffer buf;
-
- /**
- * Create a new {@link BufferHolder} to hold the given {@linkplain Buffer buffer}.
- *
- * Note: this increases the reference count of the given buffer.
- *
- * @param buf The {@linkplain Buffer buffer} to be held by this holder.
- */
- protected BufferHolder(Buffer buf) {
- this.buf = Objects.requireNonNull(buf, "The buffer cannot be null.");
- }
-
- /**
- * Create a new {@link BufferHolder} to hold the {@linkplain Buffer buffer} received from the given {@link Send}.
- *
- * The {@link BufferHolder} will then be holding exclusive ownership of the buffer.
- *
- * @param send The {@linkplain Buffer buffer} to be held by this holder.
- */
- protected BufferHolder(Send send) {
- buf = Objects.requireNonNull(send, "The send cannot be null.").receive();
- }
-
- @Override
- public void close() {
- buf.close();
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Send send() {
- return buf.send().map((Class) getClass(), this::receive);
- }
-
- /**
- * Called when a {@linkplain #send() sent} {@link BufferHolder} is received by the recipient.
- * The {@link BufferHolder} should return a new concrete instance, that wraps the given {@link Buffer} object.
- *
- * @param buf The {@link Buffer} that is {@linkplain Send#receive() received} by the recipient,
- * and needs to be wrapped in a new {@link BufferHolder} instance.
- * @return A new {@linkplain T buffer holder} instance, containing the given {@linkplain Buffer buffer}.
- */
- protected abstract T receive(Buffer buf);
-
- /**
- * Replace the underlying referenced buffer with the given buffer.
- *
- * This method is protected to permit advanced use cases of {@link BufferHolder} sub-class implementations.
- *
- * Note: this method decreases the reference count of the current buffer,
- * and takes exclusive ownership of the sent buffer.
- *
- * The buffer assignment is performed using a plain store.
- *
- * @param send The new {@link Buffer} instance that is replacing the currently held buffer.
- */
- protected final void replaceBuffer(Send send) {
- Buffer received = send.receive();
- buf.close();
- buf = received;
- }
-
- /**
- * Replace the underlying referenced buffer with the given buffer.
- *
- * This method is protected to permit advanced use cases of {@link BufferHolder} sub-class implementations.
- *
- * Note: this method decreases the reference count of the current buffer,
- * and takes exclusive ownership of the sent buffer.
- *
- * The buffer assignment is performed using a volatile store.
- *
- * @param send The {@link Send} with the new {@link Buffer} instance that is replacing the currently held buffer.
- */
- protected final void replaceBufferVolatile(Send send) {
- Buffer received = send.receive();
- var prev = (Buffer) BUF.getAndSet(this, received);
- prev.close();
- }
-
- /**
- * Access the held {@link Buffer} instance.
- *
- * The access is performed using a plain load.
- *
- * @return The {@link Buffer} instance being held by this {@linkplain T buffer holder}.
- */
- protected final Buffer getBuffer() {
- return buf;
- }
-
- /**
- * Access the held {@link Buffer} instance.
- *
- * The access is performed using a volatile load.
- *
- * @return The {@link Buffer} instance being held by this {@linkplain T buffer holder}.
- */
- protected final Buffer getBufferVolatile() {
- return (Buffer) BUF.getVolatile(this);
- }
-
- @Override
- public boolean isAccessible() {
- return buf.isAccessible();
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/BufferReadOnlyException.java b/buffer-api/src/main/java/io/netty/buffer/api/BufferReadOnlyException.java
deleted file mode 100644
index aaf712a..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/BufferReadOnlyException.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-/**
- * An exception thrown when an operation is attempted on a {@linkplain Buffer#readOnly() read-only} {@link Buffer}.
- */
-public final class BufferReadOnlyException extends UnsupportedOperationException {
- private static final long serialVersionUID = 4855825594125231593L;
-
- public BufferReadOnlyException(final String message) {
- super(message);
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/BufferRef.java b/buffer-api/src/main/java/io/netty/buffer/api/BufferRef.java
deleted file mode 100644
index 3a87c6f..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/BufferRef.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-import java.lang.invoke.VarHandle;
-
-/**
- * A mutable reference to a buffer.
- */
-public final class BufferRef extends BufferHolder {
- /**
- * Create a reference to the given {@linkplain Buffer buffer}.
- * This increments the reference count of the buffer.
- *
- * @param buf The buffer to reference.
- */
- private BufferRef(Buffer buf) {
- super(buf);
- // BufferRef is meant to be atomic, so we need to add a fence to get the semantics of a volatile store.
- VarHandle.fullFence();
- }
-
- /**
- * Create a reference that holds the exclusive ownership of the sent buffer.
- *
- * @param send The {@linkplain Send sent} buffer to take ownership of.
- */
- public BufferRef(Send send) {
- super(send);
- // BufferRef is meant to be atomic, so we need to add a fence to get the semantics of a volatile store.
- VarHandle.fullFence();
- }
-
- @Override
- protected BufferRef receive(Buffer buf) {
- return new BufferRef(buf);
- }
-
- /**
- * Replace the underlying referenced buffer with the given buffer.
- *
- * Note: this method decreases the reference count of the current buffer,
- * and takes exclusive ownership of the sent buffer.
- *
- * The buffer assignment is performed using a volatile store.
- *
- * @param send The {@link Send} with the new {@link Buffer} instance that is replacing the currently held buffer.
- */
- public void replace(Send send) {
- replaceBufferVolatile(send);
- }
-
- /**
- * Access the buffer in this reference.
- *
- * @return The buffer held by the reference.
- */
- public Buffer contents() {
- return getBufferVolatile();
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/ByteCursor.java b/buffer-api/src/main/java/io/netty/buffer/api/ByteCursor.java
deleted file mode 100644
index 3c85ad5..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/ByteCursor.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package io.netty.buffer.api;
-
-import io.netty.util.ByteProcessor;
-
-/**
- * The ByteCursor scans through a sequence of bytes.
- * This is similar to {@link ByteProcessor}, but for external iteration rather than internal iteration.
- * The external iteration allows the callers to control the pace of the iteration.
- * The API includes methods for reading {@code long}s as a batch of 8 bytes.
- * The long values are always in big-endian format, so that the highest-order byte in the long value, contain the byte
- * that would otherwise have been returned by the next call to {@link #getByte()}.
- */
-public interface ByteCursor {
- /**
- * Check if the iterator has at least 8 bytes left, and if so, read those 8 bytes and move the cursor forward.
- * The bytes are packed as a {@code long} value in big-endian format, such that the highest-order byte
- * in the long, is the byte that would otherwise have been returned by the next call to {@link #getByte()},
- * after a call to {@link #readByte()}.
- * The bytes (as a {@code long}) will then be available through the {@link #getLong()} method.
- *
- * Note that when this method returns {@code false}, the {@link #readByte()} can still return {@code true}.
- * It is recommended to have any long-processing loop be followed by a byte-processing loop for the 7 or fewer
- * bytes that might form a tail in the cursor.
- *
- * Also note that this method will not influence what is returned the {@link #getByte()} method.
- *
- * @return {@code true} if the cursor read 8 bytes and moved forward, otherwise {@code false}.
- */
- boolean readLong();
-
- /**
- * Return the last 8 bytes read by {@link #readLong()}.
- * If {@link #readLong()} has not been called on this cursor before, then {@code -1} is returned.
- *
- * The long value is in the big-endian format, such that the highest-order by of the long value, is the byte that
- * would otherwise have been produced by a {@link #readByte()} / {@link #getByte()} pair.
- * This means that cursors that iterate in reverse, e.g. from {@link Buffer#openReverseCursor()}, return longs in a
- * "mirrored" or "reversed" big-endian format.
- *
- * @return The 8 bytes, in big-endian format, that was read by the most recent successful call to
- * {@link #readLong()}.
- */
- long getLong();
-
- /**
- * Check if the iterator has at least one byte left, and if so, read that byte and move the cursor forward.
- * The byte will then be available through the {@link #getByte()}.
- *
- * Note that this method will not influence what is returned from the {@link #getLong()} method.
- *
- * @return {@code true} if the cursor read a byte and moved forward, otherwise {@code false}.
- */
- boolean readByte();
-
- /**
- * Return the last byte that was read by {@link #readByte()}.
- * If {@link #readByte()} has not been called on this cursor before, then {@code -1} is returned.
- *
- * @return The next byte that was read by the most recent successful call to {@link #readByte()}.
- */
- byte getByte();
-
- /**
- * The current position of this iterator into the underlying sequence of bytes.
- * For instance, if we are iterating a buffer, this would be the iterators current offset into the buffer.
- *
- * @return The current iterator offset into the underlying sequence of bytes.
- */
- int currentOffset();
-
- /**
- * Get the current number of bytes left in the iterator.
- *
- * @return The number of bytes left in the iterator.
- */
- int bytesLeft();
-
- /**
- * Process the remaining bytes in this iterator with the given {@link ByteProcessor}.
- * This method consumes the iterator.
- *
- * @param processor The processor to use for processing the bytes in the iterator.
- * @return The number of bytes processed, if the {@link ByteProcessor#process(byte) process} method returned
- * {@code false}, or {@code -1} if the whole iterator was processed.
- */
- default int process(ByteProcessor processor) {
- boolean requestMore = true;
- int count = 0;
- while (readByte() && (requestMore = processor.process(getByte()))) {
- count++;
- }
- return requestMore? -1 : count;
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/CompositeBuffer.java b/buffer-api/src/main/java/io/netty/buffer/api/CompositeBuffer.java
deleted file mode 100644
index c5c56e2..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/CompositeBuffer.java
+++ /dev/null
@@ -1,2016 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-import io.netty.buffer.api.internal.ResourceSupport;
-import io.netty.buffer.api.internal.Statics;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.Objects;
-import java.util.Set;
-import java.util.stream.Stream;
-
-import static io.netty.buffer.api.internal.Statics.bufferIsClosed;
-import static io.netty.buffer.api.internal.Statics.bufferIsReadOnly;
-
-/**
- * The {@code CompositeBuffer} is a concrete {@link Buffer} implementation that make a number of other buffers appear
- * as one. A composite buffer behaves the same as a normal, non-composite buffer in every way, so you normally don't
- * need to handle them specially.
- *
- * A composite buffer is constructed using one of the {@code compose} methods:
- *
- * -
- * {@link #compose(BufferAllocator, Send[])} creates a composite buffer from the buffers that are sent to it via
- * the passed in send objects. Since {@link Send#receive()} transfers ownership, the resulting composite buffer
- * will have ownership, because it is guaranteed that there are no other references to its constituent buffers.
- *
- * -
- * {@link #compose(BufferAllocator)} creates and empty, zero capacity, composite buffer. Such empty buffers may
- * change their {@linkplain #order() byte order} or {@linkplain #readOnly() read-only} states when they gain
- * their first component.
- *
- *
- * Composite buffers can later be extended with internally allocated components, with {@link #ensureWritable(int)},
- * or with externally allocated buffers, using {@link #extendWith(Send)}.
- *
- * Constituent buffer requirements
- *
- * The buffers that a being composed to form the composite buffer, need to live up to a number of requirements.
- * Basically, if we imagine that the constituent buffers have their memory regions concatenated together, then the
- * result needs to make sense.
- *
- * All the constituent buffers must have the same {@linkplain Buffer#order() byte order}.
- * An exception will be thrown if you attempt to compose buffers that have different byte orders,
- * and changing the byte order of the constituent buffers so that they become inconsistent after construction,
- * will result in unspecified behaviour.
- *
- * The read and write offsets of the constituent buffers must be arranged such that there are no "gaps" when viewed
- * as a single connected chunk of memory.
- * Specifically, there can be at most one buffer whose write offset is neither zero nor at capacity,
- * and all buffers prior to it must have their write offsets at capacity, and all buffers after it must have a
- * write-offset of zero.
- * Likewise, there can be at most one buffer whose read offset is neither zero nor at capacity,
- * and all buffers prior to it must have their read offsets at capacity, and all buffers after it must have a read
- * offset of zero.
- * Furthermore, the sum of the read offsets must be less than or equal to the sum of the write-offsets.
- *
- * Reads and writes to the composite buffer that modifies the read or write offsets, will also modify the relevant
- * offsets in the constituent buffers.
- *
- * It is not a requirement that the buffers have the same size.
- *
- * It is not a requirement that the buffers are allocated by this allocator, but if
- * {@link Buffer#ensureWritable(int)} is called on the composed buffer, and the composed buffer needs to be
- * expanded, then this allocator instance will be used for allocation the extra memory.
- *
- *
Ownership and Send
- *
- * {@linkplain Resource#send() Sending} a composite buffer implies sending all of its constituent buffers.
- * For sending to be possible, both the composite buffer itself, and all of its constituent buffers, must be in a
- * state that permits them being sent. This should be the case by default, as it shouldn't be possible to create
- * composite buffers that can't be sent.
- */
-public final class CompositeBuffer extends ResourceSupport implements Buffer {
- /**
- * The max array size is JVM implementation dependant, but most seem to settle on {@code Integer.MAX_VALUE - 8}.
- * We set the max composite buffer capacity to the same, since it would otherwise be impossible to create a
- * non-composite copy of the buffer.
- */
- private static final int MAX_CAPACITY = Integer.MAX_VALUE - 8;
- private static final Drop COMPOSITE_DROP = new Drop() {
- @Override
- public void drop(CompositeBuffer buf) {
- for (Buffer b : buf.bufs) {
- b.close();
- }
- buf.makeInaccessible();
- }
-
- @Override
- public String toString() {
- return "COMPOSITE_DROP";
- }
- };
- private static final Buffer[] EMPTY_BUFFER_ARRAY = new Buffer[0];
-
- private final BufferAllocator allocator;
- private final TornBufferAccessors tornBufAccessors;
- private Buffer[] bufs;
- private int[] offsets; // The offset, for the composite buffer, where each constituent buffer starts.
- private int capacity;
- private int roff;
- private int woff;
- private int subOffset; // The next offset *within* a consituent buffer to read from or write to.
- private ByteOrder order;
- private boolean closed;
- private boolean readOnly;
-
- /**
- * Compose the given sequence of sends of buffers and present them as a single buffer.
- *
- * Note: The composite buffer holds a reference to all the constituent buffers,
- * until the composite buffer is deallocated.
- * This means the constituent buffers must still have their outside-reference count decremented as normal.
- * If the buffers are allocated for the purpose of participating in the composite buffer,
- * then they should be closed as soon as the composite buffer has been created, like in this example:
- *
{@code
- * try (Buffer a = allocator.allocate(size);
- * Buffer b = allocator.allocate(size)) {
- * return allocator.compose(a, b); // Reference counts for 'a' and 'b' incremented here.
- * } // Reference count for 'a' and 'b' decremented here; composite buffer now holds the last references.
- * }
- *
- * See the class documentation for more information on what is required of the given buffers for composition to be
- * allowed.
- *
- * @param allocator The allocator for the composite buffer. This allocator will be used e.g. to service
- * {@link #ensureWritable(int)} calls.
- * @param sends The sent buffers to compose into a single buffer view.
- * @return A buffer composed of, and backed by, the given buffers.
- * @throws IllegalArgumentException if the given buffers have an inconsistent
- * {@linkplain Buffer#order() byte order}.
- * @throws IllegalStateException if one of the sends have already been received. The remaining buffers and sends
- * will be closed and discarded, respectively.
- */
- @SafeVarargs
- public static CompositeBuffer compose(BufferAllocator allocator, Send... sends) {
- Buffer[] bufs = new Buffer[sends.length];
- IllegalStateException ise = null;
- for (int i = 0; i < sends.length; i++) {
- if (ise != null) {
- sends[i].discard();
- } else {
- try {
- bufs[i] = sends[i].receive();
- } catch (IllegalStateException e) {
- ise = e;
- for (int j = 0; j < i; j++) {
- bufs[j].close();
- }
- }
- }
- }
- if (ise != null) {
- throw ise;
- }
- return new CompositeBuffer(allocator, filterExternalBufs(Arrays.stream(bufs)), COMPOSITE_DROP);
- }
-
- /**
- * Create an empty composite buffer, that has no components. The buffer can be extended with components using either
- * {@link #ensureWritable(int)} or {@link #extendWith(Send)}.
- *
- * @param allocator The allocator for the composite buffer. This allocator will be used e.g. to service
- * {@link #ensureWritable(int)} calls.
- * @return A composite buffer that has no components, and has a capacity of zero.
- */
- public static CompositeBuffer compose(BufferAllocator allocator) {
- return new CompositeBuffer(allocator, EMPTY_BUFFER_ARRAY, COMPOSITE_DROP);
- }
-
- /**
- * Check if the given buffer is a {@linkplain #compose(BufferAllocator, Send...) composite} buffer or not.
- * @param composite The buffer to check.
- * @return {@code true} if the given buffer was created with {@link #compose(BufferAllocator, Send...)},
- * {@code false} otherwise.
- */
- public static boolean isComposite(Buffer composite) {
- return composite.getClass() == CompositeBuffer.class;
- }
-
- private static Buffer[] filterExternalBufs(Stream refs) {
- // We filter out all zero-capacity buffers because they wouldn't contribute to the composite buffer anyway,
- // and also, by ensuring that all constituent buffers contribute to the size of the composite buffer,
- // we make sure that the number of composite buffers will never become greater than the number of bytes in
- // the composite buffer.
- // This restriction guarantees that methods like countComponents, forEachReadable and forEachWritable,
- // will never overflow their component counts.
- // Allocating a new array unconditionally also prevents external modification of the array.
- Buffer[] bufs = refs
- .filter(CompositeBuffer::discardEmpty)
- .flatMap(CompositeBuffer::flattenBuffer)
- .toArray(Buffer[]::new);
- // Make sure there are no duplicates among the buffers.
- Set duplicatesCheck = Collections.newSetFromMap(new IdentityHashMap<>());
- duplicatesCheck.addAll(Arrays.asList(bufs));
- if (duplicatesCheck.size() < bufs.length) {
- for (Buffer buf : bufs) {
- buf.close(); // Undo the increment we did with Deref.get().
- }
- throw new IllegalArgumentException(
- "Cannot create composite buffer with duplicate constituent buffer components.");
- }
- return bufs;
- }
-
- private static boolean discardEmpty(Buffer buf) {
- if (buf.capacity() > 0) {
- return true;
- } else {
- // If we filter a buffer out, then we must make sure to close it since we incremented the reference count
- // with Deref.get() earlier.
- buf.close();
- return false;
- }
- }
-
- private static Stream flattenBuffer(Buffer buf) {
- if (buf instanceof CompositeBuffer) {
- // Extract components and move our reference count from the composite onto the components.
- var composite = (CompositeBuffer) buf;
- var bufs = composite.bufs;
- return Stream.of(bufs);
- }
- return Stream.of(buf);
- }
-
- private CompositeBuffer(BufferAllocator allocator, Buffer[] bufs, Drop drop) {
- super(drop);
- this.allocator = allocator;
- try {
- if (bufs.length > 0) {
- ByteOrder targetOrder = bufs[0].order();
- for (Buffer buf : bufs) {
- if (buf.order() != targetOrder) {
- throw new IllegalArgumentException("Constituent buffers have inconsistent byte order.");
- }
- }
- order = bufs[0].order();
-
- boolean targetReadOnly = bufs[0].readOnly();
- for (Buffer buf : bufs) {
- if (buf.readOnly() != targetReadOnly) {
- throw new IllegalArgumentException("Constituent buffers have inconsistent read-only state.");
- }
- }
- readOnly = targetReadOnly;
- } else {
- order = ByteOrder.nativeOrder();
- }
- this.bufs = bufs;
- computeBufferOffsets();
- tornBufAccessors = new TornBufferAccessors(this);
- } catch (Exception e) {
- // Always close bufs on exception, regardless of acquireBufs value.
- // If acquireBufs is false, it just means the ref count increments happened prior to this constructor call.
- for (Buffer buf : bufs) {
- buf.close();
- }
- throw e;
- }
- }
-
- private void computeBufferOffsets() {
- if (bufs.length > 0) {
- int woff = 0;
- int roff = 0;
- boolean woffMidpoint = false;
- for (Buffer buf : bufs) {
- if (buf.writableBytes() == 0) {
- woff += buf.capacity();
- } else if (!woffMidpoint) {
- woff += buf.writerOffset();
- woffMidpoint = true;
- } else if (buf.writerOffset() != 0) {
- throw new IllegalArgumentException(
- "The given buffers cannot be composed because they leave an unwritten gap: " +
- Arrays.toString(bufs) + '.');
- }
- }
- boolean roffMidpoint = false;
- for (Buffer buf : bufs) {
- if (buf.readableBytes() == 0 && buf.writableBytes() == 0) {
- roff += buf.capacity();
- } else if (!roffMidpoint) {
- roff += buf.readerOffset();
- roffMidpoint = true;
- } else if (buf.readerOffset() != 0) {
- throw new IllegalArgumentException(
- "The given buffers cannot be composed because they leave an unread gap: " +
- Arrays.toString(bufs) + '.');
- }
- }
- assert roff <= woff:
- "The given buffers place the read offset ahead of the write offset: " + Arrays.toString(bufs) + '.';
- // Commit computed offsets.
- this.woff = woff;
- this.roff = roff;
- }
-
- offsets = new int[bufs.length];
- long cap = 0;
- for (int i = 0; i < bufs.length; i++) {
- offsets[i] = (int) cap;
- cap += bufs[i].capacity();
- }
- if (cap > MAX_CAPACITY) {
- throw new IllegalArgumentException(
- "Combined size of the constituent buffers is too big. " +
- "The maximum buffer capacity is " + MAX_CAPACITY + " (Integer.MAX_VALUE - 8), " +
- "but the sum of the constituent buffer capacities was " + cap + '.');
- }
- capacity = (int) cap;
- }
-
- @Override
- public String toString() {
- return "Buffer[roff:" + roff + ", woff:" + woff + ", cap:" + capacity + ']';
- }
-
- @Override
- protected RuntimeException createResourceClosedException() {
- return bufferIsClosed(this);
- }
-
- @Override
- public CompositeBuffer order(ByteOrder order) {
- if (this.order != order) {
- this.order = order;
- for (Buffer buf : bufs) {
- buf.order(order);
- }
- }
- return this;
- }
-
- @Override
- public ByteOrder order() {
- return order;
- }
-
- @Override
- public int capacity() {
- return capacity;
- }
-
- @Override
- public int readerOffset() {
- return roff;
- }
-
- @Override
- public CompositeBuffer readerOffset(int index) {
- prepRead(index, 0);
- int indexLeft = index;
- for (Buffer buf : bufs) {
- buf.readerOffset(Math.min(indexLeft, buf.capacity()));
- indexLeft = Math.max(0, indexLeft - buf.capacity());
- }
- roff = index;
- return this;
- }
-
- @Override
- public int writerOffset() {
- return woff;
- }
-
- @Override
- public CompositeBuffer writerOffset(int index) {
- checkWriteBounds(index, 0);
- int indexLeft = index;
- for (Buffer buf : bufs) {
- buf.writerOffset(Math.min(indexLeft, buf.capacity()));
- indexLeft = Math.max(0, indexLeft - buf.capacity());
- }
- woff = index;
- return this;
- }
-
- @Override
- public CompositeBuffer fill(byte value) {
- for (Buffer buf : bufs) {
- buf.fill(value);
- }
- return this;
- }
-
- @Override
- public long nativeAddress() {
- return 0;
- }
-
- @Override
- public CompositeBuffer makeReadOnly() {
- for (Buffer buf : bufs) {
- buf.makeReadOnly();
- }
- readOnly = true;
- return this;
- }
-
- @Override
- public boolean readOnly() {
- return readOnly;
- }
-
- @Override
- public CompositeBuffer copy(int offset, int length) {
- checkWriteBounds(offset, length);
- if (offset < 0 || length < 0) {
- throw new IllegalArgumentException(
- "Offset and length cannot be negative, but offset was " +
- offset + ", and length was " + length + '.');
- }
- Buffer choice = (Buffer) chooseBuffer(offset, 0);
- Buffer[] copies;
-
- if (length > 0) {
- copies = new Buffer[bufs.length];
- int off = subOffset;
- int cap = length;
- int i;
- for (i = searchOffsets(offset); cap > 0; i++) {
- var buf = bufs[i];
- int avail = buf.capacity() - off;
- copies[i] = buf.copy(off, Math.min(cap, avail));
- cap -= avail;
- off = 0;
- }
- copies = Arrays.copyOf(copies, i);
- } else {
- // Specialize for length == 0, since we must copy from at least one constituent buffer.
- copies = new Buffer[] { choice.copy(subOffset, 0) };
- }
-
- return new CompositeBuffer(allocator, copies, COMPOSITE_DROP);
- }
-
- @Override
- public void copyInto(int srcPos, byte[] dest, int destPos, int length) {
- copyInto(srcPos, (b, s, d, l) -> b.copyInto(s, dest, d, l), destPos, length);
- }
-
- @Override
- public void copyInto(int srcPos, ByteBuffer dest, int destPos, int length) {
- copyInto(srcPos, (b, s, d, l) -> b.copyInto(s, dest, d, l), destPos, length);
- }
-
- private void copyInto(int srcPos, CopyInto dest, int destPos, int length) {
- if (length < 0) {
- throw new IndexOutOfBoundsException("Length cannot be negative: " + length + '.');
- }
- if (srcPos < 0) {
- throw indexOutOfBounds(srcPos, false);
- }
- if (srcPos + length > capacity) {
- throw indexOutOfBounds(srcPos + length, false);
- }
- while (length > 0) {
- var buf = (Buffer) chooseBuffer(srcPos, 0);
- int toCopy = Math.min(buf.capacity() - subOffset, length);
- dest.copyInto(buf, subOffset, destPos, toCopy);
- srcPos += toCopy;
- destPos += toCopy;
- length -= toCopy;
- }
- }
-
- @FunctionalInterface
- private interface CopyInto {
- void copyInto(Buffer src, int srcPos, int destPos, int length);
- }
-
- @Override
- public void copyInto(int srcPos, Buffer dest, int destPos, int length) {
- if (length < 0) {
- throw new IndexOutOfBoundsException("Length cannot be negative: " + length + '.');
- }
- if (srcPos < 0) {
- throw indexOutOfBounds(srcPos, false);
- }
- if (srcPos + length > capacity) {
- throw indexOutOfBounds(srcPos + length, false);
- }
-
- // Iterate in reverse to account for src and dest buffer overlap.
- // todo optimise by delegating to constituent buffers.
- var cursor = openReverseCursor(srcPos + length - 1, length);
- ByteOrder prevOrder = dest.order();
- // We read longs in BE, in reverse, so they need to be flipped for writing.
- dest.order(ByteOrder.LITTLE_ENDIAN);
- try {
- while (cursor.readLong()) {
- length -= Long.BYTES;
- dest.setLong(destPos + length, cursor.getLong());
- }
- while (cursor.readByte()) {
- dest.setByte(destPos + --length, cursor.getByte());
- }
- } finally {
- dest.order(prevOrder);
- }
- }
-
- @Override
- public ByteCursor openCursor() {
- return openCursor(readerOffset(), readableBytes());
- }
-
- @Override
- public ByteCursor openCursor(int fromOffset, int length) {
- if (fromOffset < 0) {
- throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.');
- }
- if (length < 0) {
- throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
- }
- if (capacity < fromOffset + length) {
- throw new IllegalArgumentException("The fromOffset+length is beyond the end of the buffer: " +
- "fromOffset=" + fromOffset + ", length=" + length + '.');
- }
- int startBufferIndex = searchOffsets(fromOffset);
- int off = fromOffset - offsets[startBufferIndex];
- Buffer startBuf = bufs[startBufferIndex];
- ByteCursor startCursor = startBuf.openCursor(off, Math.min(startBuf.capacity() - off, length));
- return new ByteCursor() {
- int index = fromOffset;
- final int end = fromOffset + length;
- int bufferIndex = startBufferIndex;
- int initOffset = startCursor.currentOffset();
- ByteCursor cursor = startCursor;
- long longValue = -1;
- byte byteValue = -1;
-
- @Override
- public boolean readLong() {
- if (cursor.readLong()) {
- longValue = cursor.getLong();
- return true;
- }
- if (bytesLeft() >= Long.BYTES) {
- longValue = nextLongFromBytes();
- return true;
- }
- return false;
- }
-
- private long nextLongFromBytes() {
- if (cursor.bytesLeft() == 0) {
- nextCursor();
- if (cursor.readLong()) {
- return cursor.getLong();
- }
- }
- long val = 0;
- for (int i = 0; i < 8; i++) {
- readByte();
- val <<= 8;
- val |= getByte();
- }
- return val;
- }
-
- @Override
- public long getLong() {
- return longValue;
- }
-
- @Override
- public boolean readByte() {
- if (cursor.readByte()) {
- byteValue = cursor.getByte();
- return true;
- }
- if (bytesLeft() > 0) {
- nextCursor();
- cursor.readByte();
- byteValue = cursor.getByte();
- return true;
- }
- return false;
- }
-
- private void nextCursor() {
- bufferIndex++;
- Buffer nextBuf = bufs[bufferIndex];
- cursor = nextBuf.openCursor(0, Math.min(nextBuf.capacity(), bytesLeft()));
- initOffset = 0;
- }
-
- @Override
- public byte getByte() {
- return byteValue;
- }
-
- @Override
- public int currentOffset() {
- int currOff = cursor.currentOffset();
- index += currOff - initOffset;
- initOffset = currOff;
- return index;
- }
-
- @Override
- public int bytesLeft() {
- return end - currentOffset();
- }
- };
- }
-
- @Override
- public ByteCursor openReverseCursor(int fromOffset, int length) {
- if (fromOffset < 0) {
- throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.');
- }
- if (length < 0) {
- throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
- }
- if (fromOffset - length < -1) {
- throw new IllegalArgumentException("The fromOffset-length would underflow the buffer: " +
- "fromOffset=" + fromOffset + ", length=" + length + '.');
- }
- int startBufferIndex = searchOffsets(fromOffset);
- int off = fromOffset - offsets[startBufferIndex];
- Buffer startBuf = bufs[startBufferIndex];
- ByteCursor startCursor = startBuf.openReverseCursor(off, Math.min(off + 1, length));
- return new ByteCursor() {
- int index = fromOffset;
- final int end = fromOffset - length;
- int bufferIndex = startBufferIndex;
- int initOffset = startCursor.currentOffset();
- ByteCursor cursor = startCursor;
- long longValue = -1;
- byte byteValue = -1;
-
- @Override
- public boolean readLong() {
- if (cursor.readLong()) {
- longValue = cursor.getLong();
- return true;
- }
- if (bytesLeft() >= Long.BYTES) {
- longValue = nextLongFromBytes();
- return true;
- }
- return false;
- }
-
- private long nextLongFromBytes() {
- if (cursor.bytesLeft() == 0) {
- nextCursor();
- if (cursor.readLong()) {
- return cursor.getLong();
- }
- }
- long val = 0;
- for (int i = 0; i < 8; i++) {
- readByte();
- val <<= 8;
- val |= getByte();
- }
- return val;
- }
-
- @Override
- public long getLong() {
- return longValue;
- }
-
- @Override
- public boolean readByte() {
- if (cursor.readByte()) {
- byteValue = cursor.getByte();
- return true;
- }
- if (bytesLeft() > 0) {
- nextCursor();
- cursor.readByte();
- byteValue = cursor.getByte();
- return true;
- }
- return false;
- }
-
- private void nextCursor() {
- bufferIndex--;
- Buffer nextBuf = bufs[bufferIndex];
- int length = Math.min(nextBuf.capacity(), bytesLeft());
- int offset = nextBuf.capacity() - 1;
- cursor = nextBuf.openReverseCursor(offset, length);
- initOffset = offset;
- }
-
- @Override
- public byte getByte() {
- return byteValue;
- }
-
- @Override
- public int currentOffset() {
- int currOff = cursor.currentOffset();
- index -= initOffset - currOff;
- initOffset = currOff;
- return index;
- }
-
- @Override
- public int bytesLeft() {
- return currentOffset() - end;
- }
- };
- }
-
- @Override
- public void ensureWritable(int size, int minimumGrowth, boolean allowCompaction) {
- if (!isAccessible()) {
- throw bufferIsClosed(this);
- }
- if (!isOwned()) {
- throw new IllegalStateException("Buffer is not owned. Only owned buffers can call ensureWritable.");
- }
- if (size < 0) {
- throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.');
- }
- if (minimumGrowth < 0) {
- throw new IllegalArgumentException("The minimum growth cannot be negative: " + minimumGrowth + '.');
- }
- if (readOnly) {
- throw bufferIsReadOnly(this);
- }
- if (writableBytes() >= size) {
- // We already have enough space.
- return;
- }
-
- if (allowCompaction && size <= roff) {
- // Let's see if we can solve some or all of the requested size with compaction.
- // We always compact as much as is possible, regardless of size. This amortizes our work.
- int compactableBuffers = 0;
- for (Buffer buf : bufs) {
- if (buf.capacity() != buf.readerOffset()) {
- break;
- }
- compactableBuffers++;
- }
- if (compactableBuffers > 0) {
- Buffer[] compactable;
- if (compactableBuffers < bufs.length) {
- compactable = new Buffer[compactableBuffers];
- System.arraycopy(bufs, 0, compactable, 0, compactable.length);
- System.arraycopy(bufs, compactable.length, bufs, 0, bufs.length - compactable.length);
- System.arraycopy(compactable, 0, bufs, bufs.length - compactable.length, compactable.length);
- } else {
- compactable = bufs;
- }
- for (Buffer buf : compactable) {
- buf.reset();
- }
- computeBufferOffsets();
- if (writableBytes() >= size) {
- // Now we have enough space.
- return;
- }
- } else if (bufs.length == 1) {
- // If we only have a single component buffer, then we can safely compact that in-place.
- bufs[0].compact();
- computeBufferOffsets();
- if (writableBytes() >= size) {
- // Now we have enough space.
- return;
- }
- }
- }
-
- int growth = Math.max(size - writableBytes(), minimumGrowth);
- BufferAllocator.checkSize(capacity() + (long) growth);
- Buffer extension = allocator.allocate(growth, order());
- unsafeExtendWith(extension);
- }
-
- /**
- * Extend this composite buffer with the given extension buffer.
- * This works as if the extension had originally been included at the end of the list of constituent buffers when
- * the composite buffer was created.
- * The extension buffer is added to the end of this composite buffer, which is modified in-place.
- *
- * @see #compose(BufferAllocator, Send...)
- * @param extension The buffer to extend the composite buffer with.
- */
- public void extendWith(Send extension) {
- Objects.requireNonNull(extension, "Extension buffer cannot be null.");
- Buffer buffer = extension.receive();
- if (!isAccessible() || !isOwned()) {
- buffer.close();
- if (!isAccessible()) {
- throw bufferIsClosed(this);
- }
- throw new IllegalStateException("This buffer cannot be extended because it is not in an owned state.");
- }
- if (bufs.length > 0 && buffer.order() != order()) {
- buffer.close();
- throw new IllegalArgumentException(
- "This buffer uses " + order() + " byte order, and cannot be extended with " +
- "a buffer that uses " + buffer.order() + " byte order.");
- }
- if (bufs.length > 0 && buffer.readOnly() != readOnly()) {
- buffer.close();
- throw new IllegalArgumentException(
- "This buffer is " + (readOnly? "read-only" : "writable") + ", " +
- "and cannot be extended with a buffer that is " +
- (buffer.readOnly()? "read-only." : "writable."));
- }
-
- long extensionCapacity = buffer.capacity();
- if (extensionCapacity == 0) {
- // Extending by a zero-sized buffer makes no difference. Especially since it's not allowed to change the
- // capacity of buffers that are constiuents of composite buffers.
- // This also ensures that methods like countComponents, and forEachReadable, do not have to worry about
- // overflow in their component counters.
- buffer.close();
- return;
- }
-
- long newSize = capacity() + extensionCapacity;
- BufferAllocator.checkSize(newSize);
-
- Buffer[] restoreTemp = bufs; // We need this to restore our buffer array, in case offset computations fail.
- try {
- if (buffer instanceof CompositeBuffer) {
- // If the extension is itself a composite buffer, then extend this one by all the constituent
- // component buffers.
- CompositeBuffer compositeExtension = (CompositeBuffer) buffer;
- Buffer[] addedBuffers = compositeExtension.bufs;
- Set duplicatesCheck = Collections.newSetFromMap(new IdentityHashMap<>());
- duplicatesCheck.addAll(Arrays.asList(bufs));
- duplicatesCheck.addAll(Arrays.asList(addedBuffers));
- if (duplicatesCheck.size() < bufs.length + addedBuffers.length) {
- throw extensionDuplicatesException();
- }
- int extendAtIndex = bufs.length;
- bufs = Arrays.copyOf(bufs, extendAtIndex + addedBuffers.length);
- System.arraycopy(addedBuffers, 0, bufs, extendAtIndex, addedBuffers.length);
- computeBufferOffsets();
- } else {
- for (Buffer buf : restoreTemp) {
- if (buf == buffer) {
- throw extensionDuplicatesException();
- }
- }
- unsafeExtendWith(buffer);
- }
- if (restoreTemp.length == 0) {
- order = buffer.order();
- readOnly = buffer.readOnly();
- }
- } catch (Exception e) {
- bufs = restoreTemp;
- throw e;
- }
- }
-
- private static IllegalArgumentException extensionDuplicatesException() {
- return new IllegalArgumentException(
- "The composite buffer cannot be extended with the given extension," +
- " as it would cause the buffer to have duplicate constituent buffers.");
- }
-
- private void unsafeExtendWith(Buffer extension) {
- bufs = Arrays.copyOf(bufs, bufs.length + 1);
- bufs[bufs.length - 1] = extension;
- computeBufferOffsets();
- }
-
- private void checkSplit(int splitOffset) {
- if (splitOffset < 0) {
- throw new IllegalArgumentException("The split offset cannot be negative: " + splitOffset + '.');
- }
- if (capacity() < splitOffset) {
- throw new IllegalArgumentException("The split offset cannot be greater than the buffer capacity, " +
- "but the split offset was " + splitOffset + ", and capacity is " + capacity() + '.');
- }
- if (!isAccessible()) {
- throw attachTrace(bufferIsClosed(this));
- }
- if (!isOwned()) {
- throw new IllegalStateException("Cannot split a buffer that is not owned.");
- }
- }
-
- @Override
- public CompositeBuffer split(int splitOffset) {
- checkSplit(splitOffset);
- if (bufs.length == 0) {
- // Splitting a zero-length buffer is trivial.
- return new CompositeBuffer(allocator, bufs, unsafeGetDrop()).order(order);
- }
-
- int i = searchOffsets(splitOffset);
- int off = splitOffset - offsets[i];
- Buffer[] splits = Arrays.copyOf(bufs, off == 0? i : 1 + i);
- bufs = Arrays.copyOfRange(bufs, off == bufs[i].capacity()? 1 + i : i, bufs.length);
- if (off > 0 && splits.length > 0 && off < splits[splits.length - 1].capacity()) {
- splits[splits.length - 1] = bufs[0].split(off);
- }
- computeBufferOffsets();
- return buildSplitBuffer(splits);
- }
-
- private CompositeBuffer buildSplitBuffer(Buffer[] splits) {
- var compositeBuf = new CompositeBuffer(allocator, splits, unsafeGetDrop());
- compositeBuf.order = order; // Preserve byte order even if splits array is empty.
- return compositeBuf;
- }
-
- /**
- * Split this buffer at a component boundary that is less than or equal to the given offset.
- *
- * This method behaves the same as {@link #split(int)}, except no components are split.
- *
- * @param splitOffset The maximum split offset. The real split offset will be at a component boundary that is less
- * than or equal to this offset.
- * @return A new buffer with independent and exclusive ownership over the bytes from the beginning to a component
- * boundary less than or equal to the given offset of this buffer.
- */
- public CompositeBuffer splitComponentsFloor(int splitOffset) {
- checkSplit(splitOffset);
- if (bufs.length == 0) {
- // Splitting a zero-length buffer is trivial.
- return new CompositeBuffer(allocator, bufs, unsafeGetDrop()).order(order);
- }
-
- int i = searchOffsets(splitOffset);
- int off = splitOffset - offsets[i];
- if (off == bufs[i].capacity()) {
- i++;
- }
- Buffer[] splits = Arrays.copyOf(bufs, i);
- bufs = Arrays.copyOfRange(bufs, i, bufs.length);
- computeBufferOffsets();
- return buildSplitBuffer(splits);
- }
-
- /**
- * Split this buffer at a component boundary that is greater than or equal to the given offset.
- *
- * This method behaves the same as {@link #split(int)}, except no components are split.
- *
- * @param splitOffset The minimum split offset. The real split offset will be at a component boundary that is
- * greater than or equal to this offset.
- * @return A new buffer with independent and exclusive ownership over the bytes from the beginning to a component
- * boundary greater than or equal to the given offset of this buffer.
- */
- public CompositeBuffer splitComponentsCeil(int splitOffset) {
- checkSplit(splitOffset);
- if (bufs.length == 0) {
- // Splitting a zero-length buffer is trivial.
- return new CompositeBuffer(allocator, bufs, unsafeGetDrop()).order(order);
- }
-
- int i = searchOffsets(splitOffset);
- int off = splitOffset - offsets[i];
- if (0 < off && off <= bufs[i].capacity()) {
- i++;
- }
- Buffer[] splits = Arrays.copyOf(bufs, i);
- bufs = Arrays.copyOfRange(bufs, i, bufs.length);
- computeBufferOffsets();
- return buildSplitBuffer(splits);
- }
-
- @Override
- public void compact() {
- if (!isOwned()) {
- throw new IllegalStateException("Buffer must be owned in order to compact.");
- }
- if (readOnly()) {
- throw new BufferReadOnlyException("Buffer must be writable in order to compact, but was read-only.");
- }
- int distance = roff;
- if (distance == 0) {
- return;
- }
- int pos = 0;
- var oldOrder = order;
- order = ByteOrder.BIG_ENDIAN;
- try {
- var cursor = openCursor();
- while (cursor.readLong()) {
- setLong(pos, cursor.getLong());
- pos += Long.BYTES;
- }
- while (cursor.readByte()) {
- setByte(pos, cursor.getByte());
- pos++;
- }
- } finally {
- order = oldOrder;
- }
- readerOffset(0);
- writerOffset(woff - distance);
- }
-
- @Override
- public int countComponents() {
- int sum = 0;
- for (Buffer buf : bufs) {
- sum += buf.countComponents();
- }
- return sum;
- }
-
- @Override
- public int countReadableComponents() {
- int sum = 0;
- for (Buffer buf : bufs) {
- sum += buf.countReadableComponents();
- }
- return sum;
- }
-
- @Override
- public int countWritableComponents() {
- int sum = 0;
- for (Buffer buf : bufs) {
- sum += buf.countWritableComponents();
- }
- return sum;
- }
-
- @Override
- public int forEachReadable(int initialIndex, ReadableComponentProcessor processor)
- throws E {
- checkReadBounds(readerOffset(), Math.max(1, readableBytes()));
- int visited = 0;
- for (Buffer buf : bufs) {
- if (buf.readableBytes() > 0) {
- int count = buf.forEachReadable(visited + initialIndex, processor);
- if (count > 0) {
- visited += count;
- } else {
- visited = -visited + count;
- break;
- }
- }
- }
- return visited;
- }
-
- @Override
- public int forEachWritable(int initialIndex, WritableComponentProcessor processor)
- throws E {
- checkWriteBounds(writerOffset(), Math.max(1, writableBytes()));
- int visited = 0;
- for (Buffer buf : bufs) {
- if (buf.writableBytes() > 0) {
- int count = buf.forEachWritable(visited + initialIndex, processor);
- if (count > 0) {
- visited += count;
- } else {
- visited = -visited + count;
- break;
- }
- }
- }
- return visited;
- }
-
- //
- @Override
- public byte readByte() {
- return prepRead(Byte.BYTES).readByte();
- }
-
- @Override
- public byte getByte(int roff) {
- return prepGet(roff, Byte.BYTES).getByte(subOffset);
- }
-
- @Override
- public int readUnsignedByte() {
- return prepRead(Byte.BYTES).readUnsignedByte();
- }
-
- @Override
- public int getUnsignedByte(int roff) {
- return prepGet(roff, Byte.BYTES).getUnsignedByte(subOffset);
- }
-
- @Override
- public CompositeBuffer writeByte(byte value) {
- prepWrite(Byte.BYTES).writeByte(value);
- return this;
- }
-
- @Override
- public CompositeBuffer setByte(int woff, byte value) {
- prepWrite(woff, Byte.BYTES).setByte(subOffset, value);
- return this;
- }
-
- @Override
- public CompositeBuffer writeUnsignedByte(int value) {
- prepWrite(Byte.BYTES).writeUnsignedByte(value);
- return this;
- }
-
- @Override
- public CompositeBuffer setUnsignedByte(int woff, int value) {
- prepWrite(woff, Byte.BYTES).setUnsignedByte(subOffset, value);
- return this;
- }
-
- @Override
- public char readChar() {
- return prepRead(2).readChar();
- }
-
- @Override
- public char getChar(int roff) {
- return prepGet(roff, 2).getChar(subOffset);
- }
-
- @Override
- public CompositeBuffer writeChar(char value) {
- prepWrite(2).writeChar(value);
- return this;
- }
-
- @Override
- public CompositeBuffer setChar(int woff, char value) {
- prepWrite(woff, 2).setChar(subOffset, value);
- return this;
- }
-
- @Override
- public short readShort() {
- return prepRead(Short.BYTES).readShort();
- }
-
- @Override
- public short getShort(int roff) {
- return prepGet(roff, Short.BYTES).getShort(subOffset);
- }
-
- @Override
- public int readUnsignedShort() {
- return prepRead(Short.BYTES).readShort();
- }
-
- @Override
- public int getUnsignedShort(int roff) {
- return prepGet(roff, Short.BYTES).getUnsignedShort(subOffset);
- }
-
- @Override
- public CompositeBuffer writeShort(short value) {
- prepWrite(Short.BYTES).writeShort(value);
- return this;
- }
-
- @Override
- public CompositeBuffer setShort(int woff, short value) {
- prepWrite(woff, Short.BYTES).setShort(subOffset, value);
- return this;
- }
-
- @Override
- public CompositeBuffer writeUnsignedShort(int value) {
- prepWrite(Short.BYTES).writeUnsignedShort(value);
- return this;
- }
-
- @Override
- public CompositeBuffer setUnsignedShort(int woff, int value) {
- prepWrite(woff, Short.BYTES).setUnsignedShort(subOffset, value);
- return this;
- }
-
- @Override
- public int readMedium() {
- return prepRead(3).readMedium();
- }
-
- @Override
- public int getMedium(int roff) {
- return prepGet(roff, 3).getMedium(subOffset);
- }
-
- @Override
- public int readUnsignedMedium() {
- return prepRead(3).readMedium();
- }
-
- @Override
- public int getUnsignedMedium(int roff) {
- return prepGet(roff, 3).getMedium(subOffset);
- }
-
- @Override
- public CompositeBuffer writeMedium(int value) {
- prepWrite(3).writeMedium(value);
- return this;
- }
-
- @Override
- public CompositeBuffer setMedium(int woff, int value) {
- prepWrite(woff, 3).setMedium(subOffset, value);
- return this;
- }
-
- @Override
- public CompositeBuffer writeUnsignedMedium(int value) {
- prepWrite(3).writeUnsignedMedium(value);
- return this;
- }
-
- @Override
- public CompositeBuffer setUnsignedMedium(int woff, int value) {
- prepWrite(woff, 3).setUnsignedMedium(subOffset, value);
- return this;
- }
-
- @Override
- public int readInt() {
- return prepRead(Integer.BYTES).readInt();
- }
-
- @Override
- public int getInt(int roff) {
- return prepGet(roff, Integer.BYTES).getInt(subOffset);
- }
-
- @Override
- public long readUnsignedInt() {
- return prepRead(Integer.BYTES).readUnsignedInt();
- }
-
- @Override
- public long getUnsignedInt(int roff) {
- return prepGet(roff, Integer.BYTES).getUnsignedInt(subOffset);
- }
-
- @Override
- public CompositeBuffer writeInt(int value) {
- prepWrite(Integer.BYTES).writeInt(value);
- return this;
- }
-
- @Override
- public CompositeBuffer setInt(int woff, int value) {
- prepWrite(woff, Integer.BYTES).setInt(subOffset, value);
- return this;
- }
-
- @Override
- public CompositeBuffer writeUnsignedInt(long value) {
- prepWrite(Integer.BYTES).writeUnsignedInt(value);
- return this;
- }
-
- @Override
- public CompositeBuffer setUnsignedInt(int woff, long value) {
- prepWrite(woff, Integer.BYTES).setUnsignedInt(subOffset, value);
- return this;
- }
-
- @Override
- public float readFloat() {
- return prepRead(Float.BYTES).readFloat();
- }
-
- @Override
- public float getFloat(int roff) {
- return prepGet(roff, Float.BYTES).getFloat(subOffset);
- }
-
- @Override
- public CompositeBuffer writeFloat(float value) {
- prepWrite(Float.BYTES).writeFloat(value);
- return this;
- }
-
- @Override
- public CompositeBuffer setFloat(int woff, float value) {
- prepWrite(woff, Float.BYTES).setFloat(subOffset, value);
- return this;
- }
-
- @Override
- public long readLong() {
- return prepRead(Long.BYTES).readLong();
- }
-
- @Override
- public long getLong(int roff) {
- return prepGet(roff, Long.BYTES).getLong(subOffset);
- }
-
- @Override
- public CompositeBuffer writeLong(long value) {
- prepWrite(Long.BYTES).writeLong(value);
- return this;
- }
-
- @Override
- public CompositeBuffer setLong(int woff, long value) {
- prepWrite(woff, Long.BYTES).setLong(subOffset, value);
- return this;
- }
-
- @Override
- public double readDouble() {
- return prepRead(Double.BYTES).readDouble();
- }
-
- @Override
- public double getDouble(int roff) {
- return prepGet(roff, Double.BYTES).getDouble(subOffset);
- }
-
- @Override
- public CompositeBuffer writeDouble(double value) {
- prepWrite(Double.BYTES).writeDouble(value);
- return this;
- }
-
- @Override
- public CompositeBuffer setDouble(int woff, double value) {
- prepWrite(woff, Double.BYTES).setDouble(subOffset, value);
- return this;
- }
- //
-
- @Override
- protected Owned prepareSend() {
- @SuppressWarnings("unchecked")
- Send[] sends = new Send[bufs.length];
- try {
- for (int i = 0; i < bufs.length; i++) {
- sends[i] = bufs[i].send();
- }
- } catch (Throwable throwable) {
- // Repair our bufs array.
- for (int i = 0; i < sends.length; i++) {
- if (sends[i] != null) {
- try {
- bufs[i] = sends[i].receive();
- } catch (Exception e) {
- throwable.addSuppressed(e);
- }
- }
- }
- throw throwable;
- }
- boolean readOnly = this.readOnly;
- makeInaccessible();
- return new Owned() {
- @Override
- public CompositeBuffer transferOwnership(Drop drop) {
- Buffer[] received = new Buffer[sends.length];
- for (int i = 0; i < sends.length; i++) {
- received[i] = sends[i].receive();
- }
- var composite = new CompositeBuffer(allocator, received, drop);
- composite.readOnly = readOnly;
- drop.attach(composite);
- return composite;
- }
- };
- }
-
- void makeInaccessible() {
- capacity = 0;
- roff = 0;
- woff = 0;
- readOnly = false;
- closed = true;
- }
-
- @Override
- protected boolean isOwned() {
- return super.isOwned() && allConstituentsAreOwned();
- }
-
- private boolean allConstituentsAreOwned() {
- boolean result = true;
- for (Buffer buf : bufs) {
- result &= Statics.isOwned((ResourceSupport, ?>) buf);
- }
- return result;
- }
-
- long readPassThrough() {
- var buf = choosePassThroughBuffer(subOffset++);
- assert buf != tornBufAccessors: "Recursive call to torn buffer.";
- return buf.readUnsignedByte();
- }
-
- void writePassThrough(int value) {
- var buf = choosePassThroughBuffer(subOffset++);
- assert buf != tornBufAccessors: "Recursive call to torn buffer.";
- buf.writeUnsignedByte(value);
- }
-
- long getPassThrough(int roff) {
- var buf = chooseBuffer(roff, 1);
- assert buf != tornBufAccessors: "Recursive call to torn buffer.";
- return buf.getUnsignedByte(subOffset);
- }
-
- void setPassThrough(int woff, int value) {
- var buf = chooseBuffer(woff, 1);
- assert buf != tornBufAccessors: "Recursive call to torn buffer.";
- buf.setUnsignedByte(subOffset, value);
- }
-
- private BufferAccessors prepRead(int size) {
- var buf = prepRead(roff, size);
- roff += size;
- return buf;
- }
-
- private BufferAccessors prepRead(int index, int size) {
- checkReadBounds(index, size);
- return chooseBuffer(index, size);
- }
-
- private void checkReadBounds(int index, int size) {
- if (index < 0 || woff < index + size) {
- throw indexOutOfBounds(index, false);
- }
- }
-
- private BufferAccessors prepGet(int index, int size) {
- checkGetBounds(index, size);
- return chooseBuffer(index, size);
- }
-
- private void checkGetBounds(int index, int size) {
- if (index < 0 || capacity < index + size) {
- throw indexOutOfBounds(index, false);
- }
- }
-
- private BufferAccessors prepWrite(int size) {
- var buf = prepWrite(woff, size);
- woff += size;
- return buf;
- }
-
- private BufferAccessors prepWrite(int index, int size) {
- checkWriteBounds(index, size);
- return chooseBuffer(index, size);
- }
-
- private void checkWriteBounds(int index, int size) {
- if (index < 0 || capacity < index + size) {
- throw indexOutOfBounds(index, true);
- }
- }
-
- private RuntimeException indexOutOfBounds(int index, boolean write) {
- if (closed) {
- return bufferIsClosed(this);
- }
- if (write && readOnly) {
- return bufferIsReadOnly(this);
- }
- return new IndexOutOfBoundsException(
- "Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
- capacity + "].");
- }
-
- private BufferAccessors chooseBuffer(int index, int size) {
- int i = searchOffsets(index);
- if (i == bufs.length) {
- // This happens when the read/write offsets are parked 1 byte beyond the end of the buffer.
- // In that case it should not matter what buffer is returned, because it shouldn't be used anyway.
- return null;
- }
- int off = index - offsets[i];
- Buffer candidate = bufs[i];
- if (off + size <= candidate.capacity()) {
- subOffset = off;
- return candidate;
- }
- subOffset = index;
- return tornBufAccessors;
- }
-
- private BufferAccessors choosePassThroughBuffer(int index) {
- int i = searchOffsets(index);
- return bufs[i];
- }
-
- private int searchOffsets(int index) {
- int i = Arrays.binarySearch(offsets, index);
- return i < 0? -(i + 2) : i;
- }
-
- //
- private static final class TornBufferAccessors implements BufferAccessors {
- private final CompositeBuffer buf;
-
- private TornBufferAccessors(CompositeBuffer buf) {
- this.buf = buf;
- }
-
- @Override
- public byte readByte() {
- throw new AssertionError("Method should not be used.");
- }
-
- @Override
- public byte getByte(int roff) {
- throw new AssertionError("Method should not be used.");
- }
-
- @Override
- public int readUnsignedByte() {
- throw new AssertionError("Method should not be used.");
- }
-
- @Override
- public int getUnsignedByte(int roff) {
- throw new AssertionError("Method should not be used.");
- }
-
- @Override
- public Buffer writeByte(byte value) {
- throw new AssertionError("Method should not be used.");
- }
-
- @Override
- public Buffer setByte(int woff, byte value) {
- throw new AssertionError("Method should not be used.");
- }
-
- @Override
- public Buffer writeUnsignedByte(int value) {
- throw new AssertionError("Method should not be used.");
- }
-
- @Override
- public Buffer setUnsignedByte(int woff, int value) {
- throw new AssertionError("Method should not be used.");
- }
-
- @Override
- public char readChar() {
- if (bigEndian()) {
- return (char) (read() << 8 | read());
- } else {
- return (char) (read() | read() << 8);
- }
- }
-
- @Override
- public char getChar(int roff) {
- if (bigEndian()) {
- return (char) (read(roff) << 8 | read(roff + 1));
- } else {
- return (char) (read(roff) | read(roff + 1) << 8);
- }
- }
-
- @Override
- public Buffer writeChar(char value) {
- if (bigEndian()) {
- write(value >>> 8);
- write(value & 0xFF);
- } else {
- write(value & 0xFF);
- write(value >>> 8);
- }
- return buf;
- }
-
- @Override
- public Buffer setChar(int woff, char value) {
- if (bigEndian()) {
- write(woff, value >>> 8);
- write(woff + 1, value & 0xFF);
- } else {
- write(woff, value & 0xFF);
- write(woff + 1, value >>> 8);
- }
- return buf;
- }
-
- @Override
- public short readShort() {
- if (bigEndian()) {
- return (short) (read() << 8 | read());
- } else {
- return (short) (read() | read() << 8);
- }
- }
-
- @Override
- public short getShort(int roff) {
- if (bigEndian()) {
- return (short) (read(roff) << 8 | read(roff + 1));
- } else {
- return (short) (read(roff) | read(roff + 1) << 8);
- }
- }
-
- @Override
- public int readUnsignedShort() {
- if (bigEndian()) {
- return (int) (read() << 8 | read()) & 0xFFFF;
- } else {
- return (int) (read() | read() << 8) & 0xFFFF;
- }
- }
-
- @Override
- public int getUnsignedShort(int roff) {
- if (bigEndian()) {
- return (int) (read(roff) << 8 | read(roff + 1)) & 0xFFFF;
- } else {
- return (int) (read(roff) | read(roff + 1) << 8) & 0xFFFF;
- }
- }
-
- @Override
- public Buffer writeShort(short value) {
- if (bigEndian()) {
- write(value >>> 8);
- write(value & 0xFF);
- } else {
- write(value & 0xFF);
- write(value >>> 8);
- }
- return buf;
- }
-
- @Override
- public Buffer setShort(int woff, short value) {
- if (bigEndian()) {
- write(woff, value >>> 8);
- write(woff + 1, value & 0xFF);
- } else {
- write(woff, value & 0xFF);
- write(woff + 1, value >>> 8);
- }
- return buf;
- }
-
- @Override
- public Buffer writeUnsignedShort(int value) {
- if (bigEndian()) {
- write(value >>> 8);
- write(value & 0xFF);
- } else {
- write(value & 0xFF);
- write(value >>> 8);
- }
- return buf;
- }
-
- @Override
- public Buffer setUnsignedShort(int woff, int value) {
- if (bigEndian()) {
- write(woff, value >>> 8);
- write(woff + 1, value & 0xFF);
- } else {
- write(woff, value & 0xFF);
- write(woff + 1, value >>> 8);
- }
- return buf;
- }
-
- @Override
- public int readMedium() {
- if (bigEndian()) {
- return (int) (read() << 16 | read() << 8 | read());
- } else {
- return (int) (read() | read() << 8 | read() << 16);
- }
- }
-
- @Override
- public int getMedium(int roff) {
- if (bigEndian()) {
- return (int) (read(roff) << 16 | read(roff + 1) << 8 | read(roff + 2));
- } else {
- return (int) (read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16);
- }
- }
-
- @Override
- public int readUnsignedMedium() {
- if (bigEndian()) {
- return (int) (read() << 16 | read() << 8 | read()) & 0xFFFFFF;
- } else {
- return (int) (read() | read() << 8 | read() << 16) & 0xFFFFFF;
- }
- }
-
- @Override
- public int getUnsignedMedium(int roff) {
- if (bigEndian()) {
- return (int) (read(roff) << 16 | read(roff + 1) << 8 | read(roff + 2)) & 0xFFFFFF;
- } else {
- return (int) (read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16) & 0xFFFFFF;
- }
- }
-
- @Override
- public Buffer writeMedium(int value) {
- if (bigEndian()) {
- write(value >>> 16);
- write(value >>> 8 & 0xFF);
- write(value & 0xFF);
- } else {
- write(value & 0xFF);
- write(value >>> 8 & 0xFF);
- write(value >>> 16);
- }
- return buf;
- }
-
- @Override
- public Buffer setMedium(int woff, int value) {
- if (bigEndian()) {
- write(woff, value >>> 16);
- write(woff + 1, value >>> 8 & 0xFF);
- write(woff + 2, value & 0xFF);
- } else {
- write(woff, value & 0xFF);
- write(woff + 1, value >>> 8 & 0xFF);
- write(woff + 2, value >>> 16);
- }
- return buf;
- }
-
- @Override
- public Buffer writeUnsignedMedium(int value) {
- if (bigEndian()) {
- write(value >>> 16);
- write(value >>> 8 & 0xFF);
- write(value & 0xFF);
- } else {
- write(value & 0xFF);
- write(value >>> 8 & 0xFF);
- write(value >>> 16);
- }
- return buf;
- }
-
- @Override
- public Buffer setUnsignedMedium(int woff, int value) {
- if (bigEndian()) {
- write(woff, value >>> 16);
- write(woff + 1, value >>> 8 & 0xFF);
- write(woff + 2, value & 0xFF);
- } else {
- write(woff, value & 0xFF);
- write(woff + 1, value >>> 8 & 0xFF);
- write(woff + 2, value >>> 16);
- }
- return buf;
- }
-
- @Override
- public int readInt() {
- if (bigEndian()) {
- return (int) (read() << 24 | read() << 16 | read() << 8 | read());
- } else {
- return (int) (read() | read() << 8 | read() << 16 | read() << 24);
- }
- }
-
- @Override
- public int getInt(int roff) {
- if (bigEndian()) {
- return (int) (read(roff) << 24 | read(roff + 1) << 16 | read(roff + 2) << 8 | read(roff + 3));
- } else {
- return (int) (read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16 | read(roff + 3) << 24);
- }
- }
-
- @Override
- public long readUnsignedInt() {
- if (bigEndian()) {
- return (read() << 24 | read() << 16 | read() << 8 | read()) & 0xFFFFFFFFL;
- } else {
- return (read() | read() << 8 | read() << 16 | read() << 24) & 0xFFFFFFFFL;
- }
- }
-
- @Override
- public long getUnsignedInt(int roff) {
- if (bigEndian()) {
- return (read(roff) << 24 | read(roff + 1) << 16 | read(roff + 2) << 8 | read(roff + 3)) & 0xFFFFFFFFL;
- } else {
- return (read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16 | read(roff + 3) << 24) & 0xFFFFFFFFL;
- }
- }
-
- @Override
- public Buffer writeInt(int value) {
- if (bigEndian()) {
- write(value >>> 24);
- write(value >>> 16 & 0xFF);
- write(value >>> 8 & 0xFF);
- write(value & 0xFF);
- } else {
- write(value & 0xFF);
- write(value >>> 8 & 0xFF);
- write(value >>> 16 & 0xFF);
- write(value >>> 24);
- }
- return buf;
- }
-
- @Override
- public Buffer setInt(int woff, int value) {
- if (bigEndian()) {
- write(woff, value >>> 24);
- write(woff + 1, value >>> 16 & 0xFF);
- write(woff + 2, value >>> 8 & 0xFF);
- write(woff + 3, value & 0xFF);
- } else {
- write(woff, value & 0xFF);
- write(woff + 1, value >>> 8 & 0xFF);
- write(woff + 2, value >>> 16 & 0xFF);
- write(woff + 3, value >>> 24);
- }
- return buf;
- }
-
- @Override
- public Buffer writeUnsignedInt(long value) {
- if (bigEndian()) {
- write((int) (value >>> 24));
- write((int) (value >>> 16 & 0xFF));
- write((int) (value >>> 8 & 0xFF));
- write((int) (value & 0xFF));
- } else {
- write((int) (value & 0xFF));
- write((int) (value >>> 8 & 0xFF));
- write((int) (value >>> 16 & 0xFF));
- write((int) (value >>> 24));
- }
- return buf;
- }
-
- @Override
- public Buffer setUnsignedInt(int woff, long value) {
- if (bigEndian()) {
- write(woff, (int) (value >>> 24));
- write(woff + 1, (int) (value >>> 16 & 0xFF));
- write(woff + 2, (int) (value >>> 8 & 0xFF));
- write(woff + 3, (int) (value & 0xFF));
- } else {
- write(woff, (int) (value & 0xFF));
- write(woff + 1, (int) (value >>> 8 & 0xFF));
- write(woff + 2, (int) (value >>> 16 & 0xFF));
- write(woff + 3, (int) (value >>> 24));
- }
- return buf;
- }
-
- @Override
- public float readFloat() {
- return Float.intBitsToFloat(readInt());
- }
-
- @Override
- public float getFloat(int roff) {
- return Float.intBitsToFloat(getInt(roff));
- }
-
- @Override
- public Buffer writeFloat(float value) {
- return writeUnsignedInt(Float.floatToRawIntBits(value));
- }
-
- @Override
- public Buffer setFloat(int woff, float value) {
- return setUnsignedInt(woff, Float.floatToRawIntBits(value));
- }
-
- @Override
- public long readLong() {
- if (bigEndian()) {
- return read() << 56 | read() << 48 | read() << 40 | read() << 32 |
- read() << 24 | read() << 16 | read() << 8 | read();
- } else {
- return read() | read() << 8 | read() << 16 | read() << 24 |
- read() << 32 | read() << 40 | read() << 48 | read() << 56;
- }
- }
-
- @Override
- public long getLong(int roff) {
- if (bigEndian()) {
- return read(roff) << 56 | read(roff + 1) << 48 | read(roff + 2) << 40 | read(roff + 3) << 32 |
- read(roff + 4) << 24 | read(roff + 5) << 16 | read(roff + 6) << 8 | read(roff + 7);
- } else {
- return read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16 | read(roff + 3) << 24 |
- read(roff + 4) << 32 | read(roff + 5) << 40 | read(roff + 6) << 48 | read(roff + 7) << 56;
- }
- }
-
- @Override
- public Buffer writeLong(long value) {
- if (bigEndian()) {
- write((int) (value >>> 56));
- write((int) (value >>> 48 & 0xFF));
- write((int) (value >>> 40 & 0xFF));
- write((int) (value >>> 32 & 0xFF));
- write((int) (value >>> 24 & 0xFF));
- write((int) (value >>> 16 & 0xFF));
- write((int) (value >>> 8 & 0xFF));
- write((int) (value & 0xFF));
- } else {
- write((int) (value & 0xFF));
- write((int) (value >>> 8 & 0xFF));
- write((int) (value >>> 16 & 0xFF));
- write((int) (value >>> 24));
- write((int) (value >>> 32));
- write((int) (value >>> 40));
- write((int) (value >>> 48));
- write((int) (value >>> 56));
- }
- return buf;
- }
-
- @Override
- public Buffer setLong(int woff, long value) {
- if (bigEndian()) {
- write(woff, (int) (value >>> 56));
- write(woff + 1, (int) (value >>> 48 & 0xFF));
- write(woff + 2, (int) (value >>> 40 & 0xFF));
- write(woff + 3, (int) (value >>> 32 & 0xFF));
- write(woff + 4, (int) (value >>> 24 & 0xFF));
- write(woff + 5, (int) (value >>> 16 & 0xFF));
- write(woff + 6, (int) (value >>> 8 & 0xFF));
- write(woff + 7, (int) (value & 0xFF));
- } else {
- write(woff, (int) (value & 0xFF));
- write(woff + 1, (int) (value >>> 8 & 0xFF));
- write(woff + 2, (int) (value >>> 16 & 0xFF));
- write(woff + 3, (int) (value >>> 24));
- write(woff + 4, (int) (value >>> 32));
- write(woff + 5, (int) (value >>> 40));
- write(woff + 6, (int) (value >>> 48));
- write(woff + 7, (int) (value >>> 56));
- }
- return buf;
- }
-
- @Override
- public double readDouble() {
- return Double.longBitsToDouble(readLong());
- }
-
- @Override
- public double getDouble(int roff) {
- return Double.longBitsToDouble(getLong(roff));
- }
-
- @Override
- public Buffer writeDouble(double value) {
- return writeLong(Double.doubleToRawLongBits(value));
- }
-
- @Override
- public Buffer setDouble(int woff, double value) {
- return setLong(woff, Double.doubleToRawLongBits(value));
- }
-
- private boolean bigEndian() {
- return buf.order() == ByteOrder.BIG_ENDIAN;
- }
-
- private long read() {
- return buf.readPassThrough();
- }
-
- private void write(int value) {
- buf.writePassThrough(value);
- }
-
- private long read(int roff) {
- return buf.getPassThrough(roff);
- }
-
- private void write(int woff, int value) {
- buf.setPassThrough(woff, value);
- }
- }
- //
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/Drop.java b/buffer-api/src/main/java/io/netty/buffer/api/Drop.java
deleted file mode 100644
index 1461620..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/Drop.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-/**
- * The Drop interface is used by {@link Resource} instances to implement their resource disposal mechanics.
- * The {@link #drop(Object)} method will be called by the resource when they are closed.
- *
- * @param
- */
-@FunctionalInterface
-public interface Drop {
- /**
- * Dispose of the resources in the given {@link Resource} instance.
- *
- * @param obj The {@link Resource} instance being dropped.
- */
- void drop(T obj);
-
- /**
- * Called when the resource changes owner.
- *
- * @param obj The new {@link Resource} instance with the new owner.
- */
- default void attach(T obj) {
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/ManagedBufferAllocator.java b/buffer-api/src/main/java/io/netty/buffer/api/ManagedBufferAllocator.java
deleted file mode 100644
index a132772..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/ManagedBufferAllocator.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-import io.netty.buffer.api.internal.Statics;
-
-import java.util.function.Supplier;
-
-import static io.netty.buffer.api.internal.Statics.NO_OP_DROP;
-
-class ManagedBufferAllocator implements BufferAllocator, AllocatorControl {
- private final MemoryManager manager;
-
- ManagedBufferAllocator(MemoryManager manager) {
- this.manager = manager;
- }
-
- @Override
- public Buffer allocate(int size) {
- BufferAllocator.checkSize(size);
- return manager.allocateShared(this, size, manager.drop(), Statics.CLEANER);
- }
-
- @Override
- public Supplier constBufferSupplier(byte[] bytes) {
- Buffer constantBuffer = manager.allocateShared(this, bytes.length, manager.drop(), Statics.CLEANER);
- constantBuffer.writeBytes(bytes).makeReadOnly();
- return () -> manager.allocateConstChild(constantBuffer);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public UntetheredMemory allocateUntethered(Buffer originator, int size) {
- BufferAllocator.checkSize(size);
- var buf = manager.allocateShared(this, size, NO_OP_DROP, Statics.CLEANER);
- return new UntetheredMemory() {
- @Override
- public Memory memory() {
- return (Memory) manager.unwrapRecoverableMemory(buf);
- }
-
- @Override
- public Drop drop() {
- return (Drop) manager.drop();
- }
- };
- }
-
- @Override
- public void recoverMemory(Object memory) {
- // Free the recovered memory.
- manager.recoverMemory(this, memory, manager.drop()).close();
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/MemoryManager.java b/buffer-api/src/main/java/io/netty/buffer/api/MemoryManager.java
deleted file mode 100644
index 730b0ca..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/MemoryManager.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-import java.lang.ref.Cleaner;
-
-public interface MemoryManager {
- boolean isNative();
- Buffer allocateShared(AllocatorControl allocatorControl, long size, Drop drop, Cleaner cleaner);
- Buffer allocateConstChild(Buffer readOnlyConstParent);
- Drop drop();
- Object unwrapRecoverableMemory(Buffer buf);
- int capacityOfRecoverableMemory(Object memory);
- void discardRecoverableMemory(Object recoverableMemory);
- // todo should recoverMemory re-attach a cleaner?
- Buffer recoverMemory(AllocatorControl allocatorControl, Object recoverableMemory, Drop drop);
- Object sliceMemory(Object memory, int offset, int length);
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/MemoryManagers.java b/buffer-api/src/main/java/io/netty/buffer/api/MemoryManagers.java
deleted file mode 100644
index c9a4af4..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/MemoryManagers.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-import io.netty.buffer.api.internal.MemoryManagersOverride;
-
-import java.util.Optional;
-import java.util.ServiceLoader;
-import java.util.function.Supplier;
-import java.util.stream.Stream;
-
-/**
- * The MemoryManagers interface is the handle through which {@link BufferAllocator buffer allocators} access the low
- * level memory management APIs.
- *
- * This is hidden behind this interface in order to make allocation and pool agnostic and reusable across buffer and
- * memory implementations.
- */
-public interface MemoryManagers {
- /**
- * Get the default, or currently configured, memory managers instance.
- * @return A MemoryManagers instance.
- */
- static MemoryManagers getManagers() {
- return MemoryManagersOverride.getManagers();
- }
-
- /**
- * Temporarily override the default configured memory managers instance.
- *
- * Calls to {@link #getManagers()} from within the given supplier will get the given managers instance.
- *
- * @param managers Override the default configured managers instance with this instance.
- * @param supplier The supplier function to be called while the override is in place.
- * @param The result type from the supplier.
- * @return The result from the supplier.
- */
- static T using(MemoryManagers managers, Supplier supplier) {
- return MemoryManagersOverride.using(managers, supplier);
- }
-
- /**
- * Get a lazy-loading stream of all available memory managers.
- *
- * Note: All available {@link MemoryManagers} instances are service loaded and instantiated on every call.
- *
- * @return A stream of providers of memory managers instances.
- */
- static Stream> getAllManagers() {
- var loader = ServiceLoader.load(MemoryManagers.class);
- return loader.stream();
- }
-
- /**
- * Find a {@link MemoryManagers} implementation by its {@linkplain #getImplementationName() implementation name}.
- *
- * Note: All available {@link MemoryManagers} instances are service loaded and instantiated every time this
- * method is called.
- *
- * @param implementationName The named implementation to look for.
- * @return A {@link MemoryManagers} implementation, if any was found.
- */
- static Optional lookupImplementation(String implementationName) {
- return getAllManagers()
- .flatMap(provider -> {
- try {
- return Stream.ofNullable(provider.get());
- } catch (Exception e) {
- return Stream.empty();
- }
- })
- .filter(impl -> implementationName.equals(impl.getImplementationName()))
- .findFirst();
- }
-
- /**
- * Get a {@link MemoryManager} instance that is suitable for allocating on-heap {@link Buffer} instances.
- *
- * @return An on-heap {@link MemoryManager}.
- */
- MemoryManager getHeapMemoryManager();
-
- /**
- * Get a {@link MemoryManager} instance that is suitable for allocating off-heap {@link Buffer} instances.
- *
- * @return An off-heap {@link MemoryManager}.
- */
- MemoryManager getNativeMemoryManager();
-
- /**
- * Get the name for this implementation, which can be used for finding this particular implementation via the
- * {@link #lookupImplementation(String)} method.
- *
- * @return The name of this memory managers implementation.
- */
- String getImplementationName();
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/Owned.java b/buffer-api/src/main/java/io/netty/buffer/api/Owned.java
deleted file mode 100644
index 9f22ecc..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/Owned.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-/**
- * This interface encapsulates the ownership of a {@link Resource}, and exposes a method that may be used to transfer
- * this ownership to the specified recipient thread.
- *
- * @param The concrete type of {@link Resource} that is owned.
- */
-@SuppressWarnings("InterfaceMayBeAnnotatedFunctional")
-public interface Owned {
- /**
- * Transfer the ownership of the resource, to the calling thread. The resource instance is invalidated but without
- * disposing of its internal state. Then a new resource instance with the given owner is produced in its stead.
- *
- * This method is called by {@link Send} implementations. These implementations will ensure that the transfer of
- * ownership (the calling of this method) happens-before the new owner begins accessing the new object. This ensures
- * that the new resource instanec is safely published to the new owners.
- *
- * @param drop The drop object that knows how to dispose of the state represented by this {@link Resource}.
- * @return A new resource instance that is exactly the same as this resource.
- */
- T transferOwnership(Drop drop);
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/ReadableComponent.java b/buffer-api/src/main/java/io/netty/buffer/api/ReadableComponent.java
deleted file mode 100644
index bdcc045..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/ReadableComponent.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-import java.nio.ByteBuffer;
-
-/**
- * A view onto the buffer component being processed in a given iteration of
- * {@link Buffer#forEachReadable(int, ReadableComponentProcessor)}.
- */
-public interface ReadableComponent {
-
- /**
- * Check if this component is backed by a cached byte array than can be accessed cheaply.
- *
- * Note that regardless of what this method returns, the array should not be used to modify the
- * contents of this buffer component.
- *
- * @return {@code true} if {@link #readableArray()} is a cheap operation, otherwise {@code false}.
- */
- boolean hasReadableArray();
-
- /**
- * Get a byte array of the contents of this component.
- *
- * Note that the array is meant to be read-only. It may either be a direct reference to the
- * concrete array instance that is backing this component, or it is a fresh copy. Writing to the array may produce
- * undefined behaviour.
- *
- * @return A byte array of the contents of this component.
- * @throws UnsupportedOperationException if {@link #hasReadableArray()} returns {@code false}.
- * @see #readableArrayOffset()
- * @see #readableArrayLength()
- */
- byte[] readableArray();
-
- /**
- * An offset into the {@link #readableArray()} where this component starts.
- *
- * @return An offset into {@link #readableArray()}.
- * @throws UnsupportedOperationException if {@link #hasReadableArray()} returns {@code false}.
- */
- int readableArrayOffset();
-
- /**
- * The number of bytes in the {@link #readableArray()} that belong to this component.
- *
- * @return The number of bytes, from the {@link #readableArrayOffset()} into the {@link #readableArray()},
- * that belong to this component.
- * @throws UnsupportedOperationException if {@link #hasReadableArray()} returns {@code false}.
- */
- int readableArrayLength();
-
- /**
- * Give the native memory address backing this buffer, or return 0 if this buffer has no native memory address.
- *
- * Note that the address should not be used for writing to the buffer memory, and doing so may
- * produce undefined behaviour.
- *
- * @return The native memory address, if any, otherwise 0.
- */
- long readableNativeAddress();
-
- /**
- * Get a {@link ByteBuffer} instance for this memory component.
- *
- * Note that the {@link ByteBuffer} is read-only, to prevent write accesses to the memory,
- * when the buffer component is obtained through {@link Buffer#forEachReadable(int, ReadableComponentProcessor)}.
- *
- * @return A new {@link ByteBuffer}, with its own position and limit, for this memory component.
- */
- ByteBuffer readableBuffer();
-
- /**
- * Open a cursor to iterate the readable bytes of this component.
- * Any offsets internal to the component are not modified by the cursor.
- *
- * Care should be taken to ensure that the buffers lifetime extends beyond the cursor and the iteration, and that
- * the internal offsets of the component (such as {@link Buffer#readerOffset()} and {@link Buffer#writerOffset()})
- * are not modified while the iteration takes place. Otherwise unpredictable behaviour might result.
- *
- * @return A {@link ByteCursor} for iterating the readable bytes of this buffer.
- * @see Buffer#openCursor()
- */
- ByteCursor openCursor();
- // todo for Unsafe-based impl, DBB.attachment needs to keep underlying memory alive
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/ReadableComponentProcessor.java b/buffer-api/src/main/java/io/netty/buffer/api/ReadableComponentProcessor.java
deleted file mode 100644
index 74232d4..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/ReadableComponentProcessor.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-import java.nio.ByteBuffer;
-
-/**
- * A processor of {@linkplain ReadableComponent readable components}.
- */
-@FunctionalInterface
-public interface ReadableComponentProcessor {
- /**
- * Process the given component at the given index in the
- * {@link Buffer#forEachReadable(int, ReadableComponentProcessor) iteration}.
- *
- * The component object itself is only valid during this call, but the {@link ByteBuffer byte buffers}, arrays, and
- * native address pointers obtained from it, will be valid until any operation is performed on the buffer, which
- * changes the internal memory.
- *
- * @param index The current index of the given buffer component, based on the initial index passed to the
- * {@link Buffer#forEachReadable(int, ReadableComponentProcessor)} method.
- * @param component The current buffer component being processed.
- * @return {@code true} if the iteration should continue and more components should be processed, otherwise
- * {@code false} to stop the iteration early.
- */
- boolean process(int index, ReadableComponent component) throws E;
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/Resource.java b/buffer-api/src/main/java/io/netty/buffer/api/Resource.java
deleted file mode 100644
index 73604ec..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/Resource.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-/**
- * A resource that has a life-time, and can be {@linkplain #close() closed}.
- * Resources are initially {@linkplain #isAccessible() accessible}, but closing them makes them inaccessible.
- */
-public interface Resource> extends AutoCloseable {
- /**
- * Send this object instance to another Thread, transferring the ownership to the recipient.
- *
- * The object must be in a state where it can be sent, which includes at least being
- * {@linkplain #isAccessible() accessible}.
- *
- * When sent, this instance will immediately become inaccessible, as if by {@linkplain #close() closing} it.
- * All attempts at accessing an object that has been sent, even if that object has not yet been received, should
- * cause an exception to be thrown.
- *
- * Calling {@link #close()} on an object that has been sent will have no effect, so this method is safe to call
- * within a try-with-resources statement.
- */
- Send send();
-
- /**
- * Close the resource, making it inaccessible.
- *
- * Note, this method is not thread-safe unless otherwise specific.
- *
- * @throws IllegalStateException If this {@code Resource} has already been closed.
- */
- @Override
- void close();
-
- /**
- * Check if this object is accessible.
- *
- * @return {@code true} if this object is still valid and can be accessed,
- * otherwise {@code false} if, for instance, this object has been dropped/deallocated,
- * or been {@linkplain #send() sent} elsewhere.
- */
- boolean isAccessible();
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/ResourceDisposeFailedException.java b/buffer-api/src/main/java/io/netty/buffer/api/ResourceDisposeFailedException.java
deleted file mode 100644
index 5206af2..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/ResourceDisposeFailedException.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-/**
- * Thrown when resource disposal fails while closing a resource pool.
- */
-public class ResourceDisposeFailedException extends RuntimeException {
- private static final long serialVersionUID = -1413426368835341993L;
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/Scope.java b/buffer-api/src/main/java/io/netty/buffer/api/Scope.java
deleted file mode 100644
index ce746d3..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/Scope.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-import java.util.ArrayDeque;
-
-/**
- * A scope is a convenient mechanism for capturing the life cycles of multiple reference counted objects. Once the scope
- * is closed, all the added objects will also be closed in reverse insert order. That is, the most recently added
- * object will be closed first.
- *
- * Scopes can be reused. After a scope has been closed, new objects can be added to it, and they will be closed when the
- * scope is closed again.
- *
- * Objects will not be closed multiple times if the scope is closed multiple times, unless said objects are also added
- * multiple times.
- *
- * Note that scopes are not thread-safe. They are intended to be used from a single thread.
- */
-public final class Scope implements AutoCloseable {
- private final ArrayDeque> deque = new ArrayDeque<>();
-
- /**
- * Add the given reference counted object to this scope, so that it will be {@linkplain Resource#close() closed}
- * when this scope is {@linkplain #close() closed}.
- *
- * @param obj The reference counted object to add to this scope.
- * @param The type of the reference counted object.
- * @return The same exact object that was added; further operations can be chained on the object after this method
- * call.
- */
- public > T add(T obj) {
- deque.addLast(obj);
- return obj;
- }
-
- /**
- * Close this scope and all the reference counted object it contains.
- */
- @Override
- public void close() {
- Resource> obj;
- while ((obj = deque.pollLast()) != null) {
- obj.close();
- }
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/Send.java b/buffer-api/src/main/java/io/netty/buffer/api/Send.java
deleted file mode 100644
index 0b414b7..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/Send.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Function;
-import java.util.function.Supplier;
-
-/**
- * A {@code Send} object is a temporary holder of a {@link Resource}, used for transferring the ownership of the
- * resource from one thread to another.
- *
- * Prior to the {@code Send} being created, the originating resource is invalidated, to prevent access while it is being
- * sent. This means it cannot be accessed, closed, or disposed of, while it is in-flight. Once the resource is
- * {@linkplain #receive() received}, the new ownership is established.
- *
- * Care must be taken to ensure that the resource is always received by some thread.
- * Failure to do so can result in a resource leak.
- *
- * @param
- */
-public interface Send> {
- /**
- * Construct a {@link Send} based on the given {@link Supplier}.
- * The supplier will be called only once, in the receiving thread.
- *
- * @param concreteObjectType The concrete type of the object being sent. Specifically, the object returned from the
- * {@link Supplier#get()} method must be an instance of this class.
- * @param supplier The supplier of the object being sent, which will be called when the object is ready to be
- * received.
- * @param The type of object being sent.
- * @return A {@link Send} which will deliver an object of the given type, from the supplier.
- */
- static > Send sending(Class concreteObjectType, Supplier extends T> supplier) {
- return new Send() {
- private final AtomicBoolean gate = new AtomicBoolean();
-
- @Override
- public T receive() {
- if (gate.getAndSet(true)) {
- throw new IllegalStateException("This object has already been received.");
- }
- return supplier.get();
- }
-
- @Override
- public boolean referentIsInstanceOf(Class> cls) {
- return cls.isAssignableFrom(concreteObjectType);
- }
-
- @Override
- public void discard() {
- if (!gate.getAndSet(true)) {
- supplier.get().close();
- }
- }
- };
- }
-
- /**
- * Determine if the given candidate object is an instance of a {@link Send} from which an object of the given type
- * can be received.
- *
- * @param type The type of object we wish to receive.
- * @param candidate The candidate object that might be a {@link Send} of an object of the given type.
- * @return {@code true} if the candidate object is a {@link Send} that would deliver an object of the given type,
- * otherwise {@code false}.
- */
- static boolean isSendOf(Class> type, Object candidate) {
- return candidate instanceof Send && ((Send>) candidate).referentIsInstanceOf(type);
- }
-
- /**
- * Receive the {@link Resource} instance being sent, and bind its ownership to the calling thread.
- * The invalidation of the sent resource in the sending thread happens-before the return of this method.
- *
- * This method can only be called once, and will throw otherwise.
- *
- * @return The sent resource instance.
- * @throws IllegalStateException If this method is called more than once.
- */
- T receive();
-
- /**
- * Apply a mapping function to the object being sent. The mapping will occur when the object is received.
- *
- * @param type The result type of the mapping function.
- * @param mapper The mapping function to apply to the object being sent.
- * @param The result type of the mapping function.
- * @return A new {@link Send} instance that will deliver an object that is the result of the mapping.
- */
- default > Send map(Class type, Function mapper) {
- return sending(type, () -> mapper.apply(receive()));
- }
-
- /**
- * Discard this {@link Send} and the object it contains.
- * This has no effect if the send object has already been received.
- */
- default void discard() {
- try {
- receive().close();
- } catch (IllegalStateException ignore) {
- // Don't do anything if the "Send" has already been consumed.
- }
- }
-
- /**
- * Determine if the object received from this {@code Send} is an instance of the given class.
- *
- * @param cls The type to check.
- * @return {@code true} if the object received from this {@code Send} can be assigned fields or variables of the
- * given type, otherwise false.
- */
- boolean referentIsInstanceOf(Class> cls);
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/WritableComponent.java b/buffer-api/src/main/java/io/netty/buffer/api/WritableComponent.java
deleted file mode 100644
index 4ee6c92..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/WritableComponent.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-import java.nio.ByteBuffer;
-
-/**
- * A view onto the buffer component being processed in a given iteration of
- * {@link Buffer#forEachWritable(int, WritableComponentProcessor)}.
- */
-public interface WritableComponent {
-
- /**
- * Check if this component is backed by a cached byte array than can be accessed cheaply.
- *
- * @return {@code true} if {@link #writableArray()} is a cheap operation, otherwise {@code false}.
- */
- boolean hasWritableArray();
-
- /**
- * Get a byte array of the contents of this component.
- *
- * @return A byte array of the contents of this component.
- * @throws UnsupportedOperationException if {@link #hasWritableArray()} returns {@code false}.
- * @see #writableArrayOffset()
- * @see #writableArrayLength()
- */
- byte[] writableArray();
-
- /**
- * An offset into the {@link #writableArray()} where this component starts.
- *
- * @return An offset into {@link #writableArray()}.
- * @throws UnsupportedOperationException if {@link #hasWritableArray()} returns {@code false}.
- */
- int writableArrayOffset();
-
- /**
- * The number of bytes in the {@link #writableArray()} that belong to this component.
- *
- * @return The number of bytes, from the {@link #writableArrayOffset()} into the {@link #writableArray()},
- * that belong to this component.
- * @throws UnsupportedOperationException if {@link #hasWritableArray()} returns {@code false}.
- */
- int writableArrayLength();
-
- /**
- * Give the native memory address backing this buffer, or return 0 if this buffer has no native memory address.
- *
- * @return The native memory address, if any, otherwise 0.
- */
- long writableNativeAddress();
-
- /**
- * Get a {@link ByteBuffer} instance for this memory component, which can be used for modifying the buffer
- * contents.
- *
- * @return A new {@link ByteBuffer}, with its own position and limit, for this memory component.
- */
- ByteBuffer writableBuffer();
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/WritableComponentProcessor.java b/buffer-api/src/main/java/io/netty/buffer/api/WritableComponentProcessor.java
deleted file mode 100644
index d4000d3..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/WritableComponentProcessor.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api;
-
-import java.nio.ByteBuffer;
-
-/**
- * A processor of {@linkplain WritableComponent writable components}.
- */
-@FunctionalInterface
-public interface WritableComponentProcessor {
- /**
- * Process the given component at the given index in the
- * {@link Buffer#forEachWritable(int, WritableComponentProcessor)} iteration}.
- *
- * The component object itself is only valid during this call, but the {@link ByteBuffer byte buffers}, arrays, and
- * native address pointers obtained from it, will be valid until any {@link Buffer#isOwned() ownership} requiring
- * operation is performed on the buffer.
- *
- * @param index The current index of the given buffer component, based on the initial index passed to the
- * {@link Buffer#forEachWritable(int, WritableComponentProcessor)} method.
- * @param component The current buffer component being processed.
- * @return {@code true} if the iteration should continue and more components should be processed, otherwise
- * {@code false} to stop the iteration early.
- */
- boolean process(int index, WritableComponent component) throws E;
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/BufferIntegratable.java b/buffer-api/src/main/java/io/netty/buffer/api/adaptor/BufferIntegratable.java
deleted file mode 100644
index fe9a73d..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/BufferIntegratable.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.adaptor;
-
-import io.netty.buffer.ByteBufConvertible;
-import io.netty.util.ReferenceCounted;
-
-/**
- * Interfaces that are required for an object to stand-in for a {@link io.netty.buffer.ByteBuf} in Netty.
- */
-public interface BufferIntegratable extends ByteBufConvertible, ReferenceCounted {
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/ByteBufAdaptor.java b/buffer-api/src/main/java/io/netty/buffer/api/adaptor/ByteBufAdaptor.java
deleted file mode 100644
index 3ada76d..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/ByteBufAdaptor.java
+++ /dev/null
@@ -1,1710 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.adaptor;
-
-import io.netty.buffer.ByteBufConvertible;
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufAllocator;
-import io.netty.buffer.ByteBufUtil;
-import io.netty.buffer.DuplicatedByteBuf;
-import io.netty.buffer.SlicedByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.buffer.api.BufferAllocator;
-import io.netty.buffer.api.BufferClosedException;
-import io.netty.buffer.api.BufferReadOnlyException;
-import io.netty.buffer.api.internal.Statics;
-import io.netty.buffer.api.Buffer;
-import io.netty.buffer.api.internal.ResourceSupport;
-import io.netty.util.ByteProcessor;
-import io.netty.util.IllegalReferenceCountException;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.channels.FileChannel;
-import java.nio.channels.GatheringByteChannel;
-import java.nio.channels.ScatteringByteChannel;
-import java.nio.charset.Charset;
-import java.util.concurrent.atomic.AtomicReference;
-
-import static io.netty.buffer.api.internal.Statics.acquire;
-import static io.netty.buffer.api.internal.Statics.isOwned;
-
-public final class ByteBufAdaptor extends ByteBuf {
- private final ByteBufAllocatorAdaptor alloc;
- private final Buffer buffer;
- private final boolean hasMemoryAddress;
-
- public ByteBufAdaptor(ByteBufAllocatorAdaptor alloc, Buffer buffer) {
- this.alloc = alloc;
- this.buffer = buffer;
- hasMemoryAddress = buffer.nativeAddress() != 0;
- }
-
- /**
- * Extracts the underlying {@link Buffer} instance that is backing this {@link ByteBuf}, if any.
- * This is similar to {@link #unwrap()} except the return type is a {@link Buffer}.
- * If this {@link ByteBuf} does not wrap a {@link Buffer}, then {@code null} is returned.
- *
- * @param byteBuf The {@link ByteBuf} to extract the {@link Buffer} from.
- * @return The {@link Buffer} instance that is backing the given {@link ByteBuf}, or {@code null} if the given
- * {@link ByteBuf} is not backed by a {@link Buffer}.
- */
- public static Buffer extract(ByteBuf byteBuf) {
- if (byteBuf instanceof ByteBufAdaptor) {
- ByteBufAdaptor bba = (ByteBufAdaptor) byteBuf;
- return bba.buffer;
- }
- return null;
- }
-
- @Override
- public int capacity() {
- return buffer.capacity();
- }
-
- @Override
- public ByteBuf capacity(int newCapacity) {
- int diff = newCapacity - capacity() - buffer.writableBytes();
- if (diff > 0) {
- try {
- buffer.ensureWritable(diff);
- } catch (IllegalStateException e) {
- if (!isOwned((ResourceSupport, ?>) buffer)) {
- throw new UnsupportedOperationException(e);
- }
- throw e;
- }
- }
- return this;
- }
-
- @Override
- public int maxCapacity() {
- return capacity();
- }
-
- @Override
- public ByteBufAllocator alloc() {
- return alloc;
- }
-
- @Override
- public ByteOrder order() {
- return buffer.order();
- }
-
- @Override
- public ByteBuf order(ByteOrder endianness) {
- buffer.order(endianness);
- return this;
- }
-
- @Override
- public ByteBuf unwrap() {
- return null;
- }
-
- @Override
- public boolean isDirect() {
- return hasMemoryAddress;
- }
-
- @Override
- public boolean isReadOnly() {
- return buffer.readOnly();
- }
-
- @Override
- public ByteBuf asReadOnly() {
- return Unpooled.unreleasableBuffer(this);
- }
-
- @Override
- public int readerIndex() {
- return buffer.readerOffset();
- }
-
- @Override
- public ByteBuf readerIndex(int readerIndex) {
- buffer.readerOffset(readerIndex);
- return this;
- }
-
- @Override
- public int writerIndex() {
- return buffer.writerOffset();
- }
-
- @Override
- public ByteBuf writerIndex(int writerIndex) {
- buffer.writerOffset(writerIndex);
- return this;
- }
-
- @Override
- public ByteBuf setIndex(int readerIndex, int writerIndex) {
- buffer.reset().writerOffset(writerIndex).readerOffset(readerIndex);
- return this;
- }
-
- @Override
- public int readableBytes() {
- return buffer.readableBytes();
- }
-
- @Override
- public int writableBytes() {
- return buffer.writableBytes();
- }
-
- @Override
- public int maxWritableBytes() {
- return writableBytes();
- }
-
- @Override
- public boolean isReadable() {
- return readableBytes() > 0;
- }
-
- @Override
- public boolean isReadable(int size) {
- return readableBytes() >= size;
- }
-
- @Override
- public boolean isWritable() {
- return writableBytes() > 0;
- }
-
- @Override
- public boolean isWritable(int size) {
- return writableBytes() >= size;
- }
-
- @Override
- public ByteBuf clear() {
- return setIndex(0, 0);
- }
-
- @Override
- public ByteBuf discardReadBytes() {
- checkAccess();
- buffer.compact();
- return this;
- }
-
- @Override
- public ByteBuf discardSomeReadBytes() {
- return discardReadBytes();
- }
-
- @Override
- public ByteBuf ensureWritable(int minWritableBytes) {
- checkAccess();
- if (writableBytes() < minWritableBytes) {
- try {
- if (isOwned((ResourceSupport, ?>) buffer)) {
- // Good place.
- buffer.ensureWritable(minWritableBytes);
- } else {
- // Highly questionable place, but ByteBuf technically allows this, so we have to emulate.
- int borrows = countBorrows();
- release(borrows);
- try {
- buffer.ensureWritable(minWritableBytes);
- } finally {
- retain(borrows);
- }
- }
- } catch (IllegalArgumentException e) {
- throw new IndexOutOfBoundsException(e.getMessage());
- }
- }
- return this;
- }
-
- @Override
- public int ensureWritable(int minWritableBytes, boolean force) {
- ensureWritable(minWritableBytes);
- return minWritableBytes;
- }
-
- @Override
- public boolean getBoolean(int index) {
- return getByte(index) != 0;
- }
-
- @Override
- public byte getByte(int index) {
- try {
- return buffer.getByte(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public short getUnsignedByte(int index) {
- try {
- return (short) buffer.getUnsignedByte(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public short getShort(int index) {
- try {
- return buffer.getShort(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public short getShortLE(int index) {
- ByteOrder originalOrder = buffer.order();
- try {
- return buffer.order(ByteOrder.LITTLE_ENDIAN).getShort(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public int getUnsignedShort(int index) {
- try {
- return buffer.getUnsignedShort(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public int getUnsignedShortLE(int index) {
- ByteOrder originalOrder = buffer.order();
- try {
- return buffer.order(ByteOrder.LITTLE_ENDIAN).getUnsignedShort(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public int getMedium(int index) {
- try {
- return buffer.getMedium(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public int getMediumLE(int index) {
- ByteOrder originalOrder = buffer.order();
- try {
- return buffer.order(ByteOrder.LITTLE_ENDIAN).getMedium(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public int getUnsignedMedium(int index) {
- try {
- return buffer.getUnsignedMedium(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public int getUnsignedMediumLE(int index) {
- ByteOrder originalOrder = buffer.order();
- try {
- return buffer.order(ByteOrder.LITTLE_ENDIAN).getUnsignedMedium(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public int getInt(int index) {
- try {
- return buffer.getInt(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public int getIntLE(int index) {
- ByteOrder originalOrder = buffer.order();
- try {
- return buffer.order(ByteOrder.LITTLE_ENDIAN).getInt(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public long getUnsignedInt(int index) {
- try {
- return buffer.getUnsignedInt(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public long getUnsignedIntLE(int index) {
- ByteOrder originalOrder = buffer.order();
- try {
- return buffer.order(ByteOrder.LITTLE_ENDIAN).getUnsignedInt(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public long getLong(int index) {
- try {
- return buffer.getLong(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public long getLongLE(int index) {
- ByteOrder originalOrder = buffer.order();
- try {
- return buffer.order(ByteOrder.LITTLE_ENDIAN).getLong(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public char getChar(int index) {
- try {
- return buffer.getChar(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public float getFloat(int index) {
- try {
- return buffer.getFloat(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public double getDouble(int index) {
- try {
- return buffer.getDouble(index);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public ByteBuf getBytes(int index, ByteBuf dst) {
- while (dst.isWritable()) {
- dst.writeByte(getByte(index++));
- }
- return this;
- }
-
- @Override
- public ByteBuf getBytes(int index, ByteBuf dst, int length) {
- for (int i = 0; i < length; i++) {
- dst.writeByte(getByte(index + i));
- }
- return this;
- }
-
- @Override
- public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
- for (int i = 0; i < length; i++) {
- dst.setByte(dstIndex + i, getByte(index + i));
- }
- return this;
- }
-
- @Override
- public ByteBuf getBytes(int index, byte[] dst) {
- return getBytes(index, dst, 0, dst.length);
- }
-
- @Override
- public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
- checkAccess();
- if (index < 0 || capacity() < index + length || dst.length < dstIndex + length) {
- throw new IndexOutOfBoundsException();
- }
- for (int i = 0; i < length; i++) {
- dst[dstIndex + i] = getByte(index + i);
- }
- return this;
- }
-
- @Override
- public ByteBuf getBytes(int index, ByteBuffer dst) {
- checkAccess();
- if (index < 0 || capacity() < index + dst.remaining()) {
- throw new IndexOutOfBoundsException();
- }
- while (dst.hasRemaining()) {
- dst.put(getByte(index));
- index++;
- }
- return this;
- }
-
- @Override
- public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
- for (int i = 0; i < length; i++) {
- out.write(getByte(index + i));
- }
- return this;
- }
-
- @Override
- public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
- checkAccess();
- ByteBuffer transfer = ByteBuffer.allocate(length);
- buffer.copyInto(index, transfer, 0, length);
- return out.write(transfer);
- }
-
- @Override
- public int getBytes(int index, FileChannel out, long position, int length) throws IOException {
- checkAccess();
- ByteBuffer transfer = ByteBuffer.allocate(length);
- buffer.copyInto(index, transfer, 0, length);
- return out.write(transfer, position);
- }
-
- @Override
- public CharSequence getCharSequence(int index, int length, Charset charset) {
- byte[] bytes = new byte[length];
- getBytes(index, bytes);
- return new String(bytes, charset);
- }
-
- @Override
- public ByteBuf setBoolean(int index, boolean value) {
- return setByte(index, value? 1 : 0);
- }
-
- @Override
- public ByteBuf setByte(int index, int value) {
- try {
- buffer.setByte(index, (byte) value);
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- return this;
- }
-
- @Override
- public ByteBuf setShort(int index, int value) {
- try {
- buffer.setShort(index, (short) value);
- return this;
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public ByteBuf setShortLE(int index, int value) {
- ByteOrder originalOrder = buffer.order();
- try {
- buffer.order(ByteOrder.LITTLE_ENDIAN).setShort(index, (short) value);
- return this;
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public ByteBuf setMedium(int index, int value) {
- try {
- buffer.setMedium(index, value);
- return this;
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public ByteBuf setMediumLE(int index, int value) {
- ByteOrder originalOrder = buffer.order();
- try {
- buffer.order(ByteOrder.LITTLE_ENDIAN).setMedium(index, value);
- return this;
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public ByteBuf setInt(int index, int value) {
- try {
- buffer.setInt(index, value);
- return this;
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public ByteBuf setIntLE(int index, int value) {
- ByteOrder originalOrder = buffer.order();
- try {
- buffer.order(ByteOrder.LITTLE_ENDIAN).setInt(index, value);
- return this;
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public ByteBuf setLong(int index, long value) {
- try {
- buffer.setLong(index, value);
- return this;
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public ByteBuf setLongLE(int index, long value) {
- ByteOrder originalOrder = buffer.order();
- try {
- buffer.order(ByteOrder.LITTLE_ENDIAN).setLong(index, value);
- return this;
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public ByteBuf setChar(int index, int value) {
- try {
- buffer.setChar(index, (char) value);
- return this;
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public ByteBuf setFloat(int index, float value) {
- try {
- buffer.setFloat(index, value);
- return this;
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public ByteBuf setDouble(int index, double value) {
- try {
- buffer.setDouble(index, value);
- return this;
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public ByteBuf setBytes(int index, ByteBuf src) {
- checkAccess();
- while (src.isReadable() && index < capacity()) {
- setByte(index++, src.readByte());
- }
- return this;
- }
-
- @Override
- public ByteBuf setBytes(int index, ByteBuf src, int length) {
- checkAccess();
- for (int i = 0; i < length; i++) {
- setByte(index + i, src.readByte());
- }
- return this;
- }
-
- @Override
- public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
- for (int i = 0; i < length; i++) {
- setByte(index + i, src.getByte(srcIndex + i));
- }
- return this;
- }
-
- @Override
- public ByteBuf setBytes(int index, byte[] src) {
- return setBytes(index, src, 0, src.length);
- }
-
- @Override
- public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
- for (int i = 0; i < length; i++) {
- setByte(index + i, src[srcIndex + i]);
- }
- return this;
- }
-
- @Override
- public ByteBuf setBytes(int index, ByteBuffer src) {
- while (src.hasRemaining()) {
- setByte(index, src.get());
- index++;
- }
- return this;
- }
-
- @Override
- public int setBytes(int index, InputStream in, int length) throws IOException {
- checkAccess();
- byte[] bytes = in.readNBytes(length);
- setBytes(index, bytes, 0, length);
- return bytes.length;
- }
-
- @Override
- public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
- checkAccess();
- ByteBuffer transfer = ByteBuffer.allocate(length);
- int bytes = in.read(transfer);
- transfer.flip();
- setBytes(index, transfer);
- return bytes;
- }
-
- @Override
- public int setBytes(int index, FileChannel in, long position, int length) throws IOException {
- checkAccess();
- ByteBuffer transfer = ByteBuffer.allocate(length);
- int bytes = in.read(transfer, position);
- transfer.flip();
- setBytes(index, transfer);
- return bytes;
- }
-
- @Override
- public ByteBuf setZero(int index, int length) {
- for (int i = 0; i < length; i++) {
- setByte(index + i, 0);
- }
- return this;
- }
-
- @Override
- public int setCharSequence(int index, CharSequence sequence, Charset charset) {
- byte[] bytes = sequence.toString().getBytes(charset);
- for (int i = 0; i < bytes.length; i++) {
- setByte(index + i, bytes[i]);
- }
- return bytes.length;
- }
-
- @Override
- public boolean readBoolean() {
- return readByte() != 0;
- }
-
- @Override
- public byte readByte() {
- try {
- return buffer.readByte();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public short readUnsignedByte() {
- try {
- return (short) buffer.readUnsignedByte();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public short readShort() {
- try {
- return buffer.readShort();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public short readShortLE() {
- ByteOrder originalOrder = buffer.order();
- try {
- return buffer.order(ByteOrder.LITTLE_ENDIAN).readShort();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public int readUnsignedShort() {
- try {
- return buffer.readUnsignedShort();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public int readUnsignedShortLE() {
- ByteOrder originalOrder = buffer.order();
- try {
- return buffer.order(ByteOrder.LITTLE_ENDIAN).readUnsignedShort();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public int readMedium() {
- try {
- return buffer.readMedium();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public int readMediumLE() {
- ByteOrder originalOrder = buffer.order();
- try {
- return buffer.order(ByteOrder.LITTLE_ENDIAN).readMedium();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public int readUnsignedMedium() {
- try {
- return buffer.readUnsignedMedium();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public int readUnsignedMediumLE() {
- ByteOrder originalOrder = buffer.order();
- try {
- return buffer.order(ByteOrder.LITTLE_ENDIAN).readUnsignedMedium();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public int readInt() {
- try {
- return buffer.readInt();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public int readIntLE() {
- ByteOrder originalOrder = buffer.order();
- try {
- return buffer.order(ByteOrder.LITTLE_ENDIAN).readInt();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public long readUnsignedInt() {
- try {
- return buffer.readUnsignedInt();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public long readUnsignedIntLE() {
- ByteOrder originalOrder = buffer.order();
- try {
- return buffer.order(ByteOrder.LITTLE_ENDIAN).readUnsignedInt();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public long readLong() {
- try {
- return buffer.readLong();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public long readLongLE() {
- ByteOrder originalOrder = buffer.order();
- try {
- return buffer.order(ByteOrder.LITTLE_ENDIAN).readLong();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public char readChar() {
- try {
- return buffer.readChar();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public float readFloat() {
- try {
- return buffer.readFloat();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public double readDouble() {
- try {
- return buffer.readDouble();
- } catch (IllegalStateException | BufferClosedException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
-
- @Override
- public ByteBuf readBytes(int length) {
- checkAccess();
- Buffer copy = preferredBufferAllocator().allocate(length);
- buffer.copyInto(readerIndex(), copy, 0, length);
- readerIndex(readerIndex() + length);
- return wrap(copy).writerIndex(length);
- }
-
- @Override
- public ByteBuf readSlice(int length) {
- ByteBuf slice = slice(readerIndex(), length);
- buffer.readerOffset(buffer.readerOffset() + length);
- return slice;
- }
-
- @Override
- public ByteBuf readRetainedSlice(int length) {
- ByteBuf slice = retainedSlice(readerIndex(), length);
- buffer.readerOffset(buffer.readerOffset() + length);
- return slice;
- }
-
- @Override
- public ByteBuf readBytes(ByteBuf dst) {
- while (dst.isWritable()) {
- dst.writeByte(readByte());
- }
- return this;
- }
-
- @Override
- public ByteBuf readBytes(ByteBuf dst, int length) {
- for (int i = 0; i < length; i++) {
- dst.writeByte(readByte());
- }
- return this;
- }
-
- @Override
- public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
- for (int i = 0; i < length; i++) {
- dst.setByte(dstIndex + i, readByte());
- }
- return this;
- }
-
- @Override
- public ByteBuf readBytes(byte[] dst) {
- return readBytes(dst, 0, dst.length);
- }
-
- @Override
- public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
- for (int i = 0; i < length; i++) {
- dst[dstIndex + i] = readByte();
- }
- return this;
- }
-
- @Override
- public ByteBuf readBytes(ByteBuffer dst) {
- while (dst.hasRemaining()) {
- dst.put(readByte());
- }
- return this;
- }
-
- @Override
- public ByteBuf readBytes(OutputStream out, int length) throws IOException {
- for (int i = 0; i < length; i++) {
- out.write(readByte());
- }
- return this;
- }
-
- @Override
- public int readBytes(GatheringByteChannel out, int length) throws IOException {
- checkAccess();
- ByteBuffer[] components = new ByteBuffer[buffer.countReadableComponents()];
- buffer.forEachReadable(0, (i, component) -> {
- components[i] = component.readableBuffer();
- return true;
- });
- int written = (int) out.write(components);
- skipBytes(written);
- return written;
- }
-
- @Override
- public CharSequence readCharSequence(int length, Charset charset) {
- byte[] bytes = new byte[length];
- readBytes(bytes);
- return new String(bytes, charset);
- }
-
- @Override
- public int readBytes(FileChannel out, long position, int length) throws IOException {
- ByteBuffer[] components = new ByteBuffer[buffer.countReadableComponents()];
- buffer.forEachReadable(0, (i, component) -> {
- components[i] = component.readableBuffer();
- return true;
- });
- int written = 0;
- for (ByteBuffer component : components) {
- written += out.write(component, position + written);
- if (component.hasRemaining()) {
- break;
- }
- }
- skipBytes(written);
- return written;
- }
-
- @Override
- public ByteBuf skipBytes(int length) {
- buffer.readerOffset(length + buffer.readerOffset());
- return this;
- }
-
- @Override
- public ByteBuf writeBoolean(boolean value) {
- return writeByte(value? 1 : 0);
- }
-
- @Override
- public ByteBuf writeByte(int value) {
- ensureWritable(1);
- buffer.writeByte((byte) value);
- return this;
- }
-
- @Override
- public ByteBuf writeShort(int value) {
- ensureWritable(2);
- buffer.writeShort((short) value);
- return this;
- }
-
- @Override
- public ByteBuf writeShortLE(int value) {
- ensureWritable(2);
- ByteOrder originalOrder = buffer.order();
- try {
- buffer.order(ByteOrder.LITTLE_ENDIAN).writeShort((short) value);
- return this;
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public ByteBuf writeMedium(int value) {
- ensureWritable(3);
- buffer.writeMedium(value);
- return this;
- }
-
- @Override
- public ByteBuf writeMediumLE(int value) {
- ensureWritable(3);
- ByteOrder originalOrder = buffer.order();
- try {
- buffer.order(ByteOrder.LITTLE_ENDIAN).writeMedium(value);
- return this;
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public ByteBuf writeInt(int value) {
- ensureWritable(4);
- buffer.writeInt(value);
- return this;
- }
-
- @Override
- public ByteBuf writeIntLE(int value) {
- ensureWritable(4);
- ByteOrder originalOrder = buffer.order();
- try {
- buffer.order(ByteOrder.LITTLE_ENDIAN).writeInt(value);
- return this;
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public ByteBuf writeLong(long value) {
- ensureWritable(8);
- buffer.writeLong(value);
- return this;
- }
-
- @Override
- public ByteBuf writeLongLE(long value) {
- ensureWritable(8);
- ByteOrder originalOrder = buffer.order();
- try {
- buffer.order(ByteOrder.LITTLE_ENDIAN).writeLong(value);
- return this;
- } finally {
- buffer.order(originalOrder);
- }
- }
-
- @Override
- public ByteBuf writeChar(int value) {
- ensureWritable(2);
- buffer.writeChar((char) value);
- return this;
- }
-
- @Override
- public ByteBuf writeFloat(float value) {
- ensureWritable(4);
- buffer.writeFloat(value);
- return this;
- }
-
- @Override
- public ByteBuf writeDouble(double value) {
- ensureWritable(8);
- buffer.writeDouble(value);
- return this;
- }
-
- @Override
- public ByteBuf writeBytes(ByteBuf src) {
- return writeBytes(src, src.readableBytes());
- }
-
- @Override
- public ByteBuf writeBytes(ByteBuf src, int length) {
- ensureWritable(length);
- for (int i = 0; i < length; i++) {
- writeByte(src.readByte());
- }
- return this;
- }
-
- @Override
- public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
- ensureWritable(length);
- for (int i = 0; i < length; i++) {
- writeByte(src.getByte(srcIndex + i));
- }
- return this;
- }
-
- @Override
- public ByteBuf writeBytes(byte[] src) {
- ensureWritable(src.length);
- for (byte b : src) {
- writeByte(b);
- }
- return this;
- }
-
- @Override
- public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
- ensureWritable(length);
- for (int i = 0; i < length; i++) {
- writeByte(src[srcIndex + i]);
- }
- return this;
- }
-
- @Override
- public ByteBuf writeBytes(ByteBuffer src) {
- ensureWritable(src.remaining());
- while (src.hasRemaining()) {
- writeByte(src.get());
- }
- return this;
- }
-
- @Override
- public int writeBytes(InputStream in, int length) throws IOException {
- byte[] bytes = in.readNBytes(length);
- writeBytes(bytes);
- return bytes.length;
- }
-
- @Override
- public int writeBytes(ScatteringByteChannel in, int length) throws IOException {
- ensureWritable(length);
- ByteBuffer[] components = new ByteBuffer[buffer.countWritableComponents()];
- buffer.forEachWritable(0, (i, component) -> {
- components[i] = component.writableBuffer();
- return true;
- });
-
- int read = (int) in.read(components);
-
- if (read > 0) {
- writerIndex(read + writerIndex());
- }
- return read;
- }
-
- @Override
- public int writeBytes(FileChannel in, long position, int length) throws IOException {
- ensureWritable(length);
- ByteBuffer[] components = new ByteBuffer[buffer.countWritableComponents()];
- buffer.forEachWritable(0, (i, component) -> {
- components[i] = component.writableBuffer();
- return true;
- });
- int read = 0;
- for (ByteBuffer component : components) {
- int r = in.read(component, position + read);
- if (r > 0) {
- read += r;
- }
- if (component.hasRemaining()) {
- break;
- }
- }
- writerIndex(read + writerIndex());
- return read;
- }
-
- @Override
- public ByteBuf writeZero(int length) {
- if (length < 0) {
- throw new IllegalArgumentException();
- }
- ensureWritable(length);
- for (int i = 0; i < length; i++) {
- writeByte(0);
- }
- return this;
- }
-
- @Override
- public int writeCharSequence(CharSequence sequence, Charset charset) {
- byte[] bytes = sequence.toString().getBytes(charset);
- writeBytes(bytes);
- return bytes.length;
- }
-
- @Override
- public int indexOf(int fromIndex, int toIndex, byte value) {
- if (!buffer.isAccessible()) {
- return -1;
- }
- if (fromIndex <= toIndex) {
- if (fromIndex < 0) {
- fromIndex = 0; // Required to pass regression tests.
- }
- if (capacity() < toIndex) {
- throw new IndexOutOfBoundsException();
- }
- for (; fromIndex < toIndex; fromIndex++) {
- if (getByte(fromIndex) == value) {
- return fromIndex;
- }
- }
- } else {
- if (capacity() < fromIndex) {
- fromIndex = capacity(); // Required to pass regression tests.
- }
- fromIndex--;
- if (toIndex < 0) {
- throw new IndexOutOfBoundsException();
- }
- for (; fromIndex > toIndex; fromIndex--) {
- if (getByte(fromIndex) == value) {
- return fromIndex;
- }
- }
- }
- return -1;
- }
-
- @Override
- public int bytesBefore(byte value) {
- return bytesBefore(readerIndex(), writerIndex(), value);
- }
-
- @Override
- public int bytesBefore(int length, byte value) {
- return bytesBefore(readerIndex(), readerIndex() + length, value);
- }
-
- @Override
- public int bytesBefore(int index, int length, byte value) {
- int i = indexOf(index, index + length, value);
- if (i != -1) {
- i -= index;
- }
- return i;
- }
-
- @Override
- public int forEachByte(ByteProcessor processor) {
- checkAccess();
- int index = readerIndex();
- int bytes = buffer.openCursor().process(processor);
- return bytes == -1 ? -1 : index + bytes;
- }
-
- @Override
- public int forEachByte(int index, int length, ByteProcessor processor) {
- checkAccess();
- int bytes = buffer.openCursor(index, length).process(processor);
- return bytes == -1 ? -1 : index + bytes;
- }
-
- @Override
- public int forEachByteDesc(ByteProcessor processor) {
- checkAccess();
- int index = readerIndex();
- int bytes = buffer.openReverseCursor().process(processor);
- return bytes == -1 ? -1 : index - bytes;
- }
-
- @Override
- public int forEachByteDesc(int index, int length, ByteProcessor processor) {
- checkAccess();
- int bytes = buffer.openReverseCursor(index + length - 1, length).process(processor);
- return bytes == -1 ? -1 : index - bytes;
- }
-
- @Override
- public ByteBuf copy() {
- return copy(readerIndex(), readableBytes());
- }
-
- @Override
- public ByteBuf copy(int index, int length) {
- checkAccess();
- try {
- BufferAllocator allocator = preferredBufferAllocator();
- Buffer copy = allocator.allocate(length);
- buffer.copyInto(index, copy, 0, length);
- copy.order(buffer.order());
- copy.writerOffset(length);
- return wrap(copy);
- } catch (IllegalArgumentException e) {
- throw new IndexOutOfBoundsException(e.getMessage());
- }
- }
-
- @Override
- public ByteBuf slice() {
- return slice(readerIndex(), readableBytes());
- }
-
- @Override
- public ByteBuf retainedSlice() {
- return retainedSlice(readerIndex(), readableBytes());
- }
-
- @Override
- public ByteBuf slice(int index, int length) {
- checkAccess();
- return new Slice(this, index, length);
- }
-
- @Override
- public ByteBuf retainedSlice(int index, int length) {
- checkAccess();
- Slice slice = new Slice(this, index, length);
- retain();
- return slice;
- }
-
- private static final class Slice extends SlicedByteBuf {
- private final int indexAdjustment;
- private final int lengthAdjustment;
-
- Slice(ByteBuf buffer, int index, int length) {
- super(buffer, index, length);
- indexAdjustment = index;
- lengthAdjustment = length;
- }
-
- @Override
- public ByteBuf retainedDuplicate() {
- return new Slice(unwrap().retainedDuplicate(), indexAdjustment, lengthAdjustment)
- .setIndex(readerIndex(), writerIndex());
- }
-
- @Override
- public ByteBuf retainedSlice(int index, int length) {
- checkIndex(index, length);
- return unwrap().retainedSlice(indexAdjustment + index, length);
- }
- }
-
- private static final class Duplicate extends DuplicatedByteBuf {
- Duplicate(ByteBufAdaptor byteBuf) {
- super(byteBuf);
- }
-
- @Override
- public ByteBuf duplicate() {
- ((ByteBufAdaptor) unwrap()).checkAccess();
- return new Duplicate((ByteBufAdaptor) unwrap())
- .setIndex(readerIndex(), writerIndex());
- }
-
- @Override
- public ByteBuf retainedDuplicate() {
- return unwrap().retainedDuplicate();
- }
-
- @Override
- public ByteBuf retainedSlice(int index, int length) {
- return unwrap().retainedSlice(index, length);
- }
- }
-
- @Override
- public ByteBuf duplicate() {
- checkAccess();
- Duplicate duplicatedByteBuf = new Duplicate(this);
- return duplicatedByteBuf.setIndex(readerIndex(), writerIndex());
- }
-
- @Override
- public ByteBuf retainedDuplicate() {
- checkAccess();
- retain();
- Duplicate duplicatedByteBuf = new Duplicate(this);
- return duplicatedByteBuf.setIndex(readerIndex(), writerIndex());
- }
-
- @Override
- public int nioBufferCount() {
- return 1;
- }
-
- @Override
- public ByteBuffer nioBuffer() {
- return nioBuffer(readerIndex(), readableBytes());
- }
-
- @Override
- public ByteBuffer nioBuffer(int index, int length) {
- checkAccess();
- ByteBuffer copy = isDirect() ? ByteBuffer.allocateDirect(length) : ByteBuffer.allocate(length);
- while (index < length) {
- copy.put(getByte(index++));
- }
- return copy.flip();
- }
-
- @Override
- public ByteBuffer internalNioBuffer(int index, int length) {
- checkAccess();
- if (readerIndex() <= index && index < writerIndex() && length <= readableBytes()) {
- // We wish to read from the internal buffer.
- if (buffer.countReadableComponents() != 1) {
- throw new UnsupportedOperationException(
- "Unsupported number of readable components: " + buffer.countReadableComponents() + '.');
- }
- AtomicReference bufRef = new AtomicReference<>();
- buffer.forEachReadable(0, (i, component) -> {
- bufRef.set(component.readableBuffer());
- return false;
- });
- ByteBuffer buffer = bufRef.get();
- if (index != readerIndex() || length != readableBytes()) {
- buffer = Statics.bbslice(buffer, index - readerIndex(), length);
- }
- return buffer;
- } else if (writerIndex() <= index && length <= writableBytes()) {
- // We wish to write to the internal buffer.
- if (buffer.countWritableComponents() != 1) {
- throw new UnsupportedOperationException(
- "Unsupported number of writable components: " + buffer.countWritableComponents() + '.');
- }
- AtomicReference bufRef = new AtomicReference<>();
- buffer.forEachWritable(0, (i, component) -> {
- bufRef.set(component.writableBuffer());
- return false;
- });
- ByteBuffer buffer = bufRef.get();
- if (index != writerIndex() || length != writableBytes()) {
- buffer = Statics.bbslice(buffer, index - writerIndex(), length);
- }
- return buffer;
- } else {
- String message = "Cannot provide internal NIO buffer for range from " + index + " for length " + length +
- ", when writerIndex() is " + writerIndex() + " and writable bytes are " + writableBytes() +
- ", and readerIndex() is " + readerIndex() + " and readable bytes are " + readableBytes() +
- ". The requested range must fall within EITHER the readable area OR the writable area. " +
- "Straddling the two areas, or reaching outside of their bounds, is not allowed.";
- throw new UnsupportedOperationException(message);
- }
- }
-
- @Override
- public ByteBuffer[] nioBuffers() {
- return new ByteBuffer[] { nioBuffer() };
- }
-
- @Override
- public ByteBuffer[] nioBuffers(int index, int length) {
- return new ByteBuffer[] { internalNioBuffer(index, length) };
- }
-
- @Override
- public boolean hasArray() {
- return false;
- }
-
- @Override
- public byte[] array() {
- throw new UnsupportedOperationException("This buffer has no array.");
- }
-
- @Override
- public int arrayOffset() {
- throw new UnsupportedOperationException("This buffer has no array.");
- }
-
- @Override
- public boolean hasMemoryAddress() {
- return hasMemoryAddress;
- }
-
- @Override
- public long memoryAddress() {
- if (!hasMemoryAddress()) {
- throw new UnsupportedOperationException("No memory address associated with this buffer.");
- }
- return buffer.nativeAddress();
- }
-
- @Override
- public String toString(Charset charset) {
- return toString(readerIndex(), readableBytes(), charset);
- }
-
- @Override
- public String toString(int index, int length, Charset charset) {
- byte[] bytes = new byte[length];
- getBytes(index, bytes);
- return new String(bytes, charset);
- }
-
- @Override
- public int hashCode() {
- return ByteBufUtil.hashCode(this);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof ByteBufConvertible) {
- ByteBuf other = ((ByteBufConvertible) obj).asByteBuf();
- return this == other || ByteBufUtil.equals(this, other);
- }
- return false;
- }
-
- @Override
- public int compareTo(ByteBuf buffer) {
- ByteOrder orderThis = order();
- ByteOrder orderThat = buffer.order();
- try {
- // Little-ending implementation of the compare seems to be broken.
- return ByteBufUtil.compare(order(ByteOrder.BIG_ENDIAN), buffer.order(ByteOrder.BIG_ENDIAN));
- } finally {
- order(orderThis);
- buffer.order(orderThat);
- }
- }
-
- @Override
- public String toString() {
- return "ByteBuf(" + readerIndex() + ", " + writerIndex() + ", " + capacity() + ')';
- }
-
- @Override
- public ByteBuf retain(int increment) {
- for (int i = 0; i < increment; i++) {
- acquire((ResourceSupport,?>) buffer);
- }
- return this;
- }
-
- @Override
- public int refCnt() {
- return 1 + countBorrows();
- }
-
- private int countBorrows() {
- if (!buffer.isAccessible()) {
- return -1;
- }
- if (buffer instanceof ResourceSupport) {
- var rc = (ResourceSupport, ?>) buffer;
- return Statics.countBorrows(rc);
- }
- return isOwned((ResourceSupport, ?>) buffer)? 0 : 1;
- }
-
- @Override
- public ByteBuf retain() {
- return retain(1);
- }
-
- @Override
- public ByteBuf touch() {
- return this;
- }
-
- @Override
- public ByteBuf touch(Object hint) {
- return this;
- }
-
- @Override
- public boolean release() {
- return release(1);
- }
-
- @Override
- public boolean release(int decrement) {
- int refCount = 1 + Statics.countBorrows((ResourceSupport, ?>) buffer);
- if (!buffer.isAccessible() || decrement > refCount) {
- throw new IllegalReferenceCountException(refCount, -decrement);
- }
- for (int i = 0; i < decrement; i++) {
- try {
- buffer.close();
- } catch (RuntimeException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
- return !buffer.isAccessible();
- }
-
- private void checkAccess() {
- if (!buffer.isAccessible()) {
- throw new IllegalReferenceCountException();
- }
- }
-
- private ByteBufAdaptor wrap(Buffer copy) {
- return new ByteBufAdaptor(alloc, copy);
- }
-
- private BufferAllocator preferredBufferAllocator() {
- return isDirect()? alloc.getOffHeap() : alloc.getOnHeap();
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/ByteBufAllocatorAdaptor.java b/buffer-api/src/main/java/io/netty/buffer/api/adaptor/ByteBufAllocatorAdaptor.java
deleted file mode 100644
index bd65fca..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/ByteBufAllocatorAdaptor.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.adaptor;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufAllocator;
-import io.netty.buffer.CompositeByteBuf;
-import io.netty.buffer.api.BufferAllocator;
-
-import static java.nio.ByteOrder.BIG_ENDIAN;
-
-public class ByteBufAllocatorAdaptor implements ByteBufAllocator, AutoCloseable {
- private final BufferAllocator onheap;
- private final BufferAllocator offheap;
- private boolean closed;
-
- public ByteBufAllocatorAdaptor() {
- this(BufferAllocator.pooledHeap(), BufferAllocator.pooledDirect());
- }
-
- public ByteBufAllocatorAdaptor(BufferAllocator onheap, BufferAllocator offheap) {
- this.onheap = onheap;
- this.offheap = offheap;
- }
-
- @Override
- public ByteBuf buffer() {
- return buffer(256);
- }
-
- public BufferAllocator getOnHeap() {
- return onheap;
- }
-
- public BufferAllocator getOffHeap() {
- return offheap;
- }
-
- public boolean isClosed() {
- return closed;
- }
-
- @Override
- public ByteBuf buffer(int initialCapacity) {
- return new ByteBufAdaptor(this, onheap.allocate(initialCapacity).order(BIG_ENDIAN));
- }
-
- @Override
- public ByteBuf buffer(int initialCapacity, int maxCapacity) {
- return buffer(maxCapacity);
- }
-
- @Override
- public ByteBuf ioBuffer() {
- return directBuffer();
- }
-
- @Override
- public ByteBuf ioBuffer(int initialCapacity) {
- return directBuffer(initialCapacity);
- }
-
- @Override
- public ByteBuf ioBuffer(int initialCapacity, int maxCapacity) {
- return directBuffer(initialCapacity, maxCapacity);
- }
-
- @Override
- public ByteBuf heapBuffer() {
- return buffer();
- }
-
- @Override
- public ByteBuf heapBuffer(int initialCapacity) {
- return buffer(initialCapacity);
- }
-
- @Override
- public ByteBuf heapBuffer(int initialCapacity, int maxCapacity) {
- return buffer(initialCapacity, maxCapacity);
- }
-
- @Override
- public ByteBuf directBuffer() {
- return directBuffer(256);
- }
-
- @Override
- public ByteBuf directBuffer(int initialCapacity) {
- return new ByteBufAdaptor(this, offheap.allocate(initialCapacity).order(BIG_ENDIAN));
- }
-
- @Override
- public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
- return directBuffer(maxCapacity);
- }
-
- @Override
- public CompositeByteBuf compositeBuffer() {
- return compositeHeapBuffer();
- }
-
- @Override
- public CompositeByteBuf compositeBuffer(int maxNumComponents) {
- return compositeHeapBuffer(maxNumComponents);
- }
-
- @Override
- public CompositeByteBuf compositeHeapBuffer() {
- return compositeHeapBuffer(1024);
- }
-
- @Override
- public CompositeByteBuf compositeHeapBuffer(int maxNumComponents) {
- return new CompositeByteBuf(this, false, maxNumComponents, heapBuffer());
- }
-
- @Override
- public CompositeByteBuf compositeDirectBuffer() {
- return compositeDirectBuffer(1024);
- }
-
- @Override
- public CompositeByteBuf compositeDirectBuffer(int maxNumComponents) {
- return new CompositeByteBuf(this, true, maxNumComponents, directBuffer());
- }
-
- @Override
- public boolean isDirectBufferPooled() {
- return true;
- }
-
- @Override
- public int calculateNewCapacity(int minNewCapacity, int maxCapacity) {
- return 0;
- }
-
- @Override
- public void close() throws Exception {
- try (onheap) {
- try (offheap) {
- closed = true;
- }
- }
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/package-info.java b/buffer-api/src/main/java/io/netty/buffer/api/adaptor/package-info.java
deleted file mode 100644
index 1296415..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * Helpers for integrating with the existing {@link io.netty.buffer.ByteBuf} API.
- */
-package io.netty.buffer.api.adaptor;
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/ByteBufferMemoryManager.java b/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/ByteBufferMemoryManager.java
deleted file mode 100644
index f4925a0..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/ByteBufferMemoryManager.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.bytebuffer;
-
-import io.netty.buffer.api.AllocatorControl;
-import io.netty.buffer.api.Buffer;
-import io.netty.buffer.api.Drop;
-import io.netty.buffer.api.MemoryManager;
-import io.netty.buffer.api.internal.Statics;
-
-import java.lang.ref.Cleaner;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-import static io.netty.buffer.api.internal.Statics.bbslice;
-import static io.netty.buffer.api.internal.Statics.convert;
-
-public class ByteBufferMemoryManager implements MemoryManager {
- private final boolean direct;
-
- public ByteBufferMemoryManager(boolean direct) {
- this.direct = direct;
- }
-
- @Override
- public boolean isNative() {
- return direct;
- }
-
- @Override
- public Buffer allocateShared(AllocatorControl allocatorControl, long size, Drop drop, Cleaner cleaner) {
- int capacity = Math.toIntExact(size);
- ByteBuffer buffer = direct? ByteBuffer.allocateDirect(capacity) : ByteBuffer.allocate(capacity);
- buffer.order(ByteOrder.nativeOrder());
- return new NioBuffer(buffer, buffer, allocatorControl, convert(drop));
- }
-
- @Override
- public Buffer allocateConstChild(Buffer readOnlyConstParent) {
- assert readOnlyConstParent.readOnly();
- NioBuffer buf = (NioBuffer) readOnlyConstParent;
- return new NioBuffer(buf);
- }
-
- @Override
- public Drop drop() {
- return Statics.NO_OP_DROP;
- }
-
- @Override
- public Object unwrapRecoverableMemory(Buffer buf) {
- return ((NioBuffer) buf).recoverable();
- }
-
- @Override
- public int capacityOfRecoverableMemory(Object memory) {
- //noinspection OverlyStrongTypeCast
- return ((ByteBuffer) memory).capacity();
- }
-
- @Override
- public void discardRecoverableMemory(Object recoverableMemory) {
- // ByteBuffers have their memory released by the GC, so there is nothing for us to do.
- }
-
- @Override
- public Buffer recoverMemory(AllocatorControl allocatorControl, Object recoverableMemory, Drop drop) {
- ByteBuffer memory = (ByteBuffer) recoverableMemory;
- return new NioBuffer(memory, memory, allocatorControl, convert(drop));
- }
-
- @Override
- public Object sliceMemory(Object memory, int offset, int length) {
- var buffer = (ByteBuffer) memory;
- return bbslice(buffer, offset, length);
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/ByteBufferMemoryManagers.java b/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/ByteBufferMemoryManagers.java
deleted file mode 100644
index 56e731f..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/ByteBufferMemoryManagers.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.bytebuffer;
-
-import io.netty.buffer.api.MemoryManager;
-import io.netty.buffer.api.MemoryManagers;
-
-public class ByteBufferMemoryManagers implements MemoryManagers {
- @Override
- public MemoryManager getHeapMemoryManager() {
- return new ByteBufferMemoryManager(false);
- }
-
- @Override
- public MemoryManager getNativeMemoryManager() {
- return new ByteBufferMemoryManager(true);
- }
-
- @Override
- public String getImplementationName() {
- return "ByteBuffer";
- }
-
- @Override
- public String toString() {
- return "BB";
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/NioBuffer.java b/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/NioBuffer.java
deleted file mode 100644
index 6b1342d..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/NioBuffer.java
+++ /dev/null
@@ -1,1275 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.bytebuffer;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.api.AllocatorControl;
-import io.netty.buffer.api.Buffer;
-import io.netty.buffer.api.BufferAllocator;
-import io.netty.buffer.api.BufferReadOnlyException;
-import io.netty.buffer.api.ByteCursor;
-import io.netty.buffer.api.Drop;
-import io.netty.buffer.api.Owned;
-import io.netty.buffer.api.adaptor.BufferIntegratable;
-import io.netty.buffer.api.adaptor.ByteBufAdaptor;
-import io.netty.buffer.api.adaptor.ByteBufAllocatorAdaptor;
-import io.netty.buffer.api.internal.ResourceSupport;
-import io.netty.buffer.api.ReadableComponent;
-import io.netty.buffer.api.ReadableComponentProcessor;
-import io.netty.buffer.api.WritableComponent;
-import io.netty.buffer.api.WritableComponentProcessor;
-import io.netty.buffer.api.internal.ArcDrop;
-import io.netty.buffer.api.internal.Statics;
-import io.netty.util.IllegalReferenceCountException;
-import io.netty.util.ReferenceCounted;
-import io.netty.util.internal.PlatformDependent;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.ReadOnlyBufferException;
-
-import static io.netty.buffer.api.internal.Statics.bbput;
-import static io.netty.buffer.api.internal.Statics.bbslice;
-import static io.netty.buffer.api.internal.Statics.bufferIsClosed;
-import static io.netty.buffer.api.internal.Statics.bufferIsReadOnly;
-
-class NioBuffer extends ResourceSupport implements Buffer, ReadableComponent, WritableComponent,
- BufferIntegratable {
- private static final ByteBuffer CLOSED_BUFFER = ByteBuffer.allocate(0);
-
- private final AllocatorControl control;
- private ByteBuffer base;
- private ByteBuffer rmem; // For reading.
- private ByteBuffer wmem; // For writing.
-
- private int roff;
- private int woff;
- private boolean constBuffer;
-
- NioBuffer(ByteBuffer base, ByteBuffer memory, AllocatorControl control, Drop drop) {
- super(new MakeInaccessibleOnDrop(ArcDrop.wrap(drop)));
- this.base = base;
- rmem = memory;
- wmem = memory;
- this.control = control;
- }
-
- /**
- * Constructor for {@linkplain BufferAllocator#constBufferSupplier(byte[]) const buffers}.
- */
- NioBuffer(NioBuffer parent) {
- super(new MakeInaccessibleOnDrop(new ArcDrop<>(ArcDrop.acquire(parent.unsafeGetDrop()))));
- control = parent.control;
- base = parent.base;
- rmem = bbslice(parent.rmem, 0, parent.rmem.capacity()); // Need to slice to get independent byte orders.
- assert parent.wmem == CLOSED_BUFFER;
- wmem = CLOSED_BUFFER;
- roff = parent.roff;
- woff = parent.woff;
- order(parent.order());
- constBuffer = true;
- }
-
- private static final class MakeInaccessibleOnDrop implements Drop {
- final Drop delegate;
-
- private MakeInaccessibleOnDrop(Drop delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public void drop(NioBuffer buf) {
- try {
- delegate.drop(buf);
- } finally {
- buf.makeInaccessible();
- }
- }
-
- @Override
- public void attach(NioBuffer buf) {
- delegate.attach(buf);
- }
-
- @Override
- public String toString() {
- return "MakeInaccessibleOnDrop(" + delegate + ')';
- }
- }
-
- @Override
- protected Drop unsafeGetDrop() {
- MakeInaccessibleOnDrop drop = (MakeInaccessibleOnDrop) super.unsafeGetDrop();
- return drop.delegate;
- }
-
- @Override
- protected void unsafeSetDrop(Drop replacement) {
- super.unsafeSetDrop(new MakeInaccessibleOnDrop(replacement));
- }
-
- @Override
- public String toString() {
- return "Buffer[roff:" + roff + ", woff:" + woff + ", cap:" + rmem.capacity() + ']';
- }
-
- @Override
- protected RuntimeException createResourceClosedException() {
- return bufferIsClosed(this);
- }
-
- @Override
- public Buffer order(ByteOrder order) {
- rmem.order(order);
- return this;
- }
-
- @Override
- public ByteOrder order() {
- return rmem.order();
- }
-
- @Override
- public int capacity() {
- return rmem.capacity();
- }
-
- @Override
- public int readerOffset() {
- return roff;
- }
-
- @Override
- public Buffer readerOffset(int offset) {
- checkRead(offset, 0);
- roff = offset;
- return this;
- }
-
- @Override
- public int writerOffset() {
- return woff;
- }
-
- @Override
- public Buffer writerOffset(int offset) {
- checkWrite(offset, 0);
- woff = offset;
- return this;
- }
-
- @Override
- public Buffer fill(byte value) {
- int capacity = capacity();
- checkSet(0, capacity);
- if (rmem == CLOSED_BUFFER) {
- throw bufferIsClosed(this);
- }
- for (int i = 0; i < capacity; i++) {
- wmem.put(i, value);
- }
- return this;
- }
-
- @Override
- public long nativeAddress() {
- return rmem.isDirect() && PlatformDependent.hasUnsafe()? PlatformDependent.directBufferAddress(rmem) : 0;
- }
-
- @Override
- public Buffer makeReadOnly() {
- wmem = CLOSED_BUFFER;
- return this;
- }
-
- @Override
- public boolean readOnly() {
- return wmem == CLOSED_BUFFER && rmem != CLOSED_BUFFER;
- }
-
- @Override
- public Buffer copy(int offset, int length) {
- checkGet(offset, length);
- int allocSize = Math.max(length, 1); // Allocators don't support allocating zero-sized buffers.
- AllocatorControl.UntetheredMemory memory = control.allocateUntethered(this, allocSize);
- ByteBuffer base = memory.memory();
- ByteBuffer buffer = length == 0? bbslice(base, 0, 0) : base;
- Buffer copy = new NioBuffer(base, buffer, control, memory.drop());
- copyInto(offset, copy, 0, length);
- copy.writerOffset(length).order(order());
- if (readOnly()) {
- copy = copy.makeReadOnly();
- }
- return copy;
- }
-
- @Override
- public void copyInto(int srcPos, byte[] dest, int destPos, int length) {
- copyInto(srcPos, ByteBuffer.wrap(dest), destPos, length);
- }
-
- @Override
- public void copyInto(int srcPos, ByteBuffer dest, int destPos, int length) {
- if (rmem == CLOSED_BUFFER) {
- throw bufferIsClosed(this);
- }
- if (srcPos < 0) {
- throw new IllegalArgumentException("The srcPos cannot be negative: " + srcPos + '.');
- }
- if (length < 0) {
- throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
- }
- if (capacity() < srcPos + length) {
- throw new IllegalArgumentException("The srcPos + length is beyond the end of the buffer: " +
- "srcPos = " + srcPos + ", length = " + length + '.');
- }
- dest = dest.duplicate().clear();
- bbput(dest, destPos, rmem, srcPos, length);
- }
-
- @Override
- public void copyInto(int srcPos, Buffer dest, int destPos, int length) {
- if (dest instanceof NioBuffer) {
- var nb = (NioBuffer) dest;
- nb.checkSet(destPos, length);
- copyInto(srcPos, nb.wmem, destPos, length);
- return;
- }
-
- Statics.copyToViaReverseCursor(this, srcPos, dest, destPos, length);
- }
-
- @Override
- public ByteCursor openCursor() {
- return openCursor(readerOffset(), readableBytes());
- }
-
- @Override
- public ByteCursor openCursor(int fromOffset, int length) {
- if (rmem == CLOSED_BUFFER) {
- throw bufferIsClosed(this);
- }
- if (fromOffset < 0) {
- throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.');
- }
- if (length < 0) {
- throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
- }
- if (capacity() < fromOffset + length) {
- throw new IllegalArgumentException("The fromOffset + length is beyond the end of the buffer: " +
- "fromOffset = " + fromOffset + ", length = " + length + '.');
- }
- return new ByteCursor() {
- // Duplicate source buffer to keep our own byte order state.
- final ByteBuffer buffer = rmem.duplicate().order(ByteOrder.BIG_ENDIAN);
- int index = fromOffset;
- final int end = index + length;
- long longValue = -1;
- byte byteValue = -1;
-
- @Override
- public boolean readLong() {
- if (index + Long.BYTES <= end) {
- longValue = buffer.getLong(index);
- index += Long.BYTES;
- return true;
- }
- return false;
- }
-
- @Override
- public long getLong() {
- return longValue;
- }
-
- @Override
- public boolean readByte() {
- if (index < end) {
- byteValue = buffer.get(index);
- index++;
- return true;
- }
- return false;
- }
-
- @Override
- public byte getByte() {
- return byteValue;
- }
-
- @Override
- public int currentOffset() {
- return index;
- }
-
- @Override
- public int bytesLeft() {
- return end - index;
- }
- };
- }
-
- @Override
- public ByteCursor openReverseCursor(int fromOffset, int length) {
- if (rmem == CLOSED_BUFFER) {
- throw bufferIsClosed(this);
- }
- if (fromOffset < 0) {
- throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.');
- }
- if (length < 0) {
- throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
- }
- if (capacity() <= fromOffset) {
- throw new IllegalArgumentException("The fromOffset is beyond the end of the buffer: " + fromOffset + '.');
- }
- if (fromOffset - length < -1) {
- throw new IllegalArgumentException("The fromOffset - length would underflow the buffer: " +
- "fromOffset = " + fromOffset + ", length = " + length + '.');
- }
- return new ByteCursor() {
- final ByteBuffer buffer = rmem.duplicate().order(ByteOrder.LITTLE_ENDIAN);
- int index = fromOffset;
- final int end = index - length;
- long longValue = -1;
- byte byteValue = -1;
-
- @Override
- public boolean readLong() {
- if (index - Long.BYTES >= end) {
- index -= 7;
- longValue = buffer.getLong(index);
- index--;
- return true;
- }
- return false;
- }
-
- @Override
- public long getLong() {
- return longValue;
- }
-
- @Override
- public boolean readByte() {
- if (index > end) {
- byteValue = buffer.get(index);
- index--;
- return true;
- }
- return false;
- }
-
- @Override
- public byte getByte() {
- return byteValue;
- }
-
- @Override
- public int currentOffset() {
- return index;
- }
-
- @Override
- public int bytesLeft() {
- return index - end;
- }
- };
- }
-
- @Override
- public void ensureWritable(int size, int minimumGrowth, boolean allowCompaction) {
- if (!isAccessible()) {
- throw bufferIsClosed(this);
- }
- if (!isOwned()) {
- throw attachTrace(new IllegalStateException(
- "Buffer is not owned. Only owned buffers can call ensureWritable."));
- }
- if (size < 0) {
- throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.');
- }
- if (minimumGrowth < 0) {
- throw new IllegalArgumentException("The minimum growth cannot be negative: " + minimumGrowth + '.');
- }
- if (rmem != wmem) {
- throw bufferIsReadOnly(this);
- }
- if (writableBytes() >= size) {
- // We already have enough space.
- return;
- }
-
- if (allowCompaction && writableBytes() + readerOffset() >= size) {
- // We can solve this with compaction.
- compact();
- return;
- }
-
- // Allocate a bigger buffer.
- long newSize = capacity() + (long) Math.max(size - writableBytes(), minimumGrowth);
- BufferAllocator.checkSize(newSize);
- var untethered = control.allocateUntethered(this, (int) newSize);
- ByteBuffer buffer = untethered.memory();
- buffer.order(order());
-
- // Copy contents.
- copyInto(0, buffer, 0, capacity());
-
- // Release the old memory and install the new:
- Drop drop = untethered.drop();
- disconnectDrop(drop);
- attachNewBuffer(buffer, drop);
- }
-
- private void disconnectDrop(Drop newDrop) {
- var drop = (Drop) unsafeGetDrop();
- int roff = this.roff;
- int woff = this.woff;
- drop.drop(this);
- unsafeSetDrop(new ArcDrop<>(newDrop));
- this.roff = roff;
- this.woff = woff;
- }
-
- private void attachNewBuffer(ByteBuffer buffer, Drop drop) {
- base = buffer;
- rmem = buffer;
- wmem = buffer;
- constBuffer = false;
- drop.attach(this);
- }
-
- @Override
- public Buffer split(int splitOffset) {
- if (splitOffset < 0) {
- throw new IllegalArgumentException("The split offset cannot be negative: " + splitOffset + '.');
- }
- if (capacity() < splitOffset) {
- throw new IllegalArgumentException("The split offset cannot be greater than the buffer capacity, " +
- "but the split offset was " + splitOffset + ", and capacity is " + capacity() + '.');
- }
- if (!isAccessible()) {
- throw attachTrace(bufferIsClosed(this));
- }
- if (!isOwned()) {
- throw attachTrace(new IllegalStateException("Cannot split a buffer that is not owned."));
- }
- var drop = (ArcDrop) unsafeGetDrop();
- unsafeSetDrop(new ArcDrop<>(drop));
- var splitByteBuffer = bbslice(rmem, 0, splitOffset);
- // TODO maybe incrementing the existing ArcDrop is enough; maybe we don't need to wrap it in another ArcDrop.
- var splitBuffer = new NioBuffer(base, splitByteBuffer, control, new ArcDrop<>(drop.increment()));
- splitBuffer.woff = Math.min(woff, splitOffset);
- splitBuffer.roff = Math.min(roff, splitOffset);
- ByteOrder order = order();
- splitBuffer.order(order);
- boolean readOnly = readOnly();
- if (readOnly) {
- splitBuffer.makeReadOnly();
- }
- // Split preserves const-state.
- splitBuffer.constBuffer = constBuffer;
- rmem = bbslice(rmem, splitOffset, rmem.capacity() - splitOffset);
- if (!readOnly) {
- wmem = rmem;
- }
- woff = Math.max(woff, splitOffset) - splitOffset;
- roff = Math.max(roff, splitOffset) - splitOffset;
- order(order);
- return splitBuffer;
- }
-
- @Override
- public void compact() {
- if (!isOwned()) {
- throw attachTrace(new IllegalStateException("Buffer must be owned in order to compact."));
- }
- if (readOnly()) {
- throw new BufferReadOnlyException("Buffer must be writable in order to compact, but was read-only.");
- }
- if (roff == 0) {
- return;
- }
- rmem.limit(woff).position(roff).compact().clear();
- woff -= roff;
- roff = 0;
- }
-
- @Override
- public int countComponents() {
- return 1;
- }
-
- @Override
- public int countReadableComponents() {
- return readableBytes() > 0? 1 : 0;
- }
-
- @Override
- public int countWritableComponents() {
- return writableBytes() > 0? 1 : 0;
- }
-
- //
- @Override
- public boolean hasReadableArray() {
- return rmem.hasArray();
- }
-
- @Override
- public byte[] readableArray() {
- return rmem.array();
- }
-
- @Override
- public int readableArrayOffset() {
- return rmem.arrayOffset() + roff;
- }
-
- @Override
- public int readableArrayLength() {
- return woff - roff;
- }
-
- @Override
- public long readableNativeAddress() {
- return nativeAddress();
- }
-
- @Override
- public ByteBuffer readableBuffer() {
- return bbslice(rmem.asReadOnlyBuffer(), readerOffset(), readableBytes()).order(order());
- }
-
- @Override
- public boolean hasWritableArray() {
- return wmem.hasArray();
- }
-
- @Override
- public byte[] writableArray() {
- return wmem.array();
- }
-
- @Override
- public int writableArrayOffset() {
- return wmem.arrayOffset() + woff;
- }
-
- @Override
- public int writableArrayLength() {
- return capacity() - woff;
- }
-
- @Override
- public long writableNativeAddress() {
- return nativeAddress();
- }
-
- @Override
- public ByteBuffer writableBuffer() {
- return bbslice(wmem, writerOffset(), writableBytes()).order(order());
- }
- //
-
- @Override
- public int forEachReadable(int initialIndex, ReadableComponentProcessor processor)
- throws E {
- checkRead(readerOffset(), Math.max(1, readableBytes()));
- return processor.process(initialIndex, this)? 1 : -1;
- }
-
- @Override
- public int forEachWritable(int initialIndex, WritableComponentProcessor processor)
- throws E {
- checkWrite(writerOffset(), Math.max(1, writableBytes()));
- return processor.process(initialIndex, this)? 1 : -1;
- }
-
- //
- @Override
- public byte readByte() {
- checkRead(roff, Byte.BYTES);
- var value = rmem.get(roff);
- roff += Byte.BYTES;
- return value;
- }
-
- @Override
- public byte getByte(int roff) {
- checkGet(roff, Byte.BYTES);
- return rmem.get(roff);
- }
-
- @Override
- public int readUnsignedByte() {
- return readByte() & 0xFF;
- }
-
- @Override
- public int getUnsignedByte(int roff) {
- return getByte(roff) & 0xFF;
- }
-
- @Override
- public Buffer writeByte(byte value) {
- try {
- wmem.put(woff, value);
- woff += Byte.BYTES;
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public Buffer setByte(int woff, byte value) {
- try {
- wmem.put(woff, value);
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public Buffer writeUnsignedByte(int value) {
- try {
- wmem.put(woff, (byte) (value & 0xFF));
- woff += Byte.BYTES;
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public Buffer setUnsignedByte(int woff, int value) {
- try {
- wmem.put(woff, (byte) (value & 0xFF));
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public char readChar() {
- checkRead(roff, 2);
- var value = rmem.getChar(roff);
- roff += 2;
- return value;
- }
-
- @Override
- public char getChar(int roff) {
- checkGet(roff, 2);
- return rmem.getChar(roff);
- }
-
- @Override
- public Buffer writeChar(char value) {
- try {
- wmem.putChar(woff, value);
- woff += 2;
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public Buffer setChar(int woff, char value) {
- try {
- wmem.putChar(woff, value);
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public short readShort() {
- checkRead(roff, Short.BYTES);
- var value = rmem.getShort(roff);
- roff += 2;
- return value;
- }
-
- @Override
- public short getShort(int roff) {
- checkGet(roff, Short.BYTES);
- return rmem.getShort(roff);
- }
-
- @Override
- public int readUnsignedShort() {
- checkRead(roff, Short.BYTES);
- var value = rmem.getShort(roff) & 0xFFFF;
- roff += 2;
- return value;
- }
-
- @Override
- public int getUnsignedShort(int roff) {
- checkGet(roff, Short.BYTES);
- return rmem.getShort(roff) & 0xFFFF;
- }
-
- @Override
- public Buffer writeShort(short value) {
- try {
- wmem.putShort(woff, value);
- woff += Short.BYTES;
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public Buffer setShort(int woff, short value) {
- try {
- wmem.putShort(woff, value);
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public Buffer writeUnsignedShort(int value) {
- try {
- wmem.putShort(woff, (short) (value & 0xFFFF));
- woff += Short.BYTES;
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public Buffer setUnsignedShort(int woff, int value) {
- try {
- wmem.putShort(woff, (short) (value & 0xFFFF));
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public int readMedium() {
- checkRead(roff, 3);
- int value = order() == ByteOrder.BIG_ENDIAN?
- rmem.get(roff) << 16 |
- (rmem.get(roff + 1) & 0xFF) << 8 |
- rmem.get(roff + 2) & 0xFF :
- rmem.get(roff) & 0xFF |
- (rmem.get(roff + 1) & 0xFF) << 8 |
- rmem.get(roff + 2) << 16;
- roff += 3;
- return value;
- }
-
- @Override
- public int getMedium(int roff) {
- checkGet(roff, 3);
- return order() == ByteOrder.BIG_ENDIAN?
- rmem.get(roff) << 16 |
- (rmem.get(roff + 1) & 0xFF) << 8 |
- rmem.get(roff + 2) & 0xFF :
- rmem.get(roff) & 0xFF |
- (rmem.get(roff + 1) & 0xFF) << 8 |
- rmem.get(roff + 2) << 16;
- }
-
- @Override
- public int readUnsignedMedium() {
- checkRead(roff, 3);
- int value = order() == ByteOrder.BIG_ENDIAN?
- (rmem.get(roff) << 16 |
- (rmem.get(roff + 1) & 0xFF) << 8 |
- rmem.get(roff + 2) & 0xFF) & 0xFFFFFF :
- (rmem.get(roff) & 0xFF |
- (rmem.get(roff + 1) & 0xFF) << 8 |
- rmem.get(roff + 2) << 16) & 0xFFFFFF;
- roff += 3;
- return value;
- }
-
- @Override
- public int getUnsignedMedium(int roff) {
- checkGet(roff, 3);
- return order() == ByteOrder.BIG_ENDIAN?
- (rmem.get(roff) << 16 |
- (rmem.get(roff + 1) & 0xFF) << 8 |
- rmem.get(roff + 2) & 0xFF) & 0xFFFFFF :
- (rmem.get(roff) & 0xFF |
- (rmem.get(roff + 1) & 0xFF) << 8 |
- rmem.get(roff + 2) << 16) & 0xFFFFFF;
- }
-
- @Override
- public Buffer writeMedium(int value) {
- checkWrite(woff, 3);
- if (order() == ByteOrder.BIG_ENDIAN) {
- wmem.put(woff, (byte) (value >> 16));
- wmem.put(woff + 1, (byte) (value >> 8 & 0xFF));
- wmem.put(woff + 2, (byte) (value & 0xFF));
- } else {
- wmem.put(woff, (byte) (value & 0xFF));
- wmem.put(woff + 1, (byte) (value >> 8 & 0xFF));
- wmem.put(woff + 2, (byte) (value >> 16 & 0xFF));
- }
- woff += 3;
- return this;
- }
-
- @Override
- public Buffer setMedium(int woff, int value) {
- checkSet(woff, 3);
- if (order() == ByteOrder.BIG_ENDIAN) {
- wmem.put(woff, (byte) (value >> 16));
- wmem.put(woff + 1, (byte) (value >> 8 & 0xFF));
- wmem.put(woff + 2, (byte) (value & 0xFF));
- } else {
- wmem.put(woff, (byte) (value & 0xFF));
- wmem.put(woff + 1, (byte) (value >> 8 & 0xFF));
- wmem.put(woff + 2, (byte) (value >> 16 & 0xFF));
- }
- return this;
- }
-
- @Override
- public Buffer writeUnsignedMedium(int value) {
- checkWrite(woff, 3);
- if (order() == ByteOrder.BIG_ENDIAN) {
- wmem.put(woff, (byte) (value >> 16));
- wmem.put(woff + 1, (byte) (value >> 8 & 0xFF));
- wmem.put(woff + 2, (byte) (value & 0xFF));
- } else {
- wmem.put(woff, (byte) (value & 0xFF));
- wmem.put(woff + 1, (byte) (value >> 8 & 0xFF));
- wmem.put(woff + 2, (byte) (value >> 16 & 0xFF));
- }
- woff += 3;
- return this;
- }
-
- @Override
- public Buffer setUnsignedMedium(int woff, int value) {
- checkSet(woff, 3);
- if (order() == ByteOrder.BIG_ENDIAN) {
- wmem.put(woff, (byte) (value >> 16));
- wmem.put(woff + 1, (byte) (value >> 8 & 0xFF));
- wmem.put(woff + 2, (byte) (value & 0xFF));
- } else {
- wmem.put(woff, (byte) (value & 0xFF));
- wmem.put(woff + 1, (byte) (value >> 8 & 0xFF));
- wmem.put(woff + 2, (byte) (value >> 16 & 0xFF));
- }
- return this;
- }
-
- @Override
- public int readInt() {
- checkRead(roff, Integer.BYTES);
- var value = rmem.getInt(roff);
- roff += Integer.BYTES;
- return value;
- }
-
- @Override
- public int getInt(int roff) {
- checkGet(roff, Integer.BYTES);
- return rmem.getInt(roff);
- }
-
- @Override
- public long readUnsignedInt() {
- checkRead(roff, Integer.BYTES);
- var value = rmem.getInt(roff) & 0xFFFFFFFFL;
- roff += Integer.BYTES;
- return value;
- }
-
- @Override
- public long getUnsignedInt(int roff) {
- checkGet(roff, Integer.BYTES);
- return rmem.getInt(roff) & 0xFFFFFFFFL;
- }
-
- @Override
- public Buffer writeInt(int value) {
- try {
- wmem.putInt(woff, value);
- woff += Integer.BYTES;
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public Buffer setInt(int woff, int value) {
- try {
- wmem.putInt(woff, value);
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, this.woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public Buffer writeUnsignedInt(long value) {
- try {
- wmem.putInt(woff, (int) (value & 0xFFFFFFFFL));
- woff += Integer.BYTES;
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public Buffer setUnsignedInt(int woff, long value) {
- try {
- wmem.putInt(woff, (int) (value & 0xFFFFFFFFL));
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, this.woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public float readFloat() {
- checkRead(roff, Float.BYTES);
- var value = rmem.getFloat(roff);
- roff += Float.BYTES;
- return value;
- }
-
- @Override
- public float getFloat(int roff) {
- checkGet(roff, Float.BYTES);
- return rmem.getFloat(roff);
- }
-
- @Override
- public Buffer writeFloat(float value) {
- try {
- wmem.putFloat(woff, value);
- woff += Float.BYTES;
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public Buffer setFloat(int woff, float value) {
- try {
- wmem.putFloat(woff, value);
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public long readLong() {
- checkRead(roff, Long.BYTES);
- var value = rmem.getLong(roff);
- roff += Long.BYTES;
- return value;
- }
-
- @Override
- public long getLong(int roff) {
- checkGet(roff, Long.BYTES);
- return rmem.getLong(roff);
- }
-
- @Override
- public Buffer writeLong(long value) {
- try {
- wmem.putLong(woff, value);
- woff += Long.BYTES;
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public Buffer setLong(int woff, long value) {
- try {
- wmem.putLong(woff, value);
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public double readDouble() {
- checkRead(roff, Double.BYTES);
- var value = rmem.getDouble(roff);
- roff += Double.BYTES;
- return value;
- }
-
- @Override
- public double getDouble(int roff) {
- checkGet(roff, Double.BYTES);
- return rmem.getDouble(roff);
- }
-
- @Override
- public Buffer writeDouble(double value) {
- try {
- wmem.putDouble(woff, value);
- woff += Double.BYTES;
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
-
- @Override
- public Buffer setDouble(int woff, double value) {
- try {
- wmem.putDouble(woff, value);
- return this;
- } catch (IndexOutOfBoundsException e) {
- throw checkWriteState(e, woff);
- } catch (ReadOnlyBufferException e) {
- throw bufferIsReadOnly(this);
- }
- }
- //
-
- @Override
- protected Owned prepareSend() {
- var order = order();
- var roff = this.roff;
- var woff = this.woff;
- var readOnly = readOnly();
- var isConst = constBuffer;
- ByteBuffer base = this.base;
- ByteBuffer rmem = this.rmem;
- makeInaccessible();
- return new Owned() {
- @Override
- public NioBuffer transferOwnership(Drop drop) {
- NioBuffer copy = new NioBuffer(base, rmem, control, drop);
- copy.order(order);
- copy.roff = roff;
- copy.woff = woff;
- if (readOnly) {
- copy.makeReadOnly();
- }
- copy.constBuffer = isConst;
- return copy;
- }
- };
- }
-
- void makeInaccessible() {
- base = CLOSED_BUFFER;
- rmem = CLOSED_BUFFER;
- wmem = CLOSED_BUFFER;
- roff = 0;
- woff = 0;
- }
-
- @Override
- public boolean isOwned() {
- return super.isOwned() && ((ArcDrop) unsafeGetDrop()).isOwned();
- }
-
- @Override
- public int countBorrows() {
- return super.countBorrows() + ((ArcDrop) unsafeGetDrop()).countBorrows();
- }
-
- private void checkRead(int index, int size) {
- if (index < 0 || woff < index + size) {
- throw readAccessCheckException(index);
- }
- }
-
- private void checkGet(int index, int size) {
- if (index < 0 || capacity() < index + size) {
- throw readAccessCheckException(index);
- }
- }
-
- private void checkWrite(int index, int size) {
- if (index < roff || wmem.capacity() < index + size) {
- throw writeAccessCheckException(index);
- }
- }
-
- private void checkSet(int index, int size) {
- if (index < 0 || wmem.capacity() < index + size) {
- throw writeAccessCheckException(index);
- }
- }
-
- private RuntimeException checkWriteState(IndexOutOfBoundsException ioobe, int offset) {
- if (rmem == CLOSED_BUFFER) {
- return bufferIsClosed(this);
- }
- if (wmem != rmem) {
- return bufferIsReadOnly(this);
- }
-
- IndexOutOfBoundsException exception = outOfBounds(offset);
- exception.addSuppressed(ioobe);
- return exception;
- }
-
- private RuntimeException readAccessCheckException(int index) {
- if (rmem == CLOSED_BUFFER) {
- throw bufferIsClosed(this);
- }
- return outOfBounds(index);
- }
-
- private RuntimeException writeAccessCheckException(int index) {
- if (rmem == CLOSED_BUFFER) {
- throw bufferIsClosed(this);
- }
- if (wmem != rmem) {
- return bufferIsReadOnly(this);
- }
- return outOfBounds(index);
- }
-
- private IndexOutOfBoundsException outOfBounds(int index) {
- return new IndexOutOfBoundsException(
- "Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
- rmem.capacity() + "].");
- }
-
- ByteBuffer recoverable() {
- return base;
- }
-
- //
- private ByteBufAdaptor adaptor;
- @Override
- public ByteBuf asByteBuf() {
- ByteBufAdaptor bba = adaptor;
- if (bba == null) {
- ByteBufAllocatorAdaptor alloc = new ByteBufAllocatorAdaptor(
- BufferAllocator.heap(), BufferAllocator.direct());
- return adaptor = new ByteBufAdaptor(alloc, this);
- }
- return bba;
- }
-
- @Override
- public int refCnt() {
- return isAccessible()? 1 + countBorrows() : 0;
- }
-
- @Override
- public ReferenceCounted retain() {
- return retain(1);
- }
-
- @Override
- public ReferenceCounted retain(int increment) {
- for (int i = 0; i < increment; i++) {
- acquire();
- }
- return this;
- }
-
- @Override
- public ReferenceCounted touch() {
- return this;
- }
-
- @Override
- public ReferenceCounted touch(Object hint) {
- return this;
- }
-
- @Override
- public boolean release() {
- return release(1);
- }
-
- @Override
- public boolean release(int decrement) {
- int refCount = 1 + countBorrows();
- if (!isAccessible() || decrement > refCount) {
- throw new IllegalReferenceCountException(refCount, -decrement);
- }
- for (int i = 0; i < decrement; i++) {
- try {
- close();
- } catch (RuntimeException e) {
- throw new IllegalReferenceCountException(e);
- }
- }
- return !isAccessible();
- }
- //
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/package-info.java b/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/package-info.java
deleted file mode 100644
index b49f818..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * Safe ByteBuffer based implementation.
- */
-package io.netty.buffer.api.bytebuffer;
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/ArcDrop.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/ArcDrop.java
deleted file mode 100644
index b2acd10..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/internal/ArcDrop.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.internal;
-
-import io.netty.buffer.api.Drop;
-
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
-public final class ArcDrop implements Drop {
- private static final VarHandle COUNT;
- static {
- try {
- COUNT = MethodHandles.lookup().findVarHandle(ArcDrop.class, "count", int.class);
- } catch (Exception e) {
- throw new ExceptionInInitializerError(e);
- }
- }
-
- private final Drop delegate;
- @SuppressWarnings("FieldMayBeFinal")
- private volatile int count;
-
- public ArcDrop(Drop delegate) {
- this.delegate = delegate;
- count = 1;
- }
-
- public static Drop wrap(Drop drop) {
- if (drop.getClass() == ArcDrop.class) {
- return drop;
- }
- return new ArcDrop(drop);
- }
-
- public static Drop acquire(Drop drop) {
- if (drop.getClass() == ArcDrop.class) {
- ((ArcDrop) drop).increment();
- return drop;
- }
- return new ArcDrop(drop);
- }
-
- public ArcDrop increment() {
- int c;
- do {
- c = count;
- checkValidState(c);
- } while (!COUNT.compareAndSet(this, c, c + 1));
- return this;
- }
-
- @Override
- public void drop(T obj) {
- int c;
- int n;
- do {
- c = count;
- n = c - 1;
- checkValidState(c);
- } while (!COUNT.compareAndSet(this, c, n));
- if (n == 0) {
- delegate.drop(obj);
- }
- }
-
- @Override
- public void attach(T obj) {
- delegate.attach(obj);
- }
-
- public boolean isOwned() {
- return count <= 1;
- }
-
- public int countBorrows() {
- return count - 1;
- }
-
- public Drop unwrap() {
- return delegate;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder()
- .append("ArcDrop@")
- .append(Integer.toHexString(System.identityHashCode(this)))
- .append('(').append(count).append(", ");
- Drop drop = this;
- while ((drop = ((ArcDrop) drop).unwrap()) instanceof ArcDrop) {
- builder.append(((ArcDrop) drop).count).append(", ");
- }
- return builder.append(drop).append(')').toString();
- }
-
- private static void checkValidState(int count) {
- if (count == 0) {
- throw new IllegalStateException("Underlying resources have already been freed.");
- }
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/CleanerDrop.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/CleanerDrop.java
deleted file mode 100644
index 75eae0c..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/internal/CleanerDrop.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.internal;
-
-import io.netty.buffer.api.Drop;
-
-import java.lang.ref.Cleaner;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * A drop implementation that delegates to another drop instance, either when called directly, or when it becomes
- * cleanable. This ensures that objects are dropped even if they leak.
- */
-public final class CleanerDrop implements Drop {
- private Cleaner.Cleanable cleanable;
- private GatedRunner runner;
-
- /**
- * Wrap the given drop instance, and produce a new drop instance that will also call the delegate drop instance if
- * it becomes cleanable.
- */
- public static Drop wrap(Drop drop) {
- CleanerDrop cleanerDrop = new CleanerDrop<>();
- GatedRunner runner = new GatedRunner<>(drop);
- cleanerDrop.cleanable = Statics.CLEANER.register(cleanerDrop, runner);
- cleanerDrop.runner = runner;
- return cleanerDrop;
- }
-
- private CleanerDrop() {
- }
-
- @Override
- public void attach(T obj) {
- runner.set(obj);
- runner.drop.attach(obj);
- }
-
- @Override
- public void drop(T obj) {
- attach(obj);
- cleanable.clean();
- }
-
- @Override
- public String toString() {
- return "CleanerDrop(" + runner.drop + ')';
- }
-
- private static final class GatedRunner extends AtomicReference implements Runnable {
- private static final long serialVersionUID = 2685535951915798850L;
- final Drop drop;
-
- private GatedRunner(Drop drop) {
- this.drop = drop;
- }
-
- @Override
- public void run() {
- T obj = getAndSet(null); // Make absolutely sure we only delegate once.
- if (obj != null) {
- drop.drop(obj);
- }
- }
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/LifecycleTracer.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/LifecycleTracer.java
deleted file mode 100644
index 4dace3a..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/internal/LifecycleTracer.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.internal;
-
-import io.netty.buffer.api.Drop;
-import io.netty.buffer.api.Owned;
-import io.netty.buffer.api.Resource;
-
-import java.util.ArrayDeque;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Stream;
-
-public abstract class LifecycleTracer {
- public static LifecycleTracer get() {
- if (Trace.TRACE_LIFECYCLE_DEPTH == 0) {
- return NoOpTracer.INSTANCE;
- }
- StackTracer stackTracer = new StackTracer();
- stackTracer.addTrace(StackTracer.WALKER.walk(new Trace("allocate", 0)));
- return stackTracer;
- }
-
- public abstract void acquire(int acquires);
-
- public abstract void drop(int acquires);
-
- public abstract void close(int acquires);
-
- public abstract , T extends ResourceSupport> Owned send(Owned send, int acquires);
-
- public abstract E attachTrace(E throwable);
-
- private static final class NoOpTracer extends LifecycleTracer {
- private static final NoOpTracer INSTANCE = new NoOpTracer();
-
- @Override
- public void acquire(int acquires) {
- }
-
- @Override
- public void drop(int acquires) {
- }
-
- @Override
- public void close(int acquires) {
- }
-
- @Override
- public , T extends ResourceSupport> Owned send(Owned send, int acquires) {
- return send;
- }
-
- @Override
- public E attachTrace(E throwable) {
- return throwable;
- }
- }
-
- private static final class StackTracer extends LifecycleTracer {
- private static final int MAX_TRACE_POINTS = Math.min(Integer.getInteger("MAX_TRACE_POINTS", 50), 1000);
- private static final StackWalker WALKER;
- static {
- int depth = Trace.TRACE_LIFECYCLE_DEPTH;
- WALKER = depth > 0 ? StackWalker.getInstance(Set.of(), depth + 2) : null;
- }
-
- private final ArrayDeque traces = new ArrayDeque<>();
- private boolean dropped;
-
- @Override
- public void acquire(int acquires) {
- Trace trace = WALKER.walk(new Trace("acquire", acquires));
- addTrace(trace);
- }
-
- void addTrace(Trace trace) {
- synchronized (traces) {
- if (traces.size() == MAX_TRACE_POINTS) {
- traces.pollFirst();
- }
- traces.addLast(trace);
- }
- }
-
- @Override
- public void drop(int acquires) {
- dropped = true;
- addTrace(WALKER.walk(new Trace("drop", acquires)));
- }
-
- @Override
- public void close(int acquires) {
- if (!dropped) {
- addTrace(WALKER.walk(new Trace("close", acquires)));
- }
- }
-
- @Override
- public , T extends ResourceSupport> Owned send(Owned send, int acquires) {
- Trace sendTrace = new Trace("send", acquires);
- sendTrace.sent = true;
- addTrace(WALKER.walk(sendTrace));
- return new Owned() {
- @Override
- public T transferOwnership(Drop drop) {
- sendTrace.received = WALKER.walk(new Trace("received", acquires));
- return send.transferOwnership(drop);
- }
- };
- }
-
- @Override
- public E attachTrace(E throwable) {
- synchronized (traces) {
- long timestamp = System.nanoTime();
- for (Trace trace : traces) {
- trace.attach(throwable, timestamp);
- }
- }
- return throwable;
- }
- }
-
- private static final class Trace implements Function, Trace> {
- private static final int TRACE_LIFECYCLE_DEPTH;
- static {
- int traceDefault = 0;
- //noinspection AssertWithSideEffects
- assert (traceDefault = 10) > 0;
- TRACE_LIFECYCLE_DEPTH = Math.max(Integer.getInteger("TRACE_LIFECYCLE_DEPTH", traceDefault), 0);
- }
-
- final String name;
- final int acquires;
- final long timestamp;
- boolean sent;
- volatile Trace received;
- StackWalker.StackFrame[] frames;
-
- Trace(String name, int acquires) {
- this.name = name;
- this.acquires = acquires;
- timestamp = System.nanoTime();
- }
-
- @Override
- public Trace apply(Stream frames) {
- this.frames = frames.limit(TRACE_LIFECYCLE_DEPTH + 1).toArray(StackWalker.StackFrame[]::new);
- return this;
- }
-
- public void attach(E throwable, long timestamp) {
- Trace recv = received;
- String message = sent && recv == null ? name + " (sent but not received)" : name;
- message += " (current acquires = " + acquires + ") T" + (this.timestamp - timestamp) / 1000 + "µs.";
- Traceback exception = new Traceback(message);
- StackTraceElement[] stackTrace = new StackTraceElement[frames.length];
- for (int i = 0; i < frames.length; i++) {
- stackTrace[i] = frames[i].toStackTraceElement();
- }
- exception.setStackTrace(stackTrace);
- if (recv != null) {
- recv.attach(exception, timestamp);
- }
- throwable.addSuppressed(exception);
- }
- }
-
- private static final class Traceback extends Throwable {
- private static final long serialVersionUID = 941453986194634605L;
-
- Traceback(String message) {
- super(message);
- }
-
- @Override
- public synchronized Throwable fillInStackTrace() {
- return this;
- }
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/MemoryManagersOverride.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/MemoryManagersOverride.java
deleted file mode 100644
index e4b0255..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/internal/MemoryManagersOverride.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.internal;
-
-import io.netty.buffer.api.MemoryManagers;
-import io.netty.buffer.api.bytebuffer.ByteBufferMemoryManagers;
-
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Supplier;
-
-public final class MemoryManagersOverride {
- private static final MemoryManagers DEFAULT = new ByteBufferMemoryManagers();
- private static final AtomicInteger OVERRIDES_AVAILABLE = new AtomicInteger();
- private static final Map OVERRIDES = Collections.synchronizedMap(new IdentityHashMap<>());
-
- private MemoryManagersOverride() {
- }
-
- public static MemoryManagers getManagers() {
- if (OVERRIDES_AVAILABLE.get() > 0) {
- return OVERRIDES.getOrDefault(Thread.currentThread(), DEFAULT);
- }
- return DEFAULT;
- }
-
- public static T using(MemoryManagers managers, Supplier supplier) {
- Thread thread = Thread.currentThread();
- OVERRIDES.put(thread, managers);
- OVERRIDES_AVAILABLE.incrementAndGet();
- try {
- return supplier.get();
- } finally {
- OVERRIDES_AVAILABLE.decrementAndGet();
- OVERRIDES.remove(thread);
- }
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/ResourceSupport.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/ResourceSupport.java
deleted file mode 100644
index 6def829..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/internal/ResourceSupport.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.internal;
-
-import io.netty.buffer.api.Drop;
-import io.netty.buffer.api.Owned;
-import io.netty.buffer.api.Resource;
-import io.netty.buffer.api.Send;
-
-import java.util.Objects;
-
-/**
- * Internal support class for resources.
- *
- * @param The public interface for the resource.
- * @param The concrete implementation of the resource.
- */
-public abstract class ResourceSupport, T extends ResourceSupport> implements Resource {
- private int acquires; // Closed if negative.
- private Drop drop;
- private final LifecycleTracer tracer;
-
- protected ResourceSupport(Drop drop) {
- this.drop = drop;
- tracer = LifecycleTracer.get();
- }
-
- /**
- * Encapsulation bypass for calling {@link #acquire()} on the given object.
- *
- * Note: this {@code acquire} method does not check the type of the return value from acquire at compile time.
- * The type is instead checked at runtime, and will cause a {@link ClassCastException} to be thrown if done
- * incorrectly.
- *
- * @param obj The object we wish to acquire (increment reference count) on.
- * @param The type of the acquired object, given by target-typing.
- * @return The acquired object.
- */
- @SuppressWarnings("unchecked")
- static T acquire(ResourceSupport, ?> obj) {
- return (T) obj.acquire();
- }
-
- /**
- * Increment the reference count.
- *
- * Note, this method is not thread-safe because Resources are meant to thread-confined.
- *
- * @return This {@link Resource} instance.
- */
- protected final I acquire() {
- if (acquires < 0) {
- throw attachTrace(createResourceClosedException());
- }
- if (acquires == Integer.MAX_VALUE) {
- throw new IllegalStateException("Cannot acquire more references; counter would overflow.");
- }
- acquires++;
- tracer.acquire(acquires);
- return self();
- }
-
- protected abstract RuntimeException createResourceClosedException();
-
- /**
- * Decrement the reference count, and despose of the resource if the last reference is closed.
- *
- * Note, this method is not thread-safe because Resources are meant to be thread-confined.
- *
- * @throws IllegalStateException If this Resource has already been closed.
- */
- @Override
- public final void close() {
- if (acquires == -1) {
- throw attachTrace(new IllegalStateException("Double-free: Resource already closed and dropped."));
- }
- if (acquires == 0) {
- tracer.drop(acquires);
- drop.drop(impl());
- }
- acquires--;
- tracer.close(acquires);
- }
-
- /**
- * Send this Resource instance to another Thread, transferring the ownership to the recipient.
- * This method can be used when the receiving thread is not known up front.
- *
- * This instance immediately becomes inaccessible, and all attempts at accessing this resource will throw.
- * Calling {@link #close()} will have no effect, so this method is safe to call within a try-with-resources
- * statement.
- *
- * @throws IllegalStateException if this object has any outstanding acquires; that is, if this object has been
- * {@link #acquire() acquired} more times than it has been {@link #close() closed}.
- */
- @Override
- public final Send send() {
- if (acquires < 0) {
- throw attachTrace(createResourceClosedException());
- }
- if (!isOwned()) {
- throw notSendableException();
- }
- var owned = tracer.send(prepareSend(), acquires);
- acquires = -2; // Close without dropping. This also ignore future double-free attempts.
- return new TransferSend(owned, drop, getClass());
- }
-
- /**
- * Attach a trace of the life-cycle of this object as suppressed exceptions to the given throwable.
- *
- * @param throwable The throwable to attach a life-cycle trace to.
- * @param The concrete exception type.
- * @return The given exception, which can then be thrown.
- */
- protected E attachTrace(E throwable) {
- return tracer.attachTrace(throwable);
- }
-
- /**
- * Create an {@link IllegalStateException} with a custom message, tailored to this particular
- * {@link Resource} instance, for when the object cannot be sent for some reason.
- * @return An {@link IllegalStateException} to be thrown when this object cannot be sent.
- */
- protected IllegalStateException notSendableException() {
- return new IllegalStateException(
- "Cannot send() a reference counted object with " + countBorrows() + " borrows: " + this + '.');
- }
-
- /**
- * Encapsulation bypass to call {@link #isOwned()} on the given object.
- *
- * @param obj The object to query the ownership state on.
- * @return {@code true} if the given object is owned, otherwise {@code false}.
- */
- static boolean isOwned(ResourceSupport, ?> obj) {
- return obj.isOwned();
- }
-
- /**
- * Query if this object is in an "owned" state, which means no other references have been
- * {@linkplain #acquire() acquired} to it.
- *
- * This would usually be the case, since there are no public methods for acquiring references to these objects.
- *
- * @return {@code true} if this object is in an owned state, otherwise {@code false}.
- */
- protected boolean isOwned() {
- return acquires == 0;
- }
-
- /**
- * Encapsulation bypass to call {@link #countBorrows()} on the given object.
- *
- * @param obj The object to count borrows on.
- * @return The number of borrows, or outstanding {@linkplain #acquire() acquires}, if any, of the given object.
- */
- static int countBorrows(ResourceSupport, ?> obj) {
- return obj.countBorrows();
- }
-
- /**
- * Count the number of borrows of this object.
- * Note that even if the number of borrows is {@code 0}, this object might not be {@linkplain #isOwned() owned}
- * because there could be other restrictions involved in ownership.
- *
- * @return The number of borrows, if any, of this object.
- */
- protected int countBorrows() {
- return Math.max(acquires, 0);
- }
-
- @Override
- public boolean isAccessible() {
- return acquires >= 0;
- }
-
- /**
- * Prepare this instance for ownsership transfer. This method is called from {@link #send()} in the sending thread.
- * This method should put this resource in a deactivated state where it is no longer accessible from the currently
- * owning thread.
- * In this state, the resource instance should only allow a call to {@link Owned#transferOwnership(Drop)} in the
- * recipient thread.
- *
- * @return This resource instance in a deactivated state.
- */
- protected abstract Owned prepareSend();
-
- /**
- * Get access to the underlying {@link Drop} object.
- * This method is unsafe because it open the possibility of bypassing and overriding resource lifetimes.
- *
- * @return The {@link Drop} object used by this reference counted object.
- */
- protected Drop unsafeGetDrop() {
- return drop;
- }
-
- /**
- * Replace the current underlying {@link Drop} object with the given one.
- * This method is unsafe because it open the possibility of bypassing and overring resource lifetimes.
- *
- * @param replacement The new {@link Drop} object to use instead of the current one.
- */
- protected void unsafeSetDrop(Drop replacement) {
- drop = Objects.requireNonNull(replacement, "Replacement drop cannot be null.");
- }
-
- @SuppressWarnings("unchecked")
- private I self() {
- return (I) this;
- }
-
- @SuppressWarnings("unchecked")
- private T impl() {
- return (T) this;
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/Statics.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/Statics.java
deleted file mode 100644
index ab01fc2..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/internal/Statics.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.internal;
-
-import io.netty.buffer.api.Buffer;
-import io.netty.buffer.api.BufferClosedException;
-import io.netty.buffer.api.BufferReadOnlyException;
-import io.netty.buffer.api.Drop;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodHandles.Lookup;
-import java.lang.invoke.MethodType;
-import java.lang.invoke.VarHandle;
-import java.lang.ref.Cleaner;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.concurrent.atomic.LongAdder;
-
-public interface Statics {
- LongAdder MEM_USAGE_NATIVE = new LongAdder();
- Cleaner CLEANER = Cleaner.create();
- Drop NO_OP_DROP = new Drop() {
- @Override
- public void drop(Buffer obj) {
- }
-
- @Override
- public String toString() {
- return "NO_OP_DROP";
- }
- };
- MethodHandle BB_SLICE_OFFSETS = getByteBufferSliceOffsetsMethodHandle();
- MethodHandle BB_PUT_OFFSETS = getByteBufferPutOffsetsMethodHandle();
-
- static MethodHandle getByteBufferSliceOffsetsMethodHandle() {
- try {
- Lookup lookup = MethodHandles.lookup();
- MethodType type = MethodType.methodType(ByteBuffer.class, int.class, int.class);
- return lookup.findVirtual(ByteBuffer.class, "slice", type);
- } catch (Exception ignore) {
- return null;
- }
- }
-
- @SuppressWarnings("JavaLangInvokeHandleSignature")
- static MethodHandle getByteBufferPutOffsetsMethodHandle() {
- try {
- Lookup lookup = MethodHandles.lookup();
- MethodType type = MethodType.methodType(ByteBuffer.class, int.class, ByteBuffer.class, int.class, int.class);
- return lookup.findVirtual(ByteBuffer.class, "put", type);
- } catch (Exception ignore) {
- return null;
- }
- }
-
- @SuppressWarnings({"unchecked", "unused"})
- static Drop noOpDrop() {
- return (Drop) NO_OP_DROP;
- }
-
- static VarHandle findVarHandle(Lookup lookup, Class> recv, String name, Class> type) {
- try {
- return lookup.findVarHandle(recv, name, type);
- } catch (Exception e) {
- throw new ExceptionInInitializerError(e);
- }
- }
-
- @SuppressWarnings("unchecked")
- static Drop convert(Drop drop) {
- return (Drop) drop;
- }
-
- static void copyToViaReverseCursor(Buffer src, int srcPos, Buffer dest, int destPos, int length) {
- // Iterate in reverse to account for src and dest buffer overlap.
- var itr = src.openReverseCursor(srcPos + length - 1, length);
- ByteOrder prevOrder = dest.order();
- // We read longs in BE, in reverse, so they need to be flipped for writing.
- dest.order(ByteOrder.LITTLE_ENDIAN);
- try {
- while (itr.readLong()) {
- long val = itr.getLong();
- length -= Long.BYTES;
- dest.setLong(destPos + length, val);
- }
- while (itr.readByte()) {
- dest.setByte(destPos + --length, itr.getByte());
- }
- } finally {
- dest.order(prevOrder);
- }
- }
-
- /**
- * The ByteBuffer slice-with-offset-and-length method is only available from Java 13 and onwards, but we need to
- * support Java 11.
- */
- static ByteBuffer bbslice(ByteBuffer buffer, int fromOffset, int length) {
- if (BB_SLICE_OFFSETS != null) {
- return bbsliceJdk13(buffer, fromOffset, length);
- }
- return bbsliceFallback(buffer, fromOffset, length);
- }
-
- private static ByteBuffer bbsliceJdk13(ByteBuffer buffer, int fromOffset, int length) {
- try {
- return (ByteBuffer) BB_SLICE_OFFSETS.invokeExact(buffer, fromOffset, length);
- } catch (RuntimeException re) {
- throw re;
- } catch (Throwable throwable) {
- throw new LinkageError("Unexpected exception from ByteBuffer.slice(int,int).", throwable);
- }
- }
-
- private static ByteBuffer bbsliceFallback(ByteBuffer buffer, int fromOffset, int length) {
- if (fromOffset < 0) {
- throw new IndexOutOfBoundsException("The fromOffset must be positive: " + fromOffset + '.');
- }
- int newLimit = fromOffset + length;
- if (newLimit > buffer.capacity()) {
- throw new IndexOutOfBoundsException(
- "The limit of " + newLimit + " would be greater than capacity: " + buffer.capacity() + '.');
- }
- try {
- return buffer.position(fromOffset).limit(newLimit).slice();
- } finally {
- buffer.clear();
- }
- }
-
- /**
- * The ByteBuffer put-buffer-with-offset-and-length method is not available in Java 11.
- */
- static void bbput(ByteBuffer dest, int destPos, ByteBuffer src, int srcPos, int length) {
- if (BB_PUT_OFFSETS != null) {
- bbputJdk16(dest, destPos, src, srcPos, length);
- } else {
- bbputFallback(dest, destPos, src, srcPos, length);
- }
- }
-
- private static void bbputJdk16(ByteBuffer dest, int destPos, ByteBuffer src, int srcPos, int length) {
- try {
- @SuppressWarnings("unused") // We need to cast the return type in order to invokeExact.
- ByteBuffer ignore = (ByteBuffer) BB_PUT_OFFSETS.invokeExact(dest, destPos, src, srcPos, length);
- } catch (RuntimeException re) {
- throw re;
- } catch (Throwable throwable) {
- throw new LinkageError("Unexpected exception from ByteBuffer.put(int,ByteBuffer,int,int).", throwable);
- }
- }
-
- private static void bbputFallback(ByteBuffer dest, int destPos, ByteBuffer src, int srcPos, int length) {
- dest.position(destPos).put(bbslice(src, srcPos, length));
- }
-
- static BufferClosedException bufferIsClosed(Buffer buffer) {
- return new BufferClosedException("This buffer is closed: " + buffer);
- }
-
- static BufferReadOnlyException bufferIsReadOnly(Buffer buffer) {
- return new BufferReadOnlyException("This buffer is read-only: " + buffer);
- }
-
- static T acquire(ResourceSupport, ?> obj) {
- return ResourceSupport.acquire(obj);
- }
-
- static boolean isOwned(ResourceSupport, ?> obj) {
- return ResourceSupport.isOwned(obj);
- }
-
- static int countBorrows(ResourceSupport, ?> obj) {
- return ResourceSupport.countBorrows(obj);
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/TransferSend.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/TransferSend.java
deleted file mode 100644
index 0e806a1..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/internal/TransferSend.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.internal;
-
-import io.netty.buffer.api.Drop;
-import io.netty.buffer.api.Owned;
-import io.netty.buffer.api.Resource;
-import io.netty.buffer.api.Send;
-
-import java.lang.invoke.VarHandle;
-
-import static java.lang.invoke.MethodHandles.lookup;
-
-public class TransferSend, T extends ResourceSupport> implements Send {
- private static final VarHandle RECEIVED = Statics.findVarHandle(lookup(), TransferSend.class, "received", boolean.class);
- private final Owned outgoing;
- private final Drop drop;
- private final Class> concreteType;
- @SuppressWarnings("unused")
- private volatile boolean received; // Accessed via VarHandle
-
- public TransferSend(Owned outgoing, Drop drop, Class> concreteType) {
- this.outgoing = outgoing;
- this.drop = drop;
- this.concreteType = concreteType;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public I receive() {
- gateReception();
- var copy = outgoing.transferOwnership(drop);
- drop.attach(copy);
- return (I) copy;
- }
-
- private void gateReception() {
- if ((boolean) RECEIVED.getAndSet(this, true)) {
- throw new IllegalStateException("This object has already been received.");
- }
- }
-
- @Override
- public boolean referentIsInstanceOf(Class> cls) {
- return cls.isAssignableFrom(concreteType);
- }
-
- @Override
- public void discard() {
- if (!(boolean) RECEIVED.getAndSet(this, true)) {
- var copy = outgoing.transferOwnership(drop);
- drop.attach(copy);
- copy.close();
- }
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/package-info.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/package-info.java
deleted file mode 100644
index dcf90af..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/internal/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * Internal implementation details that can be shared among Buffer implementations.
- */
-package io.netty.buffer.api.internal;
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/package-info.java b/buffer-api/src/main/java/io/netty/buffer/api/package-info.java
deleted file mode 100644
index e38b44c..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2020 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * Incubating {@code Buffer} API, as a proposed alternative to {@code ByteBuf}.
- */
-package io.netty.buffer.api;
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/BufferAllocatorMetric.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/BufferAllocatorMetric.java
deleted file mode 100644
index eeaa676..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/BufferAllocatorMetric.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import io.netty.buffer.api.BufferAllocator;
-
-public interface BufferAllocatorMetric {
- /**
- * Returns the number of bytes of heap memory used by a {@link BufferAllocator} or {@code -1} if unknown.
- */
- long usedMemory();
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/BufferAllocatorMetricProvider.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/BufferAllocatorMetricProvider.java
deleted file mode 100644
index 1b19e73..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/BufferAllocatorMetricProvider.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import io.netty.buffer.api.BufferAllocator;
-
-public interface BufferAllocatorMetricProvider {
-
- /**
- * Returns a {@link BufferAllocatorMetric} for a {@link BufferAllocator}.
- */
- BufferAllocatorMetric metric();
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/LongLongHashMap.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/LongLongHashMap.java
deleted file mode 100644
index 35e3a3b..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/LongLongHashMap.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-/**
- * Internal primitive map implementation that is specifically optimised for the runs availability map use case in
- * {@link PoolChunk}.
- */
-final class LongLongHashMap {
- private static final int MASK_TEMPLATE = ~1;
- private int mask;
- private long[] array;
- private int maxProbe;
- private long zeroVal;
- private final long emptyVal;
-
- LongLongHashMap(long emptyVal) {
- this.emptyVal = emptyVal;
- zeroVal = emptyVal;
- int initialSize = 32;
- array = new long[initialSize];
- mask = initialSize - 1;
- computeMaskAndProbe();
- }
-
- public long put(long key, long value) {
- if (key == 0) {
- long prev = zeroVal;
- zeroVal = value;
- return prev;
- }
-
- for (;;) {
- int index = index(key);
- for (int i = 0; i < maxProbe; i++) {
- long existing = array[index];
- if (existing == key || existing == 0) {
- long prev = existing == 0? emptyVal : array[index + 1];
- array[index] = key;
- array[index + 1] = value;
- for (; i < maxProbe; i++) { // Nerf any existing misplaced entries.
- index = index + 2 & mask;
- if (array[index] == key) {
- array[index] = 0;
- prev = array[index + 1];
- break;
- }
- }
- return prev;
- }
- index = index + 2 & mask;
- }
- expand(); // Grow array and re-hash.
- }
- }
-
- public void remove(long key) {
- if (key == 0) {
- zeroVal = emptyVal;
- return;
- }
- int index = index(key);
- for (int i = 0; i < maxProbe; i++) {
- long existing = array[index];
- if (existing == key) {
- array[index] = 0;
- break;
- }
- index = index + 2 & mask;
- }
- }
-
- public long get(long key) {
- if (key == 0) {
- return zeroVal;
- }
- int index = index(key);
- for (int i = 0; i < maxProbe; i++) {
- long existing = array[index];
- if (existing == key) {
- return array[index + 1];
- }
- index = index + 2 & mask;
- }
- return emptyVal;
- }
-
- private int index(long key) {
- // Hash with murmur64, and mask.
- key ^= key >>> 33;
- key *= 0xff51afd7ed558ccdL;
- key ^= key >>> 33;
- key *= 0xc4ceb9fe1a85ec53L;
- key ^= key >>> 33;
- return (int) key & mask;
- }
-
- private void expand() {
- long[] prev = array;
- array = new long[prev.length * 2];
- computeMaskAndProbe();
- for (int i = 0; i < prev.length; i += 2) {
- long key = prev[i];
- if (key != 0) {
- long val = prev[i + 1];
- put(key, val);
- }
- }
- }
-
- private void computeMaskAndProbe() {
- int length = array.length;
- mask = length - 1 & MASK_TEMPLATE;
- maxProbe = (int) Math.log(length);
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/LongPriorityQueue.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/LongPriorityQueue.java
deleted file mode 100644
index 2d9aa54..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/LongPriorityQueue.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import java.util.Arrays;
-
-/**
- * Internal primitive priority queue, used by {@link PoolChunk}.
- * The implementation is based on the binary heap, as described in Algorithms by Sedgewick and Wayne.
- */
-final class LongPriorityQueue {
- public static final int NO_VALUE = -1;
- private long[] array = new long[9];
- private int size;
-
- public void offer(long handle) {
- if (handle == NO_VALUE) {
- throw new IllegalArgumentException("The NO_VALUE (" + NO_VALUE + ") cannot be added to the queue.");
- }
- size++;
- if (size == array.length) {
- // Grow queue capacity.
- array = Arrays.copyOf(array, 1 + (array.length - 1) * 2);
- }
- array[size] = handle;
- lift(size);
- }
-
- public void remove(long value) {
- for (int i = 1; i <= size; i++) {
- if (array[i] == value) {
- array[i] = array[size--];
- lift(i);
- sink(i);
- return;
- }
- }
- }
-
- public long peek() {
- if (size == 0) {
- return NO_VALUE;
- }
- return array[1];
- }
-
- public long poll() {
- if (size == 0) {
- return NO_VALUE;
- }
- long val = array[1];
- array[1] = array[size];
- array[size] = 0;
- size--;
- sink(1);
- return val;
- }
-
- public boolean isEmpty() {
- return size == 0;
- }
-
- private void lift(int index) {
- int parentIndex;
- while (index > 1 && subord(parentIndex = index >> 1, index)) {
- swap(index, parentIndex);
- index = parentIndex;
- }
- }
-
- private void sink(int index) {
- int child;
- while ((child = index << 1) <= size) {
- if (child < size && subord(child, child + 1)) {
- child++;
- }
- if (!subord(index, child)) {
- break;
- }
- swap(index, child);
- index = child;
- }
- }
-
- private boolean subord(int a, int b) {
- return array[a] > array[b];
- }
-
- private void swap(int a, int b) {
- long value = array[a];
- array[a] = array[b];
- array[b] = value;
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolArena.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolArena.java
deleted file mode 100644
index fa4cc90..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolArena.java
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import io.netty.buffer.api.AllocatorControl;
-import io.netty.buffer.api.Buffer;
-import io.netty.buffer.api.MemoryManager;
-import io.netty.util.internal.StringUtil;
-
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.LongAdder;
-
-import static io.netty.buffer.api.pool.PoolChunk.isSubpage;
-import static java.lang.Math.max;
-
-class PoolArena extends SizeClasses implements PoolArenaMetric, AllocatorControl {
- private static final VarHandle SUBPAGE_ARRAY = MethodHandles.arrayElementVarHandle(PoolSubpage[].class);
- enum SizeClass {
- Small,
- Normal
- }
-
- final PooledBufferAllocator parent;
- final MemoryManager manager;
-
- final int numSmallSubpagePools;
- final int directMemoryCacheAlignment;
- private final PoolSubpage[] smallSubpagePools;
-
- private final PoolChunkList q050;
- private final PoolChunkList q025;
- private final PoolChunkList q000;
- private final PoolChunkList qInit;
- private final PoolChunkList q075;
- private final PoolChunkList q100;
-
- private final List chunkListMetrics;
-
- // Metrics for allocations and deallocations
- private long allocationsNormal;
-
- // We need to use the LongAdder here as this is not guarded via synchronized block.
- private final LongAdder allocationsSmall = new LongAdder();
- private final LongAdder allocationsHuge = new LongAdder();
- private final LongAdder activeBytesHuge = new LongAdder();
-
- private long deallocationsSmall;
- private long deallocationsNormal;
-
- // We need to use the LongAdder here as this is not guarded via synchronized block.
- private final LongAdder deallocationsHuge = new LongAdder();
-
- // Number of thread caches backed by this arena.
- final AtomicInteger numThreadCaches = new AtomicInteger();
-
- protected PoolArena(PooledBufferAllocator parent, MemoryManager manager, int pageSize,
- int pageShifts, int chunkSize, int cacheAlignment) {
- super(pageSize, pageShifts, chunkSize, cacheAlignment);
- this.parent = parent;
- this.manager = manager;
- directMemoryCacheAlignment = cacheAlignment;
-
- numSmallSubpagePools = nSubpages;
- smallSubpagePools = newSubpagePoolArray(numSmallSubpagePools);
-
- q100 = new PoolChunkList(this, null, 100, Integer.MAX_VALUE, chunkSize);
- q075 = new PoolChunkList(this, q100, 75, 100, chunkSize);
- q050 = new PoolChunkList(this, q075, 50, 100, chunkSize);
- q025 = new PoolChunkList(this, q050, 25, 75, chunkSize);
- q000 = new PoolChunkList(this, q025, 1, 50, chunkSize);
- qInit = new PoolChunkList(this, q000, Integer.MIN_VALUE, 25, chunkSize);
-
- q100.prevList(q075);
- q075.prevList(q050);
- q050.prevList(q025);
- q025.prevList(q000);
- q000.prevList(null);
- qInit.prevList(qInit);
-
- chunkListMetrics = List.of(qInit, q000, q025, q050, q075, q100);
- }
-
- private static PoolSubpage newSubpagePoolHead() {
- PoolSubpage head = new PoolSubpage();
- head.prev = head;
- head.next = head;
- return head;
- }
-
- private static PoolSubpage[] newSubpagePoolArray(int size) {
- return new PoolSubpage[size];
- }
-
- UntetheredMemory allocate(PooledAllocatorControl control, PoolThreadCache cache, int size) {
- final int sizeIdx = size2SizeIdx(size);
-
- if (sizeIdx <= smallMaxSizeIdx) {
- return tcacheAllocateSmall(control, cache, size, sizeIdx);
- } else if (sizeIdx < nSizes) {
- return tcacheAllocateNormal(control, cache, size, sizeIdx);
- } else {
- int normCapacity = directMemoryCacheAlignment > 0
- ? normalizeSize(size) : size;
- // Huge allocations are never served via the cache so just call allocateHuge
- return allocateHuge(normCapacity);
- }
- }
-
- private UntetheredMemory tcacheAllocateSmall(PooledAllocatorControl control, PoolThreadCache cache, final int size,
- final int sizeIdx) {
- UntetheredMemory memory = cache.allocateSmall(control, size, sizeIdx);
- if (memory != null) {
- // was able to allocate out of the cache so move on
- return memory;
- }
-
- /*
- * Synchronize on the head. This is needed as {@link PoolChunk#allocateSubpage(int)} and
- * {@link PoolChunk#free(long)} may modify the doubly linked list as well.
- */
- PoolSubpage head = findSubpagePoolHead(sizeIdx);
- final boolean needsNormalAllocation;
- synchronized (head) {
- final PoolSubpage s = head.next;
- needsNormalAllocation = s == head;
- if (!needsNormalAllocation) {
- assert s.doNotDestroy && s.elemSize == sizeIdx2size(sizeIdx);
- long handle = s.allocate();
- assert handle >= 0;
- memory = s.chunk.allocateBufferWithSubpage(handle, size, cache, control);
- }
- }
-
- if (needsNormalAllocation) {
- synchronized (this) {
- memory = allocateNormal(size, sizeIdx, cache, control);
- }
- }
-
- incSmallAllocation();
- return memory;
- }
-
- private UntetheredMemory tcacheAllocateNormal(
- PooledAllocatorControl control, PoolThreadCache cache, int size, int sizeIdx) {
- UntetheredMemory memory = cache.allocateNormal(this, control, size, sizeIdx);
- if (memory != null) {
- // was able to allocate out of the cache so move on
- return memory;
- }
- synchronized (this) {
- memory = allocateNormal(size, sizeIdx, cache, control);
- allocationsNormal++;
- }
- return memory;
- }
-
- // Method must be called inside synchronized(this) { ... } block
- private UntetheredMemory allocateNormal(
- int size, int sizeIdx, PoolThreadCache threadCache, PooledAllocatorControl control) {
- UntetheredMemory memory = q050.allocate(size, sizeIdx, threadCache, control);
- if (memory != null) {
- return memory;
- }
- memory = q025.allocate(size, sizeIdx, threadCache, control);
- if (memory != null) {
- return memory;
- }
- memory = q000.allocate(size, sizeIdx, threadCache, control);
- if (memory != null) {
- return memory;
- }
- memory = qInit.allocate(size, sizeIdx, threadCache, control);
- if (memory != null) {
- return memory;
- }
- memory = q075.allocate(size, sizeIdx, threadCache, control);
- if (memory != null) {
- return memory;
- }
-
- // Add a new chunk.
- PoolChunk c = newChunk(pageSize, nPSizes, pageShifts, chunkSize);
- memory = c.allocate(size, sizeIdx, threadCache, control);
- assert memory != null;
- qInit.add(c);
- return memory;
- }
-
- private void incSmallAllocation() {
- allocationsSmall.increment();
- }
-
- private UntetheredMemory allocateHuge(int size) {
- activeBytesHuge.add(size);
- allocationsHuge.increment();
- return new UnpooledUnthetheredMemory(parent, manager, size);
- }
-
- void free(PoolChunk chunk, long handle, int normCapacity, PoolThreadCache cache) {
- SizeClass sizeClass = sizeClass(handle);
- if (cache != null && cache.add(this, chunk, handle, normCapacity, sizeClass)) {
- // cached so not free it.
- return;
- }
- freeChunk(chunk, handle, normCapacity, sizeClass);
- }
-
- private static SizeClass sizeClass(long handle) {
- return isSubpage(handle) ? SizeClass.Small : SizeClass.Normal;
- }
-
- void freeChunk(PoolChunk chunk, long handle, int normCapacity, SizeClass sizeClass) {
- final boolean destroyChunk;
- synchronized (this) {
- if (sizeClass == SizeClass.Normal) {
- ++deallocationsNormal;
- } else if (sizeClass == SizeClass.Small) {
- ++deallocationsSmall;
- } else {
- throw new AssertionError("Unexpected size class: " + sizeClass);
- }
- destroyChunk = !chunk.parent.free(chunk, handle, normCapacity);
- }
- if (destroyChunk) {
- // destroyChunk not need to be called while holding the synchronized lock.
- chunk.destroy();
- }
- }
-
- PoolSubpage findSubpagePoolHead(int sizeIdx) {
- PoolSubpage head = (PoolSubpage) SUBPAGE_ARRAY.getVolatile(smallSubpagePools, sizeIdx);
- if (head == null) {
- head = newSubpagePoolHead();
- if (!SUBPAGE_ARRAY.compareAndSet(smallSubpagePools, sizeIdx, null, head)) {
- // We lost the race. Read the winning value.
- head = (PoolSubpage) SUBPAGE_ARRAY.getVolatile(smallSubpagePools, sizeIdx);
- }
- }
- return head;
- }
-
- @Override
- public UntetheredMemory allocateUntethered(Buffer originator, int size) {
- throw new AssertionError("PoolChunk base buffers should never need to reallocate.");
- }
-
- @Override
- public void recoverMemory(Object memory) {
- // This means we've lost all strong references to a PoolChunk.
- // Probably means we don't need it anymore, so just free its memory.
- manager.discardRecoverableMemory(memory);
- }
-
- @Override
- public int numThreadCaches() {
- return numThreadCaches.get();
- }
-
- @Override
- public int numSmallSubpages() {
- return smallSubpagePools.length;
- }
-
- @Override
- public int numChunkLists() {
- return chunkListMetrics.size();
- }
-
- @Override
- public List smallSubpages() {
- return subPageMetricList(smallSubpagePools);
- }
-
- @Override
- public List chunkLists() {
- return chunkListMetrics;
- }
-
- private static List subPageMetricList(PoolSubpage[] pages) {
- List metrics = new ArrayList<>();
- for (int i = 0, len = pages.length; i < len; i++) {
- PoolSubpage head = (PoolSubpage) SUBPAGE_ARRAY.getVolatile(pages, i);
- if (head == null || head.next == head) {
- continue;
- }
- PoolSubpage s = head.next;
- do {
- metrics.add(s);
- s = s.next;
- } while (s != head);
- }
- return metrics;
- }
-
- @Override
- public long numAllocations() {
- final long allocsNormal;
- synchronized (this) {
- allocsNormal = allocationsNormal;
- }
-
- return allocationsSmall.longValue() + allocsNormal + allocationsHuge.longValue();
- }
-
- @Override
- public long numSmallAllocations() {
- return allocationsSmall.longValue();
- }
-
- @Override
- public synchronized long numNormalAllocations() {
- return allocationsNormal;
- }
-
- @Override
- public long numDeallocations() {
- final long deallocs;
- synchronized (this) {
- deallocs = deallocationsSmall + deallocationsNormal;
- }
- return deallocs + deallocationsHuge.longValue();
- }
-
- @Override
- public synchronized long numSmallDeallocations() {
- return deallocationsSmall;
- }
-
- @Override
- public synchronized long numNormalDeallocations() {
- return deallocationsNormal;
- }
-
- @Override
- public long numHugeAllocations() {
- return allocationsHuge.longValue();
- }
-
- @Override
- public long numHugeDeallocations() {
- return deallocationsHuge.longValue();
- }
-
- @Override
- public long numActiveAllocations() {
- long val = allocationsSmall.longValue() + allocationsHuge.longValue()
- - deallocationsHuge.longValue();
- synchronized (this) {
- val += allocationsNormal - (deallocationsSmall + deallocationsNormal);
- }
- return max(val, 0);
- }
-
- @Override
- public long numActiveSmallAllocations() {
- return max(numSmallAllocations() - numSmallDeallocations(), 0);
- }
-
- @Override
- public long numActiveNormalAllocations() {
- final long val;
- synchronized (this) {
- val = allocationsNormal - deallocationsNormal;
- }
- return max(val, 0);
- }
-
- @Override
- public long numActiveHugeAllocations() {
- return max(numHugeAllocations() - numHugeDeallocations(), 0);
- }
-
- @Override
- public long numActiveBytes() {
- long val = activeBytesHuge.longValue();
- synchronized (this) {
- for (int i = 0; i < chunkListMetrics.size(); i++) {
- for (PoolChunkMetric m: chunkListMetrics.get(i)) {
- val += m.chunkSize();
- }
- }
- }
- return max(0, val);
- }
-
- protected final PoolChunk newChunk(int pageSize, int maxPageIdx, int pageShifts, int chunkSize) {
- return new PoolChunk(this, pageSize, pageShifts, chunkSize, maxPageIdx);
- }
-
- @Override
- public synchronized String toString() {
- StringBuilder buf = new StringBuilder()
- .append("Chunk(s) at 0~25%:")
- .append(StringUtil.NEWLINE)
- .append(qInit)
- .append(StringUtil.NEWLINE)
- .append("Chunk(s) at 0~50%:")
- .append(StringUtil.NEWLINE)
- .append(q000)
- .append(StringUtil.NEWLINE)
- .append("Chunk(s) at 25~75%:")
- .append(StringUtil.NEWLINE)
- .append(q025)
- .append(StringUtil.NEWLINE)
- .append("Chunk(s) at 50~100%:")
- .append(StringUtil.NEWLINE)
- .append(q050)
- .append(StringUtil.NEWLINE)
- .append("Chunk(s) at 75~100%:")
- .append(StringUtil.NEWLINE)
- .append(q075)
- .append(StringUtil.NEWLINE)
- .append("Chunk(s) at 100%:")
- .append(StringUtil.NEWLINE)
- .append(q100)
- .append(StringUtil.NEWLINE)
- .append("small subpages:");
- appendPoolSubPages(buf, smallSubpagePools);
- buf.append(StringUtil.NEWLINE);
-
- return buf.toString();
- }
-
- private static void appendPoolSubPages(StringBuilder buf, PoolSubpage[] subpages) {
- for (int i = 0; i < subpages.length; i ++) {
- PoolSubpage head = (PoolSubpage) SUBPAGE_ARRAY.getVolatile(subpages, i);
- if (head == null || head.next == head) {
- continue;
- }
-
- buf.append(StringUtil.NEWLINE)
- .append(i)
- .append(": ");
- PoolSubpage s = head.next;
- do {
- buf.append(s);
- s = s.next;
- } while (s != head);
- }
- }
-
- public void close() {
- for (int i = 0, len = smallSubpagePools.length; i < len; i++) {
- PoolSubpage page = (PoolSubpage) SUBPAGE_ARRAY.getVolatile(smallSubpagePools, i);
- if (page != null) {
- page.destroy();
- }
- }
- for (PoolChunkList list : new PoolChunkList[] {qInit, q000, q025, q050, q100}) {
- list.destroy();
- }
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolArenaMetric.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolArenaMetric.java
deleted file mode 100644
index 754dd7d..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolArenaMetric.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import java.util.List;
-
-/**
- * Expose metrics for an arena.
- */
-public interface PoolArenaMetric extends SizeClassesMetric {
-
- /**
- * Returns the number of thread caches backed by this arena.
- */
- int numThreadCaches();
-
- /**
- * Returns the number of small sub-pages for the arena.
- */
- int numSmallSubpages();
-
- /**
- * Returns the number of chunk lists for the arena.
- */
- int numChunkLists();
-
- /**
- * Returns an unmodifiable {@link List} which holds {@link PoolSubpageMetric}s for small sub-pages.
- */
- List smallSubpages();
-
- /**
- * Returns an unmodifiable {@link List} which holds {@link PoolChunkListMetric}s.
- */
- List chunkLists();
-
- /**
- * Return the number of allocations done via the arena. This includes all sizes.
- */
- long numAllocations();
-
- /**
- * Return the number of small allocations done via the arena.
- */
- long numSmallAllocations();
-
- /**
- * Return the number of normal allocations done via the arena.
- */
- long numNormalAllocations();
-
- /**
- * Return the number of huge allocations done via the arena.
- */
- long numHugeAllocations();
-
- /**
- * Return the number of deallocations done via the arena. This includes all sizes.
- */
- long numDeallocations();
-
- /**
- * Return the number of small deallocations done via the arena.
- */
- long numSmallDeallocations();
-
- /**
- * Return the number of normal deallocations done via the arena.
- */
- long numNormalDeallocations();
-
- /**
- * Return the number of huge deallocations done via the arena.
- */
- long numHugeDeallocations();
-
- /**
- * Return the number of currently active allocations.
- */
- long numActiveAllocations();
-
- /**
- * Return the number of currently active small allocations.
- */
- long numActiveSmallAllocations();
-
- /**
- * Return the number of currently active normal allocations.
- */
- long numActiveNormalAllocations();
-
- /**
- * Return the number of currently active huge allocations.
- */
- long numActiveHugeAllocations();
-
- /**
- * Return the number of active bytes that are currently allocated by the arena.
- */
- long numActiveBytes();
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunk.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunk.java
deleted file mode 100644
index 7b98ade..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunk.java
+++ /dev/null
@@ -1,662 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import io.netty.buffer.api.internal.CleanerDrop;
-import io.netty.buffer.api.AllocatorControl.UntetheredMemory;
-import io.netty.buffer.api.Buffer;
-import io.netty.buffer.api.Drop;
-import io.netty.buffer.api.MemoryManager;
-import io.netty.buffer.api.internal.ArcDrop;
-import io.netty.buffer.api.internal.Statics;
-
-import java.util.PriorityQueue;
-
-/**
- * Description of algorithm for PageRun/PoolSubpage allocation from PoolChunk
- *
- * Notation: The following terms are important to understand the code
- * > page - a page is the smallest unit of memory chunk that can be allocated
- * > run - a run is a collection of pages
- * > chunk - a chunk is a collection of runs
- * > in this code chunkSize = maxPages * pageSize
- *
- * To begin we allocate a byte array of size = chunkSize
- * Whenever a ByteBuf of given size needs to be created we search for the first position
- * in the byte array that has enough empty space to accommodate the requested size and
- * return a (long) handle that encodes this offset information, (this memory segment is then
- * marked as reserved, so it is always used by exactly one ByteBuf and no more)
- *
- * For simplicity all sizes are normalized according to {@link PoolArena#size2SizeIdx(int)} method.
- * This ensures that when we request for memory segments of size > pageSize the normalizedCapacity
- * equals the next nearest size in {@link SizeClasses}.
- *
- *
- * A chunk has the following layout:
- *
- * /-----------------\
- * | run |
- * | |
- * | |
- * |-----------------|
- * | run |
- * | |
- * |-----------------|
- * | unalloctated |
- * | (freed) |
- * | |
- * |-----------------|
- * | subpage |
- * |-----------------|
- * | unallocated |
- * | (freed) |
- * | ... |
- * | ... |
- * | ... |
- * | |
- * | |
- * | |
- * \-----------------/
- *
- *
- * handle:
- * -------
- * a handle is a long number, the bit layout of a run looks like:
- *
- * oooooooo ooooooos ssssssss ssssssue bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb
- *
- * o: runOffset (page offset in the chunk), 15bit
- * s: size (number of pages) of this run, 15bit
- * u: isUsed?, 1bit
- * e: isSubpage?, 1bit
- * b: bitmapIdx of subpage, zero if it's not subpage, 32bit
- *
- * runsAvailMap:
- * ------
- * a map which manages all runs (used and not in used).
- * For each run, the first runOffset and last runOffset are stored in runsAvailMap.
- * key: runOffset
- * value: handle
- *
- * runsAvail:
- * ----------
- * an array of {@link PriorityQueue}.
- * Each queue manages same size of runs.
- * Runs are sorted by offset, so that we always allocate runs with smaller offset.
- *
- *
- * Algorithm:
- * ----------
- *
- * As we allocate runs, we update values stored in runsAvailMap and runsAvail so that the property is maintained.
- *
- * Initialization -
- * In the beginning we store the initial run which is the whole chunk.
- * The initial run:
- * runOffset = 0
- * size = chunkSize
- * isUsed = no
- * isSubpage = no
- * bitmapIdx = 0
- *
- *
- * Algorithm: [allocateRun(size)]
- * ----------
- * 1) find the first avail run using in runsAvails according to size
- * 2) if pages of run is larger than request pages then split it, and save the tailing run
- * for later using
- *
- * Algorithm: [allocateSubpage(size)]
- * ----------
- * 1) find a not full subpage according to size.
- * if it already exists just return, otherwise allocate a new PoolSubpage and call init()
- * note that this subpage object is added to subpagesPool in the PoolArena when we init() it
- * 2) call subpage.allocate()
- *
- * Algorithm: [free(handle, length, nioBuffer)]
- * ----------
- * 1) if it is a subpage, return the slab back into this subpage
- * 2) if the subpage is not used, or it is a run, then start free this run
- * 3) merge continuous avail runs
- * 4) save the merged run
- *
- */
-final class PoolChunk implements PoolChunkMetric {
- private static final int SIZE_BIT_LENGTH = 15;
- private static final int INUSED_BIT_LENGTH = 1;
- private static final int SUBPAGE_BIT_LENGTH = 1;
- private static final int BITMAP_IDX_BIT_LENGTH = 32;
-
- static final int IS_SUBPAGE_SHIFT = BITMAP_IDX_BIT_LENGTH;
- static final int IS_USED_SHIFT = SUBPAGE_BIT_LENGTH + IS_SUBPAGE_SHIFT;
- static final int SIZE_SHIFT = INUSED_BIT_LENGTH + IS_USED_SHIFT;
- static final int RUN_OFFSET_SHIFT = SIZE_BIT_LENGTH + SIZE_SHIFT;
-
- final PoolArena arena;
- final Buffer base; // The buffer that is the source of the memory. Closing it will free the memory.
- final Object memory;
- final Drop baseDrop; // An ArcDrop that manages references to the base Buffer.
-
- /**
- * store the first page and last page of each avail run
- */
- private final LongLongHashMap runsAvailMap;
-
- /**
- * manage all avail runs
- */
- private final LongPriorityQueue[] runsAvail;
-
- /**
- * manage all subpages in this chunk
- */
- private final PoolSubpage[] subpages;
-
- private final int pageSize;
- private final int pageShifts;
- private final int chunkSize;
-
- int freeBytes;
-
- PoolChunkList parent;
- PoolChunk prev;
- PoolChunk next;
-
- PoolChunk(PoolArena arena, int pageSize, int pageShifts, int chunkSize,
- int maxPageIdx) {
- this.arena = arena;
- MemoryManager manager = arena.manager;
- base = manager.allocateShared(arena, chunkSize, manager.drop(), Statics.CLEANER);
- memory = manager.unwrapRecoverableMemory(base);
- baseDrop = ArcDrop.wrap(Buffer::close);
- this.pageSize = pageSize;
- this.pageShifts = pageShifts;
- this.chunkSize = chunkSize;
- freeBytes = chunkSize;
-
- runsAvail = newRunsAvailqueueArray(maxPageIdx);
- runsAvailMap = new LongLongHashMap(-1);
- subpages = new PoolSubpage[chunkSize >> pageShifts];
-
- //insert initial run, offset = 0, pages = chunkSize / pageSize
- int pages = chunkSize >> pageShifts;
- long initHandle = (long) pages << SIZE_SHIFT;
- insertAvailRun(0, pages, initHandle);
- }
-
- private static LongPriorityQueue[] newRunsAvailqueueArray(int size) {
- LongPriorityQueue[] queueArray = new LongPriorityQueue[size];
- for (int i = 0; i < queueArray.length; i++) {
- queueArray[i] = new LongPriorityQueue();
- }
- return queueArray;
- }
-
- private void insertAvailRun(int runOffset, int pages, long handle) {
- int pageIdxFloor = arena.pages2pageIdxFloor(pages);
- LongPriorityQueue queue = runsAvail[pageIdxFloor];
- queue.offer(handle);
-
- //insert first page of run
- insertAvailRun0(runOffset, handle);
- if (pages > 1) {
- //insert last page of run
- insertAvailRun0(lastPage(runOffset, pages), handle);
- }
- }
-
- private void insertAvailRun0(int runOffset, long handle) {
- long pre = runsAvailMap.put(runOffset, handle);
- assert pre == -1;
- }
-
- private void removeAvailRun(long handle) {
- int pageIdxFloor = arena.pages2pageIdxFloor(runPages(handle));
- LongPriorityQueue queue = runsAvail[pageIdxFloor];
- removeAvailRun(queue, handle);
- }
-
- private void removeAvailRun(LongPriorityQueue queue, long handle) {
- queue.remove(handle);
-
- int runOffset = runOffset(handle);
- int pages = runPages(handle);
- //remove first page of run
- runsAvailMap.remove(runOffset);
- if (pages > 1) {
- //remove last page of run
- runsAvailMap.remove(lastPage(runOffset, pages));
- }
- }
-
- private static int lastPage(int runOffset, int pages) {
- return runOffset + pages - 1;
- }
-
- private long getAvailRunByOffset(int runOffset) {
- return runsAvailMap.get(runOffset);
- }
-
- @Override
- public int usage() {
- final int freeBytes;
- synchronized (arena) {
- freeBytes = this.freeBytes;
- }
- return usage(freeBytes);
- }
-
- private int usage(int freeBytes) {
- if (freeBytes == 0) {
- return 100;
- }
-
- int freePercentage = (int) (freeBytes * 100L / chunkSize);
- if (freePercentage == 0) {
- return 99;
- }
- return 100 - freePercentage;
- }
-
- UntetheredMemory allocate(int size, int sizeIdx, PoolThreadCache cache, PooledAllocatorControl control) {
- final long handle;
- if (sizeIdx <= arena.smallMaxSizeIdx) {
- // small
- handle = allocateSubpage(sizeIdx);
- if (handle < 0) {
- return null;
- }
- assert isSubpage(handle);
- } else {
- // normal
- // runSize must be multiple of pageSize
- int runSize = arena.sizeIdx2size(sizeIdx);
- handle = allocateRun(runSize);
- if (handle < 0) {
- return null;
- }
- }
-
- return allocateBuffer(handle, size, cache, control);
- }
-
- private long allocateRun(int runSize) {
- int pages = runSize >> pageShifts;
- int pageIdx = arena.pages2pageIdx(pages);
-
- synchronized (runsAvail) {
- //find first queue which has at least one big enough run
- int queueIdx = runFirstBestFit(pageIdx);
- if (queueIdx == -1) {
- return -1;
- }
-
- //get run with min offset in this queue
- LongPriorityQueue queue = runsAvail[queueIdx];
- long handle = queue.poll();
-
- assert handle != LongPriorityQueue.NO_VALUE && !isUsed(handle) : "invalid handle: " + handle;
-
- removeAvailRun(queue, handle);
-
- if (handle != -1) {
- handle = splitLargeRun(handle, pages);
- }
-
- freeBytes -= runSize(pageShifts, handle);
- return handle;
- }
- }
-
- private int calculateRunSize(int sizeIdx) {
- int maxElements = 1 << pageShifts - SizeClasses.LOG2_QUANTUM;
- int runSize = 0;
- int nElements;
-
- final int elemSize = arena.sizeIdx2size(sizeIdx);
-
- // Find the lowest common multiple of pageSize and elemSize
- do {
- runSize += pageSize;
- nElements = runSize / elemSize;
- } while (nElements < maxElements && runSize != nElements * elemSize);
-
- while (nElements > maxElements) {
- runSize -= pageSize;
- nElements = runSize / elemSize;
- }
-
- assert nElements > 0;
- assert runSize <= chunkSize;
- assert runSize >= elemSize;
-
- return runSize;
- }
-
- private int runFirstBestFit(int pageIdx) {
- if (freeBytes == chunkSize) {
- return arena.nPSizes - 1;
- }
- for (int i = pageIdx; i < arena.nPSizes; i++) {
- LongPriorityQueue queue = runsAvail[i];
- if (queue != null && !queue.isEmpty()) {
- return i;
- }
- }
- return -1;
- }
-
- private long splitLargeRun(long handle, int needPages) {
- assert needPages > 0;
-
- int totalPages = runPages(handle);
- assert needPages <= totalPages;
-
- int remPages = totalPages - needPages;
-
- if (remPages > 0) {
- int runOffset = runOffset(handle);
-
- // keep track of trailing unused pages for later use
- int availOffset = runOffset + needPages;
- long availRun = toRunHandle(availOffset, remPages, 0);
- insertAvailRun(availOffset, remPages, availRun);
-
- // not avail
- return toRunHandle(runOffset, needPages, 1);
- }
-
- //mark it as used
- handle |= 1L << IS_USED_SHIFT;
- return handle;
- }
-
- /**
- * Create / initialize a new PoolSubpage of normCapacity. Any PoolSubpage created / initialized here is added to
- * subpage pool in the PoolArena that owns this PoolChunk
- *
- * @param sizeIdx sizeIdx of normalized size
- *
- * @return index in memoryMap
- */
- private long allocateSubpage(int sizeIdx) {
- // Obtain the head of the PoolSubPage pool that is owned by the PoolArena and synchronize on it.
- // This is need as we may add it back and so alter the linked-list structure.
- PoolSubpage head = arena.findSubpagePoolHead(sizeIdx);
- synchronized (head) {
- //allocate a new run
- int runSize = calculateRunSize(sizeIdx);
- //runSize must be multiples of pageSize
- long runHandle = allocateRun(runSize);
- if (runHandle < 0) {
- return -1;
- }
-
- int runOffset = runOffset(runHandle);
- assert subpages[runOffset] == null;
- int elemSize = arena.sizeIdx2size(sizeIdx);
-
- PoolSubpage subpage = new PoolSubpage(head, this, pageShifts, runOffset,
- runSize(pageShifts, runHandle), elemSize);
-
- subpages[runOffset] = subpage;
- return subpage.allocate();
- }
- }
-
- /**
- * Free a subpage, or a run of pages When a subpage is freed from PoolSubpage, it might be added back to subpage
- * pool of the owning PoolArena. If the subpage pool in PoolArena has at least one other PoolSubpage of given
- * elemSize, we can completely free the owning Page, so it is available for subsequent allocations.
- *
- * @param handle handle to free
- */
- void free(long handle, int normCapacity) {
- baseDrop.drop(base); // Decrement reference count.
- if (isSubpage(handle)) {
- int sizeIdx = arena.size2SizeIdx(normCapacity);
- PoolSubpage head = arena.findSubpagePoolHead(sizeIdx);
-
- int sIdx = runOffset(handle);
- PoolSubpage subpage = subpages[sIdx];
- assert subpage != null && subpage.doNotDestroy;
-
- // Obtain the head of the PoolSubPage pool that is owned by the PoolArena and synchronize on it.
- // This is need as we may add it back and so alter the linked-list structure.
- synchronized (head) {
- if (subpage.free(head, bitmapIdx(handle))) {
- //the subpage is still used, do not free it
- return;
- }
- assert !subpage.doNotDestroy;
- // Null out slot in the array as it was freed, and we should not use it anymore.
- subpages[sIdx] = null;
- }
- }
-
- //start free run
- int pages = runPages(handle);
-
- synchronized (runsAvail) {
- // collapse continuous runs, successfully collapsed runs
- // will be removed from runsAvail and runsAvailMap
- long finalRun = collapseRuns(handle);
-
- //set run as not used
- finalRun &= ~(1L << IS_USED_SHIFT);
- //if it is a subpage, set it to run
- finalRun &= ~(1L << IS_SUBPAGE_SHIFT);
-
- insertAvailRun(runOffset(finalRun), runPages(finalRun), finalRun);
- freeBytes += pages << pageShifts;
- }
- }
-
- private long collapseRuns(long handle) {
- return collapseNext(collapsePast(handle));
- }
-
- private long collapsePast(long handle) {
- for (;;) {
- int runOffset = runOffset(handle);
- int runPages = runPages(handle);
-
- long pastRun = getAvailRunByOffset(runOffset - 1);
- if (pastRun == -1) {
- return handle;
- }
-
- int pastOffset = runOffset(pastRun);
- int pastPages = runPages(pastRun);
-
- //is continuous
- if (pastRun != handle && pastOffset + pastPages == runOffset) {
- //remove past run
- removeAvailRun(pastRun);
- handle = toRunHandle(pastOffset, pastPages + runPages, 0);
- } else {
- return handle;
- }
- }
- }
-
- private long collapseNext(long handle) {
- for (;;) {
- int runOffset = runOffset(handle);
- int runPages = runPages(handle);
-
- long nextRun = getAvailRunByOffset(runOffset + runPages);
- if (nextRun == -1) {
- return handle;
- }
-
- int nextOffset = runOffset(nextRun);
- int nextPages = runPages(nextRun);
-
- //is continuous
- if (nextRun != handle && runOffset + runPages == nextOffset) {
- //remove next run
- removeAvailRun(nextRun);
- handle = toRunHandle(runOffset, runPages + nextPages, 0);
- } else {
- return handle;
- }
- }
- }
-
- private static long toRunHandle(int runOffset, int runPages, int inUsed) {
- return (long) runOffset << RUN_OFFSET_SHIFT
- | (long) runPages << SIZE_SHIFT
- | (long) inUsed << IS_USED_SHIFT;
- }
-
- UntetheredMemory allocateBuffer(long handle, int size, PoolThreadCache threadCache,
- PooledAllocatorControl control) {
- if (isRun(handle)) {
- int offset = runOffset(handle) << pageShifts;
- int maxLength = runSize(pageShifts, handle);
- PoolThreadCache poolThreadCache = arena.parent.threadCache();
- initAllocatorControl(control, poolThreadCache, handle, maxLength);
- ArcDrop.acquire(baseDrop);
- return new UntetheredChunkAllocation(
- memory, this, poolThreadCache, handle, maxLength, offset, size);
- } else {
- return allocateBufferWithSubpage(handle, size, threadCache, control);
- }
- }
-
- UntetheredMemory allocateBufferWithSubpage(long handle, int size, PoolThreadCache threadCache,
- PooledAllocatorControl control) {
- int runOffset = runOffset(handle);
- int bitmapIdx = bitmapIdx(handle);
-
- PoolSubpage s = subpages[runOffset];
- assert s.doNotDestroy;
- assert size <= s.elemSize;
-
- int offset = (runOffset << pageShifts) + bitmapIdx * s.elemSize;
- initAllocatorControl(control, threadCache, handle, s.elemSize);
- ArcDrop.acquire(baseDrop);
- return new UntetheredChunkAllocation(memory, this, threadCache, handle, s.elemSize, offset, size);
- }
-
- @SuppressWarnings("unchecked")
- private static final class UntetheredChunkAllocation implements UntetheredMemory {
- private final Object memory;
- private final PoolChunk chunk;
- private final PoolThreadCache threadCache;
- private final long handle;
- private final int maxLength;
- private final int offset;
- private final int size;
-
- private UntetheredChunkAllocation(
- Object memory, PoolChunk chunk, PoolThreadCache threadCache,
- long handle, int maxLength, int offset, int size) {
- this.memory = memory;
- this.chunk = chunk;
- this.threadCache = threadCache;
- this.handle = handle;
- this.maxLength = maxLength;
- this.offset = offset;
- this.size = size;
- }
-
- @Override
- public Memory memory() {
- return (Memory) chunk.arena.manager.sliceMemory(memory, offset, size);
- }
-
- @Override
- public Drop drop() {
- PooledDrop pooledDrop = new PooledDrop(chunk.arena, chunk, threadCache, handle, maxLength);
- return (Drop) CleanerDrop.wrap(pooledDrop);
- }
- }
-
- private void initAllocatorControl(PooledAllocatorControl control, PoolThreadCache threadCache, long handle,
- int normSize) {
- control.arena = arena;
- control.chunk = this;
- control.threadCache = threadCache;
- control.handle = handle;
- control.normSize = normSize;
- }
-
- @Override
- public int chunkSize() {
- return chunkSize;
- }
-
- @Override
- public int freeBytes() {
- synchronized (arena) {
- return freeBytes;
- }
- }
-
- @Override
- public String toString() {
- final int freeBytes;
- synchronized (arena) {
- freeBytes = this.freeBytes;
- }
-
- return new StringBuilder()
- .append("Chunk(")
- .append(Integer.toHexString(System.identityHashCode(this)))
- .append(": ")
- .append(usage(freeBytes))
- .append("%, ")
- .append(chunkSize - freeBytes)
- .append('/')
- .append(chunkSize)
- .append(')')
- .toString();
- }
-
- void destroy() {
- baseDrop.drop(base); // Decrement reference count from the chunk (allocated buffers may keep the base alive)
- }
-
- static int runOffset(long handle) {
- return (int) (handle >> RUN_OFFSET_SHIFT);
- }
-
- static int runSize(int pageShifts, long handle) {
- return runPages(handle) << pageShifts;
- }
-
- static int runPages(long handle) {
- return (int) (handle >> SIZE_SHIFT & 0x7fff);
- }
-
- static boolean isUsed(long handle) {
- return (handle >> IS_USED_SHIFT & 1) == 1L;
- }
-
- static boolean isRun(long handle) {
- return !isSubpage(handle);
- }
-
- static boolean isSubpage(long handle) {
- return (handle >> IS_SUBPAGE_SHIFT & 1) == 1L;
- }
-
- static int bitmapIdx(long handle) {
- return (int) handle;
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkList.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkList.java
deleted file mode 100644
index 03347f6..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkList.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import io.netty.buffer.api.AllocatorControl.UntetheredMemory;
-import io.netty.util.internal.StringUtil;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
-final class PoolChunkList implements PoolChunkListMetric {
- private static final Iterator EMPTY_METRICS = Collections.emptyIterator();
- private final PoolArena arena;
- private final PoolChunkList nextList;
- private final int minUsage;
- private final int maxUsage;
- private final int maxCapacity;
- private PoolChunk head;
- private final int freeMinThreshold;
- private final int freeMaxThreshold;
-
- // This is only update once when create the linked like list of PoolChunkList in PoolArena constructor.
- private PoolChunkList prevList;
-
- PoolChunkList(PoolArena arena, PoolChunkList nextList, int minUsage, int maxUsage, int chunkSize) {
- assert minUsage <= maxUsage;
- this.arena = arena;
- this.nextList = nextList;
- this.minUsage = minUsage;
- this.maxUsage = maxUsage;
- maxCapacity = calculateMaxCapacity(minUsage, chunkSize);
-
- // the thresholds are aligned with PoolChunk.usage() logic:
- // 1) basic logic: usage() = 100 - freeBytes * 100L / chunkSize
- // so, for example: (usage() >= maxUsage) condition can be transformed in the following way:
- // 100 - freeBytes * 100L / chunkSize >= maxUsage
- // freeBytes <= chunkSize * (100 - maxUsage) / 100
- // let freeMinThreshold = chunkSize * (100 - maxUsage) / 100, then freeBytes <= freeMinThreshold
- //
- // 2) usage() returns an int value and has a floor rounding during a calculation,
- // to be aligned absolute thresholds should be shifted for "the rounding step":
- // freeBytes * 100 / chunkSize < 1
- // the condition can be converted to: freeBytes < 1 * chunkSize / 100
- // this is why we have + 0.99999999 shifts. A example why just +1 shift cannot be used:
- // freeBytes = 16777216 == freeMaxThreshold: 16777216, usage = 0 < minUsage: 1, chunkSize: 16777216
- // At the same time we want to have zero thresholds in case of (maxUsage == 100) and (minUsage == 100).
- //
- freeMinThreshold = maxUsage == 100 ? 0 : (int) (chunkSize * (100.0 - maxUsage + 0.99999999) / 100L);
- freeMaxThreshold = minUsage == 100 ? 0 : (int) (chunkSize * (100.0 - minUsage + 0.99999999) / 100L);
- }
-
- /**
- * Calculates the maximum capacity of a buffer that will ever be possible to allocate out of the {@link PoolChunk}s
- * that belong to the {@link PoolChunkList} with the given {@code minUsage} and {@code maxUsage} settings.
- */
- private static int calculateMaxCapacity(int minUsage, int chunkSize) {
- minUsage = minUsage0(minUsage);
-
- if (minUsage == 100) {
- // If the minUsage is 100 we can not allocate anything out of this list.
- return 0;
- }
-
- // Calculate the maximum amount of bytes that can be allocated from a PoolChunk in this PoolChunkList.
- //
- // As an example:
- // - If a PoolChunkList has minUsage == 25 we are allowed to allocate at most 75% of the chunkSize because
- // this is the maximum amount available in any PoolChunk in this PoolChunkList.
- return (int) (chunkSize * (100L - minUsage) / 100L);
- }
-
- void prevList(PoolChunkList prevList) {
- assert this.prevList == null;
- this.prevList = prevList;
- }
-
- UntetheredMemory allocate(int size, int sizeIdx, PoolThreadCache threadCache, PooledAllocatorControl control) {
- int normCapacity = arena.sizeIdx2size(sizeIdx);
- if (normCapacity > maxCapacity) {
- // Either this PoolChunkList is empty, or the requested capacity is larger than the capacity which can
- // be handled by the PoolChunks that are contained in this PoolChunkList.
- return null;
- }
-
- for (PoolChunk cur = head; cur != null; cur = cur.next) {
- UntetheredMemory memory = cur.allocate(size, sizeIdx, threadCache, control);
- if (memory != null) {
- if (cur.freeBytes <= freeMinThreshold) {
- remove(cur);
- nextList.add(cur);
- }
- return memory;
- }
- }
- return null;
- }
-
- boolean free(PoolChunk chunk, long handle, int normCapacity) {
- chunk.free(handle, normCapacity);
- if (chunk.freeBytes > freeMaxThreshold) {
- remove(chunk);
- // Move the PoolChunk down the PoolChunkList linked-list.
- return move0(chunk);
- }
- return true;
- }
-
- private boolean move(PoolChunk chunk) {
- if (chunk.freeBytes > freeMaxThreshold) {
- // Move the PoolChunk down the PoolChunkList linked-list.
- return move0(chunk);
- }
-
- // PoolChunk fits into this PoolChunkList, adding it here.
- add0(chunk);
- return true;
- }
-
- /**
- * Moves the {@link PoolChunk} down the {@link PoolChunkList} linked-list, so it will end up in the right
- * {@link PoolChunkList} that has the correct minUsage / maxUsage in respect to {@link PoolChunk#usage()}.
- */
- private boolean move0(PoolChunk chunk) {
- if (prevList == null) {
- // There is no previous PoolChunkList so return false which result in having the PoolChunk destroyed and
- // all memory associated with the PoolChunk will be released.
- return false;
- }
- return prevList.move(chunk);
- }
-
- void add(PoolChunk chunk) {
- if (chunk.freeBytes <= freeMinThreshold) {
- nextList.add(chunk);
- return;
- }
- add0(chunk);
- }
-
- /**
- * Adds the {@link PoolChunk} to this {@link PoolChunkList}.
- */
- void add0(PoolChunk chunk) {
- chunk.parent = this;
- if (head == null) {
- head = chunk;
- chunk.prev = null;
- chunk.next = null;
- } else {
- chunk.prev = null;
- chunk.next = head;
- head.prev = chunk;
- head = chunk;
- }
- }
-
- private void remove(PoolChunk cur) {
- if (cur == head) {
- head = cur.next;
- if (head != null) {
- head.prev = null;
- }
- } else {
- PoolChunk next = cur.next;
- cur.prev.next = next;
- if (next != null) {
- next.prev = cur.prev;
- }
- }
- }
-
- @Override
- public int minUsage() {
- return minUsage0(minUsage);
- }
-
- @Override
- public int maxUsage() {
- return min(maxUsage, 100);
- }
-
- private static int minUsage0(int value) {
- return max(1, value);
- }
-
- @Override
- public Iterator iterator() {
- synchronized (arena) {
- if (head == null) {
- return EMPTY_METRICS;
- }
- List metrics = new ArrayList<>();
- for (PoolChunk cur = head;;) {
- metrics.add(cur);
- cur = cur.next;
- if (cur == null) {
- break;
- }
- }
- return metrics.iterator();
- }
- }
-
- @Override
- public String toString() {
- StringBuilder buf = new StringBuilder();
- synchronized (arena) {
- if (head == null) {
- return "none";
- }
-
- for (PoolChunk cur = head;;) {
- buf.append(cur);
- cur = cur.next;
- if (cur == null) {
- break;
- }
- buf.append(StringUtil.NEWLINE);
- }
- }
- return buf.toString();
- }
-
- void destroy() {
- PoolChunk chunk = head;
- while (chunk != null) {
- chunk.destroy();
- chunk = chunk.next;
- }
- head = null;
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkListMetric.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkListMetric.java
deleted file mode 100644
index 9a60e1d..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkListMetric.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-/**
- * Metrics for a list of chunks.
- */
-public interface PoolChunkListMetric extends Iterable {
-
- /**
- * Return the minimum usage of the chunk list before which chunks are promoted to the previous list.
- */
- int minUsage();
-
- /**
- * Return the maximum usage of the chunk list after which chunks are promoted to the next list.
- */
- int maxUsage();
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkMetric.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkMetric.java
deleted file mode 100644
index 8a90384..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkMetric.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-/**
- * Metrics for a chunk.
- */
-public interface PoolChunkMetric {
-
- /**
- * Return the percentage of the current usage of the chunk.
- */
- int usage();
-
- /**
- * Return the size of the chunk in bytes, this is the maximum of bytes that can be served out of the chunk.
- */
- int chunkSize();
-
- /**
- * Return the number of free bytes in the chunk.
- */
- int freeBytes();
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolSubpage.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolSubpage.java
deleted file mode 100644
index c0b558d..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolSubpage.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import static io.netty.buffer.api.pool.PoolChunk.RUN_OFFSET_SHIFT;
-import static io.netty.buffer.api.pool.PoolChunk.SIZE_SHIFT;
-import static io.netty.buffer.api.pool.PoolChunk.IS_USED_SHIFT;
-import static io.netty.buffer.api.pool.PoolChunk.IS_SUBPAGE_SHIFT;
-import static io.netty.buffer.api.pool.SizeClasses.LOG2_QUANTUM;
-
-final class PoolSubpage implements PoolSubpageMetric {
- final PoolChunk chunk;
- private final int pageShifts;
- private final int runOffset;
- private final int runSize;
- private final long[] bitmap;
-
- PoolSubpage prev;
- PoolSubpage next;
-
- boolean doNotDestroy;
- int elemSize;
- private int maxNumElems;
- private int bitmapLength;
- private int nextAvail;
- private int numAvail;
-
- /** Special constructor that creates a linked list head */
- PoolSubpage() {
- chunk = null;
- pageShifts = -1;
- runOffset = -1;
- elemSize = -1;
- runSize = -1;
- bitmap = null;
- }
-
- PoolSubpage(PoolSubpage head, PoolChunk chunk, int pageShifts, int runOffset, int runSize, int elemSize) {
- this.chunk = chunk;
- this.pageShifts = pageShifts;
- this.runOffset = runOffset;
- this.runSize = runSize;
- this.elemSize = elemSize;
- bitmap = new long[runSize >>> 6 + LOG2_QUANTUM]; // runSize / 64 / QUANTUM
-
- doNotDestroy = true;
- if (elemSize != 0) {
- maxNumElems = numAvail = runSize / elemSize;
- nextAvail = 0;
- bitmapLength = maxNumElems >>> 6;
- if ((maxNumElems & 63) != 0) {
- bitmapLength ++;
- }
-
- for (int i = 0; i < bitmapLength; i ++) {
- bitmap[i] = 0;
- }
- }
- addToPool(head);
- }
-
- /**
- * Returns the bitmap index of the subpage allocation.
- */
- long allocate() {
- if (numAvail == 0 || !doNotDestroy) {
- return -1;
- }
-
- final int bitmapIdx = getNextAvail();
- int q = bitmapIdx >>> 6;
- int r = bitmapIdx & 63;
- assert (bitmap[q] >>> r & 1) == 0;
- bitmap[q] |= 1L << r;
-
- if (-- numAvail == 0) {
- removeFromPool();
- }
-
- return toHandle(bitmapIdx);
- }
-
- /**
- * @return {@code true} if this subpage is in use.
- * {@code false} if this subpage is not used by its chunk and thus it's OK to be released.
- */
- boolean free(PoolSubpage head, int bitmapIdx) {
- if (elemSize == 0) {
- return true;
- }
- int q = bitmapIdx >>> 6;
- int r = bitmapIdx & 63;
- assert (bitmap[q] >>> r & 1) != 0;
- bitmap[q] ^= 1L << r;
-
- setNextAvail(bitmapIdx);
-
- if (numAvail++ == 0) {
- addToPool(head);
- // When maxNumElems == 1, the maximum numAvail is also 1.
- // Each of these PoolSubpages will go in here when they do free operation.
- // If they return true directly from here, then the rest of the code will be unreachable,
- // and they will not actually be recycled. So return true only on maxNumElems > 1.
- if (maxNumElems > 1) {
- return true;
- }
- }
-
- if (numAvail != maxNumElems) {
- return true;
- } else {
- // Subpage not in use (numAvail == maxNumElems)
- if (prev == next) {
- // Do not remove if this subpage is the only one left in the pool.
- return true;
- }
-
- // Remove this subpage from the pool if there are other subpages left in the pool.
- doNotDestroy = false;
- removeFromPool();
- return false;
- }
- }
-
- private void addToPool(PoolSubpage head) {
- assert prev == null && next == null;
- prev = head;
- next = head.next;
- next.prev = this;
- head.next = this;
- }
-
- private void removeFromPool() {
- assert prev != null && next != null;
- prev.next = next;
- next.prev = prev;
- next = null;
- prev = null;
- }
-
- private void setNextAvail(int bitmapIdx) {
- nextAvail = bitmapIdx;
- }
-
- private int getNextAvail() {
- int nextAvail = this.nextAvail;
- if (nextAvail >= 0) {
- this.nextAvail = -1;
- return nextAvail;
- }
- return findNextAvail();
- }
-
- private int findNextAvail() {
- final long[] bitmap = this.bitmap;
- final int bitmapLength = this.bitmapLength;
- for (int i = 0; i < bitmapLength; i ++) {
- long bits = bitmap[i];
- if (~bits != 0) {
- return findNextAvail0(i, bits);
- }
- }
- return -1;
- }
-
- private int findNextAvail0(int i, long bits) {
- final int maxNumElems = this.maxNumElems;
- final int baseVal = i << 6;
-
- for (int j = 0; j < 64; j ++) {
- if ((bits & 1) == 0) {
- int val = baseVal | j;
- if (val < maxNumElems) {
- return val;
- } else {
- break;
- }
- }
- bits >>>= 1;
- }
- return -1;
- }
-
- private long toHandle(int bitmapIdx) {
- int pages = runSize >> pageShifts;
- return (long) runOffset << RUN_OFFSET_SHIFT
- | (long) pages << SIZE_SHIFT
- | 1L << IS_USED_SHIFT
- | 1L << IS_SUBPAGE_SHIFT
- | bitmapIdx;
- }
-
- @Override
- public String toString() {
- final boolean doNotDestroy;
- final int maxNumElems;
- final int numAvail;
- final int elemSize;
- if (chunk == null) {
- // This is the head so there is no need to synchronize at all as these never change.
- doNotDestroy = true;
- maxNumElems = 0;
- numAvail = 0;
- elemSize = -1;
- } else {
- synchronized (chunk.arena) {
- if (!this.doNotDestroy) {
- doNotDestroy = false;
- // Not used for creating the String.
- maxNumElems = numAvail = elemSize = -1;
- } else {
- doNotDestroy = true;
- maxNumElems = this.maxNumElems;
- numAvail = this.numAvail;
- elemSize = this.elemSize;
- }
- }
- }
-
- if (!doNotDestroy) {
- return "(" + runOffset + ": not in use)";
- }
-
- return "(" + runOffset + ": " + (maxNumElems - numAvail) + '/' + maxNumElems +
- ", offset: " + runOffset + ", length: " + runSize + ", elemSize: " + elemSize + ')';
- }
-
- @Override
- public int maxNumElements() {
- if (chunk == null) {
- // It's the head.
- return 0;
- }
-
- synchronized (chunk.arena) {
- return maxNumElems;
- }
- }
-
- @Override
- public int numAvailable() {
- if (chunk == null) {
- // It's the head.
- return 0;
- }
-
- synchronized (chunk.arena) {
- return numAvail;
- }
- }
-
- @Override
- public int elementSize() {
- if (chunk == null) {
- // It's the head.
- return -1;
- }
-
- synchronized (chunk.arena) {
- return elemSize;
- }
- }
-
- @Override
- public int pageSize() {
- return 1 << pageShifts;
- }
-
- void destroy() {
- if (chunk != null) {
- chunk.destroy();
- }
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolSubpageMetric.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolSubpageMetric.java
deleted file mode 100644
index 5793a0a..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolSubpageMetric.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-/**
- * Metrics for a sub-page.
- */
-public interface PoolSubpageMetric {
-
- /**
- * Return the number of maximal elements that can be allocated out of the sub-page.
- */
- int maxNumElements();
-
- /**
- * Return the number of available elements to be allocated.
- */
- int numAvailable();
-
- /**
- * Return the size (in bytes) of the elements that will be allocated.
- */
- int elementSize();
-
- /**
- * Return the page size (in bytes) of this page.
- */
- int pageSize();
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolThreadCache.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolThreadCache.java
deleted file mode 100644
index 2771b7f..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolThreadCache.java
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import io.netty.buffer.api.AllocatorControl.UntetheredMemory;
-import io.netty.buffer.api.pool.PoolArena.SizeClass;
-import io.netty.util.internal.MathUtil;
-import io.netty.util.internal.ObjectPool;
-import io.netty.util.internal.ObjectPool.Handle;
-import io.netty.util.internal.PlatformDependent;
-import io.netty.util.internal.logging.InternalLogger;
-import io.netty.util.internal.logging.InternalLoggerFactory;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Queue;
-
-import static io.netty.buffer.api.pool.PoolArena.SizeClass.Normal;
-import static io.netty.buffer.api.pool.PoolArena.SizeClass.Small;
-import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
-
-/**
- * Acts a Thread cache for allocations. This implementation is modelled after
- * jemalloc and the described
- * techniques of
- *
- * Scalable memory allocation using jemalloc.
- */
-final class PoolThreadCache {
-
- private static final InternalLogger logger = InternalLoggerFactory.getInstance(PoolThreadCache.class);
- private static final int INTEGER_SIZE_MINUS_ONE = Integer.SIZE - 1;
-
- final PoolArena arena;
-
- // Hold the caches for the different size classes, which are tiny, small and normal.
- private final MemoryRegionCache[] smallSubPageCaches;
- private final MemoryRegionCache[] normalCaches;
-
- private final int freeSweepAllocationThreshold;
-
- private int allocations;
-
- PoolThreadCache(PoolArena arena,
- int smallCacheSize, int normalCacheSize, int maxCachedBufferCapacity,
- int freeSweepAllocationThreshold) {
- checkPositiveOrZero(maxCachedBufferCapacity, "maxCachedBufferCapacity");
- this.freeSweepAllocationThreshold = freeSweepAllocationThreshold;
- this.arena = arena;
- if (arena != null) {
- // Create the caches for the heap allocations
- smallSubPageCaches = createSubPageCaches(
- smallCacheSize, arena.numSmallSubpagePools);
-
- normalCaches = createNormalCaches(
- normalCacheSize, maxCachedBufferCapacity, arena);
-
- arena.numThreadCaches.getAndIncrement();
- } else {
- // No heapArea is configured so just null out all caches
- smallSubPageCaches = null;
- normalCaches = null;
- }
-
- // Only check if there are caches in use.
- if ((smallSubPageCaches != null || normalCaches != null)
- && freeSweepAllocationThreshold < 1) {
- throw new IllegalArgumentException("freeSweepAllocationThreshold: "
- + freeSweepAllocationThreshold + " (expected: > 0)");
- }
- }
-
- private static MemoryRegionCache[] createSubPageCaches(
- int cacheSize, int numCaches) {
- if (cacheSize > 0 && numCaches > 0) {
- MemoryRegionCache[] cache = new MemoryRegionCache[numCaches];
- for (int i = 0; i < cache.length; i++) {
- // TODO: maybe use cacheSize / cache.length
- cache[i] = new SubPageMemoryRegionCache(cacheSize);
- }
- return cache;
- } else {
- return null;
- }
- }
-
- private static MemoryRegionCache[] createNormalCaches(
- int cacheSize, int maxCachedBufferCapacity, PoolArena area) {
- if (cacheSize > 0 && maxCachedBufferCapacity > 0) {
- int max = Math.min(area.chunkSize, maxCachedBufferCapacity);
-
- // Create as many normal caches as we support based on how many sizeIdx we have and what the upper
- // bound is that we want to cache in general.
- List cache = new ArrayList<>() ;
- for (int idx = area.numSmallSubpagePools; idx < area.nSizes && area.sizeIdx2size(idx) <= max ; idx++) {
- cache.add(new NormalMemoryRegionCache(cacheSize));
- }
- return cache.toArray(MemoryRegionCache[]::new);
- } else {
- return null;
- }
- }
-
- // val > 0
- static int log2(int val) {
- return INTEGER_SIZE_MINUS_ONE - Integer.numberOfLeadingZeros(val);
- }
-
- /**
- * Try to allocate a small buffer out of the cache. Returns {@code true} if successful {@code false} otherwise
- */
- UntetheredMemory allocateSmall(PooledAllocatorControl control, int size, int sizeIdx) {
- return allocate(cacheForSmall(sizeIdx), control, size);
- }
-
- /**
- * Try to allocate a normal buffer out of the cache. Returns {@code true} if successful {@code false} otherwise
- */
- UntetheredMemory allocateNormal(PoolArena area, PooledAllocatorControl control, int size, int sizeIdx) {
- return allocate(cacheForNormal(area, sizeIdx), control, size);
- }
-
- private UntetheredMemory allocate(MemoryRegionCache cache, PooledAllocatorControl control, int size) {
- if (cache == null) {
- // no cache found so just return false here
- return null;
- }
- UntetheredMemory allocated = cache.allocate(size, this, control);
- if (++allocations >= freeSweepAllocationThreshold) {
- allocations = 0;
- trim();
- }
- return allocated;
- }
-
- /**
- * Add {@link PoolChunk} and {@code handle} to the cache if there is enough room.
- * Returns {@code true} if it fit into the cache {@code false} otherwise.
- */
- boolean add(PoolArena area, PoolChunk chunk,
- long handle, int normCapacity, SizeClass sizeClass) {
- int sizeIdx = area.size2SizeIdx(normCapacity);
- MemoryRegionCache cache = cache(area, sizeIdx, sizeClass);
- if (cache == null) {
- return false;
- }
- return cache.add(chunk, handle, normCapacity);
- }
-
- private MemoryRegionCache cache(PoolArena area, int sizeIdx, SizeClass sizeClass) {
- if (sizeClass == Normal) {
- return cacheForNormal(area, sizeIdx);
- }
- if (sizeClass == Small) {
- return cacheForSmall(sizeIdx);
- }
- throw new AssertionError("Unexpected size class: " + sizeClass);
- }
-
- /**
- * Should be called if the Thread that uses this cache is about to exist to release resources out of the cache
- */
- void free() {
- int numFreed = free(smallSubPageCaches) + free(normalCaches);
-
- if (numFreed > 0 && logger.isDebugEnabled()) {
- logger.debug("Freed {} thread-local buffer(s) from thread: {}", numFreed,
- Thread.currentThread().getName());
- }
-
- if (arena != null) {
- arena.numThreadCaches.getAndDecrement();
- }
- }
-
- private static int free(MemoryRegionCache[] caches) {
- if (caches == null) {
- return 0;
- }
-
- int numFreed = 0;
- for (MemoryRegionCache c: caches) {
- numFreed += free(c);
- }
- return numFreed;
- }
-
- private static int free(MemoryRegionCache cache) {
- if (cache == null) {
- return 0;
- }
- return cache.free();
- }
-
- void trim() {
- trim(smallSubPageCaches);
- trim(normalCaches);
- }
-
- private static void trim(MemoryRegionCache[] caches) {
- if (caches == null) {
- return;
- }
- for (MemoryRegionCache c: caches) {
- trim(c);
- }
- }
-
- private static void trim(MemoryRegionCache cache) {
- if (cache == null) {
- return;
- }
- cache.trim();
- }
-
- private MemoryRegionCache cacheForSmall(int sizeIdx) {
- return cache(smallSubPageCaches, sizeIdx);
- }
-
- private MemoryRegionCache cacheForNormal(PoolArena area, int sizeIdx) {
- // We need to substract area.numSmallSubpagePools as sizeIdx is the overall index for all sizes.
- int idx = sizeIdx - area.numSmallSubpagePools;
- return cache(normalCaches, idx);
- }
-
- private static MemoryRegionCache cache(MemoryRegionCache[] cache, int sizeIdx) {
- if (cache == null || sizeIdx > cache.length - 1) {
- return null;
- }
- return cache[sizeIdx];
- }
-
- /**
- * Cache used for buffers which are backed by SMALL size.
- */
- private static final class SubPageMemoryRegionCache extends MemoryRegionCache {
- SubPageMemoryRegionCache(int size) {
- super(size, Small);
- }
-
- @Override
- protected UntetheredMemory allocBuf(PoolChunk chunk, long handle, int size, PoolThreadCache threadCache,
- PooledAllocatorControl control) {
- return chunk.allocateBufferWithSubpage(handle, size, threadCache, control);
- }
- }
-
- /**
- * Cache used for buffers which are backed by NORMAL size.
- */
- private static final class NormalMemoryRegionCache extends MemoryRegionCache {
- NormalMemoryRegionCache(int size) {
- super(size, Normal);
- }
-
- @Override
- protected UntetheredMemory allocBuf(PoolChunk chunk, long handle, int size, PoolThreadCache threadCache,
- PooledAllocatorControl control) {
- return chunk.allocateBuffer(handle, size, threadCache, control);
- }
- }
-
- private abstract static class MemoryRegionCache {
- private final int size;
- private final Queue queue;
- private final SizeClass sizeClass;
- private int allocations;
-
- MemoryRegionCache(int size, SizeClass sizeClass) {
- this.size = MathUtil.safeFindNextPositivePowerOfTwo(size);
- queue = PlatformDependent.newFixedMpscQueue(this.size);
- this.sizeClass = sizeClass;
- }
-
- /**
- * Allocate a new {@link UntetheredMemory} using the provided chunk and handle with the capacity restrictions.
- */
- protected abstract UntetheredMemory allocBuf(
- PoolChunk chunk, long handle, int size, PoolThreadCache threadCache, PooledAllocatorControl control);
-
- /**
- * Add to cache if not already full.
- */
- public final boolean add(PoolChunk chunk, long handle, int normCapacity) {
- Entry entry = newEntry(chunk, handle, normCapacity);
- boolean queued = queue.offer(entry);
- if (!queued) {
- // If it was not possible to cache the chunk, immediately recycle the entry
- entry.recycle();
- }
-
- return queued;
- }
-
- /**
- * Allocate something out of the cache if possible and remove the entry from the cache.
- */
- public final UntetheredMemory allocate(int size, PoolThreadCache threadCache, PooledAllocatorControl control) {
- Entry entry = queue.poll();
- if (entry == null) {
- return null;
- }
- UntetheredMemory buffer = allocBuf(entry.chunk, entry.handle, size, threadCache, control);
- entry.recycle();
-
- // allocations are not thread-safe which is fine as this is only called from the same thread all time.
- allocations++;
- return buffer;
- }
-
- /**
- * Clear out this cache and free up all previous cached {@link PoolChunk}s and {@code handle}s.
- */
- public final int free() {
- return free(Integer.MAX_VALUE);
- }
-
- private int free(int max) {
- int numFreed = 0;
- for (; numFreed < max; numFreed++) {
- Entry entry = queue.poll();
- if (entry != null) {
- freeEntry(entry);
- } else {
- // all cleared
- return numFreed;
- }
- }
- return numFreed;
- }
-
- /**
- * Free up cached {@link PoolChunk}s if not allocated frequently enough.
- */
- public final void trim() {
- int free = size - allocations;
- allocations = 0;
-
- // We not even allocated all the number that are
- if (free > 0) {
- free(free);
- }
- }
-
- private void freeEntry(Entry entry) {
- PoolChunk chunk = entry.chunk;
- long handle = entry.handle;
-
- entry.recycle();
- chunk.arena.freeChunk(chunk, handle, entry.normCapacity, sizeClass);
- }
-
- static final class Entry {
- final Handle recyclerHandle;
- PoolChunk chunk;
- long handle = -1;
- int normCapacity;
-
- Entry(Handle recyclerHandle) {
- this.recyclerHandle = recyclerHandle;
- }
-
- void recycle() {
- chunk = null;
- handle = -1;
- recyclerHandle.recycle(this);
- }
- }
-
- private static Entry newEntry(PoolChunk chunk, long handle, int normCapacity) {
- Entry entry = RECYCLER.get();
- entry.chunk = chunk;
- entry.handle = handle;
- entry.normCapacity = normCapacity;
- return entry;
- }
-
- private static final ObjectPool RECYCLER = ObjectPool.newPool(handle -> new Entry(handle));
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledAllocatorControl.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledAllocatorControl.java
deleted file mode 100644
index 2e177c8..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledAllocatorControl.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import io.netty.buffer.api.AllocatorControl;
-import io.netty.buffer.api.Buffer;
-
-class PooledAllocatorControl implements AllocatorControl {
- public PooledBufferAllocator parent;
- public PoolArena arena;
- public PoolChunk chunk;
- public PoolThreadCache threadCache;
- public long handle;
- public int normSize;
-
- @Override
- public UntetheredMemory allocateUntethered(Buffer originator, int size) {
- return parent.allocate(this, size);
- }
-
- @Override
- public void recoverMemory(Object memory) {
- arena.free(chunk, handle, normSize, threadCache);
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledBufferAllocator.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledBufferAllocator.java
deleted file mode 100644
index c8ae60b..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledBufferAllocator.java
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import io.netty.buffer.api.AllocatorControl.UntetheredMemory;
-import io.netty.buffer.api.Buffer;
-import io.netty.buffer.api.BufferAllocator;
-import io.netty.buffer.api.MemoryManager;
-import io.netty.util.NettyRuntime;
-import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.FastThreadLocal;
-import io.netty.util.concurrent.FastThreadLocalThread;
-import io.netty.util.internal.PlatformDependent;
-import io.netty.util.internal.StringUtil;
-import io.netty.util.internal.SystemPropertyUtil;
-import io.netty.util.internal.ThreadExecutorMap;
-import io.netty.util.internal.logging.InternalLogger;
-import io.netty.util.internal.logging.InternalLoggerFactory;
-
-import java.nio.ByteOrder;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
-import static java.util.Objects.requireNonNull;
-
-public class PooledBufferAllocator implements BufferAllocator, BufferAllocatorMetricProvider {
-
- private static final InternalLogger logger = InternalLoggerFactory.getInstance(PooledBufferAllocator.class);
- private static final int DEFAULT_NUM_HEAP_ARENA;
- private static final int DEFAULT_NUM_DIRECT_ARENA;
-
- private static final int DEFAULT_PAGE_SIZE;
- private static final int DEFAULT_MAX_ORDER; // 8192 << 9 = 4 MiB per chunk
- private static final int DEFAULT_SMALL_CACHE_SIZE;
- private static final int DEFAULT_NORMAL_CACHE_SIZE;
- static final int DEFAULT_MAX_CACHED_BUFFER_CAPACITY;
- private static final int DEFAULT_CACHE_TRIM_INTERVAL;
- private static final long DEFAULT_CACHE_TRIM_INTERVAL_MILLIS;
- private static final boolean DEFAULT_USE_CACHE_FOR_ALL_THREADS;
- private static final int DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT;
- static final int DEFAULT_MAX_CACHED_BYTEBUFFERS_PER_CHUNK;
-
- private static final int MIN_PAGE_SIZE = 4096;
- private static final int MAX_CHUNK_SIZE = (int) (((long) Integer.MAX_VALUE + 1) / 2);
-
- private final Runnable trimTask = this::trimCurrentThreadCache;
-
- static {
- int defaultAlignment = SystemPropertyUtil.getInt(
- "io.netty.allocator.directMemoryCacheAlignment", 0);
- int defaultPageSize = SystemPropertyUtil.getInt("io.netty.allocator.pageSize", 8192);
- Throwable pageSizeFallbackCause = null;
- try {
- validateAndCalculatePageShifts(defaultPageSize, defaultAlignment);
- } catch (Throwable t) {
- pageSizeFallbackCause = t;
- defaultPageSize = 8192;
- defaultAlignment = 0;
- }
- DEFAULT_PAGE_SIZE = defaultPageSize;
- DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT = defaultAlignment;
-
- int defaultMaxOrder = SystemPropertyUtil.getInt("io.netty.allocator.maxOrder", 9);
- Throwable maxOrderFallbackCause = null;
- try {
- validateAndCalculateChunkSize(DEFAULT_PAGE_SIZE, defaultMaxOrder);
- } catch (Throwable t) {
- maxOrderFallbackCause = t;
- defaultMaxOrder = 11;
- }
- DEFAULT_MAX_ORDER = defaultMaxOrder;
-
- // Determine reasonable default for nHeapArena and nDirectArena.
- // Assuming each arena has 3 chunks, the pool should not consume more than 50% of max memory.
- final Runtime runtime = Runtime.getRuntime();
-
- /*
- * We use 2 * available processors by default to reduce contention as we use 2 * available processors for the
- * number of EventLoops in NIO and EPOLL as well. If we choose a smaller number we will run into hot spots as
- * allocation and de-allocation needs to be synchronized on the PoolArena.
- *
- * See https://github.com/netty/netty/issues/3888.
- */
- final int defaultMinNumArena = NettyRuntime.availableProcessors() * 2;
- final int defaultChunkSize = DEFAULT_PAGE_SIZE << DEFAULT_MAX_ORDER;
- DEFAULT_NUM_HEAP_ARENA = Math.max(0,
- SystemPropertyUtil.getInt(
- "io.netty.allocator.numArenas",
- (int) Math.min(
- defaultMinNumArena,
- runtime.maxMemory() / defaultChunkSize / 2 / 3)));
- DEFAULT_NUM_DIRECT_ARENA = Math.max(0,
- SystemPropertyUtil.getInt(
- "io.netty.allocator.numDirectArenas",
- (int) Math.min(
- defaultMinNumArena,
- PlatformDependent.maxDirectMemory() / defaultChunkSize / 2 / 3)));
-
- // cache sizes
- DEFAULT_SMALL_CACHE_SIZE = SystemPropertyUtil.getInt("io.netty.allocator.smallCacheSize", 256);
- DEFAULT_NORMAL_CACHE_SIZE = SystemPropertyUtil.getInt("io.netty.allocator.normalCacheSize", 64);
-
- // 32 kb is the default maximum capacity of the cached buffer. Similar to what is explained in
- // 'Scalable memory allocation using jemalloc'
- DEFAULT_MAX_CACHED_BUFFER_CAPACITY = SystemPropertyUtil.getInt(
- "io.netty.allocator.maxCachedBufferCapacity", 32 * 1024);
-
- // the number of threshold of allocations when cached entries will be freed up if not frequently used
- DEFAULT_CACHE_TRIM_INTERVAL = SystemPropertyUtil.getInt(
- "io.netty.allocator.cacheTrimInterval", 8192);
-
- DEFAULT_CACHE_TRIM_INTERVAL_MILLIS = SystemPropertyUtil.getLong(
- "io.netty.allocator.cacheTrimIntervalMillis", 0);
-
- DEFAULT_USE_CACHE_FOR_ALL_THREADS = SystemPropertyUtil.getBoolean(
- "io.netty.allocator.useCacheForAllThreads", false);
-
- // Use 1023 by default as we use an ArrayDeque as backing storage which will then allocate an internal array
- // of 1024 elements. Otherwise, we would allocate 2048 and only use 1024 which is wasteful.
- DEFAULT_MAX_CACHED_BYTEBUFFERS_PER_CHUNK = SystemPropertyUtil.getInt(
- "io.netty.allocator.maxCachedByteBuffersPerChunk", 1023);
-
- if (logger.isDebugEnabled()) {
- logger.debug("-Dio.netty.allocator.numArenas: {}", DEFAULT_NUM_HEAP_ARENA);
- logger.debug("-Dio.netty.allocator.numDirectArenas: {}", DEFAULT_NUM_DIRECT_ARENA);
- if (pageSizeFallbackCause == null) {
- logger.debug("-Dio.netty.allocator.pageSize: {}", DEFAULT_PAGE_SIZE);
- } else {
- logger.debug("-Dio.netty.allocator.pageSize: {}", DEFAULT_PAGE_SIZE, pageSizeFallbackCause);
- }
- if (maxOrderFallbackCause == null) {
- logger.debug("-Dio.netty.allocator.maxOrder: {}", DEFAULT_MAX_ORDER);
- } else {
- logger.debug("-Dio.netty.allocator.maxOrder: {}", DEFAULT_MAX_ORDER, maxOrderFallbackCause);
- }
- logger.debug("-Dio.netty.allocator.chunkSize: {}", DEFAULT_PAGE_SIZE << DEFAULT_MAX_ORDER);
- logger.debug("-Dio.netty.allocator.smallCacheSize: {}", DEFAULT_SMALL_CACHE_SIZE);
- logger.debug("-Dio.netty.allocator.normalCacheSize: {}", DEFAULT_NORMAL_CACHE_SIZE);
- logger.debug("-Dio.netty.allocator.maxCachedBufferCapacity: {}", DEFAULT_MAX_CACHED_BUFFER_CAPACITY);
- logger.debug("-Dio.netty.allocator.cacheTrimInterval: {}", DEFAULT_CACHE_TRIM_INTERVAL);
- logger.debug("-Dio.netty.allocator.cacheTrimIntervalMillis: {}", DEFAULT_CACHE_TRIM_INTERVAL_MILLIS);
- logger.debug("-Dio.netty.allocator.useCacheForAllThreads: {}", DEFAULT_USE_CACHE_FOR_ALL_THREADS);
- logger.debug("-Dio.netty.allocator.maxCachedByteBuffersPerChunk: {}",
- DEFAULT_MAX_CACHED_BYTEBUFFERS_PER_CHUNK);
- }
- }
-
- private final MemoryManager manager;
- private final PoolArena[] arenas;
- private final int smallCacheSize;
- private final int normalCacheSize;
- private final List arenaMetrics;
- private final List arenaMetricsView;
- private final PoolThreadLocalCache threadCache;
- private final int chunkSize;
- private final PooledBufferAllocatorMetric metric;
-
- public PooledBufferAllocator(MemoryManager manager) {
- this(manager, manager.isNative()? DEFAULT_NUM_DIRECT_ARENA : DEFAULT_NUM_HEAP_ARENA,
- DEFAULT_PAGE_SIZE, DEFAULT_MAX_ORDER, DEFAULT_SMALL_CACHE_SIZE,
- DEFAULT_NORMAL_CACHE_SIZE, DEFAULT_USE_CACHE_FOR_ALL_THREADS,
- DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT);
- }
-
- public PooledBufferAllocator(MemoryManager manager, int numArenas, int pageSize, int maxOrder) {
- this(manager, numArenas, pageSize, maxOrder, DEFAULT_SMALL_CACHE_SIZE,
- DEFAULT_NORMAL_CACHE_SIZE, DEFAULT_USE_CACHE_FOR_ALL_THREADS,
- DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT);
- }
-
- public PooledBufferAllocator(MemoryManager manager, int numArenas, int pageSize, int maxOrder,
- int smallCacheSize, int normalCacheSize,
- boolean useCacheForAllThreads) {
- this(manager, numArenas, pageSize, maxOrder,
- smallCacheSize, normalCacheSize,
- useCacheForAllThreads, DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT);
- }
-
- public PooledBufferAllocator(MemoryManager manager, int numArenas, int pageSize, int maxOrder,
- int smallCacheSize, int normalCacheSize,
- boolean useCacheForAllThreads, int directMemoryCacheAlignment) {
- this.manager = requireNonNull(manager, "MemoryManager");
- threadCache = new PoolThreadLocalCache(useCacheForAllThreads);
- this.smallCacheSize = smallCacheSize;
- this.normalCacheSize = normalCacheSize;
-
- if (directMemoryCacheAlignment != 0) {
- if (!PlatformDependent.hasAlignDirectByteBuffer()) {
- throw new UnsupportedOperationException("Buffer alignment is not supported. " +
- "Either Unsafe or ByteBuffer.alignSlice() must be available.");
- }
-
- // Ensure page size is a whole multiple of the alignment, or bump it to the next whole multiple.
- pageSize = (int) PlatformDependent.align(pageSize, directMemoryCacheAlignment);
- }
-
- chunkSize = validateAndCalculateChunkSize(pageSize, maxOrder);
-
- checkPositiveOrZero(numArenas, "numArenas");
-
- checkPositiveOrZero(directMemoryCacheAlignment, "directMemoryCacheAlignment");
- if (directMemoryCacheAlignment > 0 && !isDirectMemoryCacheAlignmentSupported()) {
- throw new IllegalArgumentException("directMemoryCacheAlignment is not supported");
- }
-
- if ((directMemoryCacheAlignment & -directMemoryCacheAlignment) != directMemoryCacheAlignment) {
- throw new IllegalArgumentException("directMemoryCacheAlignment: "
- + directMemoryCacheAlignment + " (expected: power of two)");
- }
-
- int pageShifts = validateAndCalculatePageShifts(pageSize, directMemoryCacheAlignment);
-
- if (numArenas > 0) {
- arenas = newArenaArray(numArenas);
- List metrics = new ArrayList<>(arenas.length);
- for (int i = 0; i < arenas.length; i ++) {
- PoolArena arena = new PoolArena(this, manager,
- pageSize, pageShifts, chunkSize,
- directMemoryCacheAlignment);
- arenas[i] = arena;
- metrics.add(arena);
- }
- arenaMetrics = metrics;
- arenaMetricsView = Collections.unmodifiableList(metrics);
- } else {
- arenas = null;
- arenaMetrics = new ArrayList<>(1);
- arenaMetricsView = Collections.emptyList();
- }
-
- metric = new PooledBufferAllocatorMetric(this);
- }
-
- private static PoolArena[] newArenaArray(int size) {
- return new PoolArena[size];
- }
-
- private static int validateAndCalculatePageShifts(int pageSize, int alignment) {
- if (pageSize < MIN_PAGE_SIZE) {
- throw new IllegalArgumentException("pageSize: " + pageSize + " (expected: " + MIN_PAGE_SIZE + ')');
- }
-
- if ((pageSize & pageSize - 1) != 0) {
- throw new IllegalArgumentException("pageSize: " + pageSize + " (expected: power of 2)");
- }
-
- if (pageSize < alignment) {
- throw new IllegalArgumentException("Alignment cannot be greater than page size. " +
- "Alignment: " + alignment + ", page size: " + pageSize + '.');
- }
-
- // Logarithm base 2. At this point we know that pageSize is a power of two.
- return Integer.SIZE - 1 - Integer.numberOfLeadingZeros(pageSize);
- }
-
- private static int validateAndCalculateChunkSize(int pageSize, int maxOrder) {
- if (maxOrder > 14) {
- throw new IllegalArgumentException("maxOrder: " + maxOrder + " (expected: 0-14)");
- }
-
- // Ensure the resulting chunkSize does not overflow.
- int chunkSize = pageSize;
- for (int i = maxOrder; i > 0; i--) {
- if (chunkSize > MAX_CHUNK_SIZE / 2) {
- throw new IllegalArgumentException(String.format(
- "pageSize (%d) << maxOrder (%d) must not exceed %d", pageSize, maxOrder, MAX_CHUNK_SIZE));
- }
- chunkSize <<= 1;
- }
- return chunkSize;
- }
-
- @Override
- public Buffer allocate(int size) {
- if (size < 1) {
- throw new IllegalArgumentException("Allocation size must be positive, but was " + size + '.');
- }
- PooledAllocatorControl control = new PooledAllocatorControl();
- control.parent = this;
- UntetheredMemory memory = allocate(control, size);
- Buffer buffer = manager.recoverMemory(control, memory.memory(), memory.drop());
- return buffer.fill((byte) 0).order(ByteOrder.nativeOrder());
- }
-
- UntetheredMemory allocate(PooledAllocatorControl control, int size) {
- PoolThreadCache cache = threadCache.get();
- PoolArena arena = cache.arena;
-
- if (arena != null) {
- return arena.allocate(control, cache, size);
- }
- return allocateUnpooled(size);
- }
-
- private UntetheredMemory allocateUnpooled(int size) {
- return new UnpooledUnthetheredMemory(this, manager, size);
- }
-
- @Override
- public void close() {
- trimCurrentThreadCache();
- threadCache.remove();
- for (int i = 0, arenasLength = arenas.length; i < arenasLength; i++) {
- PoolArena arena = arenas[i];
- if (arena != null) {
- arena.close();
- arenas[i] = null;
- }
- }
- arenaMetrics.clear();
- }
-
- /**
- * Default number of heap arenas - System Property: io.netty.allocator.numHeapArenas - default 2 * cores
- */
- public static int defaultNumHeapArena() {
- return DEFAULT_NUM_HEAP_ARENA;
- }
-
- /**
- * Default number of direct arenas - System Property: io.netty.allocator.numDirectArenas - default 2 * cores
- */
- public static int defaultNumDirectArena() {
- return DEFAULT_NUM_DIRECT_ARENA;
- }
-
- /**
- * Default buffer page size - System Property: io.netty.allocator.pageSize - default 8192
- */
- public static int defaultPageSize() {
- return DEFAULT_PAGE_SIZE;
- }
-
- /**
- * Default maximum order - System Property: io.netty.allocator.maxOrder - default 11
- */
- public static int defaultMaxOrder() {
- return DEFAULT_MAX_ORDER;
- }
-
- /**
- * Default thread caching behavior - System Property: io.netty.allocator.useCacheForAllThreads - default true
- */
- public static boolean defaultUseCacheForAllThreads() {
- return DEFAULT_USE_CACHE_FOR_ALL_THREADS;
- }
-
- /**
- * Default prefer direct - System Property: io.netty.noPreferDirect - default false
- */
- public static boolean defaultPreferDirect() {
- return PlatformDependent.directBufferPreferred();
- }
-
- /**
- * Default small cache size - System Property: io.netty.allocator.smallCacheSize - default 256
- */
- public static int defaultSmallCacheSize() {
- return DEFAULT_SMALL_CACHE_SIZE;
- }
-
- /**
- * Default normal cache size - System Property: io.netty.allocator.normalCacheSize - default 64
- */
- public static int defaultNormalCacheSize() {
- return DEFAULT_NORMAL_CACHE_SIZE;
- }
-
- /**
- * Return {@code true} if direct memory cache alignment is supported, {@code false} otherwise.
- */
- public static boolean isDirectMemoryCacheAlignmentSupported() {
- return PlatformDependent.hasUnsafe();
- }
-
- public boolean isDirectBufferPooled() {
- return manager.isNative();
- }
-
- public int numArenas() {
- return arenas.length;
- }
-
- final class PoolThreadLocalCache extends FastThreadLocal {
- private final boolean useCacheForAllThreads;
-
- PoolThreadLocalCache(boolean useCacheForAllThreads) {
- this.useCacheForAllThreads = useCacheForAllThreads;
- }
-
- @Override
- protected synchronized PoolThreadCache initialValue() {
- final PoolArena arena = leastUsedArena(arenas);
-
- final Thread current = Thread.currentThread();
- if (useCacheForAllThreads || current instanceof FastThreadLocalThread) {
- final PoolThreadCache cache = new PoolThreadCache(
- arena, smallCacheSize, normalCacheSize,
- DEFAULT_MAX_CACHED_BUFFER_CAPACITY, DEFAULT_CACHE_TRIM_INTERVAL);
-
- if (DEFAULT_CACHE_TRIM_INTERVAL_MILLIS > 0) {
- final EventExecutor executor = ThreadExecutorMap.currentExecutor();
- if (executor != null) {
- executor.scheduleAtFixedRate(trimTask, DEFAULT_CACHE_TRIM_INTERVAL_MILLIS,
- DEFAULT_CACHE_TRIM_INTERVAL_MILLIS, TimeUnit.MILLISECONDS);
- }
- }
- return cache;
- }
- // No caching so just use 0 as sizes.
- return new PoolThreadCache(null, 0, 0, 0, 0);
- }
-
- @Override
- protected void onRemoval(PoolThreadCache threadCache) {
- threadCache.free();
- }
- }
-
- static PoolArena leastUsedArena(PoolArena[] arenas) {
- if (arenas == null || arenas.length == 0) {
- return null;
- }
-
- PoolArena minArena = arenas[0];
- for (int i = 1; i < arenas.length; i++) {
- PoolArena arena = arenas[i];
- if (arena.numThreadCaches.get() < minArena.numThreadCaches.get()) {
- minArena = arena;
- }
- }
-
- return minArena;
- }
-
- @Override
- public PooledBufferAllocatorMetric metric() {
- return metric;
- }
-
- /**
- * Return a {@link List} of all heap {@link PoolArenaMetric}s that are provided by this pool.
- */
- List arenaMetrics() {
- return arenaMetricsView;
- }
-
- /**
- * Return the number of thread local caches used by this {@link PooledBufferAllocator}.
- */
- int numThreadLocalCaches() {
- if (arenas == null) {
- return 0;
- }
-
- int total = 0;
- for (PoolArena arena : arenas) {
- total += arena.numThreadCaches.get();
- }
-
- return total;
- }
-
- /**
- * Return the size of the small cache.
- */
- int smallCacheSize() {
- return smallCacheSize;
- }
-
- /**
- * Return the size of the normal cache.
- */
- int normalCacheSize() {
- return normalCacheSize;
- }
-
- /**
- * Return the chunk size for an arena.
- */
- final int chunkSize() {
- return chunkSize;
- }
-
- final long usedMemory() {
- return usedMemory(arenas);
- }
-
- private static long usedMemory(PoolArena[] arenas) {
- if (arenas == null) {
- return -1;
- }
- long used = 0;
- for (PoolArena arena : arenas) {
- used += arena.numActiveBytes();
- if (used < 0) {
- return Long.MAX_VALUE;
- }
- }
- return used;
- }
-
- final PoolThreadCache threadCache() {
- PoolThreadCache cache = threadCache.get();
- assert cache != null;
- return cache;
- }
-
- /**
- * Trim thread local cache for the current {@link Thread}, which will give back any cached memory that was not
- * allocated frequently since the last trim operation.
- *
- * Returns {@code true} if a cache for the current {@link Thread} exists and so was trimmed, false otherwise.
- */
- public boolean trimCurrentThreadCache() {
- PoolThreadCache cache = threadCache.getIfExists();
- if (cache != null) {
- cache.trim();
- return true;
- }
- return false;
- }
-
- /**
- * Returns the status of the allocator (which contains all metrics) as string. Be aware this may be expensive
- * and so should not be called too frequently.
- */
- public String dumpStats() {
- int heapArenasLen = arenas == null ? 0 : arenas.length;
- StringBuilder buf = new StringBuilder(512)
- .append(heapArenasLen)
- .append(" arena(s):")
- .append(StringUtil.NEWLINE);
- if (heapArenasLen > 0) {
- for (PoolArena a: arenas) {
- buf.append(a);
- }
- }
-
- return buf.toString();
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledBufferAllocatorMetric.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledBufferAllocatorMetric.java
deleted file mode 100644
index e4d4f04..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledBufferAllocatorMetric.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import io.netty.util.internal.StringUtil;
-
-import java.util.List;
-
-/**
- * Exposed metric for {@link PooledBufferAllocator}.
- */
-final class PooledBufferAllocatorMetric implements BufferAllocatorMetric {
-
- private final PooledBufferAllocator allocator;
-
- PooledBufferAllocatorMetric(PooledBufferAllocator allocator) {
- this.allocator = allocator;
- }
-
- /**
- * Return the number of arenas.
- */
- public int numArenas() {
- return allocator.numArenas();
- }
-
- /**
- * Return a {@link List} of all {@link PoolArenaMetric}s that are provided by this pool.
- */
- public List arenaMetrics() {
- return allocator.arenaMetrics();
- }
-
- /**
- * Return the number of thread local caches used by this {@link PooledBufferAllocator}.
- */
- public int numThreadLocalCaches() {
- return allocator.numThreadLocalCaches();
- }
-
- /**
- * Return the size of the small cache.
- */
- public int smallCacheSize() {
- return allocator.smallCacheSize();
- }
-
- /**
- * Return the size of the normal cache.
- */
- public int normalCacheSize() {
- return allocator.normalCacheSize();
- }
-
- /**
- * Return the chunk size for an arena.
- */
- public int chunkSize() {
- return allocator.chunkSize();
- }
-
- @Override
- public long usedMemory() {
- return allocator.usedMemory();
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder(256);
- sb.append(StringUtil.simpleClassName(this))
- .append("(usedMemory: ").append(usedMemory())
- .append("; numArenas: ").append(numArenas())
- .append("; smallCacheSize: ").append(smallCacheSize())
- .append("; normalCacheSize: ").append(normalCacheSize())
- .append("; numThreadLocalCaches: ").append(numThreadLocalCaches())
- .append("; chunkSize: ").append(chunkSize()).append(')');
- return sb.toString();
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledDrop.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledDrop.java
deleted file mode 100644
index a3191a2..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledDrop.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import io.netty.buffer.api.Buffer;
-import io.netty.buffer.api.Drop;
-
-class PooledDrop implements Drop {
- private final PoolArena arena;
- private final PoolChunk chunk;
- private final PoolThreadCache threadCache;
- private final long handle;
- private final int normSize;
-
- PooledDrop(PoolArena arena, PoolChunk chunk, PoolThreadCache threadCache, long handle, int normSize) {
- this.arena = arena;
- this.chunk = chunk;
- this.threadCache = threadCache;
- this.handle = handle;
- this.normSize = normSize;
- }
-
- @Override
- public void drop(Buffer obj) {
- arena.free(chunk, handle, normSize, threadCache);
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/SizeClasses.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/SizeClasses.java
deleted file mode 100644
index 534cdf1..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/SizeClasses.java
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * SizeClasses requires {@code pageShifts} to be defined prior to inclusion,
- * and it in turn defines:
- *
- * LOG2_SIZE_CLASS_GROUP: Log of size class count for each size doubling.
- * LOG2_MAX_LOOKUP_SIZE: Log of max size class in the lookup table.
- * sizeClasses: Complete table of [index, log2Group, log2Delta, nDelta, isMultiPageSize,
- * isSubPage, log2DeltaLookup] tuples.
- * index: Size class index.
- * log2Group: Log of group base size (no deltas added).
- * log2Delta: Log of delta to previous size class.
- * nDelta: Delta multiplier.
- * isMultiPageSize: 'yes' if a multiple of the page size, 'no' otherwise.
- * isSubPage: 'yes' if a subpage size class, 'no' otherwise.
- * log2DeltaLookup: Same as log2Delta if a lookup table size class, 'no'
- * otherwise.
- *
- * nSubpages: Number of subpages size classes.
- * nSizes: Number of size classes.
- * nPSizes: Number of size classes that are multiples of pageSize.
- *
- * smallMaxSizeIdx: Maximum small size class index.
- *
- * lookupMaxclass: Maximum size class included in lookup table.
- * log2NormalMinClass: Log of minimum normal size class.
- *
- * The first size class and spacing are 1 << LOG2_QUANTUM.
- * Each group has 1 << LOG2_SIZE_CLASS_GROUP of size classes.
- *
- * size = 1 << log2Group + nDelta * (1 << log2Delta)
- *
- * The first size class has an unusual encoding, because the size has to be
- * split between group and delta*nDelta.
- *
- * If pageShift = 13, sizeClasses looks like this:
- *
- * (index, log2Group, log2Delta, nDelta, isMultiPageSize, isSubPage, log2DeltaLookup)
- *
- * ( 0, 4, 4, 0, no, yes, 4)
- * ( 1, 4, 4, 1, no, yes, 4)
- * ( 2, 4, 4, 2, no, yes, 4)
- * ( 3, 4, 4, 3, no, yes, 4)
- *
- * ( 4, 6, 4, 1, no, yes, 4)
- * ( 5, 6, 4, 2, no, yes, 4)
- * ( 6, 6, 4, 3, no, yes, 4)
- * ( 7, 6, 4, 4, no, yes, 4)
- *
- * ( 8, 7, 5, 1, no, yes, 5)
- * ( 9, 7, 5, 2, no, yes, 5)
- * ( 10, 7, 5, 3, no, yes, 5)
- * ( 11, 7, 5, 4, no, yes, 5)
- * ...
- * ...
- * ( 72, 23, 21, 1, yes, no, no)
- * ( 73, 23, 21, 2, yes, no, no)
- * ( 74, 23, 21, 3, yes, no, no)
- * ( 75, 23, 21, 4, yes, no, no)
- *
- * ( 76, 24, 22, 1, yes, no, no)
- */
-abstract class SizeClasses implements SizeClassesMetric {
- private static final ConcurrentHashMap CACHE =
- new ConcurrentHashMap();
-
- static final int LOG2_QUANTUM = 4;
-
- private static final int LOG2_SIZE_CLASS_GROUP = 2;
- private static final int LOG2_MAX_LOOKUP_SIZE = 12;
-
- private static final int LOG2GROUP_IDX = 1;
- private static final int LOG2DELTA_IDX = 2;
- private static final int NDELTA_IDX = 3;
- private static final int PAGESIZE_IDX = 4;
- private static final int SUBPAGE_IDX = 5;
- private static final int LOG2_DELTA_LOOKUP_IDX = 6;
-
- private static final byte no = 0, yes = 1;
-
- protected SizeClasses(int pageSize, int pageShifts, int chunkSize, int directMemoryCacheAlignment) {
- this.pageSize = pageSize;
- this.pageShifts = pageShifts;
- this.chunkSize = chunkSize;
- this.directMemoryCacheAlignment = directMemoryCacheAlignment;
-
- SizeClassValue value = CACHE.computeIfAbsent(
- new SizeClassKey(pageSize, pageShifts, chunkSize, directMemoryCacheAlignment),
- SizeClassValue::new);
- nSizes = value.nSizes;
- nSubpages = value.nSubpages;
- nPSizes = value.nPSizes;
- smallMaxSizeIdx = value.smallMaxSizeIdx;
- lookupMaxSize = value.lookupMaxSize;
- pageIdx2sizeTab = value.pageIdx2sizeTab;
- sizeIdx2sizeTab = value.sizeIdx2sizeTab;
- size2idxTab = value.size2idxTab;
- }
-
- protected final int pageSize;
- protected final int pageShifts;
- protected final int chunkSize;
- protected final int directMemoryCacheAlignment;
-
- final int nSizes;
- final int nSubpages;
- final int nPSizes;
- final int smallMaxSizeIdx;
-
- private final int lookupMaxSize;
- private final int[] pageIdx2sizeTab;
-
- // lookup table for sizeIdx <= smallMaxSizeIdx
- private final int[] sizeIdx2sizeTab;
-
- // lookup table used for size <= lookupMaxclass
- // spacing is 1 << LOG2_QUANTUM, so the size of array is lookupMaxclass >> LOG2_QUANTUM
- private final int[] size2idxTab;
-
- @Override
- public int sizeIdx2size(int sizeIdx) {
- return sizeIdx2sizeTab[sizeIdx];
- }
-
- @Override
- public int sizeIdx2sizeCompute(int sizeIdx) {
- int group = sizeIdx >> LOG2_SIZE_CLASS_GROUP;
- int mod = sizeIdx & (1 << LOG2_SIZE_CLASS_GROUP) - 1;
-
- int groupSize = group == 0? 0 :
- 1 << LOG2_QUANTUM + LOG2_SIZE_CLASS_GROUP - 1 << group;
-
- int shift = group == 0? 1 : group;
- int lgDelta = shift + LOG2_QUANTUM - 1;
- int modSize = mod + 1 << lgDelta;
-
- return groupSize + modSize;
- }
-
- @Override
- public long pageIdx2size(int pageIdx) {
- return pageIdx2sizeTab[pageIdx];
- }
-
- @Override
- public long pageIdx2sizeCompute(int pageIdx) {
- int group = pageIdx >> LOG2_SIZE_CLASS_GROUP;
- int mod = pageIdx & (1 << LOG2_SIZE_CLASS_GROUP) - 1;
-
- long groupSize = group == 0? 0 :
- 1L << pageShifts + LOG2_SIZE_CLASS_GROUP - 1 << group;
-
- int shift = group == 0? 1 : group;
- int log2Delta = shift + pageShifts - 1;
- int modSize = mod + 1 << log2Delta;
-
- return groupSize + modSize;
- }
-
- @Override
- public int size2SizeIdx(int size) {
- if (size == 0) {
- return 0;
- }
- if (size > chunkSize) {
- return nSizes;
- }
-
- if (directMemoryCacheAlignment > 0) {
- size = alignSize(size);
- }
-
- if (size <= lookupMaxSize) {
- //size-1 / MIN_TINY
- return size2idxTab[size - 1 >> LOG2_QUANTUM];
- }
-
- int x = PoolThreadCache.log2((size << 1) - 1);
- int shift = x < LOG2_SIZE_CLASS_GROUP + LOG2_QUANTUM + 1
- ? 0 : x - (LOG2_SIZE_CLASS_GROUP + LOG2_QUANTUM);
-
- int group = shift << LOG2_SIZE_CLASS_GROUP;
-
- int log2Delta = x < LOG2_SIZE_CLASS_GROUP + LOG2_QUANTUM + 1
- ? LOG2_QUANTUM : x - LOG2_SIZE_CLASS_GROUP - 1;
-
- int deltaInverseMask = -1 << log2Delta;
- int mod = (size - 1 & deltaInverseMask) >> log2Delta &
- (1 << LOG2_SIZE_CLASS_GROUP) - 1;
-
- return group + mod;
- }
-
- @Override
- public int pages2pageIdx(int pages) {
- return pages2pageIdxCompute(pages, false);
- }
-
- @Override
- public int pages2pageIdxFloor(int pages) {
- return pages2pageIdxCompute(pages, true);
- }
-
- private int pages2pageIdxCompute(int pages, boolean floor) {
- int pageSize = pages << pageShifts;
- if (pageSize > chunkSize) {
- return nPSizes;
- }
-
- int x = PoolThreadCache.log2((pageSize << 1) - 1);
-
- int shift = x < LOG2_SIZE_CLASS_GROUP + pageShifts
- ? 0 : x - (LOG2_SIZE_CLASS_GROUP + pageShifts);
-
- int group = shift << LOG2_SIZE_CLASS_GROUP;
-
- int log2Delta = x < LOG2_SIZE_CLASS_GROUP + pageShifts + 1?
- pageShifts : x - LOG2_SIZE_CLASS_GROUP - 1;
-
- int deltaInverseMask = -1 << log2Delta;
- int mod = (pageSize - 1 & deltaInverseMask) >> log2Delta &
- (1 << LOG2_SIZE_CLASS_GROUP) - 1;
-
- int pageIdx = group + mod;
-
- if (floor && pageIdx2sizeTab[pageIdx] > pages << pageShifts) {
- pageIdx--;
- }
-
- return pageIdx;
- }
-
- // Round size up to the nearest multiple of alignment.
- private int alignSize(int size) {
- int delta = size & directMemoryCacheAlignment - 1;
- return delta == 0? size : size + directMemoryCacheAlignment - delta;
- }
-
- @Override
- public int normalizeSize(int size) {
- if (size == 0) {
- return sizeIdx2sizeTab[0];
- }
- if (directMemoryCacheAlignment > 0) {
- size = alignSize(size);
- }
-
- if (size <= lookupMaxSize) {
- int ret = sizeIdx2sizeTab[size2idxTab[size - 1 >> LOG2_QUANTUM]];
- assert ret == normalizeSizeCompute(size);
- return ret;
- }
- return normalizeSizeCompute(size);
- }
-
- private static int normalizeSizeCompute(int size) {
- int x = PoolThreadCache.log2((size << 1) - 1);
- int log2Delta = x < LOG2_SIZE_CLASS_GROUP + LOG2_QUANTUM + 1
- ? LOG2_QUANTUM : x - LOG2_SIZE_CLASS_GROUP - 1;
- int delta = 1 << log2Delta;
- int delta_mask = delta - 1;
- return size + delta_mask & ~delta_mask;
- }
-
- private static final class SizeClassKey {
- final int pageSize;
- final int pageShifts;
- final int chunkSize;
- final int directMemoryCacheAlignment;
-
- private SizeClassKey(int pageSize, int pageShifts, int chunkSize, int directMemoryCacheAlignment) {
- this.pageSize = pageSize;
- this.pageShifts = pageShifts;
- this.chunkSize = chunkSize;
- this.directMemoryCacheAlignment = directMemoryCacheAlignment;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- SizeClassKey that = (SizeClassKey) o;
-
- if (pageSize != that.pageSize) {
- return false;
- }
- if (pageShifts != that.pageShifts) {
- return false;
- }
- if (chunkSize != that.chunkSize) {
- return false;
- }
- return directMemoryCacheAlignment == that.directMemoryCacheAlignment;
- }
-
- @Override
- public int hashCode() {
- int result = pageSize;
- result = 31 * result + pageShifts;
- result = 31 * result + chunkSize;
- result = 31 * result + directMemoryCacheAlignment;
- return result;
- }
- }
-
- private static final class SizeClassValue {
- final SizeClassKey key;
- final int nSizes;
- int nSubpages;
- int nPSizes;
- int smallMaxSizeIdx;
- int lookupMaxSize;
- final short[][] sizeClasses;
- final int[] pageIdx2sizeTab;
- final int[] sizeIdx2sizeTab;
- final int[] size2idxTab;
-
- SizeClassValue(SizeClassKey key) {
- this.key = key;
- int group = PoolThreadCache.log2(key.chunkSize) + 1 - LOG2_QUANTUM;
-
- //generate size classes
- //[index, log2Group, log2Delta, nDelta, isMultiPageSize, isSubPage, log2DeltaLookup]
- sizeClasses = new short[group << LOG2_SIZE_CLASS_GROUP][7];
- nSizes = sizeClasses();
-
- //generate lookup table
- sizeIdx2sizeTab = new int[nSizes];
- pageIdx2sizeTab = new int[nPSizes];
- idx2SizeTab(sizeIdx2sizeTab, pageIdx2sizeTab);
-
- size2idxTab = new int[lookupMaxSize >> LOG2_QUANTUM];
- size2idxTab(size2idxTab);
- }
-
- private int sizeClasses() {
- int normalMaxSize = -1;
-
- int index = 0;
- int size = 0;
-
- int log2Group = LOG2_QUANTUM;
- int log2Delta = LOG2_QUANTUM;
- int ndeltaLimit = 1 << LOG2_SIZE_CLASS_GROUP;
-
- //First small group, nDelta start at 0.
- //first size class is 1 << LOG2_QUANTUM
- int nDelta = 0;
- while (nDelta < ndeltaLimit) {
- size = sizeClass(index++, log2Group, log2Delta, nDelta++);
- }
- log2Group += LOG2_SIZE_CLASS_GROUP;
-
- //All remaining groups, nDelta start at 1.
- while (size < key.chunkSize) {
- nDelta = 1;
-
- while (nDelta <= ndeltaLimit && size < key.chunkSize) {
- size = sizeClass(index++, log2Group, log2Delta, nDelta++);
- normalMaxSize = size;
- }
-
- log2Group++;
- log2Delta++;
- }
-
- //chunkSize must be normalMaxSize
- assert key.chunkSize == normalMaxSize;
-
- //return number of size index
- return index;
- }
-
- //calculate size class
- private int sizeClass(int index, int log2Group, int log2Delta, int nDelta) {
- short isMultiPageSize;
- if (log2Delta >= key.pageShifts) {
- isMultiPageSize = yes;
- } else {
- int pageSize = 1 << key.pageShifts;
- int size = (1 << log2Group) + (1 << log2Delta) * nDelta;
-
- isMultiPageSize = size == size / pageSize * pageSize? yes : no;
- }
-
- int log2Ndelta = nDelta == 0? 0 : PoolThreadCache.log2(nDelta);
-
- byte remove = 1 << log2Ndelta < nDelta? yes : no;
-
- int log2Size = log2Delta + log2Ndelta == log2Group? log2Group + 1 : log2Group;
- if (log2Size == log2Group) {
- remove = yes;
- }
-
- short isSubpage = log2Size < key.pageShifts + LOG2_SIZE_CLASS_GROUP? yes : no;
-
- int log2DeltaLookup = log2Size < LOG2_MAX_LOOKUP_SIZE ||
- log2Size == LOG2_MAX_LOOKUP_SIZE && remove == no
- ? log2Delta : no;
-
- short[] sz = {
- (short) index, (short) log2Group, (short) log2Delta,
- (short) nDelta, isMultiPageSize, isSubpage, (short) log2DeltaLookup
- };
-
- sizeClasses[index] = sz;
- int size = (1 << log2Group) + (nDelta << log2Delta);
-
- if (sz[PAGESIZE_IDX] == yes) {
- nPSizes++;
- }
- if (sz[SUBPAGE_IDX] == yes) {
- nSubpages++;
- smallMaxSizeIdx = index;
- }
- if (sz[LOG2_DELTA_LOOKUP_IDX] != no) {
- lookupMaxSize = size;
- }
- return size;
- }
-
- private void idx2SizeTab(int[] sizeIdx2sizeTab, int[] pageIdx2sizeTab) {
- int pageIdx = 0;
-
- for (int i = 0; i < nSizes; i++) {
- short[] sizeClass = sizeClasses[i];
- int log2Group = sizeClass[LOG2GROUP_IDX];
- int log2Delta = sizeClass[LOG2DELTA_IDX];
- int nDelta = sizeClass[NDELTA_IDX];
-
- int size = (1 << log2Group) + (nDelta << log2Delta);
- sizeIdx2sizeTab[i] = size;
-
- if (sizeClass[PAGESIZE_IDX] == yes) {
- pageIdx2sizeTab[pageIdx++] = size;
- }
- }
- }
-
- private void size2idxTab(int[] size2idxTab) {
- int idx = 0;
- int size = 0;
-
- for (int i = 0; size <= lookupMaxSize; i++) {
- int log2Delta = sizeClasses[i][LOG2DELTA_IDX];
- int times = 1 << log2Delta - LOG2_QUANTUM;
-
- while (size <= lookupMaxSize && times-- > 0) {
- size2idxTab[idx++] = i;
- size = idx + 1 << LOG2_QUANTUM;
- }
- }
- }
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/SizeClassesMetric.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/SizeClassesMetric.java
deleted file mode 100644
index 3f3ac3e..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/SizeClassesMetric.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-/**
- * Expose metrics for an SizeClasses.
- */
-public interface SizeClassesMetric {
-
- /**
- * Computes size from lookup table according to sizeIdx.
- *
- * @return size
- */
- int sizeIdx2size(int sizeIdx);
-
- /**
- * Computes size according to sizeIdx.
- *
- * @return size
- */
- int sizeIdx2sizeCompute(int sizeIdx);
-
- /**
- * Computes size from lookup table according to pageIdx.
- *
- * @return size which is multiples of pageSize.
- */
- long pageIdx2size(int pageIdx);
-
- /**
- * Computes size according to pageIdx.
- *
- * @return size which is multiples of pageSize
- */
- long pageIdx2sizeCompute(int pageIdx);
-
- /**
- * Normalizes request size up to the nearest size class.
- *
- * @param size request size
- *
- * @return sizeIdx of the size class
- */
- int size2SizeIdx(int size);
-
- /**
- * Normalizes request size up to the nearest pageSize class.
- *
- * @param pages multiples of pageSizes
- *
- * @return pageIdx of the pageSize class
- */
- int pages2pageIdx(int pages);
-
- /**
- * Normalizes request size down to the nearest pageSize class.
- *
- * @param pages multiples of pageSizes
- *
- * @return pageIdx of the pageSize class
- */
- int pages2pageIdxFloor(int pages);
-
- /**
- * Normalizes usable size that would result from allocating an object with the
- * specified size and alignment.
- *
- * @param size request size
- *
- * @return normalized size
- */
- int normalizeSize(int size);
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/UnpooledUnthetheredMemory.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/UnpooledUnthetheredMemory.java
deleted file mode 100644
index 475087f..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/UnpooledUnthetheredMemory.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.pool;
-
-import io.netty.buffer.api.AllocatorControl;
-import io.netty.buffer.api.Buffer;
-import io.netty.buffer.api.Drop;
-import io.netty.buffer.api.MemoryManager;
-import io.netty.buffer.api.internal.Statics;
-
-@SuppressWarnings("unchecked")
-class UnpooledUnthetheredMemory implements AllocatorControl.UntetheredMemory {
- private final MemoryManager manager;
- private final Buffer buffer;
-
- UnpooledUnthetheredMemory(PooledBufferAllocator allocator, MemoryManager manager, int size) {
- this.manager = manager;
- PooledAllocatorControl allocatorControl = new PooledAllocatorControl();
- allocatorControl.parent = allocator;
- buffer = manager.allocateShared(allocatorControl, size, manager.drop(), Statics.CLEANER);
- }
-
- @Override
- public Memory memory() {
- return (Memory) manager.unwrapRecoverableMemory(buffer);
- }
-
- @Override
- public Drop drop() {
- return (Drop) manager.drop();
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/package-info.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/package-info.java
deleted file mode 100644
index ce60c3b..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/pool/package-info.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-/**
- * A pooling {@link io.netty.buffer.api.BufferAllocator} implementation based on jemalloc.
- */
-package io.netty.buffer.api.pool;
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/CleanerDrop.java b/buffer-api/src/main/java/io/netty/buffer/api/unsafe/CleanerDrop.java
deleted file mode 100644
index d252936..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/CleanerDrop.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.unsafe;
-
-import io.netty.buffer.api.Buffer;
-import io.netty.buffer.api.Drop;
-import io.netty.util.internal.PlatformDependent;
-
-import java.lang.ref.Cleaner;
-
-public class CleanerDrop implements Drop {
- private final Drop drop;
-
- public CleanerDrop(UnsafeMemory memory, Drop drop, Cleaner cleaner) {
- this.drop = drop;
- long address = memory.address;
- cleaner.register(memory, new FreeAddress(address));
- }
-
- @Override
- public void drop(Buffer obj) {
- drop.drop(obj);
- }
-
- @Override
- public void attach(Buffer obj) {
- drop.attach(obj);
- }
-
- private static class FreeAddress implements Runnable {
- private final long address;
-
- FreeAddress(long address) {
- this.address = address;
- }
-
- @Override
- public void run() {
- PlatformDependent.freeMemory(address);
- }
- }
-}
diff --git a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeBuffer.java b/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeBuffer.java
deleted file mode 100644
index d0920e9..0000000
--- a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeBuffer.java
+++ /dev/null
@@ -1,1690 +0,0 @@
-/*
- * Copyright 2021 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package io.netty.buffer.api.unsafe;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.api.BufferAllocator;
-import io.netty.buffer.api.AllocatorControl;
-import io.netty.buffer.api.Buffer;
-import io.netty.buffer.api.BufferReadOnlyException;
-import io.netty.buffer.api.ByteCursor;
-import io.netty.buffer.api.Drop;
-import io.netty.buffer.api.Owned;
-import io.netty.buffer.api.adaptor.BufferIntegratable;
-import io.netty.buffer.api.adaptor.ByteBufAdaptor;
-import io.netty.buffer.api.adaptor.ByteBufAllocatorAdaptor;
-import io.netty.buffer.api.internal.ResourceSupport;
-import io.netty.buffer.api.ReadableComponent;
-import io.netty.buffer.api.ReadableComponentProcessor;
-import io.netty.buffer.api.WritableComponent;
-import io.netty.buffer.api.WritableComponentProcessor;
-import io.netty.buffer.api.internal.ArcDrop;
-import io.netty.buffer.api.internal.Statics;
-import io.netty.util.IllegalReferenceCountException;
-import io.netty.util.ReferenceCounted;
-import io.netty.util.internal.PlatformDependent;
-
-import java.lang.ref.Reference;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-import static io.netty.buffer.api.internal.Statics.bbslice;
-import static io.netty.buffer.api.internal.Statics.bufferIsClosed;
-import static io.netty.buffer.api.internal.Statics.bufferIsReadOnly;
-import static io.netty.util.internal.PlatformDependent.BIG_ENDIAN_NATIVE_ORDER;
-
-class UnsafeBuffer extends ResourceSupport implements Buffer, ReadableComponent,
- WritableComponent, BufferIntegratable {
- private static final int CLOSED_SIZE = -1;
- private static final boolean ACCESS_UNALIGNED = PlatformDependent.isUnaligned();
- private UnsafeMemory memory; // The memory liveness; monitored by Cleaner.
- private Object base; // On-heap address reference object, or null for off-heap.
- private long baseOffset; // Offset of this buffer into the memory.
- private long address; // Resolved address (baseOffset + memory.address).
- private int rsize;
- private int wsize;
- private final AllocatorControl control;
- private ByteOrder order;
- private boolean flipBytes;
- private boolean readOnly;
- private int roff;
- private int woff;
- private boolean constBuffer;
-
- UnsafeBuffer(UnsafeMemory memory, long offset, int size, AllocatorControl allocatorControl,
- Drop drop) {
- super(new MakeInaccessibleOnDrop(ArcDrop.wrap(drop)));
- this.memory = memory;
- base = memory.base;
- baseOffset = offset;
- address = memory.address + offset;
- rsize = size;
- wsize = size;
- control = allocatorControl;
- order = ByteOrder.nativeOrder();
- }
-
- UnsafeBuffer(UnsafeBuffer parent) {
- super(new MakeInaccessibleOnDrop(new ArcDrop<>(ArcDrop.acquire(parent.unsafeGetDrop()))));
- control = parent.control;
- memory = parent.memory;
- base = parent.base;
- baseOffset = parent.baseOffset;
- address = parent.address;
- rsize = parent.rsize;
- wsize = parent.wsize;
- order = parent.order;
- flipBytes = parent.flipBytes;
- readOnly = parent.readOnly;
- roff = parent.roff;
- woff = parent.woff;
- constBuffer = true;
- }
-
- @Override
- public String toString() {
- return "Buffer[roff:" + roff + ", woff:" + woff + ", cap:" + rsize + ']';
- }
-
- @Override
- protected RuntimeException createResourceClosedException() {
- return bufferIsClosed(this);
- }
-
- @Override
- public Buffer order(ByteOrder order) {
- this.order = order;
- flipBytes = order != ByteOrder.nativeOrder();
- return this;
- }
-
- @Override
- public ByteOrder order() {
- return order;
- }
-
- @Override
- public int capacity() {
- return Math.max(0, rsize); // Use Math.max to make capacity of closed buffer equal to zero.
- }
-
- @Override
- public int readerOffset() {
- return roff;
- }
-
- @Override
- public Buffer readerOffset(int offset) {
- checkRead(offset, 0);
- roff = offset;
- return this;
- }
-
- @Override
- public int writerOffset() {
- return woff;
- }
-
- @Override
- public Buffer writerOffset(int offset) {
- checkWrite(offset, 0);
- woff = offset;
- return this;
- }
-
- @Override
- public Buffer fill(byte value) {
- checkSet(0, capacity());
- if (rsize == CLOSED_SIZE) {
- throw bufferIsClosed(this);
- }
- try {
- PlatformDependent.setMemory(base, address, rsize, value);
- } finally {
- Reference.reachabilityFence(memory);
- }
- return this;
- }
-
- @Override
- public long nativeAddress() {
- return base == null? address : 0;
- }
-
- @Override
- public Buffer makeReadOnly() {
- readOnly = true;
- wsize = CLOSED_SIZE;
- return this;
- }
-
- @Override
- public boolean readOnly() {
- return readOnly;
- }
-
- @Override
- public Buffer copy(int offset, int length) {
- checkGet(offset, length);
- int allocSize = Math.max(length, 1); // Allocators don't support allocating zero-sized buffers.
- AllocatorControl.UntetheredMemory memory = control.allocateUntethered(this, allocSize);
- UnsafeMemory unsafeMemory = memory.memory();
- Buffer copy = new UnsafeBuffer(unsafeMemory, 0, length, control, memory.drop());
- copyInto(offset, copy, 0, length);
- copy.writerOffset(length).order(order);
- if (readOnly) {
- copy = copy.makeReadOnly();
- }
- return copy;
- }
-
- @Override
- public void copyInto(int srcPos, byte[] dest, int destPos, int length) {
- checkCopyIntoArgs(srcPos, length, destPos, dest.length);
- copyIntoArray(srcPos, dest, destPos, length);
- }
-
- private void copyIntoArray(int srcPos, byte[] dest, int destPos, int length) {
- long destOffset = PlatformDependent.byteArrayBaseOffset();
- try {
- PlatformDependent.copyMemory(base, address + srcPos, dest, destOffset + destPos, length);
- } finally {
- Reference.reachabilityFence(memory);
- Reference.reachabilityFence(dest);
- }
- }
-
- @Override
- public void copyInto(int srcPos, ByteBuffer dest, int destPos, int length) {
- checkCopyIntoArgs(srcPos, length, destPos, dest.capacity());
- if (dest.hasArray()) {
- copyIntoArray(srcPos, dest.array(), dest.arrayOffset() + destPos, length);
- } else {
- assert dest.isDirect();
- long destAddr = PlatformDependent.directBufferAddress(dest);
- try {
- PlatformDependent.copyMemory(base, address + srcPos, null, destAddr + destPos, length);
- } finally {
- Reference.reachabilityFence(memory);
- Reference.reachabilityFence(dest);
- }
- }
- }
-
- private void checkCopyIntoArgs(int srcPos, int length, int destPos, int destLength) {
- if (rsize == CLOSED_SIZE) {
- throw bufferIsClosed(this);
- }
- if (srcPos < 0) {
- throw new IllegalArgumentException("The srcPos cannot be negative: " + srcPos + '.');
- }
- if (length < 0) {
- throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
- }
- if (rsize < srcPos + length) {
- throw new IllegalArgumentException("The srcPos + length is beyond the end of the buffer: " +
- "srcPos = " + srcPos + ", length = " + length + '.');
- }
- if (destPos < 0) {
- throw new IllegalArgumentException("The destPos cannot be negative: " + destPos + '.');
- }
- if (destLength < destPos + length) {
- throw new IllegalArgumentException("The destPos + length is beyond the end of the destination: " +
- "destPos = " + destPos + ", length = " + length + '.');
- }
- }
-
- @Override
- public void copyInto(int srcPos, Buffer dest, int destPos, int length) {
- checkCopyIntoArgs(srcPos, length, destPos, dest.capacity());
- if (dest.readOnly()) {
- throw bufferIsReadOnly(this);
- }
- long nativeAddress = dest.nativeAddress();
- try {
- if (nativeAddress != 0) {
- PlatformDependent.copyMemory(base, address + srcPos, null, nativeAddress + destPos, length);
- } else if (dest instanceof UnsafeBuffer) {
- UnsafeBuffer destUnsafe = (UnsafeBuffer) dest;
- PlatformDependent.copyMemory(
- base, address + srcPos, destUnsafe.base, destUnsafe.address + destPos, length);
- } else {
- Statics.copyToViaReverseCursor(this, srcPos, dest, destPos, length);
- }
- } finally {
- Reference.reachabilityFence(memory);
- Reference.reachabilityFence(dest);
- }
- }
-
- @Override
- public ByteCursor openCursor() {
- return openCursor(readerOffset(), readableBytes());
- }
-
- @Override
- public ByteCursor openCursor(int fromOffset, int length) {
- if (rsize == CLOSED_SIZE) {
- throw bufferIsClosed(this);
- }
- if (fromOffset < 0) {
- throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.');
- }
- if (length < 0) {
- throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
- }
- if (capacity() < fromOffset + length) {
- throw new IllegalArgumentException("The fromOffset + length is beyond the end of the buffer: " +
- "fromOffset = " + fromOffset + ", length = " + length + '.');
- }
- return new ByteCursor() {
- final UnsafeMemory memory = UnsafeBuffer.this.memory; // Keep memory alive.
- final Object baseObj = base;
- final long baseAddress = address;
- int index = fromOffset;
- final int end = index + length;
- long longValue = -1;
- byte byteValue = -1;
-
- @Override
- public boolean readLong() {
- if (index + Long.BYTES <= end) {
- try {
- long value = PlatformDependent.getLong(baseObj, baseAddress + index);
- longValue = BIG_ENDIAN_NATIVE_ORDER? value : Long.reverseBytes(value);
- } finally {
- Reference.reachabilityFence(memory);
- }
- index += Long.BYTES;
- return true;
- }
- return false;
- }
-
- @Override
- public long getLong() {
- return longValue;
- }
-
- @Override
- public boolean readByte() {
- if (index < end) {
- try {
- byteValue = PlatformDependent.getByte(baseObj, baseAddress + index);
- } finally {
- Reference.reachabilityFence(memory);
- }
- index++;
- return true;
- }
- return false;
- }
-
- @Override
- public byte getByte() {
- return byteValue;
- }
-
- @Override
- public int currentOffset() {
- return index;
- }
-
- @Override
- public int bytesLeft() {
- return end - index;
- }
- };
- }
-
- @Override
- public ByteCursor openReverseCursor(int fromOffset, int length) {
- if (rsize == CLOSED_SIZE) {
- throw bufferIsClosed(this);
- }
- if (fromOffset < 0) {
- throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.');
- }
- if (length < 0) {
- throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
- }
- if (capacity() <= fromOffset) {
- throw new IllegalArgumentException("The fromOffset is beyond the end of the buffer: " + fromOffset + '.');
- }
- if (fromOffset - length < -1) {
- throw new IllegalArgumentException("The fromOffset - length would underflow the buffer: " +
- "fromOffset = " + fromOffset + ", length = " + length + '.');
- }
- return new ByteCursor() {
- final UnsafeMemory memory = UnsafeBuffer.this.memory; // Keep memory alive.
- final Object baseObj = base;
- final long baseAddress = address;
- int index = fromOffset;
- final int end = index - length;
- long longValue = -1;
- byte byteValue = -1;
-
- @Override
- public boolean readLong() {
- if (index - Long.BYTES >= end) {
- index -= 7;
- try {
- long value = PlatformDependent.getLong(baseObj, baseAddress + index);
- longValue = BIG_ENDIAN_NATIVE_ORDER? Long.reverseBytes(value) : value;
- } finally {
- Reference.reachabilityFence(memory);
- }
- index--;
- return true;
- }
- return false;
- }
-
- @Override
- public long getLong() {
- return longValue;
- }
-
- @Override
- public boolean readByte() {
- if (index > end) {
- try {
- byteValue = PlatformDependent.getByte(baseObj, baseAddress + index);
- } finally {
- Reference.reachabilityFence(memory);
- }
- index--;
- return true;
- }
- return false;
- }
-
- @Override
- public byte getByte() {
- return byteValue;
- }
-
- @Override
- public int currentOffset() {
- return index;
- }
-
- @Override
- public int bytesLeft() {
- return index - end;
- }
- };
- }
-
- @Override
- public void ensureWritable(int size, int minimumGrowth, boolean allowCompaction) {
- if (!isAccessible()) {
- throw bufferIsClosed(this);
- }
- if (!isOwned()) {
- throw attachTrace(new IllegalStateException(
- "Buffer is not owned. Only owned buffers can call ensureWritable."));
- }
- if (size < 0) {
- throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.');
- }
- if (minimumGrowth < 0) {
- throw new IllegalArgumentException("The minimum growth cannot be negative: " + minimumGrowth + '.');
- }
- if (rsize != wsize) {
- throw bufferIsReadOnly(this);
- }
- if (writableBytes() >= size) {
- // We already have enough space.
- return;
- }
-
- if (allowCompaction && writableBytes() + readerOffset() >= size) {
- // We can solve this with compaction.
- compact();
- return;
- }
-
- // Allocate a bigger buffer.
- long newSize = capacity() + (long) Math.max(size - writableBytes(), minimumGrowth);
- BufferAllocator.checkSize(newSize);
- var untethered = control.allocateUntethered(this, (int) newSize);
- UnsafeMemory memory = untethered.memory();
-
- // Copy contents.
- try {
- PlatformDependent.copyMemory(base, address, memory.base, memory.address, rsize);
- } finally {
- Reference.reachabilityFence(this.memory);
- Reference.reachabilityFence(memory);
- }
-
- // Release the old memory, and install the new memory:
- Drop drop = untethered.drop();
- disconnectDrop(drop);
- attachNewMemory(memory, drop);
- }
-
- private Drop disconnectDrop(Drop