001: // Jericho HTML Parser - Java based library for analysing and manipulating HTML
002: // Version 2.5
003: // Copyright (C) 2007 Martin Jericho
004: // http://jerichohtml.sourceforge.net/
005: //
006: // This library is free software; you can redistribute it and/or
007: // modify it under the terms of either one of the following licences:
008: //
009: // 1. The Eclipse Public License (EPL) version 1.0,
010: // included in this distribution in the file licence-epl-1.0.html
011: // or available at http://www.eclipse.org/legal/epl-v10.html
012: //
013: // 2. The GNU Lesser General Public License (LGPL) version 2.1 or later,
014: // included in this distribution in the file licence-lgpl-2.1.txt
015: // or available at http://www.gnu.org/licenses/lgpl.txt
016: //
017: // This library is distributed on an "AS IS" basis,
018: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
019: // See the individual licence texts for more details.
020:
021: package au.id.jericho.lib.html;
022:
023: import java.util.*;
024:
025: /**
026: * This is an internal class used to efficiently map integers to strings, which is used in the CharacterEntityReference class.
027: */
028: final class IntStringHashMap {
029: private static final int DEFAULT_INITIAL_CAPACITY = 15;
030: private static final float DEFAULT_LOAD_FACTOR = 0.75f;
031: private transient Entry[] entries; // length must always be a power of 2.
032: private transient int size;
033: private int threshold;
034: private float loadFactor;
035: private int bitmask; // always entries.length-1
036:
037: public IntStringHashMap(int initialCapacity, final float loadFactor) {
038: this .loadFactor = loadFactor;
039: int capacity = 1;
040: while (capacity < initialCapacity)
041: capacity <<= 1;
042: threshold = (int) (capacity * loadFactor);
043: entries = new Entry[capacity];
044: bitmask = capacity - 1;
045: }
046:
047: public IntStringHashMap(final int initialCapacity) {
048: this (initialCapacity, DEFAULT_LOAD_FACTOR);
049: }
050:
051: public IntStringHashMap() {
052: this (DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
053: }
054:
055: public int size() {
056: return size;
057: }
058:
059: public boolean isEmpty() {
060: return size == 0;
061: }
062:
063: private int getIndex(final int key) {
064: return key & bitmask; // equivalent to (key%entries.length) but more efficient.
065: }
066:
067: public String get(final int key) {
068: Entry entry = entries[getIndex(key)];
069: while (entry != null) {
070: if (key == entry.key)
071: return entry.value;
072: entry = entry.next;
073: }
074: return null;
075: }
076:
077: private Entry getEntry(final int key) {
078: Entry entry = entries[getIndex(key)];
079: while (entry != null && key != entry.key)
080: entry = entry.next;
081: return entry;
082: }
083:
084: public boolean containsKey(final int key) {
085: return getEntry(key) != null;
086: }
087:
088: public String put(final int key, final String value) {
089: final int index = getIndex(key);
090: for (Entry entry = entries[index]; entry != null; entry = entry.next) {
091: if (key == entry.key) {
092: final String oldValue = entry.value;
093: entry.value = value;
094: return oldValue;
095: }
096: }
097: entries[index] = new Entry(key, value, entries[index]);
098: if (size++ >= threshold)
099: increaseCapacity();
100: return null;
101: }
102:
103: private void increaseCapacity() {
104: final int oldCapacity = entries.length;
105: final Entry[] oldEntries = entries;
106: entries = new Entry[oldCapacity << 1];
107: bitmask = entries.length - 1;
108: for (int i = 0; i < oldCapacity; i++) {
109: Entry entry = oldEntries[i];
110: while (entry != null) {
111: final Entry next = entry.next;
112: final int index = getIndex(entry.key);
113: entry.next = entries[index];
114: entries[index] = entry;
115: entry = next;
116: }
117: }
118: threshold = (int) (entries.length * loadFactor);
119: }
120:
121: public String remove(final int key) {
122: final int index = getIndex(key);
123: Entry previous = null;
124: for (Entry entry = entries[index]; entry != null; entry = (previous = entry).next) {
125: if (key == entry.key) {
126: if (previous == null)
127: entries[index] = entry.next;
128: else
129: previous.next = entry.next;
130: size--;
131: return entry.value;
132: }
133: }
134: return null;
135: }
136:
137: public void clear() {
138: for (int i = bitmask; i >= 0; i--)
139: entries[i] = null;
140: size = 0;
141: }
142:
143: public boolean containsValue(final String value) {
144: if (value == null) {
145: for (int i = bitmask; i >= 0; i--)
146: for (Entry entry = entries[i]; entry != null; entry = entry.next)
147: if (entry.value == null)
148: return true;
149: } else {
150: for (int i = bitmask; i >= 0; i--)
151: for (Entry entry = entries[i]; entry != null; entry = entry.next)
152: if (value.equals(entry.value))
153: return true;
154: }
155: return false;
156: }
157:
158: private static final class Entry {
159: final int key;
160: String value;
161: Entry next;
162:
163: public Entry(final int key, final String value, final Entry next) {
164: this.key = key;
165: this.value = value;
166: this.next = next;
167: }
168: }
169: }
|