Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

380
LINES

< > BotCompany Repo | #1035172 // CompactHashMap - backup

JavaX fragment (include)

1  
// size:
2  
// 64 bytes for 0 to 1 elements
3  
// 96 bytes for 2 to 4 elements
4  
5  
/*
6  
 * #!
7  
 * Ontopia Engine
8  
 * #-
9  
 * Copyright (C) 2001 - 2013 The Ontopia Project
10  
 * #-
11  
 * Licensed under the Apache License, Version 2.0 (the "License");
12  
 * you may not use this file except in compliance with the License.
13  
 * You may obtain a copy of the License at
14  
 * 
15  
 *      http://www.apache.org/licenses/LICENSE-2.0
16  
 * 
17  
 * Unless required by applicable law or agreed to in writing, software
18  
 * distributed under the License is distributed on an "AS IS" BASIS,
19  
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  
 * See the License for the specific language governing permissions and
21  
 * limitations under the License.
22  
 * !#
23  
 */
24  
25  
sclass CompactHashMap<K, V> extends CompactAbstractMap<K, V> {
26  
  final static int INITIAL_SIZE = 3;
27  
  final static double LOAD_FACTOR = 0.6;
28  
29  
  // This object is used to represent null, should clients use that as
30  
  final static Object nullObject = new Object();
31  
  
32  
  /**
33  
   * When a key is deleted this object is put into the hashtable in
34  
   * its place, so that other entries with the same key (collisions)
35  
   * further down the hashtable are not lost after we delete an object
36  
   * in the collision chain.
37  
   */
38  
  final static Object deletedObject = new Object();
39  
  int elements;
40  
  int freecells;
41  
  O[] table; // key, value, key, value, ...
42  
  //int modCount;
43  
44  
  *() {
45  
    this(INITIAL_SIZE);
46  
  }
47  
48  
  *(int size) {
49  
    table = new Object[(size==0 ? 1 : size)*2];
50  
    elements = 0;
51  
    freecells = tableSize();
52  
    //modCount = 0;
53  
  }
54  
  
55  
  // TODO: allocate smarter
56  
  *(Map<K, V> map) {
57  
    this(0);
58  
    if (map != null) putAll(map);
59  
  }
60  
61  
  // ===== MAP IMPLEMENTATION =============================================
62  
63  
  /**
64  
   * Returns the number of key/value mappings in this map.
65  
   */
66  
  public synchronized int size() {
67  
    return elements;
68  
  }
69  
  
70  
  /**
71  
   * Returns <tt>true</tt> if this map contains no mappings.
72  
   */
73  
  public synchronized boolean isEmpty() {
74  
    return elements == 0;
75  
  }
76  
77  
  /**
78  
   * Removes all key/value mappings in the map.
79  
   */
80  
  public synchronized void clear() {
81  
    elements = 0;
82  
    for (int ix = 0; ix < tableSize(); ix++) {
83  
      key(ix, null);
84  
      value(ix, null);
85  
    }
86  
    freecells = tableSize();
87  
    //modCount++;
88  
  }
89  
  
90  
  /**
91  
   * Returns <tt>true</tt> if this map contains the specified key.
92  
   */
93  
  public synchronized boolean containsKey(Object k) {
94  
    return key(findKeyIndex(k)) != null;
95  
  }
96  
  
97  
  /**
98  
   * Returns <tt>true</tt> if this map contains the specified value.
99  
   */
100  
  public synchronized boolean containsValue(Object v) {
101  
    if (v == null)
102  
      v = (V)nullObject;
103  
104  
    for (int ix = 0; ix < tableSize(); ix++)
105  
      if (value(ix) != null && value(ix).equals(v))
106  
        return true;
107  
108  
    return false;
109  
  }
110  
111  
  /**
112  
   * Returns a read-only set view of the map's keys.
113  
   */
114  
  public synchronized Set<Entry<K, V>> entrySet() {
115  
    throw new UnsupportedOperationException();
116  
  }
117  
118  
  /**
119  
   * Removes the mapping with key k, if there is one, and returns its
120  
   * value, if there is one, and null if there is none.
121  
   */
122  
  public synchronized V remove(Object k) {
123  
    int index = findKeyIndex(k);
124  
125  
    // we found the right position, now do the removal
126  
    if (key(index) != null) {
127  
      // we found the object
128  
129  
      // same problem here as with put
130  
      V v = value(index);
131  
      key(index, deletedObject);
132  
      value(index, deletedObject);
133  
      //modCount++;
134  
      elements--;
135  
      return v;
136  
    } else
137  
      // we did not find the key
138  
      return null;
139  
  }
140  
141  
  /**
142  
   * Adds the specified mapping to this map, returning the old value for
143  
   * the mapping, if there was one.
144  
   */
145  
  public synchronized V put(K k, V v) {
146  
    if (k == null)
147  
      k = (K)nullObject;
148  
149  
    int hash = k.hashCode();
150  
    int index = (hash & 0x7FFFFFFF) % tableSize();
151  
    int offset = 1;
152  
    int deletedix = -1;
153  
    
154  
    // search for the key (continue while !null and !this key)
155  
    while(key(index) != null &&
156  
          !(key(index).hashCode() == hash &&
157  
            key(index).equals(k))) {
158  
159  
      // if there's a deleted mapping here we can put this mapping here,
160  
      // provided it's not in here somewhere else already
161  
      if (key(index) == deletedObject)
162  
        deletedix = index;
163  
      
164  
      index = ((index + offset) & 0x7FFFFFFF) % tableSize();
165  
      offset = offset*2 + 1;
166  
167  
      if (offset == -1)
168  
        offset = 2;
169  
    }
170  
    
171  
    if (key(index) == null) { // wasn't present already
172  
      if (deletedix != -1) // reusing a deleted cell
173  
        index = deletedix;
174  
      else
175  
        freecells--;
176  
177  
      //modCount++;
178  
      elements++;
179  
180  
      key(index, k);
181  
      value(index, v);
182  
      
183  
      // rehash with increased capacity
184  
      if (1 - (freecells / (double) tableSize()) > LOAD_FACTOR)
185  
        rehash(tableSize()*2 + 1);
186  
      return null;
187  
    } else { // was there already
188  
      //modCount++;
189  
      V oldv = value(index);
190  
      value(index, v);
191  
      return oldv;
192  
    }
193  
  }
194  
195  
  /**
196  
   * INTERNAL: Rehashes the hashmap to a bigger size.
197  
   */
198  
  void rehash(int newCapacity) {
199  
    int oldCapacity = tableSize();
200  
    O[] newTable = new Object[newCapacity*2];
201  
202  
    for (int ix = 0; ix < oldCapacity; ix++) {
203  
      Object k = key(ix);
204  
      if (k == null || k == deletedObject)
205  
        continue;
206  
      
207  
      int hash = k.hashCode();
208  
      int index = (hash & 0x7FFFFFFF) % newCapacity;
209  
      int offset = 1;
210  
211  
      // search for the key
212  
      while(newTable[index*2] != null) { // no need to test for duplicates
213  
        index = ((index + offset) & 0x7FFFFFFF) % newCapacity;
214  
        offset = offset*2 + 1;
215  
216  
        if (offset == -1)
217  
          offset = 2;
218  
      }
219  
220  
      newTable[index*2] = k;
221  
      newTable[index*2+1] = value(ix);
222  
    }
223  
224  
    table = newTable;
225  
    freecells = tableSize() - elements;
226  
  }
227  
228  
  /**
229  
   * Returns the value for the key k, if there is one, and null if
230  
   * there is none.
231  
   */
232  
  public synchronized V get(Object k) {
233  
    return value(findKeyIndex(k));
234  
  }
235  
236  
  /**
237  
   * Returns a virtual read-only collection containing all the values
238  
   * in the map.
239  
   */
240  
  public synchronized Collection<V> values() {
241  
    return new ValueCollection();
242  
  }
243  
244  
  /**
245  
   * Returns a virtual read-only set of all the keys in the map.
246  
   */
247  
  public synchronized Set<K> keySet() {
248  
    return new KeySet();
249  
  }
250  
251  
  // --- Internal utilities
252  
253  
  final int findKeyIndex(Object k) {
254  
    if (k == null)
255  
      k = nullObject;
256  
257  
    int hash = k.hashCode();
258  
    int index = (hash & 0x7FFFFFFF) % tableSize();
259  
    int offset = 1;
260  
261  
    // search for the key (continue while !null and !this key)
262  
    while(key(index) != null &&
263  
          !(key(index).hashCode() == hash &&
264  
            key(index).equals(k))) {
265  
      index = ((index + offset) & 0x7FFFFFFF) % tableSize();
266  
      offset = offset*2 + 1;
267  
268  
      if (offset == -1)
269  
        offset = 2;
270  
    }
271  
    return index;
272  
  }
273  
  
274  
  // --- Key set
275  
276  
  class KeySet<K> extends AbstractSet<K> {
277  
    public synchronized int size() {
278  
      return elements;
279  
    }
280  
281  
    public synchronized boolean contains(Object k) {
282  
      return containsKey(k);
283  
    }
284  
285  
    public synchronized Iterator<K> iterator() {
286  
      return new KeyIterator();
287  
    }
288  
  }
289  
290  
  class KeyIterator<K> implements Iterator<K> {
291  
    private int ix;
292  
    
293  
    private KeyIterator() {
294  
      // walk up to first value, so that hasNext() and next() return
295  
      // correct results
296  
      for (; ix < tableSize(); ix++)
297  
        if (value(ix) != null && key(ix) != deletedObject)
298  
          break;
299  
    }
300  
301  
    public synchronized boolean hasNext() {
302  
      return ix < tableSize();
303  
    }
304  
305  
    public synchronized void remove() {
306  
      throw new UnsupportedOperationException("Collection is read-only");
307  
    }
308  
309  
    public synchronized K next() {
310  
      if (ix >= tableSize())
311  
        throw new NoSuchElementException();
312  
      K key = (K) key(ix++);
313  
      
314  
      // walk up to next value
315  
      for (; ix < tableSize(); ix++)
316  
        if (key(ix) != null && key(ix) != deletedObject)
317  
          break;
318  
      
319  
      // ix now either points to next key, or outside array (if no next)
320  
      return key;
321  
    }
322  
  }
323  
  
324  
  // --- Value collection
325  
326  
  class ValueCollection<V> extends AbstractCollection<V> {
327  
    public synchronized int size() {
328  
      return elements;
329  
    }
330  
331  
    public synchronized Iterator<V> iterator() {
332  
      return new ValueIterator();
333  
    }
334  
335  
    public synchronized boolean contains(Object v) {
336  
      return containsValue(v);
337  
    }
338  
  }
339  
340  
  class ValueIterator<V> implements Iterator<V> {
341  
    private int ix;
342  
    
343  
    private ValueIterator() {
344  
      // walk up to first value, so that hasNext() and next() return
345  
      // correct results
346  
      for (; ix < table.length/2; ix++)
347  
        if (value(ix) != null && value(ix) != deletedObject)
348  
          break;
349  
    }
350  
351  
    public synchronized boolean hasNext() {
352  
      return ix < tableSize();
353  
    }
354  
355  
    public synchronized void remove() {
356  
      throw new UnsupportedOperationException("Collection is read-only");
357  
    }
358  
359  
    public synchronized V next() {
360  
      if (ix >= tableSize())
361  
        throw new NoSuchElementException();
362  
      V value = (V) value(ix++);
363  
      
364  
      // walk up to next value
365  
      for (; ix < tableSize(); ix++)
366  
        if (value(ix) != null && value(ix) != deletedObject)
367  
          break;
368  
      
369  
      // ix now either points to next value, or outside array (if no next)
370  
      return value;
371  
    }
372  
  }
373  
  
374  
  K key(int i) { ret (K) table[i*2]; }
375  
  void key(int i, O key) { table[i*2] = key; }
376  
  V value(int i) { ret (V) table[i*2+1]; }
377  
  void value(int i, O value) { table[i*2+1] = value; }
378  
  
379  
  int tableSize() { ret table.length/2; }
380  
}

Author comment

Began life as a copy of #1031040

download  show line numbers  debug dex  old transpilations   

Travelled to 3 computer(s): bhatertpkbcr, mowyntqkapby, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1035172
Snippet name: CompactHashMap - backup
Eternal ID of this version: #1035172/1
Text MD5: f32dc136c4959c559b5b03f6613d7e73
Author: stefan
Category: javax / collections
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-04-04 00:15:35
Source code size: 9963 bytes / 380 lines
Pitched / IR pitched: No / No
Views / Downloads: 72 / 78
Referenced in: [show references]