blob: 996da677bdddad8afabe9c912a0394da2b19bbed [file] [log] [blame]
/*
* 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 java.nio;
import org.apache.harmony.luni.platform.PlatformAddress;
import org.apache.harmony.luni.platform.PlatformAddressFactory;
import org.apache.harmony.nio.internal.DirectBuffer;
import org.apache.harmony.nio.internal.nls.Messages;
/**
* DirectByteBuffer, ReadWriteDirectByteBuffer and ReadOnlyDirectByteBuffer
* compose the implementation of platform memory based byte buffers.
* <p>
* DirectByteBuffer implements all the shared readonly methods and is extended
* by the other two classes.
* </p>
* <p>
* All methods are marked final for runtime performance.
* </p>
*
*/
abstract class DirectByteBuffer extends BaseByteBuffer implements DirectBuffer {
// This is the base address of the buffer memory.
protected PlatformAddress address;
// This is the offset from the base address at which this buffer logically
// starts.
protected final int offset;
/*
* Constructs a new direct byte buffer of the given capacity on newly
* allocated OS memory. The memory will have been zeroed. When the instance
* is discarded the OS memory will be freed if it has not already been done
* so by an explicit call to #free(). Callers are encouraged to explicitly
* free the memory where possible.
*/
DirectByteBuffer(int capacity) {
this(PlatformAddressFactory.alloc(capacity, (byte) 0), capacity, 0);
address.autoFree();
}
DirectByteBuffer(PlatformAddress address, int capacity, int offset) {
super(capacity);
this.address = address;
this.offset = offset;
}
/*
* Override ByteBuffer.get(byte[], int, int) to improve performance.
*
* (non-Javadoc)
*
* @see java.nio.ByteBuffer#get(byte[], int, int)
*/
@Override
public final ByteBuffer get(byte[] dest, int off, int len) {
int length = dest.length;
if ((off < 0) || (len < 0) || (long) off + (long) len > length) {
throw new IndexOutOfBoundsException();
}
if (len > remaining()) {
throw new BufferUnderflowException();
}
getBaseAddress().getByteArray(offset + position, dest, off, len);
position += len;
return this;
}
@Override
public final byte get() {
if (position == limit) {
throw new BufferUnderflowException();
}
return getBaseAddress().getByte(offset + position++);
}
@Override
public final byte get(int index) {
if (index < 0 || index >= limit) {
throw new IndexOutOfBoundsException();
}
return getBaseAddress().getByte(offset + index);
}
@Override
public final double getDouble() {
int newPosition = position + 8;
if (newPosition > limit) {
throw new BufferUnderflowException();
}
double result = getBaseAddress().getDouble(offset + position, order);
position = newPosition;
return result;
}
@Override
public final double getDouble(int index) {
if (index < 0 || (long) index + 8 > limit) {
throw new IndexOutOfBoundsException();
}
return getBaseAddress().getDouble(offset + index, order);
}
@Override
public final float getFloat() {
int newPosition = position + 4;
if (newPosition > limit) {
throw new BufferUnderflowException();
}
float result = getBaseAddress().getFloat(offset + position, order);
position = newPosition;
return result;
}
@Override
public final float getFloat(int index) {
if (index < 0 || (long) index + 4 > limit) {
throw new IndexOutOfBoundsException();
}
return getBaseAddress().getFloat(offset + index, order);
}
@Override
public final int getInt() {
int newPosition = position + 4;
if (newPosition > limit) {
throw new BufferUnderflowException();
}
int result = getBaseAddress().getInt(offset + position, order);
position = newPosition;
return result;
}
@Override
public final int getInt(int index) {
if (index < 0 || (long) index + 4 > limit) {
throw new IndexOutOfBoundsException();
}
return getBaseAddress().getInt(offset + index, order);
}
@Override
public final long getLong() {
int newPosition = position + 8;
if (newPosition > limit) {
throw new BufferUnderflowException();
}
long result = getBaseAddress().getLong(offset + position, order);
position = newPosition;
return result;
}
@Override
public final long getLong(int index) {
if (index < 0 || (long) index + 8 > limit) {
throw new IndexOutOfBoundsException();
}
return getBaseAddress().getLong(offset + index, order);
}
@Override
public final short getShort() {
int newPosition = position + 2;
if (newPosition > limit) {
throw new BufferUnderflowException();
}
short result = getBaseAddress().getShort(offset + position, order);
position = newPosition;
return result;
}
@Override
public final short getShort(int index) {
if (index < 0 || (long) index + 2 > limit) {
throw new IndexOutOfBoundsException();
}
return getBaseAddress().getShort(offset + index, order);
}
@Override
public final boolean isDirect() {
return true;
}
public final boolean isAddressValid() {
return address != PlatformAddress.INVALID;
}
public final void addressValidityCheck() {
if (!isAddressValid()) {
// nio.08=Cannot use the direct byte buffer after it has been
// explicitly freed.
throw new IllegalStateException(Messages.getString("nio.08")); //$NON-NLS-1$
}
}
/*
* Answers the base address of the buffer (i.e. before offset).
*/
public final PlatformAddress getBaseAddress() {
addressValidityCheck();
return address;
}
/**
* Answers the platform address of the start of this buffer instance.
* <em>You must not attempt to free the returned address!!</em> It may not
* be an address that was explicitly malloc'ed (i.e. if this buffer is the
* result of a split); and it may be memory shared by multiple buffers.
* <p>
* If you can guarantee that you want to free the underlying memory call the
* #free() method on this instance -- generally applications will rely on
* the garbage collector to autofree this memory.
* </p>
*
* @return the effective address of the start of the buffer.
* @throws IllegalStateException
* if this buffer address is known to have been freed
* previously.
*/
public final PlatformAddress getEffectiveAddress() {
return getBaseAddress().offsetBytes(offset);
}
/**
* Explicitly free the memory used by this direct byte buffer. If the memory
* has already been freed then this is a no-op. Once the memory has been
* freed then operations requiring access to the memory will throw an
* <code>IllegalStateException</code>.
* <p>
* Note this is is possible that the memory is freed by code that reaches
* into the address and explicitly frees it 'beneath' us -- this is bad
* form.
* </p>
*/
public final void free() {
if (isAddressValid()) {
PlatformAddress a = address;
address = PlatformAddress.INVALID;
a.free();
}
}
@Override
final protected byte[] protectedArray() {
throw new UnsupportedOperationException();
}
@Override
final protected int protectedArrayOffset() {
throw new UnsupportedOperationException();
}
@Override
final protected boolean protectedHasArray() {
return false;
}
public final int getByteCapacity() {
return capacity;
}
}