/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.netty.buffer; import io.netty.util.internal.PlatformDependent; import java.nio.ByteOrder; import java.util.concurrent.atomic.AtomicLong; /** * The underlying class we use for little-endian access to memory. Is used underneath DrillBufs to abstract away the * Netty classes and underlying Netty memory management. */ public final class UnsafeDirectLittleEndian extends WrappedByteBuf { private static final boolean NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; private static final AtomicLong ID_GENERATOR = new AtomicLong(0); public final long id = ID_GENERATOR.incrementAndGet(); private final AbstractByteBuf wrapped; private final long memoryAddress; private final AtomicLong bufferCount; private final AtomicLong bufferSize; private final long initCap; UnsafeDirectLittleEndian(DuplicatedByteBuf buf) { this(buf, true, null, null); } UnsafeDirectLittleEndian(LargeBuffer buf) { this(buf, true, null, null); } UnsafeDirectLittleEndian(PooledUnsafeDirectByteBuf buf, AtomicLong bufferCount, AtomicLong bufferSize) { this(buf, true, bufferCount, bufferSize); } private UnsafeDirectLittleEndian(AbstractByteBuf buf, boolean fake, AtomicLong bufferCount, AtomicLong bufferSize) { super(buf); if (!NATIVE_ORDER || buf.order() != ByteOrder.BIG_ENDIAN) { throw new IllegalStateException("Drill only runs on LittleEndian systems."); } this.bufferCount = bufferCount; this.bufferSize = bufferSize; // initCap is used if we're tracking memory release. If we're in non-debug mode, we'll skip this. this.initCap = ASSERT_ENABLED ? buf.capacity() : -1; this.wrapped = buf; this.memoryAddress = buf.memoryAddress(); } private long addr(int index) { return memoryAddress + index; } @Override public long getLong(int index) { // wrapped.checkIndex(index, 8); long v = PlatformDependent.getLong(addr(index)); return v; } @Override public float getFloat(int index) { return Float.intBitsToFloat(getInt(index)); } @Override public ByteBuf slice() { return slice(this.readerIndex(), readableBytes()); } @Override public ByteBuf slice(int index, int length) { return new SlicedByteBuf(this, index, length); } @Override public ByteOrder order() { return ByteOrder.LITTLE_ENDIAN; } @Override public ByteBuf order(ByteOrder endianness) { return this; } @Override public double getDouble(int index) { return Double.longBitsToDouble(getLong(index)); } @Override public char getChar(int index) { return (char) getShort(index); } @Override public long getUnsignedInt(int index) { return getInt(index) & 0xFFFFFFFFL; } @Override public int getInt(int index) { int v = PlatformDependent.getInt(addr(index)); return v; } @Override public int getUnsignedShort(int index) { return getShort(index) & 0xFFFF; } @Override public short getShort(int index) { short v = PlatformDependent.getShort(addr(index)); return v; } @Override public ByteBuf setShort(int index, int value) { wrapped.checkIndex(index, 2); _setShort(index, value); return this; } @Override public ByteBuf setInt(int index, int value) { wrapped.checkIndex(index, 4); _setInt(index, value); return this; } @Override public ByteBuf setLong(int index, long value) { wrapped.checkIndex(index, 8); _setLong(index, value); return this; } @Override public ByteBuf setChar(int index, int value) { setShort(index, value); return this; } @Override public ByteBuf setFloat(int index, float value) { setInt(index, Float.floatToRawIntBits(value)); return this; } @Override public ByteBuf setDouble(int index, double value) { setLong(index, Double.doubleToRawLongBits(value)); return this; } @Override public ByteBuf writeShort(int value) { wrapped.ensureWritable(2); _setShort(wrapped.writerIndex, value); wrapped.writerIndex += 2; return this; } @Override public ByteBuf writeInt(int value) { wrapped.ensureWritable(4); _setInt(wrapped.writerIndex, value); wrapped.writerIndex += 4; return this; } @Override public ByteBuf writeLong(long value) { wrapped.ensureWritable(8); _setLong(wrapped.writerIndex, value); wrapped.writerIndex += 8; return this; } @Override public ByteBuf writeChar(int value) { writeShort(value); return this; } @Override public ByteBuf writeFloat(float value) { writeInt(Float.floatToRawIntBits(value)); return this; } @Override public ByteBuf writeDouble(double value) { writeLong(Double.doubleToRawLongBits(value)); return this; } private void _setShort(int index, int value) { PlatformDependent.putShort(addr(index), (short) value); } private void _setInt(int index, int value) { PlatformDependent.putInt(addr(index), value); } private void _setLong(int index, long value) { PlatformDependent.putLong(addr(index), value); } @Override public byte getByte(int index) { return PlatformDependent.getByte(addr(index)); } @Override public ByteBuf setByte(int index, int value) { PlatformDependent.putByte(addr(index), (byte) value); return this; } @Override public boolean release() { return release(1); } @Override public boolean release(int decrement) { final boolean released = super.release(decrement); if (ASSERT_ENABLED && released && bufferCount != null && bufferSize != null) { bufferCount.decrementAndGet(); bufferSize.addAndGet(-initCap); } return released; } @Override public int hashCode() { return System.identityHashCode(this); } public static final boolean ASSERT_ENABLED; static { boolean isAssertEnabled = false; assert isAssertEnabled = true; ASSERT_ENABLED = isAssertEnabled; } }