// Copyright 2010-2011 Michel Kraemer
//
// 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 de.undercouch.bson4jackson.io;
import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
/**
* Keeps thread-local re-usable buffers. Each buffer is identified by a key.
* This class is a singleton, whereas the reference to the instance is hold
* in a {@link SoftReference} so buffers can be freed when they are not needed
* anymore.
* @see com.fasterxml.jackson.core.util.BufferRecycler
* @author Michel Kraemer
*/
public class StaticBuffers {
/**
* All buffers have a minimum size of 64 kb
*/
public static final int GLOBAL_MIN_SIZE = 1024 * 64;
/**
* Possible buffer keys
*/
public static enum Key {
BUFFER0,
BUFFER1,
BUFFER2,
BUFFER3,
BUFFER4,
BUFFER5,
BUFFER6,
BUFFER7,
BUFFER8,
BUFFER9
}
/**
* A thread-local soft reference to the singleton instance of this class
*/
private static final ThreadLocal<SoftReference<StaticBuffers>> _instance =
new ThreadLocal<SoftReference<StaticBuffers>>();
/**
* Maps of already allocated re-usable buffers
*/
private ByteBuffer[] _byteBuffers = new ByteBuffer[Key.values().length];
private CharBuffer[] _charBuffers = new CharBuffer[Key.values().length];
/**
* Hidden constructor
*/
private StaticBuffers() {
//nothing to do here
}
/**
* @return a thread-local singleton instance of this class
*/
public static StaticBuffers getInstance() {
SoftReference<StaticBuffers> ref = _instance.get();
StaticBuffers buf = (ref == null ? null : ref.get());
if (buf == null) {
buf = new StaticBuffers();
_instance.set(new SoftReference<StaticBuffers>(buf));
}
return buf;
}
/**
* Creates or re-uses a {@link CharBuffer} that has a minimum size. Calling
* this method multiple times with the same key will always return the
* same buffer, as long as it has the minimum size and is marked to be
* re-used. Buffers that are allowed to be re-used should be released using
* {@link #releaseCharBuffer(Key, CharBuffer)}.
* @param key the buffer's identifier
* @param minSize the minimum size
* @return the {@link CharBuffer} instance
*/
public CharBuffer charBuffer(Key key, int minSize) {
minSize = Math.max(minSize, GLOBAL_MIN_SIZE);
CharBuffer r = _charBuffers[key.ordinal()];
if (r == null || r.capacity() < minSize) {
r = CharBuffer.allocate(minSize);
} else {
_charBuffers[key.ordinal()] = null;
r.clear();
}
return r;
}
/**
* Marks a buffer a being re-usable.
* @param key the buffer's key
* @param buf the buffer
*/
public void releaseCharBuffer(Key key, CharBuffer buf) {
_charBuffers[key.ordinal()] = buf;
}
/**
* @see #charBuffer(Key, int)
*/
public ByteBuffer byteBuffer(Key key, int minSize) {
minSize = Math.max(minSize, GLOBAL_MIN_SIZE);
ByteBuffer r = _byteBuffers[key.ordinal()];
if (r == null || r.capacity() < minSize) {
r = ByteBuffer.allocate(minSize);
} else {
_byteBuffers[key.ordinal()] = null;
r.clear();
}
return r;
}
/**
* @see #releaseCharBuffer(Key, CharBuffer)
*/
public void releaseByteBuffer(Key key, ByteBuffer buf) {
_byteBuffers[key.ordinal()] = buf;
}
}