Path: blob/master/test/jdk/java/nio/Buffer/EqualsCompareTest.java
41149 views
/*1* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import org.testng.Assert;24import org.testng.annotations.DataProvider;25import org.testng.annotations.Test;2627import java.lang.invoke.MethodHandle;28import java.lang.invoke.MethodHandles;29import java.lang.invoke.MethodType;30import java.nio.Buffer;31import java.nio.ByteBuffer;32import java.nio.ByteOrder;33import java.nio.CharBuffer;34import java.nio.DoubleBuffer;35import java.nio.FloatBuffer;36import java.nio.IntBuffer;37import java.nio.LongBuffer;38import java.nio.ShortBuffer;39import java.util.HashMap;40import java.util.Map;41import java.util.function.BiFunction;42import java.util.function.LongFunction;43import java.util.stream.IntStream;4445/*46* @test47* @bug 8193085 819977348* @summary tests for buffer equals and compare49* @run testng EqualsCompareTest50*/5152public class EqualsCompareTest {5354// Maximum width in bits55static final int MAX_WIDTH = 512;5657static final Map<Class, Integer> typeToWidth;5859static {60typeToWidth = new HashMap<>();61typeToWidth.put(byte.class, Byte.SIZE);62typeToWidth.put(short.class, Short.SIZE);63typeToWidth.put(char.class, Character.SIZE);64typeToWidth.put(int.class, Integer.SIZE);65typeToWidth.put(long.class, Long.SIZE);66typeToWidth.put(float.class, Float.SIZE);67typeToWidth.put(double.class, Double.SIZE);68}6970static int arraySizeFor(Class<?> type) {71assert type.isPrimitive();72return 4 * MAX_WIDTH / typeToWidth.get(type);73}7475enum BufferKind {76HEAP,77HEAP_VIEW,78DIRECT;79}8081static abstract class BufferType<T extends Buffer, E> {82final BufferKind k;83final Class<?> bufferType;84final Class<?> elementType;8586final MethodHandle eq;87final MethodHandle cmp;88final MethodHandle mismtch;8990final MethodHandle getter;91final MethodHandle setter;9293BufferType(BufferKind k, Class<T> bufferType, Class<?> elementType) {94this.k = k;95this.bufferType = bufferType;96this.elementType = elementType;9798var lookup = MethodHandles.lookup();99try {100eq = lookup.findVirtual(bufferType, "equals", MethodType.methodType(boolean.class, Object.class));101cmp = lookup.findVirtual(bufferType, "compareTo", MethodType.methodType(int.class, bufferType));102mismtch = lookup.findVirtual(bufferType, "mismatch", MethodType.methodType(int.class, bufferType));103104getter = lookup.findVirtual(bufferType, "get", MethodType.methodType(elementType, int.class));105setter = lookup.findVirtual(bufferType, "put", MethodType.methodType(bufferType, int.class, elementType));106}107catch (Exception e) {108throw new AssertionError(e);109}110}111112@Override113public String toString() {114return bufferType.getName() + " " + k;115}116117T construct(int length) {118return construct(length, ByteOrder.BIG_ENDIAN);119}120121abstract T construct(int length, ByteOrder bo);122123@SuppressWarnings("unchecked")124T slice(T a, int from, int to, boolean dupOtherwiseSlice) {125a = (T) a.position(from).limit(to);126return (T) (dupOtherwiseSlice ? a.duplicate() : a.slice());127}128129@SuppressWarnings("unchecked")130E get(T a, int i) {131try {132return (E) getter.invoke(a, i);133}134catch (RuntimeException | Error e) {135throw e;136}137catch (Throwable t) {138throw new Error(t);139}140}141142void set(T a, int i, Object v) {143try {144setter.invoke(a, i, convert(v));145}146catch (RuntimeException | Error e) {147throw e;148}149catch (Throwable t) {150throw new Error(t);151}152}153154abstract Object convert(Object o);155156boolean equals(T a, T b) {157try {158return (boolean) eq.invoke(a, b);159}160catch (RuntimeException | Error e) {161throw e;162}163catch (Throwable t) {164throw new Error(t);165}166}167168int compare(T a, T b) {169try {170return (int) cmp.invoke(a, b);171}172catch (RuntimeException | Error e) {173throw e;174}175catch (Throwable t) {176throw new Error(t);177}178}179180boolean pairWiseEquals(T a, T b) {181if (a.remaining() != b.remaining())182return false;183int p = a.position();184for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--)185if (!get(a, i).equals(get(b, j)))186return false;187return true;188}189190int mismatch(T a, T b) {191try {192return (int) mismtch.invoke(a, b);193}194catch (RuntimeException | Error e) {195throw e;196}197catch (Throwable t) {198throw new Error(t);199}200}201202static class Bytes extends BufferType<ByteBuffer, Byte> {203Bytes(BufferKind k) {204super(k, ByteBuffer.class, byte.class);205}206207@Override208ByteBuffer construct(int length, ByteOrder bo) {209switch (k) {210case DIRECT:211return ByteBuffer.allocateDirect(length).order(bo);212default:213case HEAP_VIEW:214case HEAP:215return ByteBuffer.allocate(length).order(bo);216}217}218219@Override220Object convert(Object o) {221return o instanceof Integer222? ((Integer) o).byteValue()223: o;224}225}226227static class Chars extends BufferType<CharBuffer, Character> {228Chars(BufferKind k) {229super(k, CharBuffer.class, char.class);230}231232@Override233CharBuffer construct(int length, ByteOrder bo) {234switch (k) {235case DIRECT:236return ByteBuffer.allocateDirect(length * Character.BYTES).237order(bo).238asCharBuffer();239case HEAP_VIEW:240return ByteBuffer.allocate(length * Character.BYTES).241order(bo).242asCharBuffer();243default:244case HEAP:245return CharBuffer.allocate(length);246}247}248249@Override250Object convert(Object o) {251return o instanceof Integer252? (char) ((Integer) o).intValue()253: o;254}255256CharBuffer transformToStringBuffer(CharBuffer c) {257char[] chars = new char[c.remaining()];258c.get(chars);259return CharBuffer.wrap(new String(chars));260}261}262263static class Shorts extends BufferType<ShortBuffer, Short> {264Shorts(BufferKind k) {265super(k, ShortBuffer.class, short.class);266}267268@Override269ShortBuffer construct(int length, ByteOrder bo) {270switch (k) {271case DIRECT:272return ByteBuffer.allocateDirect(length * Short.BYTES).273order(bo).274asShortBuffer();275case HEAP_VIEW:276return ByteBuffer.allocate(length * Short.BYTES).277order(bo).278asShortBuffer();279default:280case HEAP:281return ShortBuffer.allocate(length);282}283}284285@Override286Object convert(Object o) {287return o instanceof Integer288? ((Integer) o).shortValue()289: o;290}291}292293static class Ints extends BufferType<IntBuffer, Integer> {294Ints(BufferKind k) {295super(k, IntBuffer.class, int.class);296}297298@Override299IntBuffer construct(int length, ByteOrder bo) {300switch (k) {301case DIRECT:302return ByteBuffer.allocateDirect(length * Integer.BYTES).303order(bo).304asIntBuffer();305case HEAP_VIEW:306return ByteBuffer.allocate(length * Integer.BYTES).307order(bo).308asIntBuffer();309default:310case HEAP:311return IntBuffer.allocate(length);312}313}314315Object convert(Object o) {316return o;317}318}319320static class Floats extends BufferType<FloatBuffer, Float> {321Floats(BufferKind k) {322super(k, FloatBuffer.class, float.class);323}324325@Override326FloatBuffer construct(int length, ByteOrder bo) {327switch (k) {328case DIRECT:329return ByteBuffer.allocateDirect(length * Float.BYTES).330order(bo).331asFloatBuffer();332case HEAP_VIEW:333return ByteBuffer.allocate(length * Float.BYTES).334order(bo).335asFloatBuffer();336default:337case HEAP:338return FloatBuffer.allocate(length);339}340}341342@Override343Object convert(Object o) {344return o instanceof Integer345? ((Integer) o).floatValue()346: o;347}348349@Override350boolean pairWiseEquals(FloatBuffer a, FloatBuffer b) {351if (a.remaining() != b.remaining())352return false;353int p = a.position();354for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--) {355float av = a.get(i);356float bv = b.get(j);357if (av != bv && (!Float.isNaN(av) || !Float.isNaN(bv)))358return false;359}360return true;361}362}363364static class Longs extends BufferType<LongBuffer, Long> {365Longs(BufferKind k) {366super(k, LongBuffer.class, long.class);367}368369@Override370LongBuffer construct(int length, ByteOrder bo) {371switch (k) {372case DIRECT:373return ByteBuffer.allocateDirect(length * Long.BYTES).374order(bo).375asLongBuffer();376case HEAP_VIEW:377return ByteBuffer.allocate(length * Long.BYTES).378order(bo).379asLongBuffer();380default:381case HEAP:382return LongBuffer.allocate(length);383}384}385386@Override387Object convert(Object o) {388return o instanceof Integer389? ((Integer) o).longValue()390: o;391}392}393394static class Doubles extends BufferType<DoubleBuffer, Double> {395Doubles(BufferKind k) {396super(k, DoubleBuffer.class, double.class);397}398399@Override400DoubleBuffer construct(int length, ByteOrder bo) {401switch (k) {402case DIRECT:403return ByteBuffer.allocateDirect(length * Double.BYTES).404order(bo).405asDoubleBuffer();406case HEAP_VIEW:407return ByteBuffer.allocate(length * Double.BYTES).408order(bo).409asDoubleBuffer();410default:411case HEAP:412return DoubleBuffer.allocate(length);413}414}415416@Override417Object convert(Object o) {418return o instanceof Integer419? ((Integer) o).doubleValue()420: o;421}422423@Override424boolean pairWiseEquals(DoubleBuffer a, DoubleBuffer b) {425if (a.remaining() != b.remaining())426return false;427int p = a.position();428for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--) {429double av = a.get(i);430double bv = b.get(j);431if (av != bv && (!Double.isNaN(av) || !Double.isNaN(bv)))432return false;433}434return true;435}436}437}438439static Object[][] bufferTypes;440441@DataProvider442public static Object[][] bufferTypesProvider() {443if (bufferTypes == null) {444bufferTypes = new Object[][]{445{new BufferType.Bytes(BufferKind.HEAP)},446{new BufferType.Bytes(BufferKind.DIRECT)},447{new BufferType.Chars(BufferKind.HEAP)},448{new BufferType.Chars(BufferKind.HEAP_VIEW)},449{new BufferType.Chars(BufferKind.DIRECT)},450{new BufferType.Shorts(BufferKind.HEAP)},451{new BufferType.Shorts(BufferKind.HEAP_VIEW)},452{new BufferType.Shorts(BufferKind.DIRECT)},453{new BufferType.Ints(BufferKind.HEAP)},454{new BufferType.Ints(BufferKind.HEAP_VIEW)},455{new BufferType.Ints(BufferKind.DIRECT)},456{new BufferType.Floats(BufferKind.HEAP)},457{new BufferType.Floats(BufferKind.HEAP_VIEW)},458{new BufferType.Floats(BufferKind.DIRECT)},459{new BufferType.Longs(BufferKind.HEAP)},460{new BufferType.Longs(BufferKind.HEAP_VIEW)},461{new BufferType.Longs(BufferKind.DIRECT)},462{new BufferType.Doubles(BufferKind.HEAP)},463{new BufferType.Doubles(BufferKind.HEAP_VIEW)},464{new BufferType.Doubles(BufferKind.DIRECT)},465};466}467return bufferTypes;468}469470471static Object[][] floatbufferTypes;472473@DataProvider474public static Object[][] floatBufferTypesProvider() {475if (floatbufferTypes == null) {476LongFunction<Object> bTof = rb -> Float.intBitsToFloat((int) rb);477LongFunction<Object> bToD = Double::longBitsToDouble;478479floatbufferTypes = new Object[][]{480// canonical and non-canonical NaNs481// If conversion is a signalling NaN it may be subject to conversion to a482// quiet NaN on some processors, even if a copy is performed483// The tests assume that if conversion occurs it does not convert to the484// canonical NaN485new Object[]{new BufferType.Floats(BufferKind.HEAP), 0x7fc00000L, 0x7f800001L, bTof},486new Object[]{new BufferType.Floats(BufferKind.HEAP_VIEW), 0x7fc00000L, 0x7f800001L, bTof},487new Object[]{new BufferType.Floats(BufferKind.DIRECT), 0x7fc00000L, 0x7f800001L, bTof},488new Object[]{new BufferType.Doubles(BufferKind.HEAP), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},489new Object[]{new BufferType.Doubles(BufferKind.HEAP_VIEW), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},490new Object[]{new BufferType.Doubles(BufferKind.DIRECT), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},491492// +0.0 and -0.0493new Object[]{new BufferType.Floats(BufferKind.HEAP), 0x0L, 0x80000000L, bTof},494new Object[]{new BufferType.Floats(BufferKind.HEAP_VIEW), 0x0L, 0x80000000L, bTof},495new Object[]{new BufferType.Floats(BufferKind.DIRECT), 0x0L, 0x80000000L, bTof},496new Object[]{new BufferType.Doubles(BufferKind.HEAP), 0x0L, 0x8000000000000000L, bToD},497new Object[]{new BufferType.Doubles(BufferKind.HEAP_VIEW), 0x0L, 0x8000000000000000L, bToD},498new Object[]{new BufferType.Doubles(BufferKind.DIRECT), 0x0L, 0x8000000000000000L, bToD},499};500}501return floatbufferTypes;502}503504505static Object[][] charBufferTypes;506507@DataProvider508public static Object[][] charBufferTypesProvider() {509if (charBufferTypes == null) {510charBufferTypes = new Object[][]{511{new BufferType.Chars(BufferKind.HEAP)},512{new BufferType.Chars(BufferKind.HEAP_VIEW)},513{new BufferType.Chars(BufferKind.DIRECT)},514};515}516return charBufferTypes;517}518519520// Tests all primitive buffers521@Test(dataProvider = "bufferTypesProvider")522<E>523void testBuffers(BufferType<Buffer, E> bufferType) {524// Test with buffers of the same byte order (BE)525BiFunction<BufferType<Buffer, E>, Integer, Buffer> constructor = (at, s) -> {526Buffer a = at.construct(s);527for (int x = 0; x < s; x++) {528at.set(a, x, x % 8);529}530return a;531};532533testBufferType(bufferType, constructor, constructor);534535// Test with buffers of different byte order536if (bufferType.elementType != byte.class &&537(bufferType.k == BufferKind.HEAP_VIEW ||538bufferType.k == BufferKind.DIRECT)) {539540BiFunction<BufferType<Buffer, E>, Integer, Buffer> leConstructor = (at, s) -> {541Buffer a = at.construct(s, ByteOrder.LITTLE_ENDIAN);542for (int x = 0; x < s; x++) {543at.set(a, x, x % 8);544}545return a;546};547testBufferType(bufferType, constructor, leConstructor);548}549}550551// Tests float and double buffers with edge-case values (NaN, -0.0, +0.0)552@Test(dataProvider = "floatBufferTypesProvider")553public void testFloatBuffers(554BufferType<Buffer, Float> bufferType,555long rawBitsA, long rawBitsB,556LongFunction<Object> bitsToFloat) {557Object av = bitsToFloat.apply(rawBitsA);558Object bv = bitsToFloat.apply(rawBitsB);559560BiFunction<BufferType<Buffer, Float>, Integer, Buffer> allAs = (at, s) -> {561Buffer b = at.construct(s);562for (int x = 0; x < s; x++) {563at.set(b, x, av);564}565return b;566};567568BiFunction<BufferType<Buffer, Float>, Integer, Buffer> allBs = (at, s) -> {569Buffer b = at.construct(s);570for (int x = 0; x < s; x++) {571at.set(b, x, bv);572}573return b;574};575576BiFunction<BufferType<Buffer, Float>, Integer, Buffer> halfBs = (at, s) -> {577Buffer b = at.construct(s);578for (int x = 0; x < s / 2; x++) {579at.set(b, x, bv);580}581for (int x = s / 2; x < s; x++) {582at.set(b, x, 1);583}584return b;585};586587// Sanity check588int size = arraySizeFor(bufferType.elementType);589Assert.assertTrue(bufferType.pairWiseEquals(allAs.apply(bufferType, size),590allBs.apply(bufferType, size)));591Assert.assertTrue(bufferType.equals(allAs.apply(bufferType, size),592allBs.apply(bufferType, size)));593594testBufferType(bufferType, allAs, allBs);595testBufferType(bufferType, allAs, halfBs);596}597598// Tests CharBuffer for region sources and CharSequence sources599@Test(dataProvider = "charBufferTypesProvider")600public void testCharBuffers(BufferType.Chars charBufferType) {601602BiFunction<BufferType.Chars, Integer, CharBuffer> constructor = (at, s) -> {603CharBuffer a = at.construct(s);604for (int x = 0; x < s; x++) {605at.set(a, x, x % 8);606}607return a;608};609610BiFunction<BufferType.Chars, Integer, CharBuffer> constructorX = constructor.611andThen(charBufferType::transformToStringBuffer);612613testBufferType(charBufferType, constructor, constructorX);614}615616617<B extends Buffer, E, BT extends BufferType<B, E>>618void testBufferType(BT bt,619BiFunction<BT, Integer, B> aConstructor,620BiFunction<BT, Integer, B> bConstructor) {621int n = arraySizeFor(bt.elementType);622623for (boolean dupOtherwiseSlice : new boolean[]{ false, true }) {624for (int s : ranges(0, n)) {625B a = aConstructor.apply(bt, s);626B b = bConstructor.apply(bt, s);627628for (int aFrom : ranges(0, s)) {629for (int aTo : ranges(aFrom, s)) {630int aLength = aTo - aFrom;631632B as = aLength != s633? bt.slice(a, aFrom, aTo, dupOtherwiseSlice)634: a;635636for (int bFrom : ranges(0, s)) {637for (int bTo : ranges(bFrom, s)) {638int bLength = bTo - bFrom;639640B bs = bLength != s641? bt.slice(b, bFrom, bTo, dupOtherwiseSlice)642: b;643644boolean eq = bt.pairWiseEquals(as, bs);645Assert.assertEquals(bt.equals(as, bs), eq);646Assert.assertEquals(bt.equals(bs, as), eq);647if (eq) {648Assert.assertEquals(bt.compare(as, bs), 0);649Assert.assertEquals(bt.compare(bs, as), 0);650651// If buffers are equal, there shall be no mismatch652Assert.assertEquals(bt.mismatch(as, bs), -1);653Assert.assertEquals(bt.mismatch(bs, as), -1);654}655else {656int aCb = bt.compare(as, bs);657int bCa = bt.compare(bs, as);658int v = Integer.signum(aCb) * Integer.signum(bCa);659Assert.assertTrue(v == -1);660661int aMs = bt.mismatch(as, bs);662int bMs = bt.mismatch(bs, as);663Assert.assertNotEquals(aMs, -1);664Assert.assertEquals(aMs, bMs);665}666}667}668669if (aLength > 0 && !a.isReadOnly()) {670for (int i = aFrom; i < aTo; i++) {671B c = aConstructor.apply(bt, a.capacity());672B cs = aLength != s673? bt.slice(c, aFrom, aTo, dupOtherwiseSlice)674: c;675676// Create common prefix with a length of i - aFrom677bt.set(c, i, -1);678679Assert.assertFalse(bt.equals(c, a));680681int cCa = bt.compare(cs, as);682int aCc = bt.compare(as, cs);683int v = Integer.signum(cCa) * Integer.signum(aCc);684Assert.assertTrue(v == -1);685686int cMa = bt.mismatch(cs, as);687int aMc = bt.mismatch(as, cs);688Assert.assertEquals(cMa, aMc);689Assert.assertEquals(cMa, i - aFrom);690}691}692}693}694}695}696}697698static int[] ranges(int from, int to) {699int width = to - from;700switch (width) {701case 0:702return new int[]{};703case 1:704return new int[]{from, to};705case 2:706return new int[]{from, from + 1, to};707case 3:708return new int[]{from, from + 1, from + 2, to};709default:710return IntStream.of(from, from + 1, from + 2, to / 2 - 1, to / 2, to / 2 + 1, to - 2, to - 1, to)711.filter(i -> i >= from && i <= to)712.distinct().toArray();713}714}715}716717718