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

367
LINES

< > BotCompany Repo | #1013303 // CompactHashMap - synchronized

JavaX fragment (include)

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

Author comment

Began life as a copy of #1012355

download  show line numbers  debug dex  old transpilations   

Travelled to 13 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1013303
Snippet name: CompactHashMap - synchronized
Eternal ID of this version: #1013303/3
Text MD5: 8356892939b7988d6cb4b6a823d16628
Author: stefan
Category: javax / collections
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2017-12-31 19:41:35
Source code size: 9748 bytes / 367 lines
Pitched / IR pitched: No / No
Views / Downloads: 342 / 804
Version history: 2 change(s)
Referenced in: [show references]