jdk/test/java/nio/Buffer/ByteBufferViews.java
author psandoz
Fri, 29 Jul 2016 10:18:47 +0200
changeset 40195 a13e4945de1d
permissions -rw-r--r--
8162458: Buffer view implementations use incorrect offset for Unsafe access Reviewed-by: alanb

/*
 * Copyright (c) 2016, 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<Map.Entry<String, IntFunction<ByteBuffer>>> 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()),
            // 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()),

            // 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()),
            // 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())
    );

    // List of buffer byte order functions
    static final List<Map.Entry<String, UnaryOperator<ByteBuffer>>> 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<Map.Entry<String, IntFunction<ByteBuffer>>> composeBufferFunctions(
            List<Map.Entry<String, IntFunction<ByteBuffer>>> af,
            List<Map.Entry<String, UnaryOperator<ByteBuffer>>> of) {
        return af.stream().flatMap(afe -> of.stream().
                map(ofe -> {
                    String s = afe.getKey() + "." + ofe.getKey();
                    IntFunction<ByteBuffer> 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<Map.Entry<String, IntFunction<ByteBuffer>>> 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<? extends Map.Entry<String, ?>> la,
                              List<? extends Map.Entry<String, ?>> 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<ByteBuffer> f) {
        return allocate(f, i -> i);
    }

    static ByteBuffer allocate(IntFunction<ByteBuffer> 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<Map.Entry<String, Function<ByteBuffer, ShortBuffer>>> 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<ByteBuffer> fbb,
                             Function<ByteBuffer, ShortBuffer> 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<ByteBuffer> fbb,
                             Function<ByteBuffer, ShortBuffer> 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<Map.Entry<String, Function<ByteBuffer, CharBuffer>>> 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<ByteBuffer> fbb,
                            Function<ByteBuffer, CharBuffer> 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<ByteBuffer> fbb,
                            Function<ByteBuffer, CharBuffer> 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<Map.Entry<String, Function<ByteBuffer, IntBuffer>>> 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<ByteBuffer> fbb,
                           Function<ByteBuffer, IntBuffer> 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<ByteBuffer> fbb,
                           Function<ByteBuffer, IntBuffer> 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<Map.Entry<String, Function<ByteBuffer, LongBuffer>>> 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<ByteBuffer> fbb,
                            Function<ByteBuffer, LongBuffer> 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<ByteBuffer> fbb,
                            Function<ByteBuffer, LongBuffer> 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<Map.Entry<String, Function<ByteBuffer, FloatBuffer>>> 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<ByteBuffer> fbb,
                             Function<ByteBuffer, FloatBuffer> 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<ByteBuffer> fbb,
                             Function<ByteBuffer, FloatBuffer> 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<Map.Entry<String, Function<ByteBuffer, DoubleBuffer>>> 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<ByteBuffer> fbb,
                              Function<ByteBuffer, DoubleBuffer> 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<ByteBuffer> fbb,
                              Function<ByteBuffer, DoubleBuffer> 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));
    }
}