/*
* Copyright (c) 2012-2014, Parallel Universe Software Co. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 3.0
* as published by the Free Software Foundation.
*/
package co.paralleluniverse.common.io;
import co.paralleluniverse.common.util.UtilUnsafe;
import java.lang.reflect.Array;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import sun.misc.Unsafe;
import sun.nio.ch.DirectBuffer;
/**
*
* @author pron
*/
public final class ByteBufferUtil {
public static byte[] toByteArray(ByteBuffer bb) {
if (bb.hasArray() && bb.arrayOffset() == 0 && bb.position() == 0) {
return bb.array();
} else {
byte[] arr = new byte[bb.remaining()];
int p = bb.position();
bb.get(arr);
bb.position(p);
return arr;
}
}
public static ByteBuffer putArray(ByteBuffer bb, int position, Object array) {
putArray0(bb, position, array);
return bb;
}
public static ByteBuffer putArray(ByteBuffer bb, Object array) {
int p = bb.position();
p += putArray0(bb, p, array);
if (p > bb.limit())
bb.limit(p);
bb.position(p);
return bb;
}
public static ByteBuffer getArray(ByteBuffer bb, int position, Object array) {
getArray0(bb, position, array);
return bb;
}
public static ByteBuffer getArray(ByteBuffer bb, Object array) {
int p = bb.position();
p += getArray0(bb, p, array);
bb.position(p);
return bb;
}
private static int putArray0(ByteBuffer bb, int position, Object array) {
final int size = getArraySize(array);
if (bb.capacity() - position < size)
throw new BufferOverflowException();
if (!bb.isDirect())
unsafe.copyMemory(array, getArrayBase(array), bb.array(), base + bb.arrayOffset() + position, size);
else
unsafe.copyMemory(array, getArrayBase(array), null, ((DirectBuffer) bb).address() + position, size);
return size;
}
private static int getArray0(ByteBuffer bb, int position, Object array) {
final int size = getArraySize(array);
if (bb.limit() - position < size)
throw new BufferUnderflowException();
if (!bb.isDirect())
unsafe.copyMemory(bb.array(), base + bb.arrayOffset() + position, array, getArrayBase(array), size);
else
unsafe.copyMemory(null, ((DirectBuffer) bb).address() + position, array, getArrayBase(array), size);
return size;
}
private static int getArrayBase(Object array) {
return unsafe.arrayBaseOffset(array.getClass());
}
private static int getArraySize(Object array) {
return Array.getLength(array) * getArrayScale(array);
}
private static int getArrayScale(Object array) {
return unsafe.arrayIndexScale(array.getClass());
// if(array instanceof byte[])
// return 1;
// if(array instanceof double[])
// return 8;
// if(array instanceof float[])
// return 4;
// if(array instanceof boolean[])
// return 1;
// if(array instanceof short[])
// return 2;
// if(array instanceof int[])
// return 4;
// if(array instanceof long[])
// return 8;
// if(array instanceof char[])
// return 2;
// throw new AssertionError();
}
private ByteBufferUtil() {
}
static final Unsafe unsafe = UtilUnsafe.getUnsafe();
private static final int base;
private static final int baseLong;
private static final int shift;
static {
try {
if (unsafe.arrayIndexScale(boolean[].class) != 1)
throw new AssertionError("Strange boolean array scale: " + unsafe.arrayIndexScale(boolean[].class));
if (unsafe.arrayIndexScale(byte[].class) != 1)
throw new AssertionError("Strange byte array scale: " + unsafe.arrayIndexScale(byte[].class));
if (unsafe.arrayIndexScale(short[].class) != 2)
throw new AssertionError("Strange short array scale: " + unsafe.arrayIndexScale(short[].class));
if (unsafe.arrayIndexScale(char[].class) != 2)
throw new AssertionError("Strange char array scale: " + unsafe.arrayIndexScale(char[].class));
if (unsafe.arrayIndexScale(int[].class) != 4)
throw new AssertionError("Strange int array scale: " + unsafe.arrayIndexScale(int[].class));
if (unsafe.arrayIndexScale(float[].class) != 4)
throw new AssertionError("Strange float array scale: " + unsafe.arrayIndexScale(float[].class));
if (unsafe.arrayIndexScale(long[].class) != 8)
throw new AssertionError("Strange long array scale: " + unsafe.arrayIndexScale(long[].class));
if (unsafe.arrayIndexScale(double[].class) != 8)
throw new AssertionError("Strange double array scale: " + unsafe.arrayIndexScale(double[].class));
base = unsafe.arrayBaseOffset(byte[].class);
baseLong = unsafe.arrayBaseOffset(long[].class);
if (unsafe.arrayBaseOffset(boolean[].class) != base)
throw new AssertionError("different array base");
if (unsafe.arrayBaseOffset(short[].class) != base)
throw new AssertionError("different array base");
if (unsafe.arrayBaseOffset(char[].class) != base)
throw new AssertionError("different array base");
if (unsafe.arrayBaseOffset(int[].class) != base)
throw new AssertionError("different array base");
if (unsafe.arrayBaseOffset(float[].class) != base)
throw new AssertionError("different array base");
if (unsafe.arrayBaseOffset(long[].class) != baseLong)
throw new AssertionError("different array base");
if (unsafe.arrayBaseOffset(double[].class) != baseLong)
throw new AssertionError("different array base");
int scale = unsafe.arrayIndexScale(byte[].class);
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
shift = 31 - Integer.numberOfLeadingZeros(scale);
if (scale != 1 || shift != 0)
throw new AssertionError("Strange byte array alignment");
} catch (Exception ex) {
throw new Error(ex);
}
}
}