org.apache.xerces.impl.xs.IDContext Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.xerces.impl.xs;
/**
* XML Schema 1.1 - ID value handling
*
* @xerces.internal
*
* @version $Id: IDContext.java 1175668 2011-09-26 04:30:44Z mrglavas $
*/
final class IDContext {
private static final int INITIAL_MATCH_SIZE = 16;
/** Table that stores the ID depth matched for a given element depth */
private int[] fElementIDTable = new int[INITIAL_MATCH_SIZE];
/** ID Depth */
private int fIDDepth = 0;
/**
* Current ID Scope
*
* Represents the id matched to current element (attribute handling) or to
* its parent (simple content handling)
*/
private int fIDScope = 0;
/** Current Element scope
*
* Represents the current element depth (attribute handling) or its parent
* (simple content handling)
*/
private int fElementScope = -1;
/** Element depth */
private int fElementDepth = 0;
// ID Mapping Table
/** Default table size. */
final private int fTableSize = 101;
/** Buckets. */
final private Entry[] fBuckets;
/** Number of elements. */
private int fNum = 0;
IDContext() {
fBuckets = new Entry[fTableSize];
}
void clear() {
if (fNum > 0) {
for (int i=0; i 0) {
fIDScope = fElementIDTable[--fElementScope];
}
else {
fElementScope = fIDScope = -1;
}
}
void popContext() {
--fElementDepth;
}
void pushContext() {
if (fElementDepth == fElementIDTable.length) {
resizeElementDepthIDTable();
}
fElementScope = fElementDepth++;
fElementIDTable[fElementScope] = fIDScope = 0;
}
private void resizeElementDepthIDTable() {
final int newSize = fElementDepth << 1;
final int[] newArray = new int[newSize];
System.arraycopy(fElementIDTable, 0, newArray, 0, fElementDepth);
fElementIDTable = newArray;
}
boolean isDeclared(String id) {
final int idDepth = get(id);
// did not find a match in the table
if (idDepth == -1) {
// root element with simple content of type ID is invalid
return fIDScope == -1;
}
return idDepth != fIDScope;
}
boolean containsID(String name) {
int bucket = (name.hashCode() & 0x7FFFFFFF) % fTableSize;
for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
if (name.equals(entry.key))
return true;
}
return false;
}
private int get(String key) {
int bucket = (key.hashCode() & 0x7FFFFFFF) % fTableSize;
for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
if (key.equals(entry.key))
return entry.value;
}
return -1;
}
void add(String id) {
final int bucket = (id.hashCode() & 0x7FFFFFFF) % fTableSize;
Entry entry = search(id, bucket);
if (entry == null) {
if (fElementIDTable[fElementScope] == 0) {
fElementIDTable[fElementScope] = fIDScope = ++fIDDepth;
}
entry = new Entry(id, fIDScope, fBuckets[bucket]);
fBuckets[bucket] = entry;
fNum++;
}
}
private Entry search(String id, int bucket) {
for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
if (id.equals(entry.key)) {
return entry;
}
}
return null;
}
/**
* This class is a key table entry. Each entry acts as a node
* in a linked list.
*/
private static final class Entry {
/** key/value */
public String key;
public int value;
/** The next entry. */
public Entry next;
public Entry() {
key = null;
value = -1;
next = null;
}
public Entry(String key, int value, Entry next) {
this.key = key;
this.value = value;
this.next = next;
}
} // entry
}