8193085: Vectorize the nio Buffer equals and compareTo implementations
Reviewed-by: alanb
This commit is contained in:
parent
038b5f571c
commit
fb9db6b02d
@ -996,8 +996,8 @@
|
||||
do_name( montgomerySquare_name, "implMontgomerySquare") \
|
||||
do_signature(montgomerySquare_signature, "([I[IIJ[I)[I") \
|
||||
\
|
||||
do_class(java_util_ArraysSupport, "java/util/ArraysSupport") \
|
||||
do_intrinsic(_vectorizedMismatch, java_util_ArraysSupport, vectorizedMismatch_name, vectorizedMismatch_signature, F_S)\
|
||||
do_class(jdk_internal_util_ArraysSupport, "jdk/internal/util/ArraysSupport") \
|
||||
do_intrinsic(_vectorizedMismatch, jdk_internal_util_ArraysSupport, vectorizedMismatch_name, vectorizedMismatch_signature, F_S)\
|
||||
do_name(vectorizedMismatch_name, "vectorizedMismatch") \
|
||||
do_signature(vectorizedMismatch_signature, "(Ljava/lang/Object;JLjava/lang/Object;JII)I") \
|
||||
\
|
||||
|
@ -63,38 +63,38 @@ class Bits { // package-private
|
||||
|
||||
// -- Unsafe access --
|
||||
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
static Unsafe unsafe() {
|
||||
return unsafe;
|
||||
return UNSAFE;
|
||||
}
|
||||
|
||||
|
||||
// -- Processor and memory-system properties --
|
||||
|
||||
private static final ByteOrder byteOrder
|
||||
= unsafe.isBigEndian() ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
|
||||
private static final ByteOrder BYTE_ORDER
|
||||
= UNSAFE.isBigEndian() ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
|
||||
|
||||
static ByteOrder byteOrder() {
|
||||
return byteOrder;
|
||||
return BYTE_ORDER;
|
||||
}
|
||||
|
||||
private static int pageSize = -1;
|
||||
private static int PAGE_SIZE = -1;
|
||||
|
||||
static int pageSize() {
|
||||
if (pageSize == -1)
|
||||
pageSize = unsafe().pageSize();
|
||||
return pageSize;
|
||||
if (PAGE_SIZE == -1)
|
||||
PAGE_SIZE = unsafe().pageSize();
|
||||
return PAGE_SIZE;
|
||||
}
|
||||
|
||||
static int pageCount(long size) {
|
||||
return (int)(size + (long)pageSize() - 1L) / pageSize();
|
||||
}
|
||||
|
||||
private static boolean unaligned = unsafe.unalignedAccess();
|
||||
private static boolean UNALIGNED = UNSAFE.unalignedAccess();
|
||||
|
||||
static boolean unaligned() {
|
||||
return unaligned;
|
||||
return UNALIGNED;
|
||||
}
|
||||
|
||||
|
||||
@ -103,11 +103,11 @@ class Bits { // package-private
|
||||
// A user-settable upper limit on the maximum amount of allocatable
|
||||
// direct buffer memory. This value may be changed during VM
|
||||
// initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
|
||||
private static volatile long maxMemory = VM.maxDirectMemory();
|
||||
private static final AtomicLong reservedMemory = new AtomicLong();
|
||||
private static final AtomicLong totalCapacity = new AtomicLong();
|
||||
private static final AtomicLong count = new AtomicLong();
|
||||
private static volatile boolean memoryLimitSet;
|
||||
private static volatile long MAX_MEMORY = VM.maxDirectMemory();
|
||||
private static final AtomicLong RESERVED_MEMORY = new AtomicLong();
|
||||
private static final AtomicLong TOTAL_CAPACITY = new AtomicLong();
|
||||
private static final AtomicLong COUNT = new AtomicLong();
|
||||
private static volatile boolean MEMORY_LIMIT_SET;
|
||||
|
||||
// max. number of sleeps during try-reserving with exponentially
|
||||
// increasing delay before throwing OutOfMemoryError:
|
||||
@ -120,9 +120,9 @@ class Bits { // package-private
|
||||
// which a process may access. All sizes are specified in bytes.
|
||||
static void reserveMemory(long size, int cap) {
|
||||
|
||||
if (!memoryLimitSet && VM.initLevel() >= 1) {
|
||||
maxMemory = VM.maxDirectMemory();
|
||||
memoryLimitSet = true;
|
||||
if (!MEMORY_LIMIT_SET && VM.initLevel() >= 1) {
|
||||
MAX_MEMORY = VM.maxDirectMemory();
|
||||
MEMORY_LIMIT_SET = true;
|
||||
}
|
||||
|
||||
// optimist!
|
||||
@ -200,10 +200,10 @@ class Bits { // package-private
|
||||
// actual memory usage, which will differ when buffers are page
|
||||
// aligned.
|
||||
long totalCap;
|
||||
while (cap <= maxMemory - (totalCap = totalCapacity.get())) {
|
||||
if (totalCapacity.compareAndSet(totalCap, totalCap + cap)) {
|
||||
reservedMemory.addAndGet(size);
|
||||
count.incrementAndGet();
|
||||
while (cap <= MAX_MEMORY - (totalCap = TOTAL_CAPACITY.get())) {
|
||||
if (TOTAL_CAPACITY.compareAndSet(totalCap, totalCap + cap)) {
|
||||
RESERVED_MEMORY.addAndGet(size);
|
||||
COUNT.incrementAndGet();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -213,9 +213,9 @@ class Bits { // package-private
|
||||
|
||||
|
||||
static void unreserveMemory(long size, int cap) {
|
||||
long cnt = count.decrementAndGet();
|
||||
long reservedMem = reservedMemory.addAndGet(-size);
|
||||
long totalCap = totalCapacity.addAndGet(-cap);
|
||||
long cnt = COUNT.decrementAndGet();
|
||||
long reservedMem = RESERVED_MEMORY.addAndGet(-size);
|
||||
long totalCap = TOTAL_CAPACITY.addAndGet(-cap);
|
||||
assert cnt >= 0 && reservedMem >= 0 && totalCap >= 0;
|
||||
}
|
||||
|
||||
@ -234,15 +234,15 @@ class Bits { // package-private
|
||||
}
|
||||
@Override
|
||||
public long getCount() {
|
||||
return Bits.count.get();
|
||||
return Bits.COUNT.get();
|
||||
}
|
||||
@Override
|
||||
public long getTotalCapacity() {
|
||||
return Bits.totalCapacity.get();
|
||||
return Bits.TOTAL_CAPACITY.get();
|
||||
}
|
||||
@Override
|
||||
public long getMemoryUsed() {
|
||||
return Bits.reservedMemory.get();
|
||||
return Bits.RESERVED_MEMORY.get();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
package java.nio;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
import java.util.Spliterator;
|
||||
|
||||
@ -181,6 +182,8 @@ import java.util.Spliterator;
|
||||
*/
|
||||
|
||||
public abstract class Buffer {
|
||||
// Cached unsafe-access object
|
||||
static final Unsafe UNSAFE = Bits.unsafe();
|
||||
|
||||
/**
|
||||
* The characteristics of Spliterators that traverse and split elements
|
||||
@ -616,6 +619,14 @@ public abstract class Buffer {
|
||||
|
||||
// -- Package-private methods for bounds checking, etc. --
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the base reference, paired with the address
|
||||
* field, which in combination can be used for unsafe access into a heap
|
||||
* buffer or direct byte buffer (and views of).
|
||||
*/
|
||||
abstract Object base();
|
||||
|
||||
/**
|
||||
* Checks the current position against the limit, throwing a {@link
|
||||
* BufferUnderflowException} if it is not smaller than the limit, and then
|
||||
|
198
src/java.base/share/classes/java/nio/BufferMismatch.java
Normal file
198
src/java.base/share/classes/java/nio/BufferMismatch.java
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.nio;
|
||||
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
|
||||
/**
|
||||
* Mismatch methods for buffers
|
||||
*/
|
||||
final class BufferMismatch {
|
||||
|
||||
static int mismatch(ByteBuffer a, int aOff, ByteBuffer b, int bOff, int length) {
|
||||
int i = 0;
|
||||
if (length > 7) {
|
||||
i = ArraysSupport.vectorizedMismatch(
|
||||
a.base(), a.address + aOff,
|
||||
b.base(), b.address + bOff,
|
||||
length,
|
||||
ArraysSupport.LOG2_ARRAY_BYTE_INDEX_SCALE);
|
||||
if (i >= 0) return i;
|
||||
i = length - ~i;
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
if (a.get(aOff + i) != b.get(bOff + i))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mismatch(CharBuffer a, int aOff, CharBuffer b, int bOff, int length) {
|
||||
int i = 0;
|
||||
// Ensure only heap or off-heap buffer instances use the
|
||||
// vectorized mismatch. If either buffer is a StringCharBuffer
|
||||
// (order is null) then the slow path is taken
|
||||
if (length > 3 && a.charRegionOrder() == b.charRegionOrder()
|
||||
&& a.charRegionOrder() != null && b.charRegionOrder() != null) {
|
||||
i = ArraysSupport.vectorizedMismatch(
|
||||
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_CHAR_INDEX_SCALE),
|
||||
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_CHAR_INDEX_SCALE),
|
||||
length,
|
||||
ArraysSupport.LOG2_ARRAY_CHAR_INDEX_SCALE);
|
||||
if (i >= 0) return i;
|
||||
i = length - ~i;
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
if (a.get(aOff + i) != b.get(bOff + i))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mismatch(ShortBuffer a, int aOff, ShortBuffer b, int bOff, int length) {
|
||||
int i = 0;
|
||||
if (length > 3 && a.order() == b.order()) {
|
||||
i = ArraysSupport.vectorizedMismatch(
|
||||
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_SHORT_INDEX_SCALE),
|
||||
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_SHORT_INDEX_SCALE),
|
||||
length,
|
||||
ArraysSupport.LOG2_ARRAY_SHORT_INDEX_SCALE);
|
||||
if (i >= 0) return i;
|
||||
i = length - ~i;
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
if (a.get(aOff + i) != b.get(bOff + i))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mismatch(IntBuffer a, int aOff, IntBuffer b, int bOff, int length) {
|
||||
int i = 0;
|
||||
if (length > 1 && a.order() == b.order()) {
|
||||
i = ArraysSupport.vectorizedMismatch(
|
||||
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_INT_INDEX_SCALE),
|
||||
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_INT_INDEX_SCALE),
|
||||
length,
|
||||
ArraysSupport.LOG2_ARRAY_INT_INDEX_SCALE);
|
||||
if (i >= 0) return i;
|
||||
i = length - ~i;
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
if (a.get(aOff + i) != b.get(bOff + i))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mismatch(FloatBuffer a, int aOff, FloatBuffer b, int bOff, int length) {
|
||||
int i = 0;
|
||||
if (length > 1 && a.order() == b.order()) {
|
||||
i = ArraysSupport.vectorizedMismatch(
|
||||
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_FLOAT_INDEX_SCALE),
|
||||
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_FLOAT_INDEX_SCALE),
|
||||
length,
|
||||
ArraysSupport.LOG2_ARRAY_FLOAT_INDEX_SCALE);
|
||||
// Mismatched
|
||||
if (i >= 0) {
|
||||
// Check if mismatch is not associated with two NaN values; and
|
||||
// is not associated with +0 and -0
|
||||
float av = a.get(aOff + i);
|
||||
float bv = b.get(bOff + i);
|
||||
if (av != bv && (!Float.isNaN(av) || !Float.isNaN(bv)))
|
||||
return i;
|
||||
|
||||
// Fall back to slow mechanism
|
||||
// ISSUE: Consider looping over vectorizedMismatch adjusting ranges
|
||||
// However, requires that returned value be relative to input ranges
|
||||
i++;
|
||||
}
|
||||
// Matched
|
||||
else {
|
||||
i = length - ~i;
|
||||
}
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
float av = a.get(aOff + i);
|
||||
float bv = b.get(bOff + i);
|
||||
if (av != bv && (!Float.isNaN(av) || !Float.isNaN(bv)))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mismatch(LongBuffer a, int aOff, LongBuffer b, int bOff, int length) {
|
||||
int i = 0;
|
||||
if (length > 0 && a.order() == b.order()) {
|
||||
i = ArraysSupport.vectorizedMismatch(
|
||||
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_LONG_INDEX_SCALE),
|
||||
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_LONG_INDEX_SCALE),
|
||||
length,
|
||||
ArraysSupport.LOG2_ARRAY_LONG_INDEX_SCALE);
|
||||
return i >= 0 ? i : -1;
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
if (a.get(aOff + i) != b.get(bOff + i))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mismatch(DoubleBuffer a, int aOff, DoubleBuffer b, int bOff, int length) {
|
||||
int i = 0;
|
||||
if (length > 0 && a.order() == b.order()) {
|
||||
i = ArraysSupport.vectorizedMismatch(
|
||||
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_DOUBLE_INDEX_SCALE),
|
||||
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_DOUBLE_INDEX_SCALE),
|
||||
length,
|
||||
ArraysSupport.LOG2_ARRAY_DOUBLE_INDEX_SCALE);
|
||||
// Mismatched
|
||||
if (i >= 0) {
|
||||
// Check if mismatch is not associated with two NaN values; and
|
||||
// is not associated with +0 and -0
|
||||
double av = a.get(aOff + i);
|
||||
double bv = b.get(bOff + i);
|
||||
if (av != bv && (!Double.isNaN(av) || !Double.isNaN(bv)))
|
||||
return i;
|
||||
|
||||
// Fall back to slow mechanism
|
||||
// ISSUE: Consider looping over vectorizedMismatch adjusting ranges
|
||||
// However, requires that returned value be relative to input ranges
|
||||
i++;
|
||||
}
|
||||
// Matched
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
double av = a.get(aOff + i);
|
||||
double bv = b.get(bOff + i);
|
||||
if (av != bv && (!Double.isNaN(av) || !Double.isNaN(bv)))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
@ -36,9 +36,6 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
|
||||
|
||||
#if[rw]
|
||||
|
||||
// Cached unsafe-access object
|
||||
private static final Unsafe unsafe = Bits.unsafe();
|
||||
|
||||
protected final ByteBuffer bb;
|
||||
|
||||
#end[rw]
|
||||
@ -74,6 +71,11 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
|
||||
#end[rw]
|
||||
}
|
||||
|
||||
@Override
|
||||
Object base() {
|
||||
return bb.hb;
|
||||
}
|
||||
|
||||
public $Type$Buffer slice() {
|
||||
int pos = this.position();
|
||||
int lim = this.limit();
|
||||
@ -117,20 +119,20 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
|
||||
}
|
||||
|
||||
public $type$ get() {
|
||||
$memtype$ x = unsafe.get$Memtype$Unaligned(bb.hb, byteOffset(nextGetIndex()),
|
||||
$memtype$ x = UNSAFE.get$Memtype$Unaligned(bb.hb, byteOffset(nextGetIndex()),
|
||||
{#if[boB]?true:false});
|
||||
return $fromBits$(x);
|
||||
}
|
||||
|
||||
public $type$ get(int i) {
|
||||
$memtype$ x = unsafe.get$Memtype$Unaligned(bb.hb, byteOffset(checkIndex(i)),
|
||||
$memtype$ x = UNSAFE.get$Memtype$Unaligned(bb.hb, byteOffset(checkIndex(i)),
|
||||
{#if[boB]?true:false});
|
||||
return $fromBits$(x);
|
||||
}
|
||||
|
||||
#if[streamableType]
|
||||
$type$ getUnchecked(int i) {
|
||||
$memtype$ x = unsafe.get$Memtype$Unaligned(bb.hb, byteOffset(i),
|
||||
$memtype$ x = UNSAFE.get$Memtype$Unaligned(bb.hb, byteOffset(i),
|
||||
{#if[boB]?true:false});
|
||||
return $fromBits$(x);
|
||||
}
|
||||
@ -141,7 +143,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
|
||||
public $Type$Buffer put($type$ x) {
|
||||
#if[rw]
|
||||
$memtype$ y = $toBits$(x);
|
||||
unsafe.put$Memtype$Unaligned(bb.hb, byteOffset(nextPutIndex()), y,
|
||||
UNSAFE.put$Memtype$Unaligned(bb.hb, byteOffset(nextPutIndex()), y,
|
||||
{#if[boB]?true:false});
|
||||
return this;
|
||||
#else[rw]
|
||||
@ -152,7 +154,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
|
||||
public $Type$Buffer put(int i, $type$ x) {
|
||||
#if[rw]
|
||||
$memtype$ y = $toBits$(x);
|
||||
unsafe.put$Memtype$Unaligned(bb.hb, byteOffset(checkIndex(i)), y,
|
||||
UNSAFE.put$Memtype$Unaligned(bb.hb, byteOffset(checkIndex(i)), y,
|
||||
{#if[boB]?true:false});
|
||||
return this;
|
||||
#else[rw]
|
||||
@ -241,4 +243,9 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
|
||||
#end[boL]
|
||||
}
|
||||
|
||||
#if[char]
|
||||
ByteOrder charRegionOrder() {
|
||||
return order();
|
||||
}
|
||||
#end[char]
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ class XXX {
|
||||
#if[rw]
|
||||
|
||||
private $type$ get$Type$(long a) {
|
||||
$memtype$ x = unsafe.get$Memtype$Unaligned(null, a, bigEndian);
|
||||
$memtype$ x = UNSAFE.get$Memtype$Unaligned(null, a, bigEndian);
|
||||
return $fromBits$(x);
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ class XXX {
|
||||
private ByteBuffer put$Type$(long a, $type$ x) {
|
||||
#if[rw]
|
||||
$memtype$ y = $toBits$(x);
|
||||
unsafe.put$Memtype$Unaligned(null, a, y, bigEndian);
|
||||
UNSAFE.put$Memtype$Unaligned(null, a, y, bigEndian);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -81,7 +81,7 @@ class XXX {
|
||||
int rem = (off <= lim ? lim - off : 0);
|
||||
|
||||
int size = rem >> $LG_BYTES_PER_VALUE$;
|
||||
if (!unaligned && ((address + off) % $BYTES_PER_VALUE$ != 0)) {
|
||||
if (!UNALIGNED && ((address + off) % $BYTES_PER_VALUE$ != 0)) {
|
||||
return (bigEndian
|
||||
? ($Type$Buffer)(new ByteBufferAs$Type$Buffer$RW$B(this,
|
||||
-1,
|
||||
|
@ -28,7 +28,6 @@
|
||||
package java.nio;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.misc.VM;
|
||||
import jdk.internal.ref.Cleaner;
|
||||
import sun.nio.ch.DirectBuffer;
|
||||
@ -45,14 +44,11 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
|
||||
#if[rw]
|
||||
|
||||
// Cached unsafe-access object
|
||||
protected static final Unsafe unsafe = Bits.unsafe();
|
||||
|
||||
// Cached array base offset
|
||||
private static final long arrayBaseOffset = (long)unsafe.arrayBaseOffset($type$[].class);
|
||||
private static final long ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset($type$[].class);
|
||||
|
||||
// Cached unaligned-access capability
|
||||
protected static final boolean unaligned = Bits.unaligned();
|
||||
protected static final boolean UNALIGNED = Bits.unaligned();
|
||||
|
||||
// Base address, used in all indexing calculations
|
||||
// NOTE: moved up to Buffer.java for speed in JNI GetDirectBufferAddress
|
||||
@ -73,8 +69,6 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
implements Runnable
|
||||
{
|
||||
|
||||
private static Unsafe unsafe = Unsafe.getUnsafe();
|
||||
|
||||
private long address;
|
||||
private long size;
|
||||
private int capacity;
|
||||
@ -91,7 +85,7 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
// Paranoia
|
||||
return;
|
||||
}
|
||||
unsafe.freeMemory(address);
|
||||
UNSAFE.freeMemory(address);
|
||||
address = 0;
|
||||
Bits.unreserveMemory(size, capacity);
|
||||
}
|
||||
@ -124,12 +118,12 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
|
||||
long base = 0;
|
||||
try {
|
||||
base = unsafe.allocateMemory(size);
|
||||
base = UNSAFE.allocateMemory(size);
|
||||
} catch (OutOfMemoryError x) {
|
||||
Bits.unreserveMemory(size, cap);
|
||||
throw x;
|
||||
}
|
||||
unsafe.setMemory(base, size, (byte) 0);
|
||||
UNSAFE.setMemory(base, size, (byte) 0);
|
||||
if (pa && (base % ps != 0)) {
|
||||
// Round up to page boundary
|
||||
address = base + ps - (base & (ps - 1));
|
||||
@ -206,6 +200,11 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
#end[rw]
|
||||
}
|
||||
|
||||
@Override
|
||||
Object base() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public $Type$Buffer slice() {
|
||||
int pos = this.position();
|
||||
int lim = this.limit();
|
||||
@ -258,16 +257,16 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
}
|
||||
|
||||
public $type$ get() {
|
||||
return $fromBits$($swap$(unsafe.get$Swaptype$(ix(nextGetIndex()))));
|
||||
return $fromBits$($swap$(UNSAFE.get$Swaptype$(ix(nextGetIndex()))));
|
||||
}
|
||||
|
||||
public $type$ get(int i) {
|
||||
return $fromBits$($swap$(unsafe.get$Swaptype$(ix(checkIndex(i)))));
|
||||
return $fromBits$($swap$(UNSAFE.get$Swaptype$(ix(checkIndex(i)))));
|
||||
}
|
||||
|
||||
#if[streamableType]
|
||||
$type$ getUnchecked(int i) {
|
||||
return $fromBits$($swap$(unsafe.get$Swaptype$(ix(i))));
|
||||
return $fromBits$($swap$(UNSAFE.get$Swaptype$(ix(i))));
|
||||
}
|
||||
#end[streamableType]
|
||||
|
||||
@ -282,10 +281,10 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
if (length > rem)
|
||||
throw new BufferUnderflowException();
|
||||
|
||||
long dstOffset = arrayBaseOffset + ((long)offset << $LG_BYTES_PER_VALUE$);
|
||||
long dstOffset = ARRAY_BASE_OFFSET + ((long)offset << $LG_BYTES_PER_VALUE$);
|
||||
#if[!byte]
|
||||
if (order() != ByteOrder.nativeOrder())
|
||||
unsafe.copySwapMemory(null,
|
||||
UNSAFE.copySwapMemory(null,
|
||||
ix(pos),
|
||||
dst,
|
||||
dstOffset,
|
||||
@ -293,7 +292,7 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
(long)1 << $LG_BYTES_PER_VALUE$);
|
||||
else
|
||||
#end[!byte]
|
||||
unsafe.copyMemory(null,
|
||||
UNSAFE.copyMemory(null,
|
||||
ix(pos),
|
||||
dst,
|
||||
dstOffset,
|
||||
@ -312,7 +311,7 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
|
||||
public $Type$Buffer put($type$ x) {
|
||||
#if[rw]
|
||||
unsafe.put$Swaptype$(ix(nextPutIndex()), $swap$($toBits$(x)));
|
||||
UNSAFE.put$Swaptype$(ix(nextPutIndex()), $swap$($toBits$(x)));
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -321,7 +320,7 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
|
||||
public $Type$Buffer put(int i, $type$ x) {
|
||||
#if[rw]
|
||||
unsafe.put$Swaptype$(ix(checkIndex(i)), $swap$($toBits$(x)));
|
||||
UNSAFE.put$Swaptype$(ix(checkIndex(i)), $swap$($toBits$(x)));
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -347,7 +346,7 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
|
||||
if (srem > rem)
|
||||
throw new BufferOverflowException();
|
||||
unsafe.copyMemory(sb.ix(spos), ix(pos), (long)srem << $LG_BYTES_PER_VALUE$);
|
||||
UNSAFE.copyMemory(sb.ix(spos), ix(pos), (long)srem << $LG_BYTES_PER_VALUE$);
|
||||
sb.position(spos + srem);
|
||||
position(pos + srem);
|
||||
} else if (src.hb != null) {
|
||||
@ -380,10 +379,10 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
if (length > rem)
|
||||
throw new BufferOverflowException();
|
||||
|
||||
long srcOffset = arrayBaseOffset + ((long)offset << $LG_BYTES_PER_VALUE$);
|
||||
long srcOffset = ARRAY_BASE_OFFSET + ((long)offset << $LG_BYTES_PER_VALUE$);
|
||||
#if[!byte]
|
||||
if (order() != ByteOrder.nativeOrder())
|
||||
unsafe.copySwapMemory(src,
|
||||
UNSAFE.copySwapMemory(src,
|
||||
srcOffset,
|
||||
null,
|
||||
ix(pos),
|
||||
@ -391,7 +390,7 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
(long)1 << $LG_BYTES_PER_VALUE$);
|
||||
else
|
||||
#end[!byte]
|
||||
unsafe.copyMemory(src,
|
||||
UNSAFE.copyMemory(src,
|
||||
srcOffset,
|
||||
null,
|
||||
ix(pos),
|
||||
@ -413,7 +412,7 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
|
||||
unsafe.copyMemory(ix(pos), ix(0), (long)rem << $LG_BYTES_PER_VALUE$);
|
||||
UNSAFE.copyMemory(ix(pos), ix(0), (long)rem << $LG_BYTES_PER_VALUE$);
|
||||
position(rem);
|
||||
limit(capacity());
|
||||
discardMark();
|
||||
@ -490,17 +489,22 @@ class Direct$Type$Buffer$RW$$BO$
|
||||
|
||||
#end[!byte]
|
||||
|
||||
#if[char]
|
||||
ByteOrder charRegionOrder() {
|
||||
return order();
|
||||
}
|
||||
#end[char]
|
||||
|
||||
|
||||
#if[byte]
|
||||
|
||||
byte _get(int i) { // package-private
|
||||
return unsafe.getByte(address + i);
|
||||
return UNSAFE.getByte(address + i);
|
||||
}
|
||||
|
||||
void _put(int i, byte b) { // package-private
|
||||
#if[rw]
|
||||
unsafe.putByte(address + i, b);
|
||||
UNSAFE.putByte(address + i, b);
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
#end[rw]
|
||||
|
@ -27,8 +27,6 @@
|
||||
|
||||
package java.nio;
|
||||
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
#if[rw]
|
||||
* A read/write Heap$Type$Buffer.
|
||||
@ -43,6 +41,11 @@ import jdk.internal.misc.Unsafe;
|
||||
class Heap$Type$Buffer$RW$
|
||||
extends {#if[ro]?Heap}$Type$Buffer
|
||||
{
|
||||
// Cached array base offset
|
||||
private static final long ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset($type$[].class);
|
||||
|
||||
// Cached array base offset
|
||||
private static final long ARRAY_INDEX_SCALE = UNSAFE.arrayIndexScale($type$[].class);
|
||||
|
||||
// For speed these fields are actually declared in X-Buffer;
|
||||
// these declarations are here as documentation
|
||||
@ -53,16 +56,6 @@ class Heap$Type$Buffer$RW$
|
||||
#end[rw]
|
||||
*/
|
||||
|
||||
#if[byte]
|
||||
|
||||
// Cached unsafe-access object
|
||||
private static final Unsafe unsafe = Bits.unsafe();
|
||||
|
||||
// Cached array base offset
|
||||
private static final long arrayBaseOffset = unsafe.arrayBaseOffset($type$[].class);
|
||||
|
||||
#end[byte]
|
||||
|
||||
Heap$Type$Buffer$RW$(int cap, int lim) { // package-private
|
||||
#if[rw]
|
||||
super(-1, 0, lim, cap, new $type$[cap], 0);
|
||||
@ -70,13 +63,11 @@ class Heap$Type$Buffer$RW$
|
||||
hb = new $type$[cap];
|
||||
offset = 0;
|
||||
*/
|
||||
this.address = ARRAY_BASE_OFFSET;
|
||||
#else[rw]
|
||||
super(cap, lim);
|
||||
this.isReadOnly = true;
|
||||
#end[rw]
|
||||
#if[byte]
|
||||
this.address = arrayBaseOffset;
|
||||
#end[byte]
|
||||
}
|
||||
|
||||
Heap$Type$Buffer$RW$($type$[] buf, int off, int len) { // package-private
|
||||
@ -86,13 +77,11 @@ class Heap$Type$Buffer$RW$
|
||||
hb = buf;
|
||||
offset = 0;
|
||||
*/
|
||||
this.address = ARRAY_BASE_OFFSET;
|
||||
#else[rw]
|
||||
super(buf, off, len);
|
||||
this.isReadOnly = true;
|
||||
#end[rw]
|
||||
#if[byte]
|
||||
this.address = arrayBaseOffset;
|
||||
#end[byte]
|
||||
}
|
||||
|
||||
protected Heap$Type$Buffer$RW$($type$[] buf,
|
||||
@ -105,13 +94,11 @@ class Heap$Type$Buffer$RW$
|
||||
hb = buf;
|
||||
offset = off;
|
||||
*/
|
||||
this.address = ARRAY_BASE_OFFSET + off * ARRAY_INDEX_SCALE;
|
||||
#else[rw]
|
||||
super(buf, mark, pos, lim, cap, off);
|
||||
this.isReadOnly = true;
|
||||
#end[rw]
|
||||
#if[byte]
|
||||
this.address = arrayBaseOffset + off;
|
||||
#end[byte]
|
||||
}
|
||||
|
||||
public $Type$Buffer slice() {
|
||||
@ -296,18 +283,18 @@ class Heap$Type$Buffer$RW$
|
||||
#if[rw]
|
||||
|
||||
public char getChar() {
|
||||
return unsafe.getCharUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
|
||||
return UNSAFE.getCharUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
|
||||
}
|
||||
|
||||
public char getChar(int i) {
|
||||
return unsafe.getCharUnaligned(hb, byteOffset(checkIndex(i, 2)), bigEndian);
|
||||
return UNSAFE.getCharUnaligned(hb, byteOffset(checkIndex(i, 2)), bigEndian);
|
||||
}
|
||||
|
||||
#end[rw]
|
||||
|
||||
public $Type$Buffer putChar(char x) {
|
||||
#if[rw]
|
||||
unsafe.putCharUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
|
||||
UNSAFE.putCharUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -316,7 +303,7 @@ class Heap$Type$Buffer$RW$
|
||||
|
||||
public $Type$Buffer putChar(int i, char x) {
|
||||
#if[rw]
|
||||
unsafe.putCharUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
|
||||
UNSAFE.putCharUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -347,18 +334,18 @@ class Heap$Type$Buffer$RW$
|
||||
#if[rw]
|
||||
|
||||
public short getShort() {
|
||||
return unsafe.getShortUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
|
||||
return UNSAFE.getShortUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
|
||||
}
|
||||
|
||||
public short getShort(int i) {
|
||||
return unsafe.getShortUnaligned(hb, byteOffset(checkIndex(i, 2)), bigEndian);
|
||||
return UNSAFE.getShortUnaligned(hb, byteOffset(checkIndex(i, 2)), bigEndian);
|
||||
}
|
||||
|
||||
#end[rw]
|
||||
|
||||
public $Type$Buffer putShort(short x) {
|
||||
#if[rw]
|
||||
unsafe.putShortUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
|
||||
UNSAFE.putShortUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -367,7 +354,7 @@ class Heap$Type$Buffer$RW$
|
||||
|
||||
public $Type$Buffer putShort(int i, short x) {
|
||||
#if[rw]
|
||||
unsafe.putShortUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
|
||||
UNSAFE.putShortUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -398,18 +385,18 @@ class Heap$Type$Buffer$RW$
|
||||
#if[rw]
|
||||
|
||||
public int getInt() {
|
||||
return unsafe.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
|
||||
return UNSAFE.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
|
||||
}
|
||||
|
||||
public int getInt(int i) {
|
||||
return unsafe.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
|
||||
return UNSAFE.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
|
||||
}
|
||||
|
||||
#end[rw]
|
||||
|
||||
public $Type$Buffer putInt(int x) {
|
||||
#if[rw]
|
||||
unsafe.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), x, bigEndian);
|
||||
UNSAFE.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), x, bigEndian);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -418,7 +405,7 @@ class Heap$Type$Buffer$RW$
|
||||
|
||||
public $Type$Buffer putInt(int i, int x) {
|
||||
#if[rw]
|
||||
unsafe.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), x, bigEndian);
|
||||
UNSAFE.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), x, bigEndian);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -449,18 +436,18 @@ class Heap$Type$Buffer$RW$
|
||||
#if[rw]
|
||||
|
||||
public long getLong() {
|
||||
return unsafe.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
|
||||
return UNSAFE.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
|
||||
}
|
||||
|
||||
public long getLong(int i) {
|
||||
return unsafe.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
|
||||
return UNSAFE.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
|
||||
}
|
||||
|
||||
#end[rw]
|
||||
|
||||
public $Type$Buffer putLong(long x) {
|
||||
#if[rw]
|
||||
unsafe.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), x, bigEndian);
|
||||
UNSAFE.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), x, bigEndian);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -469,7 +456,7 @@ class Heap$Type$Buffer$RW$
|
||||
|
||||
public $Type$Buffer putLong(int i, long x) {
|
||||
#if[rw]
|
||||
unsafe.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), x, bigEndian);
|
||||
UNSAFE.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), x, bigEndian);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -500,12 +487,12 @@ class Heap$Type$Buffer$RW$
|
||||
#if[rw]
|
||||
|
||||
public float getFloat() {
|
||||
int x = unsafe.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
|
||||
int x = UNSAFE.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
|
||||
return Float.intBitsToFloat(x);
|
||||
}
|
||||
|
||||
public float getFloat(int i) {
|
||||
int x = unsafe.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
|
||||
int x = UNSAFE.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
|
||||
return Float.intBitsToFloat(x);
|
||||
}
|
||||
|
||||
@ -514,7 +501,7 @@ class Heap$Type$Buffer$RW$
|
||||
public $Type$Buffer putFloat(float x) {
|
||||
#if[rw]
|
||||
int y = Float.floatToRawIntBits(x);
|
||||
unsafe.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), y, bigEndian);
|
||||
UNSAFE.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), y, bigEndian);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -524,7 +511,7 @@ class Heap$Type$Buffer$RW$
|
||||
public $Type$Buffer putFloat(int i, float x) {
|
||||
#if[rw]
|
||||
int y = Float.floatToRawIntBits(x);
|
||||
unsafe.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), y, bigEndian);
|
||||
UNSAFE.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), y, bigEndian);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -555,12 +542,12 @@ class Heap$Type$Buffer$RW$
|
||||
#if[rw]
|
||||
|
||||
public double getDouble() {
|
||||
long x = unsafe.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
|
||||
long x = UNSAFE.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
|
||||
return Double.longBitsToDouble(x);
|
||||
}
|
||||
|
||||
public double getDouble(int i) {
|
||||
long x = unsafe.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
|
||||
long x = UNSAFE.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
|
||||
return Double.longBitsToDouble(x);
|
||||
}
|
||||
|
||||
@ -569,7 +556,7 @@ class Heap$Type$Buffer$RW$
|
||||
public $Type$Buffer putDouble(double x) {
|
||||
#if[rw]
|
||||
long y = Double.doubleToRawLongBits(x);
|
||||
unsafe.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), y, bigEndian);
|
||||
UNSAFE.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), y, bigEndian);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -579,7 +566,7 @@ class Heap$Type$Buffer$RW$
|
||||
public $Type$Buffer putDouble(int i, double x) {
|
||||
#if[rw]
|
||||
long y = Double.doubleToRawLongBits(x);
|
||||
unsafe.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), y, bigEndian);
|
||||
UNSAFE.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), y, bigEndian);
|
||||
return this;
|
||||
#else[rw]
|
||||
throw new ReadOnlyBufferException();
|
||||
@ -643,7 +630,11 @@ class Heap$Type$Buffer$RW$
|
||||
public ByteOrder order() {
|
||||
return ByteOrder.nativeOrder();
|
||||
}
|
||||
|
||||
#end[!byte]
|
||||
#if[char]
|
||||
|
||||
ByteOrder charRegionOrder() {
|
||||
return order();
|
||||
}
|
||||
#end[char]
|
||||
}
|
||||
|
@ -127,4 +127,30 @@ class StringCharBuffer // package-private
|
||||
return ByteOrder.nativeOrder();
|
||||
}
|
||||
|
||||
ByteOrder charRegionOrder() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean equals(Object ob) {
|
||||
if (this == ob)
|
||||
return true;
|
||||
if (!(ob instanceof CharBuffer))
|
||||
return false;
|
||||
CharBuffer that = (CharBuffer)ob;
|
||||
if (this.remaining() != that.remaining())
|
||||
return false;
|
||||
return BufferMismatch.mismatch(this, this.position(),
|
||||
that, that.position(),
|
||||
this.remaining()) < 0;
|
||||
}
|
||||
|
||||
public int compareTo(CharBuffer that) {
|
||||
int i = BufferMismatch.mismatch(this, this.position(),
|
||||
that, that.position(),
|
||||
Math.min(this.remaining(), that.remaining()));
|
||||
if (i >= 0) {
|
||||
return Character.compare(this.get(this.position() + i), that.get(this.position() + i));
|
||||
}
|
||||
return this.remaining() - that.remaining();
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ import java.util.stream.StreamSupport;
|
||||
import java.util.stream.$Streamtype$Stream;
|
||||
#end[streamableType]
|
||||
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
|
||||
/**
|
||||
* $A$ $type$ buffer.
|
||||
*
|
||||
@ -287,6 +289,11 @@ public abstract class $Type$Buffer
|
||||
this(mark, pos, lim, cap, null, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
Object base() {
|
||||
return hb;
|
||||
}
|
||||
|
||||
#if[byte]
|
||||
|
||||
/**
|
||||
@ -1297,19 +1304,9 @@ public abstract class $Type$Buffer
|
||||
$Type$Buffer that = ($Type$Buffer)ob;
|
||||
if (this.remaining() != that.remaining())
|
||||
return false;
|
||||
int p = this.position();
|
||||
for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--)
|
||||
if (!equals(this.get(i), that.get(j)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean equals($type$ x, $type$ y) {
|
||||
#if[floatingPointType]
|
||||
return (x == y) || ($Fulltype$.isNaN(x) && $Fulltype$.isNaN(y));
|
||||
#else[floatingPointType]
|
||||
return x == y;
|
||||
#end[floatingPointType]
|
||||
return BufferMismatch.mismatch(this, this.position(),
|
||||
that, that.position(),
|
||||
this.remaining()) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1336,11 +1333,11 @@ public abstract class $Type$Buffer
|
||||
* is less than, equal to, or greater than the given buffer
|
||||
*/
|
||||
public int compareTo($Type$Buffer that) {
|
||||
int n = this.position() + Math.min(this.remaining(), that.remaining());
|
||||
for (int i = this.position(), j = that.position(); i < n; i++, j++) {
|
||||
int cmp = compare(this.get(i), that.get(j));
|
||||
if (cmp != 0)
|
||||
return cmp;
|
||||
int i = BufferMismatch.mismatch(this, this.position(),
|
||||
that, that.position(),
|
||||
Math.min(this.remaining(), that.remaining()));
|
||||
if (i >= 0) {
|
||||
return compare(this.get(this.position() + i), that.get(this.position() + i));
|
||||
}
|
||||
return this.remaining() - that.remaining();
|
||||
}
|
||||
@ -1571,6 +1568,12 @@ public abstract class $Type$Buffer
|
||||
|
||||
#end[!byte]
|
||||
|
||||
#if[char]
|
||||
// The order or null if the buffer does not cover a memory region,
|
||||
// such as StringCharBuffer
|
||||
abstract ByteOrder charRegionOrder();
|
||||
#end[char]
|
||||
|
||||
#if[byte]
|
||||
|
||||
boolean bigEndian // package-private
|
||||
|
@ -26,6 +26,7 @@
|
||||
package java.util;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017 Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -22,7 +22,7 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.util;
|
||||
package jdk.internal.util;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
@ -50,19 +50,19 @@ import jdk.internal.misc.Unsafe;
|
||||
* responsibility of the caller (direct or otherwise) to perform such checks
|
||||
* before calling this method.
|
||||
*/
|
||||
class ArraysSupport {
|
||||
public class ArraysSupport {
|
||||
static final Unsafe U = Unsafe.getUnsafe();
|
||||
|
||||
private static final boolean BIG_ENDIAN = U.isBigEndian();
|
||||
|
||||
private static final int LOG2_ARRAY_BOOLEAN_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BOOLEAN_INDEX_SCALE);
|
||||
private static final int LOG2_ARRAY_BYTE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BYTE_INDEX_SCALE);
|
||||
private static final int LOG2_ARRAY_CHAR_INDEX_SCALE = exactLog2(Unsafe.ARRAY_CHAR_INDEX_SCALE);
|
||||
private static final int LOG2_ARRAY_SHORT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_SHORT_INDEX_SCALE);
|
||||
private static final int LOG2_ARRAY_INT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_INT_INDEX_SCALE);
|
||||
private static final int LOG2_ARRAY_LONG_INDEX_SCALE = exactLog2(Unsafe.ARRAY_LONG_INDEX_SCALE);
|
||||
private static final int LOG2_ARRAY_FLOAT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_FLOAT_INDEX_SCALE);
|
||||
private static final int LOG2_ARRAY_DOUBLE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
|
||||
public static final int LOG2_ARRAY_BOOLEAN_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BOOLEAN_INDEX_SCALE);
|
||||
public static final int LOG2_ARRAY_BYTE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BYTE_INDEX_SCALE);
|
||||
public static final int LOG2_ARRAY_CHAR_INDEX_SCALE = exactLog2(Unsafe.ARRAY_CHAR_INDEX_SCALE);
|
||||
public static final int LOG2_ARRAY_SHORT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_SHORT_INDEX_SCALE);
|
||||
public static final int LOG2_ARRAY_INT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_INT_INDEX_SCALE);
|
||||
public static final int LOG2_ARRAY_LONG_INDEX_SCALE = exactLog2(Unsafe.ARRAY_LONG_INDEX_SCALE);
|
||||
public static final int LOG2_ARRAY_FLOAT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_FLOAT_INDEX_SCALE);
|
||||
public static final int LOG2_ARRAY_DOUBLE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
|
||||
|
||||
private static final int LOG2_BYTE_BIT_SIZE = exactLog2(Byte.SIZE);
|
||||
|
||||
@ -107,10 +107,10 @@ class ArraysSupport {
|
||||
* the tail of the two arrays.
|
||||
*/
|
||||
@HotSpotIntrinsicCandidate
|
||||
static int vectorizedMismatch(Object a, long aOffset,
|
||||
Object b, long bOffset,
|
||||
int length,
|
||||
int log2ArrayIndexScale) {
|
||||
public static int vectorizedMismatch(Object a, long aOffset,
|
||||
Object b, long bOffset,
|
||||
int length,
|
||||
int log2ArrayIndexScale) {
|
||||
// assert a.getClass().isArray();
|
||||
// assert b.getClass().isArray();
|
||||
// assert 0 <= length <= sizeOf(a)
|
||||
@ -161,9 +161,9 @@ class ArraysSupport {
|
||||
// Booleans
|
||||
// Each boolean element takes up one byte
|
||||
|
||||
static int mismatch(boolean[] a,
|
||||
boolean[] b,
|
||||
int length) {
|
||||
public static int mismatch(boolean[] a,
|
||||
boolean[] b,
|
||||
int length) {
|
||||
int i = 0;
|
||||
if (length > 7) {
|
||||
i = vectorizedMismatch(
|
||||
@ -181,9 +181,9 @@ class ArraysSupport {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mismatch(boolean[] a, int aFromIndex,
|
||||
boolean[] b, int bFromIndex,
|
||||
int length) {
|
||||
public static int mismatch(boolean[] a, int aFromIndex,
|
||||
boolean[] b, int bFromIndex,
|
||||
int length) {
|
||||
int i = 0;
|
||||
if (length > 7) {
|
||||
int aOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + aFromIndex;
|
||||
@ -219,9 +219,9 @@ class ArraysSupport {
|
||||
* no mismatch. The index will be within the range of (inclusive) 0 to
|
||||
* (exclusive) the smaller of the two array lengths.
|
||||
*/
|
||||
static int mismatch(byte[] a,
|
||||
byte[] b,
|
||||
int length) {
|
||||
public static int mismatch(byte[] a,
|
||||
byte[] b,
|
||||
int length) {
|
||||
// ISSUE: defer to index receiving methods if performance is good
|
||||
// assert length <= a.length
|
||||
// assert length <= b.length
|
||||
@ -264,9 +264,9 @@ class ArraysSupport {
|
||||
* otherwise -1 if no mismatch. The index will be within the range of
|
||||
* (inclusive) 0 to (exclusive) the smaller of the two array bounds.
|
||||
*/
|
||||
static int mismatch(byte[] a, int aFromIndex,
|
||||
byte[] b, int bFromIndex,
|
||||
int length) {
|
||||
public static int mismatch(byte[] a, int aFromIndex,
|
||||
byte[] b, int bFromIndex,
|
||||
int length) {
|
||||
// assert 0 <= aFromIndex < a.length
|
||||
// assert 0 <= aFromIndex + length <= a.length
|
||||
// assert 0 <= bFromIndex < b.length
|
||||
@ -295,9 +295,9 @@ class ArraysSupport {
|
||||
|
||||
// Chars
|
||||
|
||||
static int mismatch(char[] a,
|
||||
char[] b,
|
||||
int length) {
|
||||
public static int mismatch(char[] a,
|
||||
char[] b,
|
||||
int length) {
|
||||
int i = 0;
|
||||
if (length > 3) {
|
||||
i = vectorizedMismatch(
|
||||
@ -315,9 +315,9 @@ class ArraysSupport {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mismatch(char[] a, int aFromIndex,
|
||||
char[] b, int bFromIndex,
|
||||
int length) {
|
||||
public static int mismatch(char[] a, int aFromIndex,
|
||||
char[] b, int bFromIndex,
|
||||
int length) {
|
||||
int i = 0;
|
||||
if (length > 3) {
|
||||
int aOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE);
|
||||
@ -340,9 +340,9 @@ class ArraysSupport {
|
||||
|
||||
// Shorts
|
||||
|
||||
static int mismatch(short[] a,
|
||||
short[] b,
|
||||
int length) {
|
||||
public static int mismatch(short[] a,
|
||||
short[] b,
|
||||
int length) {
|
||||
int i = 0;
|
||||
if (length > 3) {
|
||||
i = vectorizedMismatch(
|
||||
@ -360,9 +360,9 @@ class ArraysSupport {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mismatch(short[] a, int aFromIndex,
|
||||
short[] b, int bFromIndex,
|
||||
int length) {
|
||||
public static int mismatch(short[] a, int aFromIndex,
|
||||
short[] b, int bFromIndex,
|
||||
int length) {
|
||||
int i = 0;
|
||||
if (length > 3) {
|
||||
int aOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE);
|
||||
@ -385,9 +385,9 @@ class ArraysSupport {
|
||||
|
||||
// Ints
|
||||
|
||||
static int mismatch(int[] a,
|
||||
int[] b,
|
||||
int length) {
|
||||
public static int mismatch(int[] a,
|
||||
int[] b,
|
||||
int length) {
|
||||
int i = 0;
|
||||
if (length > 1) {
|
||||
i = vectorizedMismatch(
|
||||
@ -405,9 +405,9 @@ class ArraysSupport {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mismatch(int[] a, int aFromIndex,
|
||||
int[] b, int bFromIndex,
|
||||
int length) {
|
||||
public static int mismatch(int[] a, int aFromIndex,
|
||||
int[] b, int bFromIndex,
|
||||
int length) {
|
||||
int i = 0;
|
||||
if (length > 1) {
|
||||
int aOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_INT_INDEX_SCALE);
|
||||
@ -430,15 +430,15 @@ class ArraysSupport {
|
||||
|
||||
// Floats
|
||||
|
||||
static int mismatch(float[] a,
|
||||
float[] b,
|
||||
int length) {
|
||||
public static int mismatch(float[] a,
|
||||
float[] b,
|
||||
int length) {
|
||||
return mismatch(a, 0, b, 0, length);
|
||||
}
|
||||
|
||||
static int mismatch(float[] a, int aFromIndex,
|
||||
float[] b, int bFromIndex,
|
||||
int length) {
|
||||
public static int mismatch(float[] a, int aFromIndex,
|
||||
float[] b, int bFromIndex,
|
||||
int length) {
|
||||
int i = 0;
|
||||
if (length > 1) {
|
||||
int aOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE);
|
||||
@ -475,9 +475,9 @@ class ArraysSupport {
|
||||
|
||||
// Long
|
||||
|
||||
static int mismatch(long[] a,
|
||||
long[] b,
|
||||
int length) {
|
||||
public static int mismatch(long[] a,
|
||||
long[] b,
|
||||
int length) {
|
||||
if (length == 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -488,9 +488,9 @@ class ArraysSupport {
|
||||
return i >= 0 ? i : -1;
|
||||
}
|
||||
|
||||
static int mismatch(long[] a, int aFromIndex,
|
||||
long[] b, int bFromIndex,
|
||||
int length) {
|
||||
public static int mismatch(long[] a, int aFromIndex,
|
||||
long[] b, int bFromIndex,
|
||||
int length) {
|
||||
if (length == 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -506,15 +506,15 @@ class ArraysSupport {
|
||||
|
||||
// Double
|
||||
|
||||
static int mismatch(double[] a,
|
||||
double[] b,
|
||||
int length) {
|
||||
public static int mismatch(double[] a,
|
||||
double[] b,
|
||||
int length) {
|
||||
return mismatch(a, 0, b, 0, length);
|
||||
}
|
||||
|
||||
static int mismatch(double[] a, int aFromIndex,
|
||||
double[] b, int bFromIndex,
|
||||
int length) {
|
||||
public static int mismatch(double[] a, int aFromIndex,
|
||||
double[] b, int bFromIndex,
|
||||
int length) {
|
||||
if (length == 0) {
|
||||
return -1;
|
||||
}
|
686
test/jdk/java/nio/Buffer/EqualsCompareTest.java
Normal file
686
test/jdk/java/nio/Buffer/EqualsCompareTest.java
Normal file
@ -0,0 +1,686 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.LongFunction;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8193085
|
||||
* @summary tests for buffer equals and compare
|
||||
* @run testng EqualsCompareTest
|
||||
*/
|
||||
|
||||
public class EqualsCompareTest {
|
||||
|
||||
// Maximum width in bits
|
||||
static final int MAX_WIDTH = 512;
|
||||
|
||||
static final Map<Class, Integer> typeToWidth;
|
||||
|
||||
static {
|
||||
typeToWidth = new HashMap<>();
|
||||
typeToWidth.put(byte.class, Byte.SIZE);
|
||||
typeToWidth.put(short.class, Short.SIZE);
|
||||
typeToWidth.put(char.class, Character.SIZE);
|
||||
typeToWidth.put(int.class, Integer.SIZE);
|
||||
typeToWidth.put(long.class, Long.SIZE);
|
||||
typeToWidth.put(float.class, Float.SIZE);
|
||||
typeToWidth.put(double.class, Double.SIZE);
|
||||
}
|
||||
|
||||
static int arraySizeFor(Class<?> type) {
|
||||
assert type.isPrimitive();
|
||||
return 4 * MAX_WIDTH / typeToWidth.get(type);
|
||||
}
|
||||
|
||||
enum BufferKind {
|
||||
HEAP,
|
||||
HEAP_VIEW,
|
||||
DIRECT;
|
||||
}
|
||||
|
||||
static abstract class BufferType<T extends Buffer, E> {
|
||||
final BufferKind k;
|
||||
final Class<?> bufferType;
|
||||
final Class<?> elementType;
|
||||
|
||||
final MethodHandle eq;
|
||||
final MethodHandle cmp;
|
||||
|
||||
final MethodHandle getter;
|
||||
final MethodHandle setter;
|
||||
|
||||
BufferType(BufferKind k, Class<T> bufferType, Class<?> elementType) {
|
||||
this.k = k;
|
||||
this.bufferType = bufferType;
|
||||
this.elementType = elementType;
|
||||
|
||||
var lookup = MethodHandles.lookup();
|
||||
try {
|
||||
eq = lookup.findVirtual(bufferType, "equals", MethodType.methodType(boolean.class, Object.class));
|
||||
cmp = lookup.findVirtual(bufferType, "compareTo", MethodType.methodType(int.class, bufferType));
|
||||
|
||||
getter = lookup.findVirtual(bufferType, "get", MethodType.methodType(elementType, int.class));
|
||||
setter = lookup.findVirtual(bufferType, "put", MethodType.methodType(bufferType, int.class, elementType));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return bufferType.getName() + " " + k;
|
||||
}
|
||||
|
||||
T construct(int length) {
|
||||
return construct(length, ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
|
||||
abstract T construct(int length, ByteOrder bo);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T slice(T a, int from, int to) {
|
||||
return (T) a.position(from).limit(to).slice();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
E get(T a, int i) {
|
||||
try {
|
||||
return (E) getter.invoke(a, i);
|
||||
}
|
||||
catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new Error(t);
|
||||
}
|
||||
}
|
||||
|
||||
void set(T a, int i, Object v) {
|
||||
try {
|
||||
setter.invoke(a, i, convert(v));
|
||||
}
|
||||
catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new Error(t);
|
||||
}
|
||||
}
|
||||
|
||||
abstract Object convert(Object o);
|
||||
|
||||
boolean equals(T a, T b) {
|
||||
try {
|
||||
return (boolean) eq.invoke(a, b);
|
||||
}
|
||||
catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new Error(t);
|
||||
}
|
||||
}
|
||||
|
||||
int compare(T a, T b) {
|
||||
try {
|
||||
return (int) cmp.invoke(a, b);
|
||||
}
|
||||
catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new Error(t);
|
||||
}
|
||||
}
|
||||
|
||||
boolean pairWiseEquals(T a, T b) {
|
||||
if (a.remaining() != b.remaining())
|
||||
return false;
|
||||
int p = a.position();
|
||||
for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--)
|
||||
if (!get(a, i).equals(get(b, j)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static class Bytes extends BufferType<ByteBuffer, Byte> {
|
||||
Bytes(BufferKind k) {
|
||||
super(k, ByteBuffer.class, byte.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
ByteBuffer construct(int length, ByteOrder bo) {
|
||||
switch (k) {
|
||||
case DIRECT:
|
||||
return ByteBuffer.allocateDirect(length).order(bo);
|
||||
default:
|
||||
case HEAP_VIEW:
|
||||
case HEAP:
|
||||
return ByteBuffer.allocate(length).order(bo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object convert(Object o) {
|
||||
return o instanceof Integer
|
||||
? ((Integer) o).byteValue()
|
||||
: o;
|
||||
}
|
||||
}
|
||||
|
||||
static class Chars extends BufferType<CharBuffer, Character> {
|
||||
Chars(BufferKind k) {
|
||||
super(k, CharBuffer.class, char.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
CharBuffer construct(int length, ByteOrder bo) {
|
||||
switch (k) {
|
||||
case DIRECT:
|
||||
return ByteBuffer.allocateDirect(length * Character.BYTES).
|
||||
order(bo).
|
||||
asCharBuffer();
|
||||
case HEAP_VIEW:
|
||||
return ByteBuffer.allocate(length * Character.BYTES).
|
||||
order(bo).
|
||||
asCharBuffer();
|
||||
default:
|
||||
case HEAP:
|
||||
return CharBuffer.allocate(length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object convert(Object o) {
|
||||
return o instanceof Integer
|
||||
? (char) ((Integer) o).intValue()
|
||||
: o;
|
||||
}
|
||||
|
||||
CharBuffer transformToStringBuffer(CharBuffer c) {
|
||||
char[] chars = new char[c.remaining()];
|
||||
c.get(chars);
|
||||
return CharBuffer.wrap(new String(chars));
|
||||
}
|
||||
}
|
||||
|
||||
static class Shorts extends BufferType<ShortBuffer, Short> {
|
||||
Shorts(BufferKind k) {
|
||||
super(k, ShortBuffer.class, short.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
ShortBuffer construct(int length, ByteOrder bo) {
|
||||
switch (k) {
|
||||
case DIRECT:
|
||||
return ByteBuffer.allocateDirect(length * Short.BYTES).
|
||||
order(bo).
|
||||
asShortBuffer();
|
||||
case HEAP_VIEW:
|
||||
return ByteBuffer.allocate(length * Short.BYTES).
|
||||
order(bo).
|
||||
asShortBuffer();
|
||||
default:
|
||||
case HEAP:
|
||||
return ShortBuffer.allocate(length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object convert(Object o) {
|
||||
return o instanceof Integer
|
||||
? ((Integer) o).shortValue()
|
||||
: o;
|
||||
}
|
||||
}
|
||||
|
||||
static class Ints extends BufferType<IntBuffer, Integer> {
|
||||
Ints(BufferKind k) {
|
||||
super(k, IntBuffer.class, int.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
IntBuffer construct(int length, ByteOrder bo) {
|
||||
switch (k) {
|
||||
case DIRECT:
|
||||
return ByteBuffer.allocateDirect(length * Integer.BYTES).
|
||||
order(bo).
|
||||
asIntBuffer();
|
||||
case HEAP_VIEW:
|
||||
return ByteBuffer.allocate(length * Integer.BYTES).
|
||||
order(bo).
|
||||
asIntBuffer();
|
||||
default:
|
||||
case HEAP:
|
||||
return IntBuffer.allocate(length);
|
||||
}
|
||||
}
|
||||
|
||||
Object convert(Object o) {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
static class Floats extends BufferType<FloatBuffer, Float> {
|
||||
Floats(BufferKind k) {
|
||||
super(k, FloatBuffer.class, float.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
FloatBuffer construct(int length, ByteOrder bo) {
|
||||
switch (k) {
|
||||
case DIRECT:
|
||||
return ByteBuffer.allocateDirect(length * Float.BYTES).
|
||||
order(bo).
|
||||
asFloatBuffer();
|
||||
case HEAP_VIEW:
|
||||
return ByteBuffer.allocate(length * Float.BYTES).
|
||||
order(bo).
|
||||
asFloatBuffer();
|
||||
default:
|
||||
case HEAP:
|
||||
return FloatBuffer.allocate(length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object convert(Object o) {
|
||||
return o instanceof Integer
|
||||
? ((Integer) o).floatValue()
|
||||
: o;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean pairWiseEquals(FloatBuffer a, FloatBuffer b) {
|
||||
if (a.remaining() != b.remaining())
|
||||
return false;
|
||||
int p = a.position();
|
||||
for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--) {
|
||||
float av = a.get(i);
|
||||
float bv = b.get(j);
|
||||
if (av != bv && (!Float.isNaN(av) || !Float.isNaN(bv)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static class Longs extends BufferType<LongBuffer, Long> {
|
||||
Longs(BufferKind k) {
|
||||
super(k, LongBuffer.class, long.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
LongBuffer construct(int length, ByteOrder bo) {
|
||||
switch (k) {
|
||||
case DIRECT:
|
||||
return ByteBuffer.allocateDirect(length * Long.BYTES).
|
||||
order(bo).
|
||||
asLongBuffer();
|
||||
case HEAP_VIEW:
|
||||
return ByteBuffer.allocate(length * Long.BYTES).
|
||||
order(bo).
|
||||
asLongBuffer();
|
||||
default:
|
||||
case HEAP:
|
||||
return LongBuffer.allocate(length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object convert(Object o) {
|
||||
return o instanceof Integer
|
||||
? ((Integer) o).longValue()
|
||||
: o;
|
||||
}
|
||||
}
|
||||
|
||||
static class Doubles extends BufferType<DoubleBuffer, Double> {
|
||||
Doubles(BufferKind k) {
|
||||
super(k, DoubleBuffer.class, double.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
DoubleBuffer construct(int length, ByteOrder bo) {
|
||||
switch (k) {
|
||||
case DIRECT:
|
||||
return ByteBuffer.allocateDirect(length * Double.BYTES).
|
||||
order(bo).
|
||||
asDoubleBuffer();
|
||||
case HEAP_VIEW:
|
||||
return ByteBuffer.allocate(length * Double.BYTES).
|
||||
order(bo).
|
||||
asDoubleBuffer();
|
||||
default:
|
||||
case HEAP:
|
||||
return DoubleBuffer.allocate(length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object convert(Object o) {
|
||||
return o instanceof Integer
|
||||
? ((Integer) o).doubleValue()
|
||||
: o;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean pairWiseEquals(DoubleBuffer a, DoubleBuffer b) {
|
||||
if (a.remaining() != b.remaining())
|
||||
return false;
|
||||
int p = a.position();
|
||||
for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--) {
|
||||
double av = a.get(i);
|
||||
double bv = b.get(j);
|
||||
if (av != bv && (!Double.isNaN(av) || !Double.isNaN(bv)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Object[][] bufferTypes;
|
||||
|
||||
@DataProvider
|
||||
public static Object[][] bufferTypesProvider() {
|
||||
if (bufferTypes == null) {
|
||||
bufferTypes = new Object[][]{
|
||||
{new BufferType.Bytes(BufferKind.HEAP)},
|
||||
{new BufferType.Bytes(BufferKind.DIRECT)},
|
||||
{new BufferType.Chars(BufferKind.HEAP)},
|
||||
{new BufferType.Chars(BufferKind.HEAP_VIEW)},
|
||||
{new BufferType.Chars(BufferKind.DIRECT)},
|
||||
{new BufferType.Shorts(BufferKind.HEAP)},
|
||||
{new BufferType.Shorts(BufferKind.HEAP_VIEW)},
|
||||
{new BufferType.Shorts(BufferKind.DIRECT)},
|
||||
{new BufferType.Ints(BufferKind.HEAP)},
|
||||
{new BufferType.Ints(BufferKind.HEAP_VIEW)},
|
||||
{new BufferType.Ints(BufferKind.DIRECT)},
|
||||
{new BufferType.Floats(BufferKind.HEAP)},
|
||||
{new BufferType.Floats(BufferKind.HEAP_VIEW)},
|
||||
{new BufferType.Floats(BufferKind.DIRECT)},
|
||||
{new BufferType.Longs(BufferKind.HEAP)},
|
||||
{new BufferType.Longs(BufferKind.HEAP_VIEW)},
|
||||
{new BufferType.Longs(BufferKind.DIRECT)},
|
||||
{new BufferType.Doubles(BufferKind.HEAP)},
|
||||
{new BufferType.Doubles(BufferKind.HEAP_VIEW)},
|
||||
{new BufferType.Doubles(BufferKind.DIRECT)},
|
||||
};
|
||||
}
|
||||
return bufferTypes;
|
||||
}
|
||||
|
||||
|
||||
static Object[][] floatbufferTypes;
|
||||
|
||||
@DataProvider
|
||||
public static Object[][] floatBufferTypesProvider() {
|
||||
if (floatbufferTypes == null) {
|
||||
LongFunction<Object> bTof = rb -> Float.intBitsToFloat((int) rb);
|
||||
LongFunction<Object> bToD = Double::longBitsToDouble;
|
||||
|
||||
floatbufferTypes = new Object[][]{
|
||||
// canonical and non-canonical NaNs
|
||||
// If conversion is a signalling NaN it may be subject to conversion to a
|
||||
// quiet NaN on some processors, even if a copy is performed
|
||||
// The tests assume that if conversion occurs it does not convert to the
|
||||
// canonical NaN
|
||||
new Object[]{new BufferType.Floats(BufferKind.HEAP), 0x7fc00000L, 0x7f800001L, bTof},
|
||||
new Object[]{new BufferType.Floats(BufferKind.HEAP_VIEW), 0x7fc00000L, 0x7f800001L, bTof},
|
||||
new Object[]{new BufferType.Floats(BufferKind.DIRECT), 0x7fc00000L, 0x7f800001L, bTof},
|
||||
new Object[]{new BufferType.Doubles(BufferKind.HEAP), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},
|
||||
new Object[]{new BufferType.Doubles(BufferKind.HEAP_VIEW), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},
|
||||
new Object[]{new BufferType.Doubles(BufferKind.DIRECT), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},
|
||||
|
||||
// +0.0 and -0.0
|
||||
new Object[]{new BufferType.Floats(BufferKind.HEAP), 0x0L, 0x80000000L, bTof},
|
||||
new Object[]{new BufferType.Floats(BufferKind.HEAP_VIEW), 0x0L, 0x80000000L, bTof},
|
||||
new Object[]{new BufferType.Floats(BufferKind.DIRECT), 0x0L, 0x80000000L, bTof},
|
||||
new Object[]{new BufferType.Doubles(BufferKind.HEAP), 0x0L, 0x8000000000000000L, bToD},
|
||||
new Object[]{new BufferType.Doubles(BufferKind.HEAP_VIEW), 0x0L, 0x8000000000000000L, bToD},
|
||||
new Object[]{new BufferType.Doubles(BufferKind.DIRECT), 0x0L, 0x8000000000000000L, bToD},
|
||||
};
|
||||
}
|
||||
return floatbufferTypes;
|
||||
}
|
||||
|
||||
|
||||
static Object[][] charBufferTypes;
|
||||
|
||||
@DataProvider
|
||||
public static Object[][] charBufferTypesProvider() {
|
||||
if (charBufferTypes == null) {
|
||||
charBufferTypes = new Object[][]{
|
||||
{new BufferType.Chars(BufferKind.HEAP)},
|
||||
{new BufferType.Chars(BufferKind.HEAP_VIEW)},
|
||||
{new BufferType.Chars(BufferKind.DIRECT)},
|
||||
};
|
||||
}
|
||||
return charBufferTypes;
|
||||
}
|
||||
|
||||
|
||||
// Tests all primitive buffers
|
||||
@Test(dataProvider = "bufferTypesProvider")
|
||||
<E>
|
||||
void testBuffers(BufferType<Buffer, E> bufferType) {
|
||||
// Test with buffers of the same byte order (BE)
|
||||
BiFunction<BufferType<Buffer, E>, Integer, Buffer> constructor = (at, s) -> {
|
||||
Buffer a = at.construct(s);
|
||||
for (int x = 0; x < s; x++) {
|
||||
at.set(a, x, x % 8);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
testBufferType(bufferType, constructor, constructor);
|
||||
|
||||
// Test with buffers of different byte order
|
||||
if (bufferType.elementType != byte.class &&
|
||||
(bufferType.k == BufferKind.HEAP_VIEW ||
|
||||
bufferType.k == BufferKind.DIRECT)) {
|
||||
|
||||
BiFunction<BufferType<Buffer, E>, Integer, Buffer> leConstructor = (at, s) -> {
|
||||
Buffer a = at.construct(s, ByteOrder.LITTLE_ENDIAN);
|
||||
for (int x = 0; x < s; x++) {
|
||||
at.set(a, x, x % 8);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
testBufferType(bufferType, constructor, leConstructor);
|
||||
}
|
||||
}
|
||||
|
||||
// Tests float and double buffers with edge-case values (NaN, -0.0, +0.0)
|
||||
@Test(dataProvider = "floatBufferTypesProvider")
|
||||
public void testFloatBuffers(
|
||||
BufferType<Buffer, Float> bufferType,
|
||||
long rawBitsA, long rawBitsB,
|
||||
LongFunction<Object> bitsToFloat) {
|
||||
Object av = bitsToFloat.apply(rawBitsA);
|
||||
Object bv = bitsToFloat.apply(rawBitsB);
|
||||
|
||||
BiFunction<BufferType<Buffer, Float>, Integer, Buffer> allAs = (at, s) -> {
|
||||
Buffer b = at.construct(s);
|
||||
for (int x = 0; x < s; x++) {
|
||||
at.set(b, x, av);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
|
||||
BiFunction<BufferType<Buffer, Float>, Integer, Buffer> allBs = (at, s) -> {
|
||||
Buffer b = at.construct(s);
|
||||
for (int x = 0; x < s; x++) {
|
||||
at.set(b, x, bv);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
|
||||
BiFunction<BufferType<Buffer, Float>, Integer, Buffer> halfBs = (at, s) -> {
|
||||
Buffer b = at.construct(s);
|
||||
for (int x = 0; x < s / 2; x++) {
|
||||
at.set(b, x, bv);
|
||||
}
|
||||
for (int x = s / 2; x < s; x++) {
|
||||
at.set(b, x, 1);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
|
||||
// Sanity check
|
||||
int size = arraySizeFor(bufferType.elementType);
|
||||
Assert.assertTrue(bufferType.pairWiseEquals(allAs.apply(bufferType, size),
|
||||
allBs.apply(bufferType, size)));
|
||||
Assert.assertTrue(bufferType.equals(allAs.apply(bufferType, size),
|
||||
allBs.apply(bufferType, size)));
|
||||
|
||||
testBufferType(bufferType, allAs, allBs);
|
||||
testBufferType(bufferType, allAs, halfBs);
|
||||
}
|
||||
|
||||
// Tests CharBuffer for region sources and CharSequence sources
|
||||
@Test(dataProvider = "charBufferTypesProvider")
|
||||
public void testCharBuffers(BufferType.Chars charBufferType) {
|
||||
|
||||
BiFunction<BufferType.Chars, Integer, CharBuffer> constructor = (at, s) -> {
|
||||
CharBuffer a = at.construct(s);
|
||||
for (int x = 0; x < s; x++) {
|
||||
at.set(a, x, x % 8);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
BiFunction<BufferType.Chars, Integer, CharBuffer> constructorX = constructor.
|
||||
andThen(charBufferType::transformToStringBuffer);
|
||||
|
||||
testBufferType(charBufferType, constructor, constructorX);
|
||||
}
|
||||
|
||||
|
||||
<B extends Buffer, E, BT extends BufferType<B, E>>
|
||||
void testBufferType(BT bt,
|
||||
BiFunction<BT, Integer, B> aConstructor,
|
||||
BiFunction<BT, Integer, B> bConstructor) {
|
||||
int n = arraySizeFor(bt.elementType);
|
||||
|
||||
for (int s : ranges(0, n)) {
|
||||
B a = aConstructor.apply(bt, s);
|
||||
B b = bConstructor.apply(bt, s);
|
||||
|
||||
for (int aFrom : ranges(0, s)) {
|
||||
for (int aTo : ranges(aFrom, s)) {
|
||||
int aLength = aTo - aFrom;
|
||||
|
||||
B as = aLength != s
|
||||
? bt.slice(a, aFrom, aTo)
|
||||
: a;
|
||||
|
||||
for (int bFrom : ranges(0, s)) {
|
||||
for (int bTo : ranges(bFrom, s)) {
|
||||
int bLength = bTo - bFrom;
|
||||
|
||||
B bs = bLength != s
|
||||
? bt.slice(b, bFrom, bTo)
|
||||
: b;
|
||||
|
||||
boolean eq = bt.pairWiseEquals(as, bs);
|
||||
Assert.assertEquals(bt.equals(as, bs), eq);
|
||||
Assert.assertEquals(bt.equals(bs, as), eq);
|
||||
if (eq) {
|
||||
Assert.assertEquals(bt.compare(as, bs), 0);
|
||||
Assert.assertEquals(bt.compare(bs, as), 0);
|
||||
}
|
||||
else {
|
||||
int aCb = bt.compare(as, bs);
|
||||
int bCa = bt.compare(bs, as);
|
||||
int v = Integer.signum(aCb) * Integer.signum(bCa);
|
||||
Assert.assertTrue(v == -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aLength > 0 && !a.isReadOnly()) {
|
||||
for (int i = aFrom; i < aTo; i++) {
|
||||
B c = aConstructor.apply(bt, a.capacity());
|
||||
B cs = aLength != s
|
||||
? bt.slice(c, aFrom, aTo)
|
||||
: c;
|
||||
|
||||
// Create common prefix with a length of i - aFrom
|
||||
bt.set(c, i, -1);
|
||||
|
||||
Assert.assertFalse(bt.equals(c, a));
|
||||
|
||||
int cCa = bt.compare(cs, as);
|
||||
int aCc = bt.compare(as, cs);
|
||||
int v = Integer.signum(cCa) * Integer.signum(aCc);
|
||||
Assert.assertTrue(v == -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int[] ranges(int from, int to) {
|
||||
int width = to - from;
|
||||
switch (width) {
|
||||
case 0:
|
||||
return new int[]{};
|
||||
case 1:
|
||||
return new int[]{from, to};
|
||||
case 2:
|
||||
return new int[]{from, from + 1, to};
|
||||
case 3:
|
||||
return new int[]{from, from + 1, from + 2, to};
|
||||
default:
|
||||
return IntStream.of(from, from + 1, from + 2, to / 2 - 1, to / 2, to / 2 + 1, to - 2, to - 1, to)
|
||||
.filter(i -> i >= from && i <= to)
|
||||
.distinct().toArray();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user