/*
* 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.mulgara.worm;
import java.nio.ByteBuffer;
/**
* This class manages the allocation and detection of blank nodes.
*
* @created July 4, 2012
* @author Paula Gearon
*/
public class BlankNodeAllocator {
/** The bit that indicates a blank node. */
static final long BLANK_NODE_BIT = 0x4000000000000000L;
/** The mask that can remove the BLANK_NODE_BIT. */
static final private long COUNTER_MASK = 0x3FFFFFFFFFFFFFFFL;
/** The first valid blank node value. */
static final long FIRST = 1;
/** The next node to be allocated. Initialized to 1, but usually set by the metaroot file. */
private long nextNode = FIRST;
/** The last committed nextNode value. */
private long committedNextNode = FIRST;
/**
* The constructor for a new blank node allocator.
*/
public BlankNodeAllocator() {
}
/**
* Creates a new blank node allocator, initialized from a data buffer.
* @param data The data to initialize from.
*/
public BlankNodeAllocator(ByteBuffer data, int offset) {
committedNextNode = data.getLong(offset);
nextNode = committedNextNode;
}
/**
* Writes the current state to the current position in a data buffer.
* @param data The buffer to write to.
*/
public void writeTo(ByteBuffer data, int offset) {
data.putLong(offset, committedNextNode);
}
/**
* Get the next blank node from this allocator.
* @return A GNode for a new blank node.
*/
public synchronized long allocate() {
return nextNode++ | BLANK_NODE_BIT;
}
/**
* Test if a GNode is a blank node.
* @param gNode The gNode to test.
* @return <code>true</code> if the gNode is for a blank node.
*/
public static boolean isBlank(long gNode) {
return (gNode & BLANK_NODE_BIT) != 0;
}
/**
* Clear all values back to their initialized states.
*/
public void clear() {
nextNode = FIRST;
committedNextNode = FIRST;
}
/**
* Get the current internal state.
* @return The next node value. This encodes all of the internal state.
*/
public long getCurrentState() {
return nextNode;
}
/**
* Set the internal state. This is just the blank node counter.
* @param state The state for this object.
*/
public void setCurrentState(long state) {
this.nextNode = state;
committedNextNode = state;
}
/**
* Convert a blank node code to a counter value.
* @param blankGNode The blank node value.
* @return A value with the blank node bit turned off.
*/
public static final long nodeToCounter(long blankGNode) {
return blankGNode & COUNTER_MASK;
}
/**
* Convert a blank node code to a counter value.
* @param counter The blank node value, with the blank node bit turned off.
* @return A value with the blank node bit turned on.
*/
public static final long counterToNode(long counter) {
return counter | BLANK_NODE_BIT;
}
}