/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id: VisitedObjects.java,v 0f73af5ae3da 2010/05/10 05:38:40 alexander $
*/
package com.sleepycat.persist.impl;
/**
* Keeps track of a set of visited objects and their corresponding offset in a
* byte array. This uses a resizable int array for speed and simplicity. If
* in the future the array resizing or linear search are performance issues, we
* could try using an IdentityHashMap instead.
*
* @author Mark Hayes
*/
class VisitedObjects {
/*
* Offset to indicate that the visited object is stored in the primary key
* byte array.
*/
static final int PRI_KEY_VISITED_OFFSET = Integer.MAX_VALUE - 1;
/* Used by RecordOutput to prevent illegal nested references. */
static final int PROHIBIT_REF_OFFSET = Integer.MAX_VALUE - 2;
/* Used by RecordInput to prevent illegal nested references. */
static final Object PROHIBIT_REF_OBJECT = new Object();
static final String PROHIBIT_NESTED_REF_MSG =
"Cannot embed a reference to a proxied object in the proxy; for " +
"example, a collection may not be an element of the collection " +
"because collections are proxied";
private static final int INIT_LEN = 50;
private Object[] objects;
private int[] offsets;
private int nextIndex;
/**
* Creates an empty set.
*/
VisitedObjects() {
objects = new Object[INIT_LEN];
offsets = new int[INIT_LEN];
nextIndex = 0;
}
/**
* Adds a visited object and offset, growing the visited arrays as needed.
* @return the index of the new slot.
*/
int add(Object o, int offset) {
int i = nextIndex;
nextIndex += 1;
if (nextIndex > objects.length) {
growVisitedArrays();
}
objects[i] = o;
offsets[i] = offset;
return i;
}
/**
* Sets the object for an existing slot index.
*/
void setObject(int index, Object o) {
objects[index] = o;
}
/**
* Sets the offset for an existing slot index.
*/
void setOffset(int index, int offset) {
offsets[index] = offset;
}
/**
* Returns the offset for a visited object, or -1 if never visited.
*/
int getOffset(Object o) {
for (int i = 0; i < nextIndex; i += 1) {
if (objects[i] == o) {
return offsets[i];
}
}
return -1;
}
/**
* Returns the visited object for a given offset, or null if never visited.
*/
Object getObject(int offset) {
for (int i = 0; i < nextIndex; i += 1) {
if (offsets[i] == offset) {
return objects[i];
}
}
return null;
}
/**
* Replaces a given object in the list. Used when an object is converted
* after adding it to the list.
*/
void replaceObject(Object existing, Object replacement) {
for (int i = nextIndex - 1; i >= 0; i -= 1) {
if (objects[i] == existing) {
objects[i] = replacement;
return;
}
}
assert false;
}
/**
* Doubles the size of the visited arrays.
*/
private void growVisitedArrays() {
int oldLen = objects.length;
int newLen = oldLen * 2;
Object[] newObjects = new Object[newLen];
int[] newOffsets = new int[newLen];
System.arraycopy(objects, 0, newObjects, 0, oldLen);
System.arraycopy(offsets, 0, newOffsets, 0, oldLen);
objects = newObjects;
offsets = newOffsets;
}
}