Prepare for configurable byte order in Buf.

Motivation:
Different protocols will prefer to use different default byte order, so it makes sense if our buffers support a configurable byte order as well.

Modification:
Break all accessor methods into 3 variants; one that uses default (configured) byte order, and two others that use big- and little-endian, respectively.

Result:
Buffers can be allocated with any byte order desired, and this byte order can even be changed later in rare cases where that's useful.
The Buf API also has accessors that explicitly uses BE or LE byte order, for when you don't want to rely on the configured default.
This commit is contained in:
Chris Vest 2020-10-06 15:54:48 +02:00
parent 1f4e33b42a
commit 8941fab5fa
4 changed files with 89 additions and 8 deletions

View File

@ -17,7 +17,9 @@ package io.netty.buffer.b2;
import jdk.incubator.foreign.MemorySegment;
import static io.netty.buffer.b2.BBuf.*;
import java.nio.ByteOrder;
import static io.netty.buffer.b2.BBuf.SEGMENT_CLOSE;
/**
* Interface for {@link Buf} allocators.
@ -38,12 +40,29 @@ public interface Allocator extends AutoCloseable {
/**
* Allocate a {@link Buf} 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 Buf} of the requested size.
* <p>
* 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 Buf} to allocate.
* @return The newly allocated {@link Buf}.
*/
Buf allocate(long size);
/**
* Allocate a {@link Buf} 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 Buf} of the requested size.
* <p>
* The buffer will use the given byte order by default.
*
* @param size The size of {@link Buf} 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 Buf}.
*/
default Buf allocate(long size, ByteOrder order) {
return allocate(size).order(order);
}
/**
* Close this allocator, freeing all of its internal resources. It is not specified if the allocator can still be
* used after this method has been called on it.

View File

@ -17,17 +17,58 @@ package io.netty.buffer.b2;
import jdk.incubator.foreign.MemorySegment;
import static jdk.incubator.foreign.MemoryAccess.*;
import java.nio.ByteOrder;
import static jdk.incubator.foreign.MemoryAccess.getByteAtOffset_BE;
import static jdk.incubator.foreign.MemoryAccess.getCharAtOffset_BE;
import static jdk.incubator.foreign.MemoryAccess.getCharAtOffset_LE;
import static jdk.incubator.foreign.MemoryAccess.getDoubleAtOffset_BE;
import static jdk.incubator.foreign.MemoryAccess.getDoubleAtOffset_LE;
import static jdk.incubator.foreign.MemoryAccess.getFloatAtOffset_BE;
import static jdk.incubator.foreign.MemoryAccess.getFloatAtOffset_LE;
import static jdk.incubator.foreign.MemoryAccess.getIntAtOffset_BE;
import static jdk.incubator.foreign.MemoryAccess.getIntAtOffset_LE;
import static jdk.incubator.foreign.MemoryAccess.getLongAtOffset_BE;
import static jdk.incubator.foreign.MemoryAccess.getLongAtOffset_LE;
import static jdk.incubator.foreign.MemoryAccess.getShortAtOffset_BE;
import static jdk.incubator.foreign.MemoryAccess.getShortAtOffset_LE;
import static jdk.incubator.foreign.MemoryAccess.setByteAtOffset_BE;
import static jdk.incubator.foreign.MemoryAccess.setByteAtOffset_LE;
import static jdk.incubator.foreign.MemoryAccess.setCharAtOffset_BE;
import static jdk.incubator.foreign.MemoryAccess.setCharAtOffset_LE;
import static jdk.incubator.foreign.MemoryAccess.setDoubleAtOffset_BE;
import static jdk.incubator.foreign.MemoryAccess.setDoubleAtOffset_LE;
import static jdk.incubator.foreign.MemoryAccess.setFloatAtOffset_BE;
import static jdk.incubator.foreign.MemoryAccess.setFloatAtOffset_LE;
import static jdk.incubator.foreign.MemoryAccess.setIntAtOffset_BE;
import static jdk.incubator.foreign.MemoryAccess.setIntAtOffset_LE;
import static jdk.incubator.foreign.MemoryAccess.setLongAtOffset_BE;
import static jdk.incubator.foreign.MemoryAccess.setLongAtOffset_LE;
import static jdk.incubator.foreign.MemoryAccess.setShortAtOffset_BE;
import static jdk.incubator.foreign.MemoryAccess.setShortAtOffset_LE;
class BBuf extends RcSupport<Buf, BBuf> implements Buf {
static final Drop<BBuf> SEGMENT_CLOSE = buf -> buf.seg.close();
final MemorySegment seg;
private boolean isBigEndian;
private int roff;
private int woff;
BBuf(MemorySegment segment, Drop<BBuf> drop) {
super(drop);
seg = segment;
isBigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
}
@Override
public Buf order(ByteOrder order) {
isBigEndian = order == ByteOrder.BIG_ENDIAN;
return this;
}
@Override
public ByteOrder order() {
return isBigEndian? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
}
@Override
@ -311,9 +352,13 @@ class BBuf extends RcSupport<Buf, BBuf> implements Buf {
@Override
public int readMedium() {
checkRead(roff, 3);
int value = getByteAtOffset_BE(seg, roff) << 16 |
(getByteAtOffset_BE(seg, roff + 1) & 0xFF) << 8 |
getByteAtOffset_BE(seg, roff + 2) & 0xFF;
int value = isBigEndian?
getByteAtOffset_BE(seg, roff) << 16 |
(getByteAtOffset_BE(seg, roff + 1) & 0xFF) << 8 |
getByteAtOffset_BE(seg, roff + 2) & 0xFF :
getByteAtOffset_BE(seg, roff) & 0xFF |
(getByteAtOffset_BE(seg, roff + 1) & 0xFF) << 8 |
getByteAtOffset_BE(seg, roff + 2) << 16;
roff += 3;
return value;
}
@ -322,8 +367,8 @@ class BBuf extends RcSupport<Buf, BBuf> implements Buf {
public int readMedium(int roff) {
checkRead(roff, 3);
return getByteAtOffset_BE(seg, roff) << 16 |
(getByteAtOffset_BE(seg, roff + 1) & 0xFF) << 8 |
getByteAtOffset_BE(seg, roff + 2) & 0xFF;
(getByteAtOffset_BE(seg, roff + 1) & 0xFF) << 8 |
getByteAtOffset_BE(seg, roff + 2) & 0xFF;
}
@Override
@ -738,6 +783,7 @@ class BBuf extends RcSupport<Buf, BBuf> implements Buf {
public BBuf transferOwnership(Thread recipient, Drop<BBuf> drop) {
var newSegment = isConfined? transferSegment.withOwnerThread(recipient) : transferSegment;
BBuf copy = new BBuf(newSegment, drop);
copy.isBigEndian = outer.isBigEndian;
copy.roff = outer.roff;
copy.woff = outer.woff;
return copy;

View File

@ -15,10 +15,26 @@
*/
package io.netty.buffer.b2;
import java.nio.ByteOrder;
/**
* A reference counted buffer API with separate reader and writer indexes.
*/
public interface Buf extends Rc<Buf> {
/**
* 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.
*/
Buf 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.
*

View File

@ -22,7 +22,7 @@ import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodHandles.lookup;
abstract class SizeClassedMemoryPool implements Allocator, Drop<BBuf> {
private static final VarHandle CLOSE = Statics.findVarHandle(