blob: dc56718740ccc171c9361217108fc36258acccf8 [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 org.apache.datasketches.memory;
import static org.apache.datasketches.memory.UnsafeUtil.unsafe;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Acquires access to a ByteBuffer.
*
* @author Lee Rhodes
* @author Praveenkumar Venkatesan
* @author Roman Leventov
*/
final class AccessByteBuffer {
static final ByteBuffer ZERO_READ_ONLY_DIRECT_BYTE_BUFFER =
ByteBuffer.allocateDirect(0).asReadOnlyBuffer();
private static final long NIO_BUFFER_ADDRESS_FIELD_OFFSET =
UnsafeUtil.getFieldOffset(java.nio.Buffer.class, "address");
private static final long NIO_BUFFER_CAPACITY_FIELD_OFFSET =
UnsafeUtil.getFieldOffset(java.nio.Buffer.class, "capacity");
private static final long BYTE_BUFFER_HB_FIELD_OFFSET =
UnsafeUtil.getFieldOffset(java.nio.ByteBuffer.class, "hb");
private static final long BYTE_BUFFER_OFFSET_FIELD_OFFSET =
UnsafeUtil.getFieldOffset(java.nio.ByteBuffer.class, "offset");
final long nativeBaseOffset;
final long capacityBytes;
final long regionOffset;
final Object unsafeObj;
final boolean resourceReadOnly;
final ByteOrder byteOrder; //not used externally, here for reference.
/**
* The given ByteBuffer may be either readOnly or writable
* @param byteBuf the given ByteBuffer
*/
AccessByteBuffer(final ByteBuffer byteBuf) {
capacityBytes = byteBuf.capacity();
resourceReadOnly = byteBuf.isReadOnly();
byteOrder = byteBuf.order();
final boolean direct = byteBuf.isDirect();
if (direct) {
nativeBaseOffset = ((sun.nio.ch.DirectBuffer) byteBuf).address();
unsafeObj = null;
regionOffset = 0L; //address() is already adjusted for direct slices, so regionOffset = 0
} else {
nativeBaseOffset = 0L;
// ByteBuffer.arrayOffset() and ByteBuffer.array() throw ReadOnlyBufferException if
// ByteBuffer is read-only. This uses reflection for both writable and read-only cases.
// Includes the slice() offset for heap.
regionOffset = unsafe.getInt(byteBuf, BYTE_BUFFER_OFFSET_FIELD_OFFSET);
unsafeObj = unsafe.getObject(byteBuf, BYTE_BUFFER_HB_FIELD_OFFSET);
}
}
/**
* This method is adapted from https://github.com/odnoklassniki/one-nio\
* /blob/master/src/one/nio/mem/DirectMemory.java : wrap(...). See LICENSE.
*/
static ByteBuffer getDummyReadOnlyDirectByteBuffer(final long address, final int capacity) {
final ByteBuffer buf = ZERO_READ_ONLY_DIRECT_BYTE_BUFFER.duplicate();
unsafe.putLong(buf, NIO_BUFFER_ADDRESS_FIELD_OFFSET, address);
unsafe.putInt(buf, NIO_BUFFER_CAPACITY_FIELD_OFFSET, capacity);
buf.limit(capacity);
return buf;
}
}