FileDocCategorySizeDatePackage
SoftReferenceSymbolTable.javaAPI DocApache Xerces 3.0.113642Fri Sep 14 20:33:54 BST 2007org.apache.xerces.util

SoftReferenceSymbolTable

public class SoftReferenceSymbolTable extends SymbolTable
This symbol table uses SoftReferences to its String entries, which means that table entries that have no references to them can be garbage collected when memory is needed. Thus, in documents with very very large numbers of unique strings, using this SymbolTable will prevent an out of memory error from occuring.
see
SymbolTable
author
Peter McCracken, IBM
version
$Id: SoftReferenceSymbolTable.java 496158 2007-01-14 21:27:15Z mrglavas $

Fields Summary
protected SREntry[]
fBuckets
private final ReferenceQueue
fReferenceQueue
Constructors Summary
public SoftReferenceSymbolTable(int initialCapacity, float loadFactor)
Constructs a new, empty SymbolTable with the specified initial capacity and the specified load factor.

param
initialCapacity the initial capacity of the SymbolTable.
param
loadFactor the load factor of the SymbolTable.
throws
IllegalArgumentException if the initial capacity is less than zero, or if the load factor is nonpositive.

    
    //
    // Constructors
    //
    
                                                                                              
         
        /*
         * Not calling super() because we don't want to initialize the Entry buckets
         * used by the base class.
         */
        if (initialCapacity < 0) {
            throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
        }
        
        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
            throw new IllegalArgumentException("Illegal Load: " + loadFactor);
        }
        
        if (initialCapacity == 0) {
            initialCapacity = 1;
        }
        
        fLoadFactor = loadFactor;
        fTableSize = initialCapacity;
        fBuckets = new SREntry[fTableSize];
        fThreshold = (int)(fTableSize * loadFactor);
        fCount = 0;

        fReferenceQueue = new ReferenceQueue();
    
public SoftReferenceSymbolTable(int initialCapacity)
Constructs a new, empty SymbolTable with the specified initial capacity and default load factor, which is 0.75.

param
initialCapacity the initial capacity of the hashtable.
throws
IllegalArgumentException if the initial capacity is less than zero.

        this(initialCapacity, 0.75f);
    
public SoftReferenceSymbolTable()
Constructs a new, empty SymbolTable with a default initial capacity (101) and load factor, which is 0.75.

        this(TABLE_SIZE, 0.75f);
    
Methods Summary
public java.lang.StringaddSymbol(java.lang.String symbol)
Adds the specified symbol to the symbol table and returns a reference to the unique symbol. If the symbol already exists, the previous symbol reference is returned instead, in order guarantee that symbol references remain unique.

param
symbol The new symbol.

        clean();
        // search for identical symbol
        int bucket = hash(symbol) % fTableSize;
        for (SREntry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
            SREntryData data = (SREntryData)entry.get();
            if (data == null) {
                continue;
            }
            if (data.symbol.equals(symbol)) {
                return data.symbol;
            }
        }
        
        if (fCount >= fThreshold) {
            // Rehash the table if the threshold is exceeded
            rehash();
            bucket = hash(symbol) % fTableSize;
        } 
        
        // add new entry
        symbol = symbol.intern();
        SREntry entry = new SREntry(symbol, fBuckets[bucket], bucket, fReferenceQueue);
        fBuckets[bucket] = entry;
        ++fCount;
        return symbol;
    
public java.lang.StringaddSymbol(char[] buffer, int offset, int length)
Adds the specified symbol to the symbol table and returns a reference to the unique symbol. If the symbol already exists, the previous symbol reference is returned instead, in order guarantee that symbol references remain unique.

param
buffer The buffer containing the new symbol.
param
offset The offset into the buffer of the new symbol.
param
length The length of the new symbol in the buffer.

        clean();
        // search for identical symbol
        int bucket = hash(buffer, offset, length) % fTableSize;
        OUTER: for (SREntry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
            SREntryData data = (SREntryData)entry.get();
            if (data == null) {
                continue;
            }
            if (length == data.characters.length) {
                for (int i = 0; i < length; i++) {
                    if (buffer[offset + i] != data.characters[i]) {
                        continue OUTER;
                    }
                }
                return data.symbol;
            }
        }
        
        if (fCount >= fThreshold) {
            // Rehash the table if the threshold is exceeded
            rehash();
            bucket = hash(buffer, offset, length) % fTableSize;
        } 
        
        // add new entry
        String symbol = new String(buffer, offset, length).intern();
        SREntry entry = new SREntry(symbol, buffer, offset, length, fBuckets[bucket], bucket, fReferenceQueue);
        fBuckets[bucket] = entry;
        ++fCount;
        return symbol;
    
private voidclean()
Removes stale symbols from the table.

        SREntry entry = (SREntry)fReferenceQueue.poll();
        while (entry != null) {
            removeEntry(entry);
            entry = (SREntry)fReferenceQueue.poll();
        }
    
public booleancontainsSymbol(java.lang.String symbol)
Returns true if the symbol table already contains the specified symbol.

param
symbol The symbol to look for.


        // search for identical symbol
        int bucket = hash(symbol) % fTableSize;
        int length = symbol.length();
        OUTER: for (SREntry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
            SREntryData data = (SREntryData)entry.get();
            if (data == null) {
                continue;
            }
            if (length == data.characters.length) {
                for (int i = 0; i < length; i++) {
                    if (symbol.charAt(i) != data.characters[i]) {
                        continue OUTER;
                    }
                }
                return true;
            }
        }

        return false;

    
public booleancontainsSymbol(char[] buffer, int offset, int length)
Returns true if the symbol table already contains the specified symbol.

param
buffer The buffer containing the symbol to look for.
param
offset The offset into the buffer.
param
length The length of the symbol in the buffer.


        // search for identical symbol
        int bucket = hash(buffer, offset, length) % fTableSize;
        OUTER: for (SREntry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
            SREntryData data = (SREntryData)entry.get();
            if (data == null) {
                continue;
            }
            if (length == data.characters.length) {
                for (int i = 0; i < length; i++) {
                    if (buffer[offset + i] != data.characters[i]) {
                        continue OUTER;
                    }
                }
                return true;
            }
        }

        return false;

    
protected voidrehash()
Increases the capacity of and internally reorganizes this SymbolTable, in order to accommodate and access its entries more efficiently. This method is called automatically when the number of keys in the SymbolTable exceeds this hashtable's capacity and load factor.


        int oldCapacity = fBuckets.length;
        SREntry[] oldTable = fBuckets;

        int newCapacity = oldCapacity * 2 + 1;
        SREntry[] newTable = new SREntry[newCapacity];

        fThreshold = (int)(newCapacity * fLoadFactor);
        fBuckets = newTable;
        fTableSize = fBuckets.length;

        for (int i = oldCapacity ; i-- > 0 ;) {
            for (SREntry old = oldTable[i] ; old != null ; ) {
                SREntry e = old;
                old = old.next;

                SREntryData data = (SREntryData)e.get();
                if (data != null) {
                    int index = hash(data.characters, 0, data.characters.length) % newCapacity;
                    if (newTable[index] != null) {
                        newTable[index].prev = e;
                    }
                    e.next = newTable[index];
                    newTable[index] = e;
                }
                else {
                    fCount--;
                }
            }
        }
    
private voidremoveEntry(org.apache.xerces.util.SoftReferenceSymbolTable$SREntry entry)

        if (entry.next != null) {
            entry.next.prev = entry.prev;
        }
        if (entry.prev != null) {
            entry.prev.next = entry.next;
        }
        else {
            fBuckets[entry.bucket] = entry.next;
        }
        fCount--;