1
10
11 package com.sun.xml.bind.v2.util;
12 import java.util.AbstractSet;
13 import java.util.Iterator;
14 import java.util.NoSuchElementException;
15 import java.util.Set;
16 import java.util.Map;
17 import java.util.Collection;
18 import java.util.HashSet;
19
20 import javax.xml.namespace.QName;
21
22 import com.sun.xml.bind.v2.runtime.Name;
23
24
33 public final class QNameMap<V> {
34
37 private static final int DEFAULT_INITIAL_CAPACITY = 16;
38
39
44 private static final int MAXIMUM_CAPACITY = 1 << 30;
45
46
49 transient Entry<V>[] table = new Entry[DEFAULT_INITIAL_CAPACITY];
50
51
54 transient int size;
55
56
61 private int threshold;
62
63
66 private static final float DEFAULT_LOAD_FACTOR = 0.75f;
67
68
69
70
73 private Set<Entry<V>> entrySet = null;
74
75 public QNameMap() {
76 threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
77 table = new Entry[DEFAULT_INITIAL_CAPACITY];
78
79 }
80
81
91 public void put(String namespaceUri,String localname, V value ) {
92
93 assert localname !=null;
94 assert namespaceUri !=null;
95
96 assert localname == localname.intern();
97 assert namespaceUri == namespaceUri.intern();
98
99 int hash = hash(localname);
100 int i = indexFor(hash, table.length);
101
102 for (Entry<V> e = table[i]; e != null; e = e.next) {
103 if (e.hash == hash && localname == e.localName && namespaceUri==e.nsUri) {
104 e.value = value;
105 return;
106 }
107 }
108
109 addEntry(hash, namespaceUri,localname, value, i);
110
111 }
112
113 public void put(QName name, V value ) {
114 put(name.getNamespaceURI(),name.getLocalPart(),value);
115 }
116
117 public void put(Name name, V value ) {
118 put(name.nsUri,name.localName,value);
119 }
120
121
131 public V get( String nsUri, String localPart ) {
132 Entry<V> e = getEntry(nsUri,localPart);
133 if(e==null) return null;
134 else return e.value;
135 }
136
137 public V get( QName name ) {
138 return get(name.getNamespaceURI(),name.getLocalPart());
139 }
140
141
146 public int size() {
147 return size;
148 }
149
150
158 public QNameMap<V> putAll(QNameMap<? extends V> map) {
159 int numKeysToBeAdded = map.size();
160 if (numKeysToBeAdded == 0)
161 return this;
162
163
164 if (numKeysToBeAdded > threshold) {
165 int targetCapacity = numKeysToBeAdded;
166 if (targetCapacity > MAXIMUM_CAPACITY)
167 targetCapacity = MAXIMUM_CAPACITY;
168 int newCapacity = table.length;
169 while (newCapacity < targetCapacity)
170 newCapacity <<= 1;
171 if (newCapacity > table.length)
172 resize(newCapacity);
173 }
174
175 for( Entry<? extends V> e : map.entrySet() )
176 put(e.nsUri,e.localName,e.getValue());
177 return this;
178 }
179
180
181
185 private static int hash(String x) {
186 int h = x.hashCode();
187
188 h += ~(h << 9);
189 h ^= (h >>> 14);
190 h += (h << 4);
191 h ^= (h >>> 10);
192 return h;
193 }
194
195
198 private static int indexFor(int h, int length) {
199 return h & (length-1);
200 }
201
202
208 private void addEntry(int hash, String nsUri, String localName, V value, int bucketIndex) {
209 Entry<V> e = table[bucketIndex];
210 table[bucketIndex] = new Entry<V>(hash, nsUri, localName, value, e);
211 if (size++ >= threshold)
212 resize(2 * table.length);
213 }
214
215
216
221 private void resize(int newCapacity) {
222 Entry[] oldTable = table;
223 int oldCapacity = oldTable.length;
224 if (oldCapacity == MAXIMUM_CAPACITY) {
225 threshold = Integer.MAX_VALUE;
226 return;
227 }
228
229 Entry[] newTable = new Entry[newCapacity];
230 transfer(newTable);
231 table = newTable;
232 threshold = newCapacity;
233 }
234
235
238 private void transfer(Entry<V>[] newTable) {
239 Entry<V>[] src = table;
240 int newCapacity = newTable.length;
241 for (int j = 0; j < src.length; j++) {
242 Entry<V> e = src[j];
243 if (e != null) {
244 src[j] = null;
245 do {
246 Entry<V> next = e.next;
247 int i = indexFor(e.hash, newCapacity);
248 e.next = newTable[i];
249 newTable[i] = e;
250 e = next;
251 } while (e != null);
252 }
253 }
254 }
255
256
263 public Entry<V> getOne() {
264 for( Entry<V> e : table ) {
265 if(e!=null)
266 return e;
267 }
268 return null;
269 }
270
271 public Collection<QName> keySet() {
272 Set<QName> r = new HashSet<QName>();
273 for (Entry<V> e : entrySet()) {
274 r.add(e.createQName());
275 }
276 return r;
277 }
278
279 private abstract class HashIterator<E> implements Iterator<E> {
280 Entry<V> next;
281 int index;
282
283 HashIterator() {
284 Entry<V>[] t = table;
285 int i = t.length;
286 Entry<V> n = null;
287 if (size != 0) {
288 while (i > 0 && (n = t[--i]) == null) {}
289 }
290 next = n;
291 index = i;
292 }
293
294 public boolean hasNext() {
295 return next != null;
296 }
297
298 Entry<V> nextEntry() {
299 Entry<V> e = next;
300 if (e == null)
301 throw new NoSuchElementException();
302
303 Entry<V> n = e.next;
304 Entry<V>[] t = table;
305 int i = index;
306 while (n == null && i > 0)
307 n = t[--i];
308 index = i;
309 next = n;
310 return e;
311 }
312
313 public void remove() {
314 throw new UnsupportedOperationException();
315 }
316 }
317
318 public boolean containsKey(String nsUri,String localName) {
319 return getEntry(nsUri,localName)!=null;
320 }
321
322
323
326 public boolean isEmpty() {
327 return size == 0;
328 }
329
330
331 public static final class Entry<V> {
332
333 public final String nsUri;
334
335
336 public final String localName;
337
338 V value;
339 final int hash;
340 Entry<V> next;
341
342
345 Entry(int h, String nsUri, String localName, V v, Entry<V> n) {
346 value = v;
347 next = n;
348 this.nsUri = nsUri;
349 this.localName = localName;
350 hash = h;
351 }
352
353
356 public QName createQName() {
357 return new QName(nsUri,localName);
358 }
359
360 public V getValue() {
361 return value;
362 }
363
364 public V setValue(V newValue) {
365 V oldValue = value;
366 value = newValue;
367 return oldValue;
368 }
369
370 @Override
371 public boolean equals(Object o) {
372 if (!(o instanceof Entry))
373 return false;
374 Entry e = (Entry)o;
375 String k1 = nsUri;
376 String k2 = e.nsUri;
377 String k3 = localName;
378 String k4 = e.localName;
379 if (k1 == k2 || (k1 != null && k1.equals(k2)) &&
380 (k3 == k4 ||(k3 !=null && k3.equals(k4)))) {
381 Object v1 = getValue();
382 Object v2 = e.getValue();
383 if (v1 == v2 || (v1 != null && v1.equals(v2)))
384 return true;
385 }
386 return false;
387 }
388
389 @Override
390 public int hashCode() {
391 return ( localName.hashCode()) ^
392 (value==null ? 0 : value.hashCode());
393 }
394
395 @Override
396 public String toString() {
397 return '"'+nsUri +"\",\"" +localName + "\"=" + getValue();
398 }
399 }
400
401 public Set<Entry<V>> entrySet() {
402 Set<Entry<V>> es = entrySet;
403 return es != null ? es : (entrySet = new EntrySet());
404 }
405
406 private Iterator<Entry<V>> newEntryIterator() {
407 return new EntryIterator();
408 }
409
410 private class EntryIterator extends HashIterator<Entry<V>> {
411 public Entry<V> next() {
412 return nextEntry();
413 }
414 }
415 private class EntrySet extends AbstractSet<Entry<V>> {
416 public Iterator<Entry<V>> iterator() {
417 return newEntryIterator();
418 }
419 @Override
420 public boolean contains(Object o) {
421 if (!(o instanceof Entry))
422 return false;
423 Entry<V> e = (Entry<V>) o;
424 Entry<V> candidate = getEntry(e.nsUri,e.localName);
425 return candidate != null && candidate.equals(e);
426 }
427 @Override
428 public boolean remove(Object o) {
429 throw new UnsupportedOperationException();
430 }
431 public int size() {
432 return size;
433 }
434 }
435
436 private Entry<V> getEntry(String nsUri,String localName) {
437
438 assert nsUri==nsUri.intern();
439 assert localName==localName.intern();
440
441 int hash = hash(localName);
442 int i = indexFor(hash, table.length);
443 Entry<V> e = table[i];
444 while (e != null && !(localName == e.localName && nsUri == e.nsUri))
445 e = e.next;
446 return e;
447 }
448
449 @Override
450 public String toString() {
451 StringBuilder buf = new StringBuilder();
452 buf.append('{');
453
454 for( Entry<V> e : entrySet() ) {
455 if(buf.length()>1)
456 buf.append(',');
457 buf.append('[');
458 buf.append(e);
459 buf.append(']');
460 }
461
462 buf.append('}');
463 return buf.toString();
464 }
465 }
466