Path: blob/master/test/jdk/java/nio/Buffer/BulkPutBuffer.java
41149 views
/*1* Copyright (c) 2020, 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 java.lang.invoke.MethodHandle;24import java.lang.invoke.MethodHandles;25import java.lang.invoke.MethodType;26import java.nio.Buffer;27import java.nio.ByteBuffer;28import java.nio.ByteOrder;29import java.nio.CharBuffer;30import java.nio.DoubleBuffer;31import java.nio.FloatBuffer;32import java.nio.IntBuffer;33import java.nio.LongBuffer;34import java.nio.ReadOnlyBufferException;35import java.nio.ShortBuffer;36import java.util.ArrayList;37import java.util.Arrays;38import java.util.HashMap;39import java.util.Iterator;40import java.util.List;41import java.util.Map;42import java.util.Random;4344import org.testng.Assert;45import org.testng.annotations.DataProvider;46import org.testng.annotations.Test;474849/*50* @test51* @bug 8219014 824512152* @summary Ensure that a bulk put of a buffer into another is correct.53* @compile --enable-preview -source ${jdk.version} BulkPutBuffer.java54* @run testng/othervm --enable-preview BulkPutBuffer55*/56public class BulkPutBuffer {57static final long SEED = System.nanoTime();58static final MyRandom RND = new MyRandom(SEED);5960static final int ITERATIONS = 100;61static final int MAX_CAPACITY = 1024;6263static class MyRandom extends Random {64MyRandom(long seed) {65super(seed);66}6768public byte nextByte() {69return (byte)next(8);70}7172public char nextChar() {73return (char)next(16);74}7576public short nextShort() {77return (short)next(16);78}79}8081enum BufferKind {82HEAP,83HEAP_VIEW,84DIRECT,85STRING;86}8788static final Map<Class<?>,TypeAttr> typeToAttr;8990static record TypeAttr(Class<?> type, int bytes, String name) {}9192static {93typeToAttr = Map.of(94byte.class, new TypeAttr(ByteBuffer.class, Byte.BYTES, "Byte"),95char.class, new TypeAttr(CharBuffer.class, Character.BYTES, "Char"),96short.class, new TypeAttr(ShortBuffer.class, Short.BYTES, "Short"),97int.class, new TypeAttr(IntBuffer.class, Integer.BYTES, "Int"),98float.class, new TypeAttr(FloatBuffer.class, Float.BYTES, "Float"),99long.class, new TypeAttr(LongBuffer.class, Long.BYTES, "Long"),100double.class, new TypeAttr(DoubleBuffer.class, Double.BYTES, "Double")101);102}103104static BufferKind[] getKinds(Class<?> elementType) {105BufferKind[] kinds;106if (elementType == byte.class)107kinds = new BufferKind[] {108BufferKind.DIRECT,109BufferKind.HEAP110};111else if (elementType == char.class)112kinds = BufferKind.values();113else114kinds = new BufferKind[] {115BufferKind.DIRECT,116BufferKind.HEAP,117BufferKind.HEAP_VIEW118};119return kinds;120}121122static ByteOrder[] getOrders(BufferKind kind, Class<?> elementType) {123switch (kind) {124case HEAP:125return new ByteOrder[] { ByteOrder.nativeOrder() };126default:127if (elementType == byte.class)128return new ByteOrder[] { ByteOrder.nativeOrder() };129else130return new ByteOrder[] { ByteOrder.BIG_ENDIAN,131ByteOrder.LITTLE_ENDIAN };132}133}134135public static class BufferProxy {136final Class<?> elementType;137final BufferKind kind;138final ByteOrder order;139140// Buffer methods141MethodHandle alloc;142MethodHandle allocBB;143MethodHandle allocDirect;144MethodHandle asReadOnlyBuffer;145MethodHandle asTypeBuffer;146MethodHandle putAbs;147MethodHandle getAbs;148MethodHandle putBufAbs;149MethodHandle putBufRel;150MethodHandle equals;151152// MyRandom method153MethodHandle nextType;154155BufferProxy(Class<?> elementType, BufferKind kind, ByteOrder order) {156this.elementType = elementType;157this.kind = kind;158this.order = order;159160Class<?> bufferType = typeToAttr.get(elementType).type;161162var lookup = MethodHandles.lookup();163try {164String name = typeToAttr.get(elementType).name;165166alloc = lookup.findStatic(bufferType, "allocate",167MethodType.methodType(bufferType, int.class));168allocBB = lookup.findStatic(ByteBuffer.class, "allocate",169MethodType.methodType(ByteBuffer.class, int.class));170allocDirect = lookup.findStatic(ByteBuffer.class, "allocateDirect",171MethodType.methodType(ByteBuffer.class, int.class));172173asReadOnlyBuffer = lookup.findVirtual(bufferType,174"asReadOnlyBuffer", MethodType.methodType(bufferType));175if (elementType != byte.class) {176asTypeBuffer = lookup.findVirtual(ByteBuffer.class,177"as" + name + "Buffer", MethodType.methodType(bufferType));178}179180putAbs = lookup.findVirtual(bufferType, "put",181MethodType.methodType(bufferType, int.class, elementType));182getAbs = lookup.findVirtual(bufferType, "get",183MethodType.methodType(elementType, int.class));184185putBufAbs = lookup.findVirtual(bufferType, "put",186MethodType.methodType(bufferType, int.class, bufferType,187int.class, int.class));188putBufRel = lookup.findVirtual(bufferType, "put",189MethodType.methodType(bufferType, bufferType));190191equals = lookup.findVirtual(bufferType, "equals",192MethodType.methodType(boolean.class, Object.class));193194nextType = lookup.findVirtual(MyRandom.class,195"next" + name, MethodType.methodType(elementType));196} catch (IllegalAccessException | NoSuchMethodException e) {197throw new AssertionError(e);198}199}200201Buffer create(int capacity) throws Throwable {202203Class<?> bufferType = typeToAttr.get(elementType).type;204205try {206if (bufferType == ByteBuffer.class ||207kind == BufferKind.DIRECT || kind == BufferKind.HEAP_VIEW) {208int len = capacity*typeToAttr.get(elementType).bytes;209ByteBuffer bb = (ByteBuffer)allocBB.invoke(len);210byte[] bytes = new byte[len];211RND.nextBytes(bytes);212bb.put(0, bytes);213if (bufferType == ByteBuffer.class) {214return (Buffer)bb;215} else {216bb.order(order);217return (Buffer)asTypeBuffer.invoke(bb);218}219} else if (bufferType == CharBuffer.class &&220kind == BufferKind.STRING) {221char[] array = new char[capacity];222for (int i = 0; i < capacity; i++) {223array[i] = RND.nextChar();224}225return CharBuffer.wrap(new String(array));226} else {227Buffer buf = (Buffer)alloc.invoke(capacity);228for (int i = 0; i < capacity; i++) {229putAbs.invoke(buf, i, nextType.invoke(RND));230}231return buf;232}233} catch (Exception e) {234throw new AssertionError(e);235}236}237238void copy(Buffer src, int srcOff, Buffer dst, int dstOff, int length)239throws Throwable {240try {241for (int i = 0; i < length; i++) {242putAbs.invoke(dst, dstOff + i, getAbs.invoke(src, srcOff + i));243}244} catch (ReadOnlyBufferException ro) {245throw ro;246} catch (Exception e) {247throw new AssertionError(e);248}249}250251Buffer asReadOnlyBuffer(Buffer buf) throws Throwable {252try {253return (Buffer)asReadOnlyBuffer.invoke(buf);254} catch (Exception e) {255throw new AssertionError(e);256}257}258259void put(Buffer src, int srcOff, Buffer dst, int dstOff, int length)260throws Throwable {261try {262putBufAbs.invoke(dst, dstOff, src, srcOff, length);263} catch (ReadOnlyBufferException ro) {264throw ro;265} catch (Exception e) {266throw new AssertionError(e);267}268}269270void put(Buffer src, Buffer dst) throws Throwable {271try {272putBufRel.invoke(dst, src);273} catch (ReadOnlyBufferException ro) {274throw ro;275} catch (Exception e) {276throw new AssertionError(e);277}278}279280boolean equals(Buffer src, Buffer dst) throws Throwable {281try {282return Boolean.class.cast(equals.invoke(dst, src));283} catch (Exception e) {284throw new AssertionError(e);285}286}287}288289static List<BufferProxy> getProxies(Class<?> type) {290List proxies = new ArrayList();291for (BufferKind kind : getKinds(type)) {292for (ByteOrder order : getOrders(kind, type)) {293proxies.add(new BufferProxy(type, kind, order));294}295}296return proxies;297}298299@DataProvider300static Object[][] proxies() {301ArrayList<Object[]> args = new ArrayList<>();302for (Class<?> type : typeToAttr.keySet()) {303List<BufferProxy> proxies = getProxies(type);304for (BufferProxy proxy : proxies) {305args.add(new Object[] {proxy});306}307}308return args.toArray(Object[][]::new);309}310311@DataProvider312static Object[][] proxyPairs() {313List<Object[]> args = new ArrayList<>();314for (Class<?> type : typeToAttr.keySet()) {315List<BufferProxy> proxies = getProxies(type);316for (BufferProxy proxy1 : proxies) {317for (BufferProxy proxy2 : proxies) {318args.add(new Object[] {proxy1, proxy2});319}320}321}322return args.toArray(Object[][]::new);323}324325private static void expectThrows(Class<?> exClass, Assert.ThrowingRunnable r) {326try {327r.run();328} catch(Throwable e) {329if (e.getClass() != exClass && e.getCause().getClass() != exClass) {330throw new RuntimeException("Expected " + exClass +331"; got " + e.getCause().getClass(), e);332}333}334}335336@Test(dataProvider = "proxies")337public static void testExceptions(BufferProxy bp) throws Throwable {338int cap = 27;339Buffer buf = bp.create(cap);340341expectThrows(IndexOutOfBoundsException.class,342() -> bp.put(buf, -1, buf, 0, 1));343expectThrows(IndexOutOfBoundsException.class,344() -> bp.put(buf, 0, buf, -1, 1));345expectThrows(IndexOutOfBoundsException.class,346() -> bp.put(buf, 1, buf, 0, cap));347expectThrows(IndexOutOfBoundsException.class,348() -> bp.put(buf, 0, buf, 1, cap));349expectThrows(IndexOutOfBoundsException.class,350() -> bp.put(buf, 0, buf, 0, cap + 1));351expectThrows(IndexOutOfBoundsException.class,352() -> bp.put(buf, 0, buf, 0, Integer.MAX_VALUE));353354Buffer rob = buf.isReadOnly() ? buf : bp.asReadOnlyBuffer(buf);355expectThrows(ReadOnlyBufferException.class,356() -> bp.put(buf, 0, rob, 0, cap));357}358359@Test(dataProvider = "proxies")360public static void testSelf(BufferProxy bp) throws Throwable {361for (int i = 0; i < ITERATIONS; i++) {362int cap = RND.nextInt(MAX_CAPACITY);363Buffer buf = bp.create(cap);364365int lowerOffset = RND.nextInt(1 + cap/10);366int lowerLength = RND.nextInt(1 + cap/2);367if (lowerLength < 2)368continue;369Buffer lower = buf.slice(lowerOffset, lowerLength);370371Buffer lowerCopy = bp.create(lowerLength);372if (lowerCopy.isReadOnly()) {373Assert.expectThrows(ReadOnlyBufferException.class,374() -> bp.copy(lower, 0, lowerCopy, 0, lowerLength));375break;376}377bp.copy(lower, 0, lowerCopy, 0, lowerLength);378379int middleOffset = RND.nextInt(1 + cap/2);380Buffer middle = buf.slice(middleOffset, lowerLength);381Buffer middleCopy = bp.create(lowerLength);382bp.copy(middle, 0, middleCopy, 0, lowerLength);383384bp.put(lower, middle);385middle.flip();386387Assert.assertTrue(bp.equals(lowerCopy, middle),388String.format("%d %s %d %d %d %d%n", SEED,389buf.getClass().getName(), cap,390lowerOffset, lowerLength, middleOffset));391392bp.copy(lowerCopy, 0, buf, lowerOffset, lowerLength);393bp.copy(middleCopy, 0, buf, middleOffset, lowerLength);394395bp.put(buf, lowerOffset, buf, middleOffset, lowerLength);396397Assert.assertTrue(bp.equals(lowerCopy, middle),398String.format("%d %s %d %d %d %d%n", SEED,399buf.getClass().getName(), cap,400lowerOffset, lowerLength, middleOffset));401}402}403404@Test(dataProvider = "proxyPairs")405public static void testPairs(BufferProxy bp, BufferProxy sbp) throws Throwable {406for (int i = 0; i < ITERATIONS; i++) {407int cap = Math.max(4, RND.nextInt(MAX_CAPACITY));408int cap2 = cap/2;409Buffer buf = bp.create(cap);410411int pos = RND.nextInt(Math.max(1, cap2));412buf.position(pos);413buf.mark();414int lim = pos + Math.max(1, cap - pos);415buf.limit(lim);416417int scap = Math.max(buf.remaining(), RND.nextInt(1024));418Buffer src = sbp.create(scap);419420int diff = scap - buf.remaining();421int spos = diff > 0 ? RND.nextInt(diff) : 0;422src.position(spos);423src.mark();424int slim = spos + buf.remaining();425src.limit(slim);426427if (buf.isReadOnly()) {428Assert.expectThrows(ReadOnlyBufferException.class,429() -> bp.put(src, buf));430break;431}432433Buffer backup = bp.create(slim - spos);434bp.copy(buf, pos, backup, 0, backup.capacity());435bp.put(src, buf);436437buf.reset();438src.reset();439440Assert.assertTrue(bp.equals(src, buf),441String.format("%d %s %d %d %d %s %d %d %d%n", SEED,442buf.getClass().getName(), cap, pos, lim,443src.getClass().getName(), scap, spos, slim));444445src.clear();446buf.clear();447bp.copy(backup, 0, buf, pos, backup.capacity());448bp.put(src, spos, buf, pos, backup.capacity());449src.position(spos);450src.limit(slim);451buf.position(pos);452buf.limit(lim);453454Assert.assertTrue(bp.equals(src, buf),455String.format("%d %s %d %d %d %s %d %d %d%n", SEED,456buf.getClass().getName(), cap, pos, lim,457src.getClass().getName(), scap, spos, slim));458}459}460}461462463