1   /*
2    *  HashMapLong.java
3    *
4    *  Copyright (c) 2001, The University of Sheffield.
5    *
6    *  This file is part of GATE (see http://gate.ac.uk/), and is free
7    *  software, licenced under the GNU Library General Public License,
8    *  Version 2, June 1991 (in the distribution as file licence.html,
9    *  and also available at http://gate.ac.uk/gate/licence.html).
10   *
11   *  D.Ognyanoff, 15/Nov/2001
12   *
13   */
14  
15   package gate.util;
16  
17  /**
18   * simple cut-off version of the hashmap with native long's as keys
19   * only get,put and isEmpty methods are implemented().
20   * This map is used in very private case in the SimpleSortedSet class.
21   * The main purpose is to optimize the speed of the SinglePhaseTransducer.transduce()
22   */
23  
24  public class HashMapLong {
25  
26      /**
27       * The hash table data.
28       */
29      private transient Entry table[];
30  
31      private transient int count;
32  
33      private int threshold;
34  
35      private float loadFactor;
36  
37      /**
38       * the main constructor. see the HashMap constructor for description
39       */
40      public HashMapLong(int initialCapacity, float loadFactor) {
41          if (initialCapacity < 0)
42              throw new IllegalArgumentException("Illegal Initial Capacity: "+
43                                                 initialCapacity);
44          if (loadFactor <= 0 || Float.isNaN(loadFactor))
45              throw new IllegalArgumentException("Illegal Load factor: "+
46                                                 loadFactor);
47          if (initialCapacity==0)
48              initialCapacity = 1;
49          this.loadFactor = loadFactor;
50          table = new Entry[initialCapacity];
51          threshold = (int)(initialCapacity * loadFactor);
52      }
53  
54      public HashMapLong(int initialCapacity) {
55          this(initialCapacity, 0.75f);
56      }
57  
58      public HashMapLong() {
59          this(11, 0.75f);
60      }
61  
62      public boolean isEmpty() {
63          return count == 0;
64      }
65  
66      public Object get(long key) {
67          Entry tab[] = table;
68      int hash = (int)(key ^ (key >> 32));
69      int index = (hash & 0x7FFFFFFF) % tab.length;
70      for (Entry e = tab[index]; e != null; e = e.next)
71          if ((e.hash == hash) && key == e.key)
72              return e.value;
73  
74          return null;
75      }
76  
77      /**
78       * Rehashes the contents of this map into a new <tt>HashMapLong</tt> instance
79       * with a larger capacity. This method is called automatically when the
80       * number of keys in this map exceeds its capacity and load factor.
81       */
82      private void rehash() {
83        int oldCapacity = table.length;
84        Entry oldMap[] = table;
85  
86        int newCapacity = oldCapacity * 2 + 1;
87        Entry newMap[] = new Entry[newCapacity];
88  
89        threshold = (int) (newCapacity * loadFactor);
90        table = newMap;
91  
92        for (int i = oldCapacity; i-- > 0; ) {
93          for (Entry old = oldMap[i]; old != null; ) {
94            Entry e = old;
95            old = old.next;
96  
97            int index = (e.hash & 0x7FFFFFFF) % newCapacity;
98            e.next = newMap[index];
99            newMap[index] = e;
100         }
101       }
102     }
103 
104     public Object put(long key, Object value) {
105         // Makes sure the key is not already in the HashMapLong.
106         Entry tab[] = table;
107         int hash = (int)(key ^ (key >> 32));
108         int index = (hash & 0x7FFFFFFF) % tab.length;
109 
110         for (Entry e = tab[index] ; e != null ; e = e.next) {
111             if ((e.hash == hash) && key == e.key) {
112                 Object old = e.value;
113                 e.value = value;
114                 return old;
115             }
116         }
117 
118         if (count >= threshold) {
119             // Rehash the table if the threshold is exceeded
120             rehash();
121 
122                 tab = table;
123                 index = (hash & 0x7FFFFFFF) % tab.length;
124         }
125 
126         // Creates the new entry.
127         Entry e = new Entry(hash, key, value, tab[index]);
128         tab[index] = e;
129         count++;
130         return null;
131     }
132 
133     /**
134      * HashMapLong collision list entry.
135      */
136     private static class Entry {
137         int hash;
138         long key;
139         Object value;
140         Entry next;
141 
142         Entry(int hash, long key, Object value, Entry next) {
143             this.hash = hash;
144             this.key = key;
145             this.value = value;
146             this.next = next;
147         }
148     } //Entry
149 } // hasnMapLong
150