
org.fusesource.lmdbjni.NativeBuffer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lmdbjni-osx64 Show documentation
Show all versions of lmdbjni-osx64 Show documentation
The lmdbjni osx 64 bit native libraries
The newest version!
/**
* Copyright (C) 2013, RedHat, Inc.
*
* http://www.redhat.com/
*
* 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 org.fusesource.lmdbjni;
import org.fusesource.hawtjni.runtime.PointerMath;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A NativeBuffer allocates a native buffer on the heap. It supports
* creating sub slices/views of that buffer and manages reference tracking
* so that the the native buffer is freed once all NativeBuffer views
* are deleted.
*
* @author Hiram Chirino
*/
class NativeBuffer extends NativeObject {
private static class Allocation extends NativeObject {
private final AtomicInteger retained = new AtomicInteger(0);
private Allocation(long size) {
super(JNI.malloc(size));
}
void retain() {
checkAllocated();
retained.incrementAndGet();
}
void release() {
checkAllocated();
int r = retained.decrementAndGet();
if (r < 0) {
throw new Error("The object has already been deleted.");
} else if (r == 0) {
JNI.free(self);
self = 0;
}
}
}
static class Pool {
private final NativeBuffer.Pool prev;
Allocation allocation;
long pos;
long remaining;
int chunk;
public Pool(int chunk, Pool prev) {
this.chunk = chunk;
this.prev = prev;
}
NativeBuffer create(long size) {
if (size >= chunk) {
Allocation allocation = new Allocation(size);
return new NativeBuffer(allocation, allocation.self, size);
}
if (remaining < size) {
delete();
}
if (allocation == null) {
allocate();
}
NativeBuffer rc = new NativeBuffer(allocation, pos, size);
pos = PointerMath.add(pos, size);
remaining -= size;
return rc;
}
private void allocate() {
allocation = new NativeBuffer.Allocation(chunk);
allocation.retain();
remaining = chunk;
pos = allocation.self;
}
public void delete() {
if (allocation != null) {
allocation.release();
allocation = null;
}
}
}
private final Allocation allocation;
private final long capacity;
static final private ThreadLocal CURRENT_POOL = new ThreadLocal();
static public NativeBuffer create(long capacity) {
Pool pool = CURRENT_POOL.get();
if (pool == null) {
Allocation allocation = new Allocation(capacity);
return new NativeBuffer(allocation, allocation.self, capacity);
} else {
return pool.create(capacity);
}
}
public static void pushMemoryPool(int size) {
Pool original = CURRENT_POOL.get();
Pool next = new Pool(size, original);
CURRENT_POOL.set(next);
}
public static void popMemoryPool() {
Pool next = CURRENT_POOL.get();
next.delete();
if (next.prev == null) {
CURRENT_POOL.remove();
} else {
CURRENT_POOL.set(next.prev);
}
}
static public NativeBuffer create(byte[] data) {
if (data == null) {
return null;
} else {
return create(data, 0, data.length);
}
}
static public NativeBuffer create(byte[] data, int offset, int length) {
NativeBuffer rc = create(length);
rc.write(0, data, offset, length);
return rc;
}
static public NativeBuffer create(long pointer, int length) {
return new NativeBuffer(null, pointer, length);
}
private NativeBuffer(Allocation allocation, long self, long capacity) {
super(self);
this.capacity = capacity;
this.allocation = allocation;
if (allocation != null) {
allocation.retain();
}
}
public void delete() {
allocation.release();
}
public long capacity() {
return capacity;
}
public void write(long at, byte[] source, int offset, int length) {
checkAllocated();
if (length < 0) throw new IllegalArgumentException("length cannot be negative");
if (offset < 0) throw new IllegalArgumentException("offset cannot be negative");
if (at < 0) throw new IllegalArgumentException("at cannot be negative");
if (at + length > capacity)
throw new ArrayIndexOutOfBoundsException("at + length exceeds the capacity of this object");
if (offset + length > source.length)
throw new ArrayIndexOutOfBoundsException("offset + length exceed the length of the source buffer");
if (Unsafe.UNSAFE != null) {
Unsafe.UNSAFE.copyMemory(source, Unsafe.ARRAY_BASE_OFFSET, null, self + at, length);
} else {
JNI.buffer_copy(source, offset, self, at, length);
}
}
public void read(long at, byte[] target, int offset, int length) {
checkAllocated();
if (length < 0) throw new IllegalArgumentException("length cannot be negative");
if (offset < 0) throw new IllegalArgumentException("offset cannot be negative");
if (at < 0) throw new IllegalArgumentException("at cannot be negative");
if (at + length > capacity)
throw new ArrayIndexOutOfBoundsException("at + length exceeds the capacity of this object");
if (offset + length > target.length)
throw new ArrayIndexOutOfBoundsException("offset + length exceed the length of the target buffer");
if (Unsafe.UNSAFE != null) {
Unsafe.UNSAFE.copyMemory(null, self + at, target, Unsafe.ARRAY_BASE_OFFSET, length);
} else {
JNI.buffer_copy(self, at, target, offset, length);
}
}
public byte[] toByteArray() {
if (capacity > Integer.MAX_VALUE) {
throw new OutOfMemoryError("Native buffer larger than the largest allowed Java byte[]");
}
byte[] rc = new byte[(int) capacity];
read(0, rc, 0, rc.length);
return rc;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy