All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.htmlunit.xpath.xml.dtm.ref.ExpandedNameTable Maven / Gradle / Ivy

There is a newer version: 4.7.0
Show newest version
/*
 * 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.htmlunit.xpath.xml.dtm.ref;

import org.htmlunit.xpath.xml.dtm.DTM;

/**
 * This is a default implementation of a table that manages mappings from expanded names to
 * expandedNameIDs.
 *
 * 

%OPT% The performance of the getExpandedTypeID() method is very important to DTM building. To * get the best performance out of this class, we implement a simple hash algorithm directly into * this class, instead of using the inefficient java.util.Hashtable. The code for the get and put * operations are combined in getExpandedTypeID() method to share the same hash calculation code. We * only need to implement the rehash() interface which is used to expand the hash table. */ public class ExpandedNameTable { /** Array of extended types for this document */ private ExtendedType[] m_extendedTypes; /** The initial size of the m_extendedTypes array */ private static final int m_initialSize = 128; /** Next available extended type */ // %REVIEW% Since this is (should be) always equal // to the length of m_extendedTypes, do we need this? private int m_nextType; // These are all the types prerotated, for caller convenience. public static final int ELEMENT = DTM.ELEMENT_NODE; public static final int ATTRIBUTE = DTM.ATTRIBUTE_NODE; public static final int NAMESPACE = DTM.NAMESPACE_NODE; /** Workspace for lookup. NOT THREAD SAFE! */ final ExtendedType hashET = new ExtendedType(-1, "", ""); /** The array to store the default extended types. */ private static final ExtendedType[] m_defaultExtendedTypes; /** The default load factor of the Hashtable. This is used to calcualte the threshold. */ private static final float m_loadFactor = 0.75f; /** * The initial capacity of the hash table. Use a bigger number to avoid the cost of expanding the * table. */ private static final int m_initialCapacity = 203; /** The capacity of the hash table, i.e. the size of the internal HashEntry array. */ private int m_capacity; /** * The threshold of the hash table, which is equal to capacity * loadFactor. If the number of * entries in the hash table is bigger than the threshold, the hash table needs to be expanded. */ private int m_threshold; /** * The internal array to store the hash entries. Each array member is a slot for a hash bucket. */ private HashEntry[] m_table; /* Init default values */ static { m_defaultExtendedTypes = new ExtendedType[DTM.NTYPES]; for (int i = 0; i < DTM.NTYPES; i++) { m_defaultExtendedTypes[i] = new ExtendedType(i, "", ""); } } /** Create an expanded name table. */ public ExpandedNameTable() { m_capacity = m_initialCapacity; m_threshold = (int) (m_capacity * m_loadFactor); m_table = new HashEntry[m_capacity]; initExtendedTypes(); } /** Initialize the vector of extended types with the basic DOM node types. */ private void initExtendedTypes() { m_extendedTypes = new ExtendedType[m_initialSize]; for (int i = 0; i < DTM.NTYPES; i++) { m_extendedTypes[i] = m_defaultExtendedTypes[i]; m_table[i] = new HashEntry(m_defaultExtendedTypes[i], i, i, null); } m_nextType = DTM.NTYPES; } /** * Given an expanded name represented by namespace, local name and node type, return an ID. If the * expanded-name does not exist in the internal tables, the entry will be created, and the ID will * be returned. Any additional nodes that are created that have this expanded name will use this * ID. * * @param namespace The namespace * @param localName The local name * @param type The node type * @return the expanded-name id of the node. */ public int getExpandedTypeID(String namespace, String localName, final int type) { if (null == namespace) { namespace = ""; } if (null == localName) { localName = ""; } // Calculate the hash code final int hash = type + namespace.hashCode() + localName.hashCode(); // Redefine the hashET object to represent the new expanded name. hashET.redefine(type, namespace, localName, hash); // Calculate the index into the HashEntry table. int index = hash % m_capacity; if (index < 0) { index = -index; } // Look up the expanded name in the hash table. Return the id if // the expanded name is already in the hash table. for (HashEntry e = m_table[index]; e != null; e = e.next) { if (e.hash == hash && e.key.equals(hashET)) { return e.value; } } // Expand the internal HashEntry array if necessary. if (m_nextType > m_threshold) { rehash(); index = hash % m_capacity; if (index < 0) { index = -index; } } // Create a new ExtendedType object final ExtendedType newET = new ExtendedType(type, namespace, localName, hash); // Expand the m_extendedTypes array if necessary. if (m_extendedTypes.length == m_nextType) { final ExtendedType[] newArray = new ExtendedType[m_extendedTypes.length * 2]; System.arraycopy(m_extendedTypes, 0, newArray, 0, m_extendedTypes.length); m_extendedTypes = newArray; } m_extendedTypes[m_nextType] = newET; // Create a new hash entry for the new ExtendedType and put it into // the table. final HashEntry entry = new HashEntry(newET, m_nextType, hash, m_table[index]); m_table[index] = entry; return m_nextType++; } /** * Increases the capacity of and internally reorganizes the hashtable, in order to accommodate and * access its entries more efficiently. This method is called when the number of keys in the * hashtable exceeds this hashtable's capacity and load factor. */ private void rehash() { final int oldCapacity = m_capacity; final HashEntry[] oldTable = m_table; final int newCapacity = 2 * oldCapacity + 1; m_capacity = newCapacity; m_threshold = (int) (newCapacity * m_loadFactor); m_table = new HashEntry[newCapacity]; for (int i = oldCapacity - 1; i >= 0; i--) { for (HashEntry old = oldTable[i]; old != null;) { final HashEntry e = old; old = old.next; int newIndex = e.hash % newCapacity; if (newIndex < 0) { newIndex = -newIndex; } e.next = m_table[newIndex]; m_table[newIndex] = e; } } } /** * Given an expanded-name ID, return the local name ID. * * @param expandedNameID an ID that represents an expanded-name. * @return The id of this local name. */ public final int getLocalNameID(final int expandedNameID) { if (m_extendedTypes[expandedNameID].getLocalName().length() == 0) { return 0; } return expandedNameID; } /** * Given an expanded-name ID, return the namespace URI ID. * * @param expandedNameID an ID that represents an expanded-name. * @return The id of this namespace. */ public final int getNamespaceID(final int expandedNameID) { if (m_extendedTypes[expandedNameID].getNamespace().length() == 0) { return 0; } return expandedNameID; } /** * Given an expanded-name ID, return the local name ID. * * @param expandedNameID an ID that represents an expanded-name. * @return The id of this local name. */ public final short getType(final int expandedNameID) { return (short) m_extendedTypes[expandedNameID].getNodeType(); } /** * Inner class which represents a hash table entry. The field next points to the next entry which * is hashed into the same bucket in the case of "hash collision". */ private static final class HashEntry { final ExtendedType key; final int value; final int hash; HashEntry next; private HashEntry( final ExtendedType key, final int value, final int hash, final HashEntry next) { this.key = key; this.value = value; this.hash = hash; this.next = next; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy