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