/** * Copyright (c) 2002-2013 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * Neo4j is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.neo4j.kernel.impl.transaction.xaframework; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; import java.util.concurrent.atomic.AtomicInteger; /** * A ByteBuffer that is lazily copied on clear. Keeps a duplication counter and * if asked to be cleared with duplicates open, it creates a new backing store * instead of clearing the current, leaving users of duplicated buffers * unbothered. * * ByteBuffer hierarchy's constructors are all package private, so we cannot * extend. Instead we present ourselves as a wrapper that delegates all calls to * the wrapped reference but returns itself. Provided that the backing buffer is * not tampered with, holders of the result of duplicate should be safe from * clear() calls from users of the original. */ class CloseableByteBuffer { private volatile ByteBuffer delegate; private final AtomicInteger dupCount; private CloseableByteBuffer( ByteBuffer delegate ) { this.delegate = delegate; this.dupCount = new AtomicInteger( 0 ); } public final void close() { dupCount.decrementAndGet(); } public static CloseableByteBuffer wrap( ByteBuffer delegate ) { return new CloseableByteBuffer( delegate ); } public final int capacity() { return delegate.capacity(); } public final int position() { return delegate.position(); } public final Buffer position( int newPosition ) { return delegate.position( newPosition ); } public final int limit() { return delegate.limit(); } public final CloseableByteBuffer limit( int newLimit ) { delegate.limit( newLimit ); return this; } public final CloseableByteBuffer mark() { delegate.mark(); return this; } public final CloseableByteBuffer reset() { delegate.reset(); return this; } public final CloseableByteBuffer clear() { if ( dupCount.get() > 0 ) { delegate = ByteBuffer.allocate( capacity() ); } else { delegate.clear(); } return this; } public final CloseableByteBuffer flip() { delegate.flip(); return this; } public final CloseableByteBuffer rewind() { delegate.rewind(); return this; } public final int remaining() { return delegate.remaining(); } public final boolean hasRemaining() { return delegate.hasRemaining(); } public boolean isReadOnly() { return delegate.isReadOnly(); } public CloseableByteBuffer slice() { delegate.slice(); return this; } public CloseableByteBuffer duplicate() { dupCount.incrementAndGet(); return CloseableByteBuffer.wrap( delegate.duplicate() ); } public CharBuffer asCharBuffer() { return delegate.asCharBuffer(); } ByteBuffer getDelegate() { return delegate; } public byte get() { return delegate.get(); } public CloseableByteBuffer put( byte b ) { delegate.put( b ); return this; } public byte get( int index ) { return delegate.get( index ); } public CloseableByteBuffer put( int index, byte b ) { delegate.put( index, b ); return this; } public CloseableByteBuffer get( byte[] dst, int offset, int length ) { delegate.get( dst, offset, length ); return this; } public CloseableByteBuffer get( byte[] dst ) { delegate.get( dst ); return this; } public CloseableByteBuffer put( ByteBuffer src ) { delegate.put( src ); return this; } public CloseableByteBuffer put( byte[] src, int offset, int length ) { delegate.put( src, offset, length ); return this; } public final CloseableByteBuffer put( byte[] src ) { delegate.put( src ); return this; } public final boolean hasArray() { return delegate.hasArray(); } public final byte[] array() { return delegate.array(); } public final int arrayOffset() { return delegate.arrayOffset(); } public CloseableByteBuffer compact() { delegate.compact(); return this; } public boolean isDirect() { return delegate.isDirect(); } public String toString() { return delegate.toString(); } public int hashCode() { return delegate.hashCode(); } public boolean equals( Object ob ) { return delegate.equals( ob ); } public int compareTo( ByteBuffer that ) { return delegate.compareTo( that ); } public final ByteOrder order() { return delegate.order(); } public final CloseableByteBuffer order( ByteOrder bo ) { delegate.order( bo ); return this; } public char getChar() { return delegate.getChar(); } public CloseableByteBuffer putChar( char value ) { delegate.putChar( value ); return this; } public char getChar( int index ) { return delegate.getChar( index ); } public CloseableByteBuffer putChar( int index, char value ) { delegate.putChar( index, value ); return this; } public short getShort() { return delegate.getShort(); } public CloseableByteBuffer putShort( short value ) { delegate.putShort( value ); return this; } public short getShort( int index ) { return delegate.getShort( index ); } public CloseableByteBuffer putShort( int index, short value ) { delegate.putShort( index, value ); return this; } public int getInt() { return delegate.getInt(); } public CloseableByteBuffer putInt( int value ) { delegate.putInt( value ); return this; } public int getInt( int index ) { return delegate.getInt( index ); } public CloseableByteBuffer putInt( int index, int value ) { delegate.putInt( index, value ); return this; } public long getLong() { return delegate.getLong(); } public CloseableByteBuffer putLong( long value ) { delegate.putLong( value ); return this; } public long getLong( int index ) { return delegate.getLong( index ); } public CloseableByteBuffer putLong( int index, long value ) { delegate.putLong( index, value ); return this; } public float getFloat() { return delegate.getFloat(); } public CloseableByteBuffer putFloat( float value ) { delegate.putFloat( value ); return this; } public float getFloat( int index ) { return delegate.getFloat( index ); } public CloseableByteBuffer putFloat( int index, float value ) { delegate.putFloat( index, value ); return this; } public double getDouble() { return delegate.getDouble(); } public CloseableByteBuffer putDouble( double value ) { delegate.putDouble( value ); return this; } public double getDouble( int index ) { return delegate.getDouble( index ); } public CloseableByteBuffer putDouble( int index, double value ) { delegate.putDouble( index, value ); return this; } }