/* * 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 org.apache.ignite.internal.processors.platform.memory; import org.apache.ignite.IgniteException; import org.apache.ignite.internal.util.GridUnsafe; /** * Interop input stream implementation. */ public class PlatformInputStreamImpl implements PlatformInputStream { /** Underlying memory. */ private final PlatformMemory mem; /** Real data pointer */ private long data; /** Amount of available data. */ private int len; /** Current position. */ private int pos; /** Heap-copied data. */ private byte[] dataCopy; /** * Constructor. * * @param mem Underlying memory chunk. */ public PlatformInputStreamImpl(PlatformMemory mem) { this.mem = mem; data = mem.data(); len = mem.length(); } /** {@inheritDoc} */ @Override public byte readByte() { ensureEnoughData(1); return GridUnsafe.getByte(data + pos++); } /** {@inheritDoc} */ @Override public byte[] readByteArray(int cnt) { byte[] res = new byte[cnt]; copyAndShift(res, GridUnsafe.BYTE_ARR_OFF, cnt); return res; } /** {@inheritDoc} */ @Override public boolean readBoolean() { return readByte() == 1; } /** {@inheritDoc} */ @Override public boolean[] readBooleanArray(int cnt) { boolean[] res = new boolean[cnt]; copyAndShift(res, GridUnsafe.BOOLEAN_ARR_OFF, cnt); return res; } /** {@inheritDoc} */ @Override public short readShort() { ensureEnoughData(2); short res = GridUnsafe.getShort(data + pos); shift(2); return res; } /** {@inheritDoc} */ @Override public short[] readShortArray(int cnt) { int len = cnt << 1; short[] res = new short[cnt]; copyAndShift(res, GridUnsafe.SHORT_ARR_OFF, len); return res; } /** {@inheritDoc} */ @Override public char readChar() { ensureEnoughData(2); char res = GridUnsafe.getChar(data + pos); shift(2); return res; } /** {@inheritDoc} */ @Override public char[] readCharArray(int cnt) { int len = cnt << 1; char[] res = new char[cnt]; copyAndShift(res, GridUnsafe.CHAR_ARR_OFF, len); return res; } /** {@inheritDoc} */ @Override public int readInt() { ensureEnoughData(4); int res = GridUnsafe.getInt(data + pos); shift(4); return res; } /** {@inheritDoc} */ @Override public byte readBytePositioned(int pos) { int delta = pos + 1 - this.pos; if (delta > 0) ensureEnoughData(delta); return GridUnsafe.getByte(data + pos); } /** {@inheritDoc} */ @Override public short readShortPositioned(int pos) { int delta = pos + 2 - this.pos; if (delta > 0) ensureEnoughData(delta); return GridUnsafe.getShort(data + pos); } /** {@inheritDoc} */ @Override public int readIntPositioned(int pos) { int delta = pos + 4 - this.pos; if (delta > 0) ensureEnoughData(delta); return GridUnsafe.getInt(data + pos); } /** {@inheritDoc} */ @Override public int[] readIntArray(int cnt) { int len = cnt << 2; int[] res = new int[cnt]; copyAndShift(res, GridUnsafe.INT_ARR_OFF, len); return res; } /** {@inheritDoc} */ @Override public float readFloat() { ensureEnoughData(4); float res = GridUnsafe.getFloat(data + pos); shift(4); return res; } /** {@inheritDoc} */ @Override public float[] readFloatArray(int cnt) { int len = cnt << 2; float[] res = new float[cnt]; copyAndShift(res, GridUnsafe.FLOAT_ARR_OFF, len); return res; } /** {@inheritDoc} */ @Override public long readLong() { ensureEnoughData(8); long res = GridUnsafe.getLong(data + pos); shift(8); return res; } /** {@inheritDoc} */ @Override public long[] readLongArray(int cnt) { int len = cnt << 3; long[] res = new long[cnt]; copyAndShift(res, GridUnsafe.LONG_ARR_OFF, len); return res; } /** {@inheritDoc} */ @Override public double readDouble() { ensureEnoughData(8); double res = GridUnsafe.getDouble(data + pos); shift(8); return res; } /** {@inheritDoc} */ @Override public double[] readDoubleArray(int cnt) { int len = cnt << 3; double[] res = new double[cnt]; copyAndShift(res, GridUnsafe.DOUBLE_ARR_OFF, len); return res; } /** {@inheritDoc} */ @Override public int read(byte[] arr, int off, int len) { if (len > remaining()) len = remaining(); copyAndShift(arr, GridUnsafe.BYTE_ARR_OFF + off, len); return len; } /** {@inheritDoc} */ @Override public int remaining() { return len - pos; } /** {@inheritDoc} */ @Override public int capacity() { return len; } /** {@inheritDoc} */ @Override public int position() { return pos; } /** {@inheritDoc} */ @Override public void position(int pos) { if (pos > len) throw new IgniteException("Position is out of bounds: " + pos); else this.pos = pos; } /** {@inheritDoc} */ @Override public byte[] array() { return arrayCopy(); } /** {@inheritDoc} */ @Override public byte[] arrayCopy() { if (dataCopy == null) { dataCopy = new byte[len]; GridUnsafe.copyOffheapHeap(data, dataCopy, GridUnsafe.BYTE_ARR_OFF, dataCopy.length); } return dataCopy; } /** {@inheritDoc} */ @Override public long offheapPointer() { return 0; } /** {@inheritDoc} */ @Override public long rawOffheapPointer() { return 0; } /** {@inheritDoc} */ @Override public boolean hasArray() { return false; } /** {@inheritDoc} */ @Override public void synchronize() { data = mem.data(); len = mem.length(); } /** * Ensure there is enough data in the stream. * * @param cnt Amount of byte expected to be available. */ private void ensureEnoughData(int cnt) { if (remaining() < cnt) throw new IgniteException("Not enough data to read the value [position=" + pos + ", requiredBytes=" + cnt + ", remainingBytes=" + remaining() + ']'); } /** * Copy required amount of data and shift position. * * @param target Target to copy data to. * @param off Offset. * @param cnt Count. */ private void copyAndShift(Object target, long off, int cnt) { ensureEnoughData(cnt); GridUnsafe.copyOffheapHeap(data + pos, target, off, cnt); shift(cnt); } /** * Shift position to the right. * * @param cnt Amount of bytes. */ private void shift(int cnt) { pos += cnt; assert pos <= len; } }