View Javadoc
1   /*
2    * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   *
25   * THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
26   */
27  
28  package com.sun.xml.internal.fastinfoset.util;
29  
30  import com.sun.xml.internal.fastinfoset.CommonResourceBundle;
31  
32  public class StringIntMap extends KeyIntMap {
33      protected static final Entry NULL_ENTRY = new Entry(null, 0, -1, null);
34  
35      protected StringIntMap _readOnlyMap;
36  
37      protected static class Entry extends BaseEntry {
38          final String _key;
39          Entry _next;
40  
41          public Entry(String key, int hash, int value, Entry next) {
42              super(hash, value);
43              _key = key;
44              _next = next;
45          }
46      }
47  
48      protected Entry _lastEntry = NULL_ENTRY;
49  
50      protected Entry[] _table;
51  
52      protected int _index;
53  
54      // Total character count of Map
55      protected int _totalCharacterCount;
56  
57      public StringIntMap(int initialCapacity, float loadFactor) {
58          super(initialCapacity, loadFactor);
59  
60          _table = new Entry[_capacity];
61      }
62  
63      public StringIntMap(int initialCapacity) {
64          this(initialCapacity, DEFAULT_LOAD_FACTOR);
65      }
66  
67      public StringIntMap() {
68          this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
69      }
70  
71      public void clear() {
72          for (int i = 0; i < _table.length; i++) {
73              _table[i] = null;
74          }
75          _lastEntry = NULL_ENTRY;
76          _size = 0;
77          _index = _readOnlyMapSize;
78          _totalCharacterCount = 0;
79      }
80  
81      public void setReadOnlyMap(KeyIntMap readOnlyMap, boolean clear) {
82          if (!(readOnlyMap instanceof StringIntMap)) {
83              throw new IllegalArgumentException(CommonResourceBundle.getInstance().
84                      getString("message.illegalClass", new Object[]{readOnlyMap}));
85          }
86  
87          setReadOnlyMap((StringIntMap)readOnlyMap, clear);
88      }
89  
90      public final void setReadOnlyMap(StringIntMap readOnlyMap, boolean clear) {
91          _readOnlyMap = readOnlyMap;
92          if (_readOnlyMap != null) {
93              _readOnlyMapSize = _readOnlyMap.size();
94              _index = _size + _readOnlyMapSize;
95  
96              if (clear) {
97                  clear();
98              }
99          }  else {
100             _readOnlyMapSize = 0;
101             _index = _size;
102         }
103     }
104 
105     public final int getNextIndex() {
106         return _index++;
107     }
108 
109     public final int getIndex() {
110         return _index;
111     }
112 
113     public final int obtainIndex(String key) {
114         final int hash = hashHash(key.hashCode());
115 
116         if (_readOnlyMap != null) {
117             final int index = _readOnlyMap.get(key, hash);
118             if (index != -1) {
119                 return index;
120             }
121         }
122 
123         final int tableIndex = indexFor(hash, _table.length);
124         for (Entry e = _table[tableIndex]; e != null; e = e._next) {
125             if (e._hash == hash && eq(key, e._key)) {
126                 return e._value;
127             }
128         }
129 
130         addEntry(key, hash, tableIndex);
131         return NOT_PRESENT;
132     }
133 
134     public final void add(String key) {
135         final int hash = hashHash(key.hashCode());
136         final int tableIndex = indexFor(hash, _table.length);
137         addEntry(key, hash, tableIndex);
138     }
139 
140     public final int get(String key) {
141         if (key == _lastEntry._key)
142             return _lastEntry._value;
143 
144         return get(key, hashHash(key.hashCode()));
145     }
146 
147     public final int getTotalCharacterCount() {
148         return _totalCharacterCount;
149     }
150 
151     private final int get(String key, int hash) {
152         if (_readOnlyMap != null) {
153             final int i = _readOnlyMap.get(key, hash);
154             if (i != -1) {
155                 return i;
156             }
157         }
158 
159         final int tableIndex = indexFor(hash, _table.length);
160         for (Entry e = _table[tableIndex]; e != null; e = e._next) {
161             if (e._hash == hash && eq(key, e._key)) {
162                 _lastEntry = e;
163                 return e._value;
164             }
165         }
166 
167         return NOT_PRESENT;
168     }
169 
170 
171     private final void addEntry(String key, int hash, int bucketIndex) {
172         Entry e = _table[bucketIndex];
173         _table[bucketIndex] = new Entry(key, hash, _index++, e);
174         _totalCharacterCount += key.length();
175         if (_size++ >= _threshold) {
176             resize(2 * _table.length);
177         }
178     }
179 
180     protected final void resize(int newCapacity) {
181         _capacity = newCapacity;
182         Entry[] oldTable = _table;
183         int oldCapacity = oldTable.length;
184         if (oldCapacity == MAXIMUM_CAPACITY) {
185             _threshold = Integer.MAX_VALUE;
186             return;
187         }
188 
189         Entry[] newTable = new Entry[_capacity];
190         transfer(newTable);
191         _table = newTable;
192         _threshold = (int)(_capacity * _loadFactor);
193     }
194 
195     private final void transfer(Entry[] newTable) {
196         Entry[] src = _table;
197         int newCapacity = newTable.length;
198         for (int j = 0; j < src.length; j++) {
199             Entry e = src[j];
200             if (e != null) {
201                 src[j] = null;
202                 do {
203                     Entry next = e._next;
204                     int i = indexFor(e._hash, newCapacity);
205                     e._next = newTable[i];
206                     newTable[i] = e;
207                     e = next;
208                 } while (e != null);
209             }
210         }
211     }
212 
213     private final boolean eq(String x, String y) {
214         return x == y || x.equals(y);
215     }
216 }