/* * Copyright (c) 2016, 2019, 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. */ /* @test * @summary Binary data and view tests for byte buffers * @bug 8159257 * @run testng ByteBufferViews */ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; 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.List; import java.util.Map; import java.util.function.Function; import java.util.function.IntFunction; import java.util.function.IntUnaryOperator; import java.util.function.UnaryOperator; import java.util.stream.Collectors; import static org.testng.Assert.*; public class ByteBufferViews { static final int SIZE = 32; // List of buffer allocator functions static final List>> BYTE_BUFFER_ALLOCATE_FUNCTIONS = List.of( // Heap Map.entry("ByteBuffer.allocate(ba)", size -> ByteBuffer.allocate(size)), // Aligned Map.entry("ByteBuffer.allocate(size).position(8)", size -> ByteBuffer.allocate(size).position(8)), Map.entry("ByteBuffer.allocate(size).position(8).slice()", size -> ByteBuffer.allocate(size).position(8).slice()), Map.entry("ByteBuffer.allocate(size).position(8).slice().duplicate()", size -> ByteBuffer.allocate(size).position(8).slice().duplicate()), Map.entry("ByteBuffer.allocate(size).slice(8,size-8)", size -> ByteBuffer.allocate(size).slice(8,size-8)), // Unaligned Map.entry("ByteBuffer.allocate(size).position(1)", size -> ByteBuffer.allocate(size).position(1)), Map.entry("ByteBuffer.allocate(size).position(1).slice()", size -> ByteBuffer.allocate(size).position(1).slice()), Map.entry("ByteBuffer.allocate(size).position(1).slice().duplicate()", size -> ByteBuffer.allocate(size).position(1).slice().duplicate()), Map.entry("ByteBuffer.allocate(size).slice(1,size-1)", size -> ByteBuffer.allocate(size).slice(1,size-1)), // Off-heap Map.entry("ByteBuffer.allocateDirect(size)", size -> ByteBuffer.allocateDirect(size)), // Aligned Map.entry("ByteBuffer.allocateDirect(size).position(8)", size -> ByteBuffer.allocateDirect(size).position(8)), Map.entry("ByteBuffer.allocateDirect(size).position(8).slice()", size -> ByteBuffer.allocateDirect(size).position(8).slice()), Map.entry("ByteBuffer.allocateDirect(size).position(8).slice().duplicate()", size -> ByteBuffer.allocateDirect(size).position(8).slice().duplicate()), Map.entry("ByteBuffer.allocateDirect(size).slice(8,size-8)", size -> ByteBuffer.allocateDirect(size).slice(8,size-8)), // Unaligned Map.entry("ByteBuffer.allocateDirect(size).position(1)", size -> ByteBuffer.allocateDirect(size).position(1)), Map.entry("ByteBuffer.allocateDirect(size).position(1).slice()", size -> ByteBuffer.allocateDirect(size).position(1).slice()), Map.entry("ByteBuffer.allocateDirect(size).position(1).slice().duplicate()", size -> ByteBuffer.allocateDirect(size).position(1).slice().duplicate()), Map.entry("ByteBuffer.allocateDirect(size).slice(1,size-1)", size -> ByteBuffer.allocateDirect(size).slice(1,size-1)) ); // List of buffer byte order functions static final List>> BYTE_BUFFER_ORDER_FUNCTIONS = List.of( Map.entry("order(ByteOrder.BIG_ENDIAN)", (ByteBuffer bb) -> bb.order(ByteOrder.BIG_ENDIAN)), Map.entry("order(ByteOrder.LITTLE_ENDIAN)", (ByteBuffer bb) -> bb.order(ByteOrder.LITTLE_ENDIAN)) ); // Produce a composition of allocation and byte order buffer functions static List>> composeBufferFunctions( List>> af, List>> of) { return af.stream().flatMap(afe -> of.stream(). map(ofe -> { String s = afe.getKey() + "." + ofe.getKey(); IntFunction f = size -> ofe.getValue(). apply(afe.getValue().apply(size)); return Map.entry(s, f); }) ).collect(Collectors.toList()); } // List of buffer allocator functions to test static final List>> BYTE_BUFFER_FUNCTIONS = composeBufferFunctions(BYTE_BUFFER_ALLOCATE_FUNCTIONS, BYTE_BUFFER_ORDER_FUNCTIONS); // Creates a cross product of test arguments for // buffer allocator functions and buffer view functions static Object[][] product(List> la, List> lb) { return la.stream().flatMap(lae -> lb.stream(). map(lbe -> List.of( lae.getKey() + " -> " + lbe.getKey(), lae.getValue(), lbe.getValue()).toArray() )).toArray(Object[][]::new); } static void assertValues(int i, Object bValue, Object bbValue, ByteBuffer bb) { if (!bValue.equals(bbValue)) { fail(String.format("Values %s and %s differ at index %d for %s", bValue, bbValue, i, bb)); } } static void assertValues(int i, Object bbValue, Object bvValue, ByteBuffer bb, Buffer bv) { if (!bbValue.equals(bvValue)) { fail(String.format("Values %s and %s differ at index %d for %s and %s", bbValue, bvValue, i, bb, bv)); } } static ByteBuffer allocate(IntFunction f) { return allocate(f, i -> i); } static ByteBuffer allocate(IntFunction f, IntUnaryOperator o) { return fill(f.apply(SIZE), o); } static ByteBuffer fill(ByteBuffer bb, IntUnaryOperator o) { for (int i = 0; i < bb.limit(); i++) { bb.put(i, (byte) o.applyAsInt(i)); } return bb; } @DataProvider public static Object[][] shortViewProvider() { List>> bfs = List.of( Map.entry("bb.asShortBuffer()", bb -> bb.asShortBuffer()), Map.entry("bb.asShortBuffer().slice()", bb -> bb.asShortBuffer().slice()), Map.entry("bb.asShortBuffer().slice().duplicate()", bb -> bb.asShortBuffer().slice().duplicate()) ); return product(BYTE_BUFFER_FUNCTIONS, bfs); } @Test(dataProvider = "shortViewProvider") public void testShortGet(String desc, IntFunction fbb, Function fbi) { ByteBuffer bb = allocate(fbb); ShortBuffer vb = fbi.apply(bb); int o = bb.position(); for (int i = 0; i < vb.limit(); i++) { short fromBytes = getShortFromBytes(bb, o + i * 2); short fromMethodView = bb.getShort(o + i * 2); assertValues(i, fromBytes, fromMethodView, bb); short fromBufferView = vb.get(i); assertValues(i, fromMethodView, fromBufferView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { short v = getShortFromBytes(bb, o + i * 2); short a = bb.getShort(); assertValues(i, v, a, bb); short b = vb.get(); assertValues(i, a, b, bb, vb); } } @Test(dataProvider = "shortViewProvider") public void testShortPut(String desc, IntFunction fbb, Function fbi) { ByteBuffer bbfilled = allocate(fbb); ByteBuffer bb = allocate(fbb, i -> 0); ShortBuffer vb = fbi.apply(bb); int o = bb.position(); for (int i = 0; i < vb.limit(); i++) { short fromFilled = bbfilled.getShort(o + i * 2); vb.put(i, fromFilled); short fromMethodView = bb.getShort(o + i * 2); assertValues(i, fromFilled, fromMethodView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { short fromFilled = bbfilled.getShort(o + i * 2); vb.put(fromFilled); short fromMethodView = bb.getShort(); assertValues(i, fromFilled, fromMethodView, bb, vb); } fill(bb, i -> 0); bb.clear().position(o); vb.clear(); for (int i = 0; i < vb.limit(); i++) { short fromFilled = bbfilled.getShort(o + i * 2); bb.putShort(o + i * 2, fromFilled); short fromBufferView = vb.get(i); assertValues(i, fromFilled, fromBufferView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { short fromFilled = bbfilled.getShort(o + i * 2); bb.putShort(fromFilled); short fromBufferView = vb.get(); assertValues(i, fromFilled, fromBufferView, bb, vb); } } static short getShortFromBytes(ByteBuffer bb, int i) { int a = bb.get(i) & 0xFF; int b = bb.get(i + 1) & 0xFF; if (bb.order() == ByteOrder.BIG_ENDIAN) { return (short) ((a << 8) | b); } else { return (short) ((b << 8) | a); } } @DataProvider public static Object[][] charViewProvider() { List>> bfs = List.of( Map.entry("bb.asCharBuffer()", bb -> bb.asCharBuffer()), Map.entry("bb.asCharBuffer().slice()", bb -> bb.asCharBuffer().slice()), Map.entry("bb.asCharBuffer().slice().duplicate()", bb -> bb.asCharBuffer().slice().duplicate()) ); return product(BYTE_BUFFER_FUNCTIONS, bfs); } @Test(dataProvider = "charViewProvider") public void testCharGet(String desc, IntFunction fbb, Function fbi) { ByteBuffer bb = allocate(fbb); CharBuffer vb = fbi.apply(bb); int o = bb.position(); for (int i = 0; i < vb.limit(); i++) { char fromBytes = getCharFromBytes(bb, o + i * 2); char fromMethodView = bb.getChar(o + i * 2); assertValues(i, fromBytes, fromMethodView, bb); char fromBufferView = vb.get(i); assertValues(i, fromMethodView, fromBufferView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { char fromBytes = getCharFromBytes(bb, o + i * 2); char fromMethodView = bb.getChar(); assertValues(i, fromBytes, fromMethodView, bb); char fromBufferView = vb.get(); assertValues(i, fromMethodView, fromBufferView, bb, vb); } } @Test(dataProvider = "charViewProvider") public void testCharPut(String desc, IntFunction fbb, Function fbi) { ByteBuffer bbfilled = allocate(fbb); ByteBuffer bb = allocate(fbb, i -> 0); CharBuffer vb = fbi.apply(bb); int o = bb.position(); for (int i = 0; i < vb.limit(); i++) { char fromFilled = bbfilled.getChar(o + i * 2); vb.put(i, fromFilled); char fromMethodView = bb.getChar(o + i * 2); assertValues(i, fromFilled, fromMethodView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { char fromFilled = bbfilled.getChar(o + i * 2); vb.put(fromFilled); char fromMethodView = bb.getChar(); assertValues(i, fromFilled, fromMethodView, bb, vb); } fill(bb, i -> 0); bb.clear().position(o); vb.clear(); for (int i = 0; i < vb.limit(); i++) { char fromFilled = bbfilled.getChar(o + i * 2); bb.putChar(o + i * 2, fromFilled); char fromBufferView = vb.get(i); assertValues(i, fromFilled, fromBufferView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { char fromFilled = bbfilled.getChar(o + i * 2); bb.putChar(fromFilled); char fromBufferView = vb.get(); assertValues(i, fromFilled, fromBufferView, bb, vb); } } static char getCharFromBytes(ByteBuffer bb, int i) { return (char) getShortFromBytes(bb, i); } @DataProvider public static Object[][] intViewProvider() { List>> bfs = List.of( Map.entry("bb.asIntBuffer()", bb -> bb.asIntBuffer()), Map.entry("bb.asIntBuffer().slice()", bb -> bb.asIntBuffer().slice()), Map.entry("bb.asIntBuffer().slice().duplicate()", bb -> bb.asIntBuffer().slice().duplicate()) ); return product(BYTE_BUFFER_FUNCTIONS, bfs); } @Test(dataProvider = "intViewProvider") public void testIntGet(String desc, IntFunction fbb, Function fbi) { ByteBuffer bb = allocate(fbb); IntBuffer vb = fbi.apply(bb); int o = bb.position(); for (int i = 0; i < vb.limit(); i++) { int fromBytes = getIntFromBytes(bb, o + i * 4); int fromMethodView = bb.getInt(o + i * 4); assertValues(i, fromBytes, fromMethodView, bb); int fromBufferView = vb.get(i); assertValues(i, fromMethodView, fromBufferView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { int v = getIntFromBytes(bb, o + i * 4); int a = bb.getInt(); assertValues(i, v, a, bb); int b = vb.get(); assertValues(i, a, b, bb, vb); } } @Test(dataProvider = "intViewProvider") public void testIntPut(String desc, IntFunction fbb, Function fbi) { ByteBuffer bbfilled = allocate(fbb); ByteBuffer bb = allocate(fbb, i -> 0); IntBuffer vb = fbi.apply(bb); int o = bb.position(); for (int i = 0; i < vb.limit(); i++) { int fromFilled = bbfilled.getInt(o + i * 4); vb.put(i, fromFilled); int fromMethodView = bb.getInt(o + i * 4); assertValues(i, fromFilled, fromMethodView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { int fromFilled = bbfilled.getInt(o + i * 4); vb.put(fromFilled); int fromMethodView = bb.getInt(); assertValues(i, fromFilled, fromMethodView, bb, vb); } fill(bb, i -> 0); bb.clear().position(o); vb.clear(); for (int i = 0; i < vb.limit(); i++) { int fromFilled = bbfilled.getInt(o + i * 4); bb.putInt(o + i * 4, fromFilled); int fromBufferView = vb.get(i); assertValues(i, fromFilled, fromBufferView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { int fromFilled = bbfilled.getInt(o + i * 4); bb.putInt(fromFilled); int fromBufferView = vb.get(); assertValues(i, fromFilled, fromBufferView, bb, vb); } } static int getIntFromBytes(ByteBuffer bb, int i) { int a = bb.get(i) & 0xFF; int b = bb.get(i + 1) & 0xFF; int c = bb.get(i + 2) & 0xFF; int d = bb.get(i + 3) & 0xFF; if (bb.order() == ByteOrder.BIG_ENDIAN) { return ((a << 24) | (b << 16) | (c << 8) | d); } else { return ((d << 24) | (c << 16) | (b << 8) | a); } } @DataProvider public static Object[][] longViewProvider() { List>> bfs = List.of( Map.entry("bb.asLongBuffer()", bb -> bb.asLongBuffer()), Map.entry("bb.asLongBuffer().slice()", bb -> bb.asLongBuffer().slice()), Map.entry("bb.asLongBuffer().slice().duplicate()", bb -> bb.asLongBuffer().slice().duplicate()) ); return product(BYTE_BUFFER_FUNCTIONS, bfs); } @Test(dataProvider = "longViewProvider") public void testLongGet(String desc, IntFunction fbb, Function fbi) { ByteBuffer bb = allocate(fbb); LongBuffer vb = fbi.apply(bb); int o = bb.position(); for (int i = 0; i < vb.limit(); i++) { long fromBytes = getLongFromBytes(bb, o + i * 8); long fromMethodView = bb.getLong(o + i * 8); assertValues(i, fromBytes, fromMethodView, bb); long fromBufferView = vb.get(i); assertValues(i, fromMethodView, fromBufferView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { long v = getLongFromBytes(bb, o + i * 8); long a = bb.getLong(); assertValues(i, v, a, bb); long b = vb.get(); assertValues(i, a, b, bb, vb); } } @Test(dataProvider = "longViewProvider") public void testLongPut(String desc, IntFunction fbb, Function fbi) { ByteBuffer bbfilled = allocate(fbb); ByteBuffer bb = allocate(fbb, i -> 0); LongBuffer vb = fbi.apply(bb); int o = bb.position(); for (int i = 0; i < vb.limit(); i++) { long fromFilled = bbfilled.getLong(o + i * 8); vb.put(i, fromFilled); long fromMethodView = bb.getLong(o + i * 8); assertValues(i, fromFilled, fromMethodView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { long fromFilled = bbfilled.getLong(o + i * 8); vb.put(fromFilled); long fromMethodView = bb.getLong(); assertValues(i, fromFilled, fromMethodView, bb, vb); } fill(bb, i -> 0); bb.clear().position(o); vb.clear(); for (int i = 0; i < vb.limit(); i++) { long fromFilled = bbfilled.getLong(o + i * 8); bb.putLong(o + i * 8, fromFilled); long fromBufferView = vb.get(i); assertValues(i, fromFilled, fromBufferView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { long fromFilled = bbfilled.getLong(o + i * 8); bb.putLong(fromFilled); long fromBufferView = vb.get(); assertValues(i, fromFilled, fromBufferView, bb, vb); } } static long getLongFromBytes(ByteBuffer bb, int i) { long a = bb.get(i) & 0xFF; long b = bb.get(i + 1) & 0xFF; long c = bb.get(i + 2) & 0xFF; long d = bb.get(i + 3) & 0xFF; long e = bb.get(i + 4) & 0xFF; long f = bb.get(i + 5) & 0xFF; long g = bb.get(i + 6) & 0xFF; long h = bb.get(i + 7) & 0xFF; if (bb.order() == ByteOrder.BIG_ENDIAN) { return ((a << 56) | (b << 48) | (c << 40) | (d << 32) | (e << 24) | (f << 16) | (g << 8) | h); } else { return ((h << 56) | (g << 48) | (f << 40) | (e << 32) | (d << 24) | (c << 16) | (b << 8) | a); } } @DataProvider public static Object[][] floatViewProvider() { List>> bfs = List.of( Map.entry("bb.asFloatBuffer()", bb -> bb.asFloatBuffer()), Map.entry("bb.asFloatBuffer().slice()", bb -> bb.asFloatBuffer().slice()), Map.entry("bb.asFloatBuffer().slice().duplicate()", bb -> bb.asFloatBuffer().slice().duplicate()) ); return product(BYTE_BUFFER_FUNCTIONS, bfs); } @Test(dataProvider = "floatViewProvider") public void testFloatGet(String desc, IntFunction fbb, Function fbi) { ByteBuffer bb = allocate(fbb); FloatBuffer vb = fbi.apply(bb); int o = bb.position(); for (int i = 0; i < vb.limit(); i++) { float fromBytes = getFloatFromBytes(bb, o + i * 4); float fromMethodView = bb.getFloat(o + i * 4); assertValues(i, fromBytes, fromMethodView, bb); float fromBufferView = vb.get(i); assertValues(i, fromMethodView, fromBufferView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { float v = getFloatFromBytes(bb, o + i * 4); float a = bb.getFloat(); assertValues(i, v, a, bb); float b = vb.get(); assertValues(i, a, b, bb, vb); } } @Test(dataProvider = "floatViewProvider") public void testFloatPut(String desc, IntFunction fbb, Function fbi) { ByteBuffer bbfilled = allocate(fbb); ByteBuffer bb = allocate(fbb, i -> 0); FloatBuffer vb = fbi.apply(bb); int o = bb.position(); for (int i = 0; i < vb.limit(); i++) { float fromFilled = bbfilled.getFloat(o + i * 4); vb.put(i, fromFilled); float fromMethodView = bb.getFloat(o + i * 4); assertValues(i, fromFilled, fromMethodView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { float fromFilled = bbfilled.getFloat(o + i * 4); vb.put(fromFilled); float fromMethodView = bb.getFloat(); assertValues(i, fromFilled, fromMethodView, bb, vb); } fill(bb, i -> 0); bb.clear().position(o); vb.clear(); for (int i = 0; i < vb.limit(); i++) { float fromFilled = bbfilled.getFloat(o + i * 4); bb.putFloat(o + i * 4, fromFilled); float fromBufferView = vb.get(i); assertValues(i, fromFilled, fromBufferView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { float fromFilled = bbfilled.getFloat(o + i * 4); bb.putFloat(fromFilled); float fromBufferView = vb.get(); assertValues(i, fromFilled, fromBufferView, bb, vb); } } static float getFloatFromBytes(ByteBuffer bb, int i) { return Float.intBitsToFloat(getIntFromBytes(bb, i)); } @DataProvider public static Object[][] doubleViewProvider() { List>> bfs = List.of( Map.entry("bb.asDoubleBuffer()", bb -> bb.asDoubleBuffer()), Map.entry("bb.asDoubleBuffer().slice()", bb -> bb.asDoubleBuffer().slice()), Map.entry("bb.asDoubleBuffer().slice().duplicate()", bb -> bb.asDoubleBuffer().slice().duplicate()) ); return product(BYTE_BUFFER_FUNCTIONS, bfs); } @Test(dataProvider = "doubleViewProvider") public void testDoubleGet(String desc, IntFunction fbb, Function fbi) { ByteBuffer bb = allocate(fbb); DoubleBuffer vb = fbi.apply(bb); int o = bb.position(); for (int i = 0; i < vb.limit(); i++) { double fromBytes = getDoubleFromBytes(bb, o + i * 8); double fromMethodView = bb.getDouble(o + i * 8); assertValues(i, fromBytes, fromMethodView, bb); double fromBufferView = vb.get(i); assertValues(i, fromMethodView, fromBufferView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { double v = getDoubleFromBytes(bb, o + i * 8); double a = bb.getDouble(); assertValues(i, v, a, bb); double b = vb.get(); assertValues(i, a, b, bb, vb); } } @Test(dataProvider = "doubleViewProvider") public void testDoublePut(String desc, IntFunction fbb, Function fbi) { ByteBuffer bbfilled = allocate(fbb); ByteBuffer bb = allocate(fbb, i -> 0); DoubleBuffer vb = fbi.apply(bb); int o = bb.position(); for (int i = 0; i < vb.limit(); i++) { double fromFilled = bbfilled.getDouble(o + i * 8); vb.put(i, fromFilled); double fromMethodView = bb.getDouble(o + i * 8); assertValues(i, fromFilled, fromMethodView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { double fromFilled = bbfilled.getDouble(o + i * 8); vb.put(fromFilled); double fromMethodView = bb.getDouble(); assertValues(i, fromFilled, fromMethodView, bb, vb); } fill(bb, i -> 0); bb.clear().position(o); vb.clear(); for (int i = 0; i < vb.limit(); i++) { double fromFilled = bbfilled.getDouble(o + i * 8); bb.putDouble(o + i * 8, fromFilled); double fromBufferView = vb.get(i); assertValues(i, fromFilled, fromBufferView, bb, vb); } for (int i = 0; i < vb.limit(); i++) { double fromFilled = bbfilled.getDouble(o + i * 8); bb.putDouble(fromFilled); double fromBufferView = vb.get(); assertValues(i, fromFilled, fromBufferView, bb, vb); } } static double getDoubleFromBytes(ByteBuffer bb, int i) { return Double.longBitsToDouble(getLongFromBytes(bb, i)); } }