// 
// Decompiled by Procyon v0.6.0
// 

package io.netty.buffer;

import java.io.OutputStream;
import java.nio.ReadOnlyBufferException;
import java.nio.ByteBuffer;
import io.netty.util.internal.MathUtil;
import io.netty.util.internal.ObjectUtil;
import java.io.IOException;
import java.io.InputStream;
import io.netty.util.internal.PlatformDependent;

final class UnsafeByteBufUtil
{
    private static final boolean UNALIGNED;
    private static final byte ZERO = 0;
    private static final int MAX_HAND_ROLLED_SET_ZERO_BYTES = 64;
    
    static byte getByte(final long address) {
        return PlatformDependent.getByte(address);
    }
    
    static short getShort(final long address) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            final short v = PlatformDependent.getShort(address);
            return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? v : Short.reverseBytes(v);
        }
        return (short)(PlatformDependent.getByte(address) << 8 | (PlatformDependent.getByte(address + 1L) & 0xFF));
    }
    
    static short getShortLE(final long address) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            final short v = PlatformDependent.getShort(address);
            return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes(v) : v;
        }
        return (short)((PlatformDependent.getByte(address) & 0xFF) | PlatformDependent.getByte(address + 1L) << 8);
    }
    
    static int getUnsignedMedium(final long address) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            return (PlatformDependent.getByte(address) & 0xFF) << 16 | ((PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? PlatformDependent.getShort(address + 1L) : Short.reverseBytes(PlatformDependent.getShort(address + 1L))) & 0xFFFF);
        }
        return (PlatformDependent.getByte(address) & 0xFF) << 16 | (PlatformDependent.getByte(address + 1L) & 0xFF) << 8 | (PlatformDependent.getByte(address + 2L) & 0xFF);
    }
    
    static int getUnsignedMediumLE(final long address) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            return (PlatformDependent.getByte(address) & 0xFF) | ((PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes(PlatformDependent.getShort(address + 1L)) : PlatformDependent.getShort(address + 1L)) & 0xFFFF) << 8;
        }
        return (PlatformDependent.getByte(address) & 0xFF) | (PlatformDependent.getByte(address + 1L) & 0xFF) << 8 | (PlatformDependent.getByte(address + 2L) & 0xFF) << 16;
    }
    
    static int getInt(final long address) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            final int v = PlatformDependent.getInt(address);
            return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? v : Integer.reverseBytes(v);
        }
        return PlatformDependent.getByte(address) << 24 | (PlatformDependent.getByte(address + 1L) & 0xFF) << 16 | (PlatformDependent.getByte(address + 2L) & 0xFF) << 8 | (PlatformDependent.getByte(address + 3L) & 0xFF);
    }
    
    static int getIntLE(final long address) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            final int v = PlatformDependent.getInt(address);
            return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Integer.reverseBytes(v) : v;
        }
        return (PlatformDependent.getByte(address) & 0xFF) | (PlatformDependent.getByte(address + 1L) & 0xFF) << 8 | (PlatformDependent.getByte(address + 2L) & 0xFF) << 16 | PlatformDependent.getByte(address + 3L) << 24;
    }
    
    static long getLong(final long address) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            final long v = PlatformDependent.getLong(address);
            return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? v : Long.reverseBytes(v);
        }
        return (long)PlatformDependent.getByte(address) << 56 | ((long)PlatformDependent.getByte(address + 1L) & 0xFFL) << 48 | ((long)PlatformDependent.getByte(address + 2L) & 0xFFL) << 40 | ((long)PlatformDependent.getByte(address + 3L) & 0xFFL) << 32 | ((long)PlatformDependent.getByte(address + 4L) & 0xFFL) << 24 | ((long)PlatformDependent.getByte(address + 5L) & 0xFFL) << 16 | ((long)PlatformDependent.getByte(address + 6L) & 0xFFL) << 8 | ((long)PlatformDependent.getByte(address + 7L) & 0xFFL);
    }
    
    static long getLongLE(final long address) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            final long v = PlatformDependent.getLong(address);
            return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Long.reverseBytes(v) : v;
        }
        return ((long)PlatformDependent.getByte(address) & 0xFFL) | ((long)PlatformDependent.getByte(address + 1L) & 0xFFL) << 8 | ((long)PlatformDependent.getByte(address + 2L) & 0xFFL) << 16 | ((long)PlatformDependent.getByte(address + 3L) & 0xFFL) << 24 | ((long)PlatformDependent.getByte(address + 4L) & 0xFFL) << 32 | ((long)PlatformDependent.getByte(address + 5L) & 0xFFL) << 40 | ((long)PlatformDependent.getByte(address + 6L) & 0xFFL) << 48 | (long)PlatformDependent.getByte(address + 7L) << 56;
    }
    
    static void setByte(final long address, final int value) {
        PlatformDependent.putByte(address, (byte)value);
    }
    
    static void setShort(final long address, final int value) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putShort(address, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? ((short)value) : Short.reverseBytes((short)value));
        }
        else {
            PlatformDependent.putByte(address, (byte)(value >>> 8));
            PlatformDependent.putByte(address + 1L, (byte)value);
        }
    }
    
    static void setShortLE(final long address, final int value) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putShort(address, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes((short)value) : ((short)value));
        }
        else {
            PlatformDependent.putByte(address, (byte)value);
            PlatformDependent.putByte(address + 1L, (byte)(value >>> 8));
        }
    }
    
    static void setMedium(final long address, final int value) {
        PlatformDependent.putByte(address, (byte)(value >>> 16));
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putShort(address + 1L, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? ((short)value) : Short.reverseBytes((short)value));
        }
        else {
            PlatformDependent.putByte(address + 1L, (byte)(value >>> 8));
            PlatformDependent.putByte(address + 2L, (byte)value);
        }
    }
    
    static void setMediumLE(final long address, final int value) {
        PlatformDependent.putByte(address, (byte)value);
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putShort(address + 1L, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes((short)(value >>> 8)) : ((short)(value >>> 8)));
        }
        else {
            PlatformDependent.putByte(address + 1L, (byte)(value >>> 8));
            PlatformDependent.putByte(address + 2L, (byte)(value >>> 16));
        }
    }
    
    static void setInt(final long address, final int value) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putInt(address, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? value : Integer.reverseBytes(value));
        }
        else {
            PlatformDependent.putByte(address, (byte)(value >>> 24));
            PlatformDependent.putByte(address + 1L, (byte)(value >>> 16));
            PlatformDependent.putByte(address + 2L, (byte)(value >>> 8));
            PlatformDependent.putByte(address + 3L, (byte)value);
        }
    }
    
    static void setIntLE(final long address, final int value) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putInt(address, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Integer.reverseBytes(value) : value);
        }
        else {
            PlatformDependent.putByte(address, (byte)value);
            PlatformDependent.putByte(address + 1L, (byte)(value >>> 8));
            PlatformDependent.putByte(address + 2L, (byte)(value >>> 16));
            PlatformDependent.putByte(address + 3L, (byte)(value >>> 24));
        }
    }
    
    static void setLong(final long address, final long value) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putLong(address, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? value : Long.reverseBytes(value));
        }
        else {
            PlatformDependent.putByte(address, (byte)(value >>> 56));
            PlatformDependent.putByte(address + 1L, (byte)(value >>> 48));
            PlatformDependent.putByte(address + 2L, (byte)(value >>> 40));
            PlatformDependent.putByte(address + 3L, (byte)(value >>> 32));
            PlatformDependent.putByte(address + 4L, (byte)(value >>> 24));
            PlatformDependent.putByte(address + 5L, (byte)(value >>> 16));
            PlatformDependent.putByte(address + 6L, (byte)(value >>> 8));
            PlatformDependent.putByte(address + 7L, (byte)value);
        }
    }
    
    static void setLongLE(final long address, final long value) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putLong(address, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Long.reverseBytes(value) : value);
        }
        else {
            PlatformDependent.putByte(address, (byte)value);
            PlatformDependent.putByte(address + 1L, (byte)(value >>> 8));
            PlatformDependent.putByte(address + 2L, (byte)(value >>> 16));
            PlatformDependent.putByte(address + 3L, (byte)(value >>> 24));
            PlatformDependent.putByte(address + 4L, (byte)(value >>> 32));
            PlatformDependent.putByte(address + 5L, (byte)(value >>> 40));
            PlatformDependent.putByte(address + 6L, (byte)(value >>> 48));
            PlatformDependent.putByte(address + 7L, (byte)(value >>> 56));
        }
    }
    
    static byte getByte(final byte[] array, final int index) {
        return PlatformDependent.getByte(array, index);
    }
    
    static short getShort(final byte[] array, final int index) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            final short v = PlatformDependent.getShort(array, index);
            return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? v : Short.reverseBytes(v);
        }
        return (short)(PlatformDependent.getByte(array, index) << 8 | (PlatformDependent.getByte(array, index + 1) & 0xFF));
    }
    
    static short getShortLE(final byte[] array, final int index) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            final short v = PlatformDependent.getShort(array, index);
            return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes(v) : v;
        }
        return (short)((PlatformDependent.getByte(array, index) & 0xFF) | PlatformDependent.getByte(array, index + 1) << 8);
    }
    
    static int getUnsignedMedium(final byte[] array, final int index) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            return (PlatformDependent.getByte(array, index) & 0xFF) << 16 | ((PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? PlatformDependent.getShort(array, index + 1) : Short.reverseBytes(PlatformDependent.getShort(array, index + 1))) & 0xFFFF);
        }
        return (PlatformDependent.getByte(array, index) & 0xFF) << 16 | (PlatformDependent.getByte(array, index + 1) & 0xFF) << 8 | (PlatformDependent.getByte(array, index + 2) & 0xFF);
    }
    
    static int getUnsignedMediumLE(final byte[] array, final int index) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            return (PlatformDependent.getByte(array, index) & 0xFF) | ((PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes(PlatformDependent.getShort(array, index + 1)) : PlatformDependent.getShort(array, index + 1)) & 0xFFFF) << 8;
        }
        return (PlatformDependent.getByte(array, index) & 0xFF) | (PlatformDependent.getByte(array, index + 1) & 0xFF) << 8 | (PlatformDependent.getByte(array, index + 2) & 0xFF) << 16;
    }
    
    static int getInt(final byte[] array, final int index) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            final int v = PlatformDependent.getInt(array, index);
            return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? v : Integer.reverseBytes(v);
        }
        return PlatformDependent.getByte(array, index) << 24 | (PlatformDependent.getByte(array, index + 1) & 0xFF) << 16 | (PlatformDependent.getByte(array, index + 2) & 0xFF) << 8 | (PlatformDependent.getByte(array, index + 3) & 0xFF);
    }
    
    static int getIntLE(final byte[] array, final int index) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            final int v = PlatformDependent.getInt(array, index);
            return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Integer.reverseBytes(v) : v;
        }
        return (PlatformDependent.getByte(array, index) & 0xFF) | (PlatformDependent.getByte(array, index + 1) & 0xFF) << 8 | (PlatformDependent.getByte(array, index + 2) & 0xFF) << 16 | PlatformDependent.getByte(array, index + 3) << 24;
    }
    
    static long getLong(final byte[] array, final int index) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            final long v = PlatformDependent.getLong(array, index);
            return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? v : Long.reverseBytes(v);
        }
        return (long)PlatformDependent.getByte(array, index) << 56 | ((long)PlatformDependent.getByte(array, index + 1) & 0xFFL) << 48 | ((long)PlatformDependent.getByte(array, index + 2) & 0xFFL) << 40 | ((long)PlatformDependent.getByte(array, index + 3) & 0xFFL) << 32 | ((long)PlatformDependent.getByte(array, index + 4) & 0xFFL) << 24 | ((long)PlatformDependent.getByte(array, index + 5) & 0xFFL) << 16 | ((long)PlatformDependent.getByte(array, index + 6) & 0xFFL) << 8 | ((long)PlatformDependent.getByte(array, index + 7) & 0xFFL);
    }
    
    static long getLongLE(final byte[] array, final int index) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            final long v = PlatformDependent.getLong(array, index);
            return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Long.reverseBytes(v) : v;
        }
        return ((long)PlatformDependent.getByte(array, index) & 0xFFL) | ((long)PlatformDependent.getByte(array, index + 1) & 0xFFL) << 8 | ((long)PlatformDependent.getByte(array, index + 2) & 0xFFL) << 16 | ((long)PlatformDependent.getByte(array, index + 3) & 0xFFL) << 24 | ((long)PlatformDependent.getByte(array, index + 4) & 0xFFL) << 32 | ((long)PlatformDependent.getByte(array, index + 5) & 0xFFL) << 40 | ((long)PlatformDependent.getByte(array, index + 6) & 0xFFL) << 48 | (long)PlatformDependent.getByte(array, index + 7) << 56;
    }
    
    static void setByte(final byte[] array, final int index, final int value) {
        PlatformDependent.putByte(array, index, (byte)value);
    }
    
    static void setShort(final byte[] array, final int index, final int value) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putShort(array, index, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? ((short)value) : Short.reverseBytes((short)value));
        }
        else {
            PlatformDependent.putByte(array, index, (byte)(value >>> 8));
            PlatformDependent.putByte(array, index + 1, (byte)value);
        }
    }
    
    static void setShortLE(final byte[] array, final int index, final int value) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putShort(array, index, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes((short)value) : ((short)value));
        }
        else {
            PlatformDependent.putByte(array, index, (byte)value);
            PlatformDependent.putByte(array, index + 1, (byte)(value >>> 8));
        }
    }
    
    static void setMedium(final byte[] array, final int index, final int value) {
        PlatformDependent.putByte(array, index, (byte)(value >>> 16));
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putShort(array, index + 1, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? ((short)value) : Short.reverseBytes((short)value));
        }
        else {
            PlatformDependent.putByte(array, index + 1, (byte)(value >>> 8));
            PlatformDependent.putByte(array, index + 2, (byte)value);
        }
    }
    
    static void setMediumLE(final byte[] array, final int index, final int value) {
        PlatformDependent.putByte(array, index, (byte)value);
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putShort(array, index + 1, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes((short)(value >>> 8)) : ((short)(value >>> 8)));
        }
        else {
            PlatformDependent.putByte(array, index + 1, (byte)(value >>> 8));
            PlatformDependent.putByte(array, index + 2, (byte)(value >>> 16));
        }
    }
    
    static void setInt(final byte[] array, final int index, final int value) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putInt(array, index, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? value : Integer.reverseBytes(value));
        }
        else {
            PlatformDependent.putByte(array, index, (byte)(value >>> 24));
            PlatformDependent.putByte(array, index + 1, (byte)(value >>> 16));
            PlatformDependent.putByte(array, index + 2, (byte)(value >>> 8));
            PlatformDependent.putByte(array, index + 3, (byte)value);
        }
    }
    
    static void setIntLE(final byte[] array, final int index, final int value) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putInt(array, index, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Integer.reverseBytes(value) : value);
        }
        else {
            PlatformDependent.putByte(array, index, (byte)value);
            PlatformDependent.putByte(array, index + 1, (byte)(value >>> 8));
            PlatformDependent.putByte(array, index + 2, (byte)(value >>> 16));
            PlatformDependent.putByte(array, index + 3, (byte)(value >>> 24));
        }
    }
    
    static void setLong(final byte[] array, final int index, final long value) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putLong(array, index, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? value : Long.reverseBytes(value));
        }
        else {
            PlatformDependent.putByte(array, index, (byte)(value >>> 56));
            PlatformDependent.putByte(array, index + 1, (byte)(value >>> 48));
            PlatformDependent.putByte(array, index + 2, (byte)(value >>> 40));
            PlatformDependent.putByte(array, index + 3, (byte)(value >>> 32));
            PlatformDependent.putByte(array, index + 4, (byte)(value >>> 24));
            PlatformDependent.putByte(array, index + 5, (byte)(value >>> 16));
            PlatformDependent.putByte(array, index + 6, (byte)(value >>> 8));
            PlatformDependent.putByte(array, index + 7, (byte)value);
        }
    }
    
    static void setLongLE(final byte[] array, final int index, final long value) {
        if (UnsafeByteBufUtil.UNALIGNED) {
            PlatformDependent.putLong(array, index, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Long.reverseBytes(value) : value);
        }
        else {
            PlatformDependent.putByte(array, index, (byte)value);
            PlatformDependent.putByte(array, index + 1, (byte)(value >>> 8));
            PlatformDependent.putByte(array, index + 2, (byte)(value >>> 16));
            PlatformDependent.putByte(array, index + 3, (byte)(value >>> 24));
            PlatformDependent.putByte(array, index + 4, (byte)(value >>> 32));
            PlatformDependent.putByte(array, index + 5, (byte)(value >>> 40));
            PlatformDependent.putByte(array, index + 6, (byte)(value >>> 48));
            PlatformDependent.putByte(array, index + 7, (byte)(value >>> 56));
        }
    }
    
    private static void batchSetZero(final byte[] data, int index, final int length) {
        for (int longBatches = length >>> 3, i = 0; i < longBatches; ++i) {
            PlatformDependent.putLong(data, index, 0L);
            index += 8;
        }
        for (int remaining = length & 0x7, j = 0; j < remaining; ++j) {
            PlatformDependent.putByte(data, index + j, (byte)0);
        }
    }
    
    static void setZero(final byte[] array, final int index, final int length) {
        if (length == 0) {
            return;
        }
        if (UnsafeByteBufUtil.UNALIGNED && length <= 64) {
            batchSetZero(array, index, length);
        }
        else {
            PlatformDependent.setMemory(array, index, length, (byte)0);
        }
    }
    
    static ByteBuf copy(final AbstractByteBuf buf, final long addr, final int index, final int length) {
        buf.checkIndex(index, length);
        final ByteBuf copy = buf.alloc().directBuffer(length, buf.maxCapacity());
        if (length != 0) {
            if (copy.hasMemoryAddress()) {
                PlatformDependent.copyMemory(addr, copy.memoryAddress(), length);
                copy.setIndex(0, length);
            }
            else {
                copy.writeBytes(buf, index, length);
            }
        }
        return copy;
    }
    
    static int setBytes(final AbstractByteBuf buf, final long addr, final int index, final InputStream in, final int length) throws IOException {
        buf.checkIndex(index, length);
        final ByteBuf tmpBuf = buf.alloc().heapBuffer(length);
        try {
            final byte[] tmp = tmpBuf.array();
            final int offset = tmpBuf.arrayOffset();
            final int readBytes = in.read(tmp, offset, length);
            if (readBytes > 0) {
                PlatformDependent.copyMemory(tmp, offset, addr, readBytes);
            }
            return readBytes;
        }
        finally {
            tmpBuf.release();
        }
    }
    
    static void getBytes(final AbstractByteBuf buf, final long addr, final int index, final ByteBuf dst, final int dstIndex, final int length) {
        buf.checkIndex(index, length);
        ObjectUtil.checkNotNull(dst, "dst");
        if (MathUtil.isOutOfBounds(dstIndex, length, dst.capacity())) {
            throw new IndexOutOfBoundsException("dstIndex: " + dstIndex);
        }
        if (dst.hasMemoryAddress()) {
            PlatformDependent.copyMemory(addr, dst.memoryAddress() + dstIndex, length);
        }
        else if (dst.hasArray()) {
            PlatformDependent.copyMemory(addr, dst.array(), dst.arrayOffset() + dstIndex, length);
        }
        else {
            dst.setBytes(dstIndex, buf, index, length);
        }
    }
    
    static void getBytes(final AbstractByteBuf buf, final long addr, final int index, final byte[] dst, final int dstIndex, final int length) {
        buf.checkIndex(index, length);
        ObjectUtil.checkNotNull(dst, "dst");
        if (MathUtil.isOutOfBounds(dstIndex, length, dst.length)) {
            throw new IndexOutOfBoundsException("dstIndex: " + dstIndex);
        }
        if (length != 0) {
            PlatformDependent.copyMemory(addr, dst, dstIndex, length);
        }
    }
    
    static void getBytes(final AbstractByteBuf buf, final long addr, final int index, final ByteBuffer dst) {
        buf.checkIndex(index, dst.remaining());
        if (dst.remaining() == 0) {
            return;
        }
        if (dst.isDirect()) {
            if (dst.isReadOnly()) {
                throw new ReadOnlyBufferException();
            }
            final long dstAddress = PlatformDependent.directBufferAddress(dst);
            PlatformDependent.copyMemory(addr, dstAddress + dst.position(), dst.remaining());
            dst.position();
        }
        else if (dst.hasArray()) {
            PlatformDependent.copyMemory(addr, dst.array(), dst.arrayOffset() + dst.position(), dst.remaining());
            dst.position();
        }
        else {
            dst.put(buf.nioBuffer());
        }
    }
    
    static void setBytes(final AbstractByteBuf buf, final long addr, final int index, final ByteBuf src, final int srcIndex, final int length) {
        buf.checkIndex(index, length);
        ObjectUtil.checkNotNull(src, "src");
        if (MathUtil.isOutOfBounds(srcIndex, length, src.capacity())) {
            throw new IndexOutOfBoundsException("srcIndex: " + srcIndex);
        }
        if (length != 0) {
            if (src.hasMemoryAddress()) {
                PlatformDependent.copyMemory(src.memoryAddress() + srcIndex, addr, length);
            }
            else if (src.hasArray()) {
                PlatformDependent.copyMemory(src.array(), src.arrayOffset() + srcIndex, addr, length);
            }
            else {
                src.getBytes(srcIndex, buf, index, length);
            }
        }
    }
    
    static void setBytes(final AbstractByteBuf buf, final long addr, final int index, final byte[] src, final int srcIndex, final int length) {
        buf.checkIndex(index, length);
        ObjectUtil.checkNotNull(src, "src");
        if (MathUtil.isOutOfBounds(srcIndex, length, src.length)) {
            throw new IndexOutOfBoundsException("srcIndex: " + srcIndex);
        }
        if (length != 0) {
            PlatformDependent.copyMemory(src, srcIndex, addr, length);
        }
    }
    
    static void setBytes(final AbstractByteBuf buf, final long addr, final int index, final ByteBuffer src) {
        final int length = src.remaining();
        if (length == 0) {
            return;
        }
        if (src.isDirect()) {
            buf.checkIndex(index, length);
            final long srcAddress = PlatformDependent.directBufferAddress(src);
            PlatformDependent.copyMemory(srcAddress + src.position(), addr, length);
            src.position();
        }
        else if (src.hasArray()) {
            buf.checkIndex(index, length);
            PlatformDependent.copyMemory(src.array(), src.arrayOffset() + src.position(), addr, length);
            src.position();
        }
        else if (length < 8) {
            setSingleBytes(buf, addr, index, src, length);
        }
        else {
            assert buf.nioBufferCount() == 1;
            final ByteBuffer internalBuffer = buf.internalNioBuffer(index, length);
            internalBuffer.put(src);
        }
    }
    
    private static void setSingleBytes(final AbstractByteBuf buf, final long addr, final int index, final ByteBuffer src, final int length) {
        buf.checkIndex(index, length);
        final int srcPosition = src.position();
        final int srcLimit = src.limit();
        long dstAddr = addr;
        for (int srcIndex = srcPosition; srcIndex < srcLimit; ++srcIndex) {
            final byte value = src.get(srcIndex);
            PlatformDependent.putByte(dstAddr, value);
            ++dstAddr;
        }
        src.position();
    }
    
    static void getBytes(final AbstractByteBuf buf, final long addr, final int index, final OutputStream out, final int length) throws IOException {
        buf.checkIndex(index, length);
        if (length != 0) {
            final int len = Math.min(length, 8192);
            if (len <= 1024 || !buf.alloc().isDirectBufferPooled()) {
                getBytes(addr, ByteBufUtil.threadLocalTempArray(len), 0, len, out, length);
            }
            else {
                final ByteBuf tmpBuf = buf.alloc().heapBuffer(len);
                try {
                    final byte[] tmp = tmpBuf.array();
                    final int offset = tmpBuf.arrayOffset();
                    getBytes(addr, tmp, offset, len, out, length);
                }
                finally {
                    tmpBuf.release();
                }
            }
        }
    }
    
    private static void getBytes(long inAddr, final byte[] in, final int inOffset, final int inLen, final OutputStream out, int outLen) throws IOException {
        do {
            final int len = Math.min(inLen, outLen);
            PlatformDependent.copyMemory(inAddr, in, inOffset, len);
            out.write(in, inOffset, len);
            outLen -= len;
            inAddr += len;
        } while (outLen > 0);
    }
    
    private static void batchSetZero(long addr, final int length) {
        for (int longBatches = length >>> 3, i = 0; i < longBatches; ++i) {
            PlatformDependent.putLong(addr, 0L);
            addr += 8L;
        }
        for (int remaining = length & 0x7, j = 0; j < remaining; ++j) {
            PlatformDependent.putByte(addr + j, (byte)0);
        }
    }
    
    static void setZero(long addr, int length) {
        if (length == 0) {
            return;
        }
        if (length <= 64) {
            if (!UnsafeByteBufUtil.UNALIGNED) {
                final int bytesToGetAligned = zeroTillAligned(addr, length);
                addr += bytesToGetAligned;
                length -= bytesToGetAligned;
                if (length == 0) {
                    return;
                }
                assert is8BytesAligned(addr);
            }
            batchSetZero(addr, length);
        }
        else {
            PlatformDependent.setMemory(addr, length, (byte)0);
        }
    }
    
    static long next8bytesAlignedAddr(final long addr) {
        return addr + 7L & 0xFFFFFFFFFFFFFFF8L;
    }
    
    static boolean is8BytesAligned(final long addr) {
        return (addr & 0x7L) == 0x0L;
    }
    
    private static int zeroTillAligned(final long addr, final int length) {
        final long alignedAddr = next8bytesAlignedAddr(addr);
        final int bytesToGetAligned = (int)(alignedAddr - addr);
        final int toZero = Math.min(bytesToGetAligned, length);
        for (int i = 0; i < toZero; ++i) {
            PlatformDependent.putByte(addr + i, (byte)0);
        }
        return toZero;
    }
    
    static UnpooledUnsafeDirectByteBuf newUnsafeDirectByteBuf(final ByteBufAllocator alloc, final int initialCapacity, final int maxCapacity, final boolean allowSectionedInternalNioBufferAccess) {
        if (PlatformDependent.useDirectBufferNoCleaner()) {
            return new UnpooledUnsafeNoCleanerDirectByteBuf(alloc, initialCapacity, maxCapacity, allowSectionedInternalNioBufferAccess);
        }
        return new UnpooledUnsafeDirectByteBuf(alloc, initialCapacity, maxCapacity, allowSectionedInternalNioBufferAccess);
    }
    
    private UnsafeByteBufUtil() {
    }
    
    static {
        UNALIGNED = PlatformDependent.isUnaligned();
    }
}
