/* * 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.b2; import java.nio.ByteBuffer; import java.nio.ByteOrder; /** * A reference counted buffer of memory, with separate reader and writer offsets. *
* A buffer is a sequential stretch of memory with a certain capacity, an offset for writing, and an offset for reading. * *
* When the buffer is initially allocated, a pairing {@link #close()} call will deallocate it. * In this state, the buffer {@linkplain #isOwned() is "owned"}. *
* The buffer can also be {@linkplain #acquire() acquired} when it's about to be involved in a complicated life time. * The {@link #acquire()} call increments the reference count of the buffer, * and a pairing {@link #close()} call will decrement the reference count. * Each acquire lends out the buffer, and the buffer is said to be in a "borrowed" state. *
* Certain operations, such as {@link #send()}, are only available on owned buffers. * *
* Confined buffers will initially be confined to the thread that allocates them. *
* If a buffer needs to be accessed by a different thread, * then the ownership of that buffer must be sent to that thread. * This can be done with the {@link #send()} method. * The send method consumes the buffer, if it is in an owned state, and produces a {@link Send} object. * The {@link Send} object can then be shared in a thread-safe way (so called "safe publication"), * with the intended recipient thread. *
* To send a buffer to another thread, the buffer must not have any outstanding borrows. * That is to say, all {@linkplain #acquire() acquires} must have been paired with a {@link #close()}; * all {@linkplain #slice() slices} must have been closed. * And if this buffer is a constituent of a {@linkplain Allocator#compose(Buf...) composite buffer}, * then that composite buffer must be closed. * And if this buffer is itself a composite buffer, then it must own all of its constituent buffers. * The {@link #isOwned()} method can be used on any buffer to check if it can be sent or not. * *
* This carves the buffer into three regions, as demonstrated by this diagram: *
* +-------------------+------------------+------------------+ * | discardable bytes | readable bytes | writable bytes | * | | (CONTENT) | | * +-------------------+------------------+------------------+ * | | | | * 0 <= readerOffset <= writerOffset <= capacity ** */ public interface Buf extends Rc
* This method increments the reference count of this buffer. * The reference count is decremented again when the slice is deallocated. *
* The slice is created with a {@linkplain #writerOffset() write offset} equal to the length of the slice, * so that the entire contents of the slice is ready to be read. * * @return A new buffer instance, with independent {@link #readerOffset()} and {@link #writerOffset()}, * that is a view of the readable region of this buffer. */ default Buf slice() { return slice(readerOffset(), readableBytes()); } /** * Returns a slice of the given region of this buffer. * Modifying the content of the returned buffer or this buffer affects each other's content, * while they maintain separate offsets. * This method does not modify {@link #readerOffset()} or {@link #writerOffset()} of this buffer. *
* This method increments the reference count of this buffer. * The reference count is decremented again when the slice is deallocated. *
* The slice is created with a {@linkplain #writerOffset() write offset} equal to the length of the slice, * so that the entire contents of the slice is ready to be read. * * @return A new buffer instance, with independent {@link #readerOffset()} and {@link #writerOffset()}, * that is a view of the given region of this buffer. */ Buf slice(int offset, int length); /** * 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, Buf dest, int destPos, int length); /** * Resets the {@linkplain #readerOffset() read offset} and the {@linkplain #writerOffset() write offset} on this * buffer to their initial values. */ default void reset() { readerOffset(0); writerOffset(0); } /** * Iterate the readable bytes of this buffer. The {@linkplain #readerOffset() reader offset} and * {@linkplain #writerOffset() witer offset} are not modified by the iterator. *
* Care should be taken to ensure that the buffers lifetime extends beyond the iteration, and 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 ByteIterator} for the readable bytes of this buffer. */ default ByteIterator iterate() { return iterate(readerOffset(), readableBytes()); } /** * 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 iterator. *
* Care should be taken to ensure that the buffers lifetime extends beyond the iteration, and 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 ByteIterator} 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 of the bounds of this buffer. */ ByteIterator iterate(int fromOffset, int length); /** * Iterate the readable bytes of this buffer, in reverse. The {@linkplain #readerOffset() reader offset} and * {@linkplain #writerOffset() witer offset} are not modified by the iterator. *
* Care should be taken to ensure that the buffers lifetime extends beyond the iteration, and 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 ByteIterator} for the readable bytes of this buffer. */ default ByteIterator iterateReverse() { int woff = writerOffset(); return iterateReverse(woff == 0? 0 : woff - 1, readableBytes()); } /** * 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 iterator. *
* Care should be taken to ensure that the buffers lifetime extends beyond the iteration, and 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 ByteIterator} 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 of the bounds of this buffer. */ ByteIterator iterateReverse(int fromOffset, int length); /** * Ensure that this buffer has {@linkplain #writableBytes() available space for writing} the given number of * bytes. * The buffer must be in {@linkplain #isOwned() an owned state}, or an exception will be thrown. * 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 Allocator} * the buffer was created with. * * @param size The requested number of bytes of space that should be available for writing. * @throws IllegalStateException if this buffer is not in an owned state. * That is, if {@link #countBorrows()} is not {@code 0}. */ void ensureWritable(int size); }