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

390
LINES

< > BotCompany Repo | #1013385 // CompactPairKeyHashMap - map Pair to Object - 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 CompactPairKeyHashMap<K, V> extends AbstractMap<Pair<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[] keys1;
38  
  K[] keys2;
39  
  V[] values; // object at pos x corresponds to key at pos x
40  
  int modCount;
41  
42  
  *() {
43  
    this(INITIAL_SIZE);
44  
  }
45  
46  
  *(int size) {
47  
    keys1 = (K[]) new Object[(size==0 ? 1 : size)];
48  
    keys2 = (K[]) new Object[(size==0 ? 1 : size)];
49  
    values = (V[]) new Object[(size==0 ? 1 : size)];
50  
    elements = 0;
51  
    freecells = keys1.length;
52  
    modCount = 0;
53  
  }
54  
55  
  // ===== MAP IMPLEMENTATION =============================================
56  
57  
  /**
58  
   * Returns the number of key/value mappings in this map.
59  
   */
60  
  public synchronized int size() {
61  
    return elements;
62  
  }
63  
  
64  
  /**
65  
   * Returns <tt>true</tt> if this map contains no mappings.
66  
   */
67  
  public synchronized boolean isEmpty() {
68  
    return elements == 0;
69  
  }
70  
71  
  /**
72  
   * Removes all key/value mappings in the map.
73  
   */
74  
  public synchronized void clear() {
75  
    elements = 0;
76  
    for (int ix = 0; ix < keys1.length; ix++) {
77  
      keys1[ix] = keys2[ix] = null;
78  
      values[ix] = null;
79  
    }
80  
    freecells = values.length;
81  
    modCount++;
82  
  }
83  
  
84  
  /**
85  
   * Returns <tt>true</tt> if this map contains the specified key.
86  
   */
87  
  public synchronized boolean containsKey(Object k) {
88  
    return keys1[findKeyIndex(k)] != null;
89  
  }
90  
  
91  
  /**
92  
   * Returns <tt>true</tt> if this map contains the specified value.
93  
   */
94  
  public synchronized boolean containsValue(Object v) {
95  
    if (v == null)
96  
      v = (V)nullObject;
97  
98  
    for (int ix = 0; ix < values.length; ix++)
99  
      if (values[ix] != null && values[ix].equals(v))
100  
        return true;
101  
102  
    return false;
103  
  }
104  
105  
  /**
106  
   * Returns a read-only set view of the map's keys.
107  
   */
108  
  public synchronized Set<Entry<Pair<K>, V>> entrySet() {
109  
    throw new UnsupportedOperationException();
110  
  }
111  
112  
  /**
113  
   * Removes the mapping with key k, if there is one, and returns its
114  
   * value, if there is one, and null if there is none.
115  
   */
116  
  public synchronized V remove(Object k) {
117  
    int index = findKeyIndex(k);
118  
119  
    // we found the right position, now do the removal
120  
    if (keys1[index] != null) {
121  
      // we found the object
122  
123  
      // same problem here as with put
124  
      V v = values[index];
125  
      keys1[index] = keys2[index] = (K) deletedObject;
126  
      values[index] = (V) deletedObject;
127  
      modCount++;
128  
      elements--;
129  
      return v;
130  
    } else
131  
      // we did not find the key
132  
      return null;
133  
  }
134  
135  
  /**
136  
   * Adds the specified mapping to this map, returning the old value for
137  
   * the mapping, if there was one.
138  
   */
139  
  public synchronized V put(Pair<K> k, V v) {
140  
    if (k.a == null)
141  
      k = pair((K)nullObject, k.b);
142  
    if (k.b == null)
143  
      k = pair(k.a, (K)nullObject);
144  
145  
    int hash = k.hashCode();
146  
    int hash1 = k.a.hashCode();
147  
    int hash2 = k.b.hashCode();
148  
    int index = (hash & 0x7FFFFFFF) % keys1.length;
149  
    int offset = 1;
150  
    int deletedix = -1;
151  
    
152  
    // search for the key (continue while !null and !this key)
153  
    while(keys1[index] != null &&
154  
          !(keys1[index].hashCode() == hash1 &&
155  
            keys2[index].hashCode() == hash2 &&
156  
            keys1[index].equals(k.a) &&
157  
            keys2[index].equals(k.b))) {
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 (keys1[index] == deletedObject)
162  
        deletedix = index;
163  
      
164  
      index = ((index + offset) & 0x7FFFFFFF) % keys1.length;
165  
      offset = offset*2 + 1;
166  
167  
      if (offset == -1)
168  
        offset = 2;
169  
    }
170  
    
171  
    if (keys1[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  
      keys1[index] = k.a;
181  
      keys2[index] = k.b;
182  
      values[index] = (V) v;
183  
      
184  
      // rehash with increased capacity
185  
      if (1 - (freecells / (double) keys1.length) > LOAD_FACTOR)
186  
        rehash(keys1.length*2 + 1);
187  
      return null;
188  
    } else { // was there already
189  
      modCount++;
190  
      V oldv = values[index];
191  
      values[index] = (V) v;
192  
      return oldv;
193  
    }
194  
  }
195  
196  
  /**
197  
   * INTERNAL: Rehashes the hashmap to a bigger size.
198  
   */
199  
  void rehash(int newCapacity) {
200  
    int oldCapacity = keys1.length;
201  
    K[] newKeys1 = (K[]) new Object[newCapacity];
202  
    K[] newKeys2 = (K[]) new Object[newCapacity];
203  
    V[] newValues = (V[]) new Object[newCapacity];
204  
205  
    for (int ix = 0; ix < oldCapacity; ix++) {
206  
      Object k1 = keys1[ix];
207  
      if (k1 == null || k1 == deletedObject)
208  
        continue;
209  
      
210  
      Object k2 = keys2[ix];
211  
      int hash = pair(k1, k2).hashCode();
212  
      int index = (hash & 0x7FFFFFFF) % newCapacity;
213  
      int offset = 1;
214  
215  
      // search for the key
216  
      while(newKeys1[index] != null) { // no need to test for duplicates
217  
        index = ((index + offset) & 0x7FFFFFFF) % newCapacity;
218  
        offset = offset*2 + 1;
219  
220  
        if (offset == -1)
221  
          offset = 2;
222  
      }
223  
224  
      newKeys1[index] = (K) k1;
225  
      newKeys2[index] = (K) k2;
226  
      newValues[index] = values[ix];
227  
    }
228  
229  
    keys1 = newKeys1;
230  
    keys2 = newKeys2;
231  
    values = newValues;
232  
    freecells = keys1.length - elements;
233  
  }
234  
235  
  /**
236  
   * Returns the value for the key k, if there is one, and null if
237  
   * there is none.
238  
   */
239  
  public synchronized V get(Object k) {
240  
    return values[findKeyIndex(k)];
241  
  }
242  
243  
  /**
244  
   * Returns a virtual read-only collection containing all the values
245  
   * in the map.
246  
   */
247  
  public synchronized Collection<V> values() {
248  
    return new ValueCollection();
249  
  }
250  
251  
  /**
252  
   * Returns a virtual read-only set of all the keys in the map.
253  
   */
254  
  public synchronized Set<Pair<K>> keySet() {
255  
    return new KeySet();
256  
  }
257  
258  
  // --- Internal utilities
259  
260  
  final int findKeyIndex(Object _k) {
261  
    Pair k = cast _k;
262  
    if (k.a == null)
263  
      k = pair((K)nullObject, k.b);
264  
    if (k.b == null)
265  
      k = pair(k.a, (K)nullObject);
266  
267  
    int hash = k.hashCode();
268  
    int hash1 = k.a.hashCode();
269  
    int hash2 = k.b.hashCode();
270  
    int index = (hash & 0x7FFFFFFF) % keys1.length;
271  
    int offset = 1;
272  
    int deletedix = -1;
273  
    
274  
    // search for the key (continue while !null and !this key)
275  
    while(keys1[index] != null &&
276  
          !(keys1[index].hashCode() == hash1 &&
277  
            keys2[index].hashCode() == hash2 &&
278  
            keys1[index].equals(k.a) &&
279  
            keys2[index].equals(k.b))) {
280  
      index = ((index + offset) & 0x7FFFFFFF) % keys1.length;
281  
      offset = offset*2 + 1;
282  
283  
      if (offset == -1)
284  
        offset = 2;
285  
    }
286  
    return index;
287  
  }
288  
  
289  
  // --- Key set
290  
291  
  class KeySet extends AbstractSet<Pair<K>> {
292  
    public synchronized int size() {
293  
      return elements;
294  
    }
295  
296  
    public synchronized boolean contains(Object k) {
297  
      return containsKey(k);
298  
    }
299  
300  
    public synchronized Iterator<Pair<K>> iterator() {
301  
      return new KeyIterator();
302  
    }
303  
  }
304  
305  
  class KeyIterator implements Iterator<Pair<K>> {
306  
    private int ix;
307  
    
308  
    private KeyIterator() {
309  
      // walk up to first value, so that hasNext() and next() return
310  
      // correct results
311  
      for (; ix < keys1.length; ix++)
312  
        if (values[ix] != null && keys1[ix] != deletedObject)
313  
          break;
314  
    }
315  
316  
    public synchronized boolean hasNext() {
317  
      return ix < keys1.length;
318  
    }
319  
320  
    public synchronized void remove() {
321  
      throw new UnsupportedOperationException("Collection is read-only");
322  
    }
323  
324  
    public synchronized Pair<K> next() {
325  
      if (ix >= keys1.length)
326  
        throw new NoSuchElementException();
327  
      K key1 = (K) keys1[ix];
328  
      K key2 = (K) keys2[ix];
329  
      ix++;
330  
      
331  
      // walk up to next value
332  
      for (; ix < keys1.length; ix++)
333  
        if (keys1[ix] != null && keys1[ix] != deletedObject)
334  
          break;
335  
      
336  
      // ix now either points to next key, or outside array (if no next)
337  
      return pair(key1, key2);
338  
    }
339  
  }
340  
  
341  
  // --- Value collection
342  
343  
  class ValueCollection extends AbstractCollection<V> {
344  
    public synchronized int size() {
345  
      return elements;
346  
    }
347  
348  
    public synchronized Iterator<V> iterator() {
349  
      return new ValueIterator();
350  
    }
351  
352  
    public synchronized boolean contains(Object v) {
353  
      return containsValue(v);
354  
    }
355  
  }
356  
357  
  class ValueIterator implements Iterator<V> {
358  
    private int ix;
359  
    
360  
    private ValueIterator() {
361  
      // walk up to first value, so that hasNext() and next() return
362  
      // correct results
363  
      for (; ix < values.length; ix++)
364  
        if (values[ix] != null && values[ix] != deletedObject)
365  
          break;
366  
    }
367  
368  
    public synchronized boolean hasNext() {
369  
      return ix < values.length;
370  
    }
371  
372  
    public synchronized void remove() {
373  
      throw new UnsupportedOperationException("Collection is read-only");
374  
    }
375  
376  
    public synchronized V next() {
377  
      if (ix >= values.length)
378  
        throw new NoSuchElementException();
379  
      V value = (V) values[ix++];
380  
      
381  
      // walk up to next value
382  
      for (; ix < values.length; ix++)
383  
        if (values[ix] != null && values[ix] != deletedObject)
384  
          break;
385  
      
386  
      // ix now either points to next value, or outside array (if no next)
387  
      return value;
388  
    }
389  
  }
390  
}

Author comment

Began life as a copy of #1013303

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: #1013385
Snippet name: CompactPairKeyHashMap - map Pair to Object - synchronized
Eternal ID of this version: #1013385/9
Text MD5: 23d7126110be94924140caad240495d7
Author: stefan
Category: javax / collections
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2018-01-04 00:12:40
Source code size: 10675 bytes / 390 lines
Pitched / IR pitched: No / No
Views / Downloads: 345 / 904
Version history: 8 change(s)
Referenced in: [show references]