blob: d1fdfe31a59f5ca08275f9d9f25a01560ba82d51 [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999,2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xerces" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, International
* Business Machines, Inc., http://www.apache.org. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xml.utils;
// %REVIEW% Should this be based on SuballocatedIntVector instead?
// (Unclear. Pools will rarely be huge. But if they ever are...)
import org.apache.xml.utils.IntVector;
import java.util.Vector;
/** <p>SparseVector can be thought of as a replacement for
* Hashtable, using int-value hashcodes/keys directly rather than requiring
* that they be objectified as Integers.
* (A standard Hashtable is relatively
* inefficient at manipulating primitives as either keys or values.)</p>
*
* Note similarity to SparseVector, though that assigns its own keys
* (allowing it to use internal position as an implied additional column)
* and puts heavier emphasis on bidirectional mapping.
*
* <p>Design Priorities:
* <li>Index-to-Object lookup speed is critical.</li>
* <li>Object-to-index lookup speed is not.</li>
* <li>Threadsafety is not guaranteed at this level.
* Enforce that in the application if needed.</li>
* <li>Storage efficiency is a major issue; that's why we're using
* a sparse vector rather than a standard one.</li>
* <li>I'm assuming a relatively small number of values will be stored;
* the current primary use for this is xsi:type overrides in XNI2DTM,
* and it is hoped these will be infrequent. To make this more general
* it would need to be adaptive to size demands, as is Java's Hashtable.
* </li>
* </ul>
* </p>
*
* Status: Not unit-tested.
* */
public class SparseVector
{
Vector m_values;
IntVector m_keys;
static final int HASHPRIME=101;
int[] m_hashStart=new int[HASHPRIME];
IntVector m_hashChain;
static final int NULL=-1;
public SparseVector()
{
m_values=new Vector();
m_keys=new IntVector();
m_hashChain=new IntVector(512);
removeAllElements();
}
public void removeAllElements()
{
m_values.removeAllElements();
m_keys.removeAllElements();
for(int i=0;i<HASHPRIME;++i)
m_hashStart[i]=NULL;
m_hashChain.removeAllElements();
}
/**
* @param value to be stored
* @param index to store it at
* @return previous value at that index (may be null), or null if none.
* */
public Object setElementAt(Object value,int index)
{
return maybeSetElementAt(value,index,true);
}
/**
* @param index to retrieve
* @return current value at that index (may be null), or null if none.
* */
public Object elementAt(int index)
{
return maybeSetElementAt(null,index,false);
}
protected Object maybeSetElementAt(Object value, int index,boolean set)
{
int hashslot=index%HASHPRIME;
if(hashslot<0) hashslot=-hashslot;
// Is it one we already know?
int hashlast=m_hashStart[hashslot];
int hashcandidate=hashlast;
while(hashcandidate!=NULL)
{
if(m_keys.elementAt(hashcandidate)==index)
{
// Found existing; update it
Object ret=m_values.elementAt(hashcandidate);
if(set)
m_values.setElementAt(value,hashcandidate);
return ret;
}
hashlast=hashcandidate;
hashcandidate=m_hashChain.elementAt(hashcandidate);
}
if(set)
{
// New value. Add to tables.
int newIndex=m_values.size();
m_values.addElement(value);
m_keys.addElement(index);
m_hashChain.addElement(NULL); // Initialize to no-following-same-hash
if(hashlast==NULL) // First for this hash
m_hashStart[hashslot]=newIndex;
else // Link from previous with same hash
m_hashChain.setElementAt(newIndex,hashlast);
}
return null;
}
}