001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: VisitedObjects.java,v 1.9.2.3 2008/01/07 15:14:20 cwl Exp $
007: */
008:
009: package com.sleepycat.persist.impl;
010:
011: /**
012: * Keeps track of a set of visited objects and their corresponding offset in a
013: * byte array. This uses a resizable int array for speed and simplicity. If
014: * in the future the array resizing or linear search are performance issues, we
015: * could try using an IdentityHashMap instead.
016: *
017: * @author Mark Hayes
018: */
019: class VisitedObjects {
020:
021: /*
022: * Offset to indicate that the visited object is stored in the primary key
023: * byte array.
024: */
025: static final int PRI_KEY_VISITED_OFFSET = Integer.MAX_VALUE - 1;
026:
027: /* Used by RecordOutput to prevent illegal nested references. */
028: static final int PROHIBIT_REF_OFFSET = Integer.MAX_VALUE - 2;
029:
030: /* Used by RecordInput to prevent illegal nested references. */
031: static final Object PROHIBIT_REF_OBJECT = new Object();
032:
033: static final String PROHIBIT_NESTED_REF_MSG = "Cannot embed a reference to a proxied object in the proxy; for "
034: + "example, a collection may not be an element of the collection "
035: + "because collections are proxied";
036:
037: private static final int INIT_LEN = 50;
038:
039: private Object[] objects;
040: private int[] offsets;
041: private int nextIndex;
042:
043: /**
044: * Creates an empty set.
045: */
046: VisitedObjects() {
047: objects = new Object[INIT_LEN];
048: offsets = new int[INIT_LEN];
049: nextIndex = 0;
050: }
051:
052: /**
053: * Adds a visited object and offset, growing the visited arrays as needed.
054: * @return the index of the new slot.
055: */
056: int add(Object o, int offset) {
057:
058: int i = nextIndex;
059: nextIndex += 1;
060: if (nextIndex > objects.length) {
061: growVisitedArrays();
062: }
063: objects[i] = o;
064: offsets[i] = offset;
065: return i;
066: }
067:
068: /**
069: * Sets the object for an existing slot index.
070: */
071: void setObject(int index, Object o) {
072: objects[index] = o;
073: }
074:
075: /**
076: * Sets the offset for an existing slot index.
077: */
078: void setOffset(int index, int offset) {
079: offsets[index] = offset;
080: }
081:
082: /**
083: * Returns the offset for a visited object, or -1 if never visited.
084: */
085: int getOffset(Object o) {
086: for (int i = 0; i < nextIndex; i += 1) {
087: if (objects[i] == o) {
088: return offsets[i];
089: }
090: }
091: return -1;
092: }
093:
094: /**
095: * Returns the visited object for a given offset, or null if never visited.
096: */
097: Object getObject(int offset) {
098: for (int i = 0; i < nextIndex; i += 1) {
099: if (offsets[i] == offset) {
100: return objects[i];
101: }
102: }
103: return null;
104: }
105:
106: /**
107: * Replaces a given object in the list. Used when an object is converted
108: * after adding it to the list.
109: */
110: void replaceObject(Object existing, Object replacement) {
111: for (int i = nextIndex - 1; i >= 0; i -= 1) {
112: if (objects[i] == existing) {
113: objects[i] = replacement;
114: return;
115: }
116: }
117: assert false;
118: }
119:
120: /**
121: * Doubles the size of the visited arrays.
122: */
123: private void growVisitedArrays() {
124:
125: int oldLen = objects.length;
126: int newLen = oldLen * 2;
127:
128: Object[] newObjects = new Object[newLen];
129: int[] newOffsets = new int[newLen];
130:
131: System.arraycopy(objects, 0, newObjects, 0, oldLen);
132: System.arraycopy(offsets, 0, newOffsets, 0, oldLen);
133:
134: objects = newObjects;
135: offsets = newOffsets;
136: }
137: }
|