/** * Copyright 2013, Landz and its contributors. All rights reserved. * * Licensed 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 z.offheap.buffer; import static z.offheap.zmalloc.Allocator.*; import static z.offheap.buffer.Buffers.*; import static z.util.Contracts.*; /** * Buffer, is one kind off-heap memory storage based on * {@link z.offheap.zmalloc.Allocator}. * <p> * Note: * <p>1. the Buffer instance is not thread safe. * <p>2. the buffer storage may contain garbage when created. It is your judgement * whether to do this clear work via {@link #clear} method. * */ public class Buffer implements NativeOrderBuffer, NetworkOrderBuffer, LittleEndianOrderBuffer { protected long capacity; protected long address; protected long readCursor; protected long writeCursor; /** * WARNING: this constructor is used to support the pre-allocated behavior in * pool-like scenario. This default constructor just returns an * uncompleted instance. *<p> * Do not use this constructor unless you know what you are doing. * Instead, you can use related static factory methods, * like {@link #create}. */ @Deprecated public Buffer() {} protected Buffer(long capacity) { this.address = allocate(capacity); this.capacity = capacity; } protected Buffer(long address, long capacity) { this.address = address; this.capacity = capacity; } public static final ByteBuffer create(long capacity) { return new Buffer(capacity); } public static final ByteBuffer create(long address, long capacity) { return new Buffer(address, capacity); } @Override public long capacity() { return capacity; } @Deprecated public void capacity(long capacity) { this.capacity = capacity; } @Override public long address() { return address; } @Deprecated public void address(long address) { this.address = address; } @Override public final Buffer clear() { Buffers.clear(address, (int) capacity); return this; } @Override public final long readCursor() { return readCursor; } @Override public final long writeCursor() { return writeCursor; } @Override public final Buffer reset() { readCursor = 0; writeCursor = 0; return this; } @Override public final boolean isReadable() { return writeCursor > readCursor; } @Override public final boolean isReadable(long numBytes) { return writeCursor - readCursor >= numBytes; } @Override public final boolean isWritable() { return capacity > writeCursor; } @Override public boolean isWritable(long numBytes) { return capacity - writeCursor >= numBytes; } @Override public final long readableBytes() { return writeCursor - readCursor; } @Override public final long writableBytes() { return capacity - writeCursor; } //======================================================================= //read primitives @Override public final byte read() { contractToRead(1); byte v = get(address + readCursor); readCursor++; return v; } @Override public final short readShort() { contractToRead(2); short v = getShort(address + readCursor); readCursor += 2; return v; } @Override public final int readInt() { contractToRead(4); int v = getInt(address + readCursor); readCursor += 4; return v; } @Override public final long readLong() { contractToRead(8); long v = getLong(address + readCursor); readCursor += 8; return v; } @Override public final char readChar() { return (char)readShort(); } @Override public final float readFloat() { contractToRead(4); float v = getFloat(address + readCursor); readCursor += 4; return v; } @Override public final double readDouble() { contractToRead(8); double v = getDouble(address + readCursor); readCursor += 8; return v; } //====================================================================== //NetworkOrder read @Override public final short readShortN() { contractToRead(2); short v = NATIVE_ORDER_SAME_TO_NETWORK_ORDER ? getShort(address + readCursor) : getShortNonNative(address + readCursor); readCursor += 2; return v; } @Override public final int readIntN() { contractToRead(4); int v = NATIVE_ORDER_SAME_TO_NETWORK_ORDER ? getInt(address + readCursor) : getIntNonNative(address + readCursor); readCursor += 4; return v; } @Override public final long readLongN() { contractToRead(8); long v = NATIVE_ORDER_SAME_TO_NETWORK_ORDER ? getLong(address + readCursor) : getLongNonNative(address + readCursor); readCursor += 8; return v; } @Override public final char readCharN() { return NATIVE_ORDER_SAME_TO_NETWORK_ORDER ? (char)readShort() : (char) readShortN(); } @Override public final float readFloatN() { contractToRead(4); float v = NATIVE_ORDER_SAME_TO_NETWORK_ORDER ? getFloat(address+readCursor) : getFloatNonNative(address+readCursor); readCursor += 4; return v; } @Override public final double readDoubleN() { contractToRead(8); double v = NATIVE_ORDER_SAME_TO_NETWORK_ORDER ? getDouble(address+readCursor) : getDoubleNonNative(address+readCursor); readCursor += 8; return v; } //====================================================================== //LittleEndian read @Override public final short readShortLE() { contractToRead(2); short v = NATIVE_ORDER_SAME_TO_NETWORK_ORDER ? getShortNonNative(address+readCursor) : getShort(address+readCursor); readCursor += 2; return v; } @Override public final int readIntLE() { contractToRead(4); int v = NATIVE_ORDER_SAME_TO_NETWORK_ORDER ? getIntNonNative(address + readCursor) : getInt(address + readCursor) ; readCursor += 4; return v; } @Override public final long readLongLE() { contractToRead(8); long v = NATIVE_ORDER_SAME_TO_NETWORK_ORDER ? getLongNonNative(address + readCursor) : getLong(address + readCursor); readCursor += 8; return v; } @Override public final char readCharLE() { return NATIVE_ORDER_SAME_TO_NETWORK_ORDER ? (char)readShortLE() : (char)readShort(); } @Override public final float readFloatLE() { contractToRead(4); float v = NATIVE_ORDER_SAME_TO_NETWORK_ORDER ? getFloatNonNative(address+readCursor) : getFloat(address+readCursor); readCursor += 4; return v; } @Override public final double readDoubleLE() { contractToRead(8); double v = NATIVE_ORDER_SAME_TO_NETWORK_ORDER ? getDoubleNonNative(address+readCursor) : getDouble(address+readCursor); readCursor += 8; return v; } /** * * WARNING: make sure you understand the bytes that you want to skip may * contain garbage, in that {@link z.offheap.buffer.Buffer} does not * clear the allocated memory area when created. */ @Override public final void skipRead(long length) { contractReadCursor(readCursor+length); readCursor += length; } /** * * WARNING: make sure you understand the bytes that you want to skip may * contain garbage, in that {@link z.offheap.buffer.Buffer} does not * clear the allocated memory area when created. */ @Override public final void skipReadTo(long index) { contractReadCursor(index); readCursor = index; } @Override public final void readTo(ByteBuffer dstbuffer, long length) { copy(address+readCursor, dstbuffer.address()+dstbuffer.writeCursor(), length); dstbuffer.skipWrite(length); } //====================================================================== //write primitives @Override public final Buffer write(byte value) { contractToWrite(1); put(address + writeCursor, value); writeCursor++; return this; } @Override public final Buffer writeShort(short value) { contractToWrite(2); putShort(address + writeCursor, value); writeCursor += 2; return this; } @Override public final Buffer writeInt(int value) { contractToWrite(4); putInt(address + writeCursor, value); writeCursor += 4; return this; } @Override public final Buffer writeLong(long value) { contractToWrite(8); putLong(address + writeCursor, value); writeCursor += 8; return this; } @Override public final Buffer writeChar(char value) { writeShort((short) value); return this; } @Override public final Buffer writeFloat(float value) { contractToWrite(4); putFloat(address + writeCursor, value); writeCursor += 4; return this; } @Override public final Buffer writeDouble(double value) { contractToWrite(8); putDouble(address + writeCursor, value); writeCursor += 8; return this; } //======================================================================= //NetworkOrder write @Override public final Buffer writeShortN(short value) { contractToWrite(2); if (NATIVE_ORDER_SAME_TO_NETWORK_ORDER) { putShort(address + writeCursor, value); }else { putShortNonNative(address + writeCursor, value); } writeCursor += 2; return this; } @Override public final Buffer writeIntN(int value) { contractToWrite(4); if (NATIVE_ORDER_SAME_TO_NETWORK_ORDER) { putInt(address + writeCursor, value); } else { putIntNonNative(address + writeCursor, value); } writeCursor += 4; return this; } @Override public final Buffer writeLongN(long value) { contractToWrite(8); if (NATIVE_ORDER_SAME_TO_NETWORK_ORDER) { putLong(address + writeCursor, value); } else { putLongNonNative(address + writeCursor, value); } writeCursor += 8; return this; } @Override public final Buffer writeCharN(char value) { if (NATIVE_ORDER_SAME_TO_NETWORK_ORDER) { writeShort((short) value); } else { writeShortN((short) value); } return this; } @Override public final Buffer writeFloatN(float value) { contractToWrite(4); if (NATIVE_ORDER_SAME_TO_NETWORK_ORDER) { putFloat(address + writeCursor, value); } else { putFloatNonNative(address + writeCursor, value); } writeCursor += 4; return this; } @Override public final Buffer writeDoubleN(double value) { contractToWrite(8); if (NATIVE_ORDER_SAME_TO_NETWORK_ORDER) { putDouble(address + writeCursor, value); } else { putDoubleNonNative(address + writeCursor, value); } writeCursor += 8; return this; } //======================================================================= //LittleEndianOrder write @Override public final Buffer writeShortLE(short value) { contractToWrite(2); if (NATIVE_ORDER_SAME_TO_NETWORK_ORDER) { putShortNonNative(address + writeCursor, value); }else { putShort(address + writeCursor, value); } writeCursor += 2; return this; } @Override public final Buffer writeIntLE(int value) { contractToWrite(4); if (NATIVE_ORDER_SAME_TO_NETWORK_ORDER) { putIntNonNative(address + writeCursor, value); } else { putInt(address + writeCursor, value); } writeCursor += 4; return this; } @Override public final Buffer writeLongLE(long value) { contractToWrite(8); if (NATIVE_ORDER_SAME_TO_NETWORK_ORDER) { putLongNonNative(address + writeCursor, value); } else { putLong(address + writeCursor, value); } writeCursor += 8; return this; } @Override public final Buffer writeCharLE(char value) { if (NATIVE_ORDER_SAME_TO_NETWORK_ORDER) { writeShortLE((short) value); } else { writeShort((short) value); } return this; } @Override public final Buffer writeFloatLE(float value) { contractToWrite(4); if (NATIVE_ORDER_SAME_TO_NETWORK_ORDER) { putFloatNonNative(address + writeCursor, value); } else { putFloat(address + writeCursor, value); } writeCursor += 4; return this; } @Override public final Buffer writeDoubleLE(double value) { contractToWrite(8); if (NATIVE_ORDER_SAME_TO_NETWORK_ORDER) { putDoubleNonNative(address + writeCursor, value); } else { putDouble(address + writeCursor, value); } writeCursor += 8; return this; } /** * * WARNING: make sure you understand the bytes that you want to skip may * contain garbage, in that {@link z.offheap.buffer.Buffer} does not * clear the allocated memory area when created. */ @Override @Deprecated public final Buffer skipWrite(long length) { contractWriteCursor(writeCursor+length); writeCursor += length; return this; } /** * * WARNING: make sure you understand the bytes that you want to skip may * contain garbage, in that {@link z.offheap.buffer.Buffer} does not * clear the allocated memory area when created. */ @Override @Deprecated public final Buffer skipWriteTo(long index) { contractWriteCursor(index); writeCursor = index; return this; } //====================================================================== //common contracts protected static boolean enable_contracts = true; protected final void contractToWrite(long nBytes) { if (enable_contracts) contract(()-> (address!=0) && isWritable(nBytes) ); } protected final void contractToRead(long nBytes) { if (enable_contracts) contract(()-> (address!=0) && isReadable(nBytes) ); } protected final void contractReadCursor(long readCursor) { if (enable_contracts) contract(()-> (address!=0) && (readCursor > 0) && (readCursor < writeCursor) ); } protected final void contractWriteCursor(long writeCursor) { if (enable_contracts) contract(()-> (address!=0) && (writeCursor > 0) && (writeCursor < capacity) ); } public static final void disableContracts() { enable_contracts = false; } //====================================================================== @Override public final NativeOrderBuffer nativeOrder() { return this; } @Override public final NetworkOrderBuffer networkOrder() { return this; } @Override public final LittleEndianOrderBuffer littleEndianOrder() { return this; } //====================================================================== //clean-up @Override public final void close() { if (address!=0) { free(address); address=0; } } @Override public final void finalize() { close(); } }