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

372
LINES

< > BotCompany Repo | #1012355 // CompactHashSet - synchronized

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Click here for Pure Java version (3577L/20K).

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  
// modified by Stefan Reich
22  
23  
// Implements the Set interface more compactly than
24  
// java.util.HashSet by using a closed hashtable. 
25  
26  
sclass CompactHashSet<A> extends java.util.AbstractSet<A> {
27  
  protected final static int INITIAL_SIZE = 0;
28  
  protected final static int FIRST_INCREMENT = 3; // 2 or 3 are useful
29  
  public final static double LOAD_FACTOR = 0.75;
30  
31  
  protected final static Object nullObject = new Object();
32  
  protected final static Object deletedObject = new Object();
33  
  protected int elements;
34  
  protected int freecells;
35  
  protected A[] objects;
36  
  ifndef NoModCount
37  
  protected int modCount;
38  
  endifndef
39  
  
40  
  CompactHashSet() {
41  
    this(INITIAL_SIZE);
42  
  }
43  
44  
  *(int size) {
45  
    objects = (A[]) (size == 0 ? emptyObjectArray() : new O[size]);
46  
    elements = 0;
47  
    freecells = objects.length;
48  
    ifndef NoModCount
49  
      modCount = 0;
50  
    endifndef
51  
  }
52  
53  
  *(Collection<A> c) {
54  
    this(c.size());
55  
    addAll(c);
56  
  }
57  
58  
  @Override
59  
  public Iterator<A> iterator() {
60  
    return new CompactHashIterator<A>();
61  
  }
62  
63  
  @Override
64  
  public int size() {
65  
    return elements;
66  
  }
67  
68  
  @Override
69  
  public boolean isEmpty() {
70  
    return elements == 0;
71  
  }
72  
73  
  @Override
74  
  public boolean contains(Object o) {
75  
    ret find(o) != null;
76  
  }
77  
  
78  
  synchronized A find(O o) {
79  
    if (objects.length == 0) null;
80  
    
81  
    if (o == null) o = nullObject;
82  
    
83  
    int hash = o.hashCode();
84  
    int index = (hash & 0x7FFFFFFF) % objects.length;
85  
    int offset = 1;
86  
87  
    // search for the object (continue while !null and !this object)
88  
    while(objects[index] != null &&
89  
          !(objects[index].hashCode() == hash &&
90  
            objects[index].equals(o))) {
91  
      index = ((index + offset) & 0x7FFFFFFF) % objects.length;
92  
      offset = offset*2 + 1;
93  
94  
      if (offset == -1)
95  
        offset = 2;
96  
    }
97  
98  
    ret objects[index];
99  
  }
100  
  
101  
  bool removeIfSame(O o) {
102  
    A value = find(o);
103  
    if (value == o) {
104  
      remove(value);
105  
      true;
106  
    }
107  
    false;
108  
  }
109  
110  
  @Override
111  
  synchronized public boolean add(Object o) {
112  
    if (objects.length == 0) rehash(FIRST_INCREMENT);
113  
    
114  
    if (o == null) o = nullObject;
115  
116  
    int hash = o.hashCode();
117  
    int index = (hash & 0x7FFFFFFF) % objects.length;
118  
    int offset = 1;
119  
    int deletedix = -1;
120  
    
121  
    // search for the object (continue while !null and !this object)
122  
    while(objects[index] != null &&
123  
          !(objects[index].hashCode() == hash &&
124  
            objects[index].equals(o))) {
125  
126  
      // if there's a deleted object here we can put this object here,
127  
      // provided it's not in here somewhere else already
128  
      if (objects[index] == deletedObject)
129  
        deletedix = index;
130  
      
131  
      index = ((index + offset) & 0x7FFFFFFF) % objects.length;
132  
      offset = offset*2 + 1;
133  
134  
      if (offset == -1)
135  
        offset = 2;
136  
    }
137  
    
138  
    if (objects[index] == null) { // wasn't present already
139  
      if (deletedix != -1) // reusing a deleted cell
140  
        index = deletedix;
141  
      else
142  
        freecells--;
143  
144  
      ifndef NoModCount
145  
        modCount++;
146  
      endifndef
147  
      elements++;
148  
149  
      // here we face a problem regarding generics:
150  
      // add(A o) is not possible because of the null Object. We cant do 'new A()' or '(A) new Object()'
151  
      // so adding an empty object is a problem here
152  
      // If (! o instanceof A) : This will cause a class cast exception
153  
      // If (o instanceof A) : This will work fine
154  
155  
      objects[index] = (A) o;
156  
      
157  
      // do we need to rehash?
158  
      if (1 - (freecells / (double) objects.length) > LOAD_FACTOR)
159  
        rehash();
160  
      true;
161  
    } else // was there already 
162  
      return false;
163  
  }
164  
  
165  
  @Override
166  
  synchronized public boolean remove(Object o) {
167  
    if (objects.length == 0) false;
168  
    if (o == null) o = nullObject;
169  
    
170  
    int hash = o.hashCode();
171  
    int index = (hash & 0x7FFFFFFF) % objects.length;
172  
    int offset = 1;
173  
    
174  
    // search for the object (continue while !null and !this object)
175  
    while(objects[index] != null &&
176  
          !(objects[index].hashCode() == hash &&
177  
            objects[index].equals(o))) {
178  
      index = ((index + offset) & 0x7FFFFFFF) % objects.length;
179  
      offset = offset*2 + 1;
180  
181  
      if (offset == -1)
182  
        offset = 2;
183  
    }
184  
185  
    // we found the right position, now do the removal
186  
    if (objects[index] != null) {
187  
      // we found the object
188  
189  
      // same problem here as with add
190  
      objects[index] = (A) deletedObject;
191  
      ifndef NoModCount
192  
        modCount++;
193  
      endifndef
194  
      elements--;
195  
      return true;
196  
    } else
197  
      // we did not find the object
198  
      return false;
199  
  }
200  
  
201  
  @Override
202  
  synchronized public void clear() {
203  
    elements = 0;
204  
    for (int ix = 0; ix < objects.length; ix++)
205  
      objects[ix] = null;
206  
    freecells = objects.length;
207  
    ifndef NoModCount
208  
      modCount++;
209  
    endifndef
210  
  }
211  
212  
  @Override
213  
  synchronized public Object[] toArray() {
214  
    Object[] result = new Object[elements];
215  
    Object[] objects = this.objects;
216  
    int pos = 0;
217  
    for (int i = 0; i < objects.length; i++)
218  
      if (objects[i] != null && objects[i] != deletedObject) {
219  
        if (objects[i] == nullObject)
220  
          result[pos++] = null;
221  
        else
222  
          result[pos++] = objects[i];
223  
      }
224  
    // unchecked because it should only contain A
225  
    return result;
226  
  }
227  
228  
  // not sure if this needs to have generics
229  
  @Override
230  
  synchronized public <T> T[] toArray(T[] a) {
231  
    int size = elements;
232  
    if (a.length < size)
233  
      a = (T[])java.lang.reflect.Array.newInstance(
234  
                                 a.getClass().getComponentType(), size);
235  
    A[] objects = this.objects;
236  
    int pos = 0;
237  
    for (int i = 0; i < objects.length; i++)
238  
      if (objects[i] != null && objects[i] != deletedObject) {
239  
        if (objects[i] == nullObject)
240  
          a[pos++] = null;
241  
        else
242  
          a[pos++] = (T) objects[i];
243  
      }
244  
    return a;
245  
  }
246  
  
247  
  protected void rehash() {
248  
    int garbagecells = objects.length - (elements + freecells);
249  
    if (garbagecells / (double) objects.length > 0.05)
250  
      // rehash with same size
251  
      rehash(objects.length);
252  
    else
253  
      // rehash with increased capacity
254  
      rehash(objects.length*2 + 1);
255  
  }
256  
  
257  
  protected void rehash(int newCapacity) {
258  
    int oldCapacity = objects.length;
259  
    @SuppressWarnings("unchecked")
260  
    A[] newObjects = (A[]) new Object[newCapacity];
261  
262  
    for (int ix = 0; ix < oldCapacity; ix++) {
263  
      Object o = objects[ix];
264  
      if (o == null || o == deletedObject)
265  
        continue;
266  
      
267  
      int hash = o.hashCode();
268  
      int index = (hash & 0x7FFFFFFF) % newCapacity;
269  
      int offset = 1;
270  
271  
      // search for the object
272  
      while(newObjects[index] != null) { // no need to test for duplicates
273  
        index = ((index + offset) & 0x7FFFFFFF) % newCapacity;
274  
        offset = offset*2 + 1;
275  
276  
        if (offset == -1)
277  
          offset = 2;
278  
      }
279  
280  
      newObjects[index] = (A) o;
281  
    }
282  
283  
    objects = newObjects;
284  
    freecells = objects.length - elements;
285  
  }
286  
  
287  
  private class CompactHashIterator<T> implements Iterator<T> {
288  
    private int index;
289  
    private int lastReturned = -1;
290  
291  
    ifndef NoModCount
292  
      private int expectedModCount;
293  
    endifndef
294  
295  
    @SuppressWarnings("empty-statement")
296  
    public CompactHashIterator() {
297  
      synchronized(CompactHashSet.this) {
298  
        for (index = 0; index < objects.length &&
299  
                        (objects[index] == null ||
300  
                        objects[index] == deletedObject); index++)
301  
          ;
302  
        ifndef NoModCount
303  
          expectedModCount = modCount;
304  
        endifndef
305  
      }
306  
    }
307  
308  
    @Override
309  
    public boolean hasNext() {
310  
      synchronized(CompactHashSet.this) {
311  
        return index < objects.length;
312  
      }
313  
    }
314  
315  
    @SuppressWarnings("empty-statement")
316  
    @Override
317  
    public T next() {
318  
      synchronized(CompactHashSet.this) {
319  
        /*if (modCount != expectedModCount)
320  
          throw new ConcurrentModificationException();*/
321  
        int length = objects.length;
322  
        if (index >= length) {
323  
          lastReturned = -2;
324  
          throw new NoSuchElementException();
325  
        }
326  
  
327  
        lastReturned = index;
328  
        for (index += 1; index < length &&
329  
                         (objects[index] == null ||
330  
                          objects[index] == deletedObject); index++)
331  
          ;
332  
        if (objects[lastReturned] == nullObject)
333  
          return null;
334  
        else
335  
          return (T) objects[lastReturned];
336  
      }
337  
    }
338  
339  
    @Override
340  
    public void remove() {
341  
      synchronized(CompactHashSet.this) {
342  
        ifndef NoModCount
343  
          if (modCount != expectedModCount)
344  
            throw new ConcurrentModificationException();
345  
        endifndef
346  
        if (lastReturned == -1 || lastReturned == -2)
347  
          throw new IllegalStateException();
348  
        // delete object
349  
        if (objects[lastReturned] != null && objects[lastReturned] != deletedObject) {
350  
          objects[lastReturned] = (A) deletedObject;
351  
          elements--;
352  
          ifndef NoModCount
353  
            modCount++;
354  
            expectedModCount = modCount; // this is expected; we made the change
355  
          endifndef
356  
        }
357  
      }
358  
    }
359  
  }
360  
  
361  
  synchronized int capacity() { ret objects.length; }
362  
  
363  
  // returns true if there was a shrink
364  
  synchronized bool shrinkToFactor(double factor) {
365  
    if (factor > LOAD_FACTOR)
366  
      fail("Shrink factor must be equal to or smaller than load factor: " + factor + " / " + LOAD_FACTOR);
367  
    int newCapacity = max(INITIAL_SIZE, iround(size()/factor);
368  
    if (newCapacity >= capacity()) false;
369  
    rehash(newCapacity);
370  
    true;
371  
  }
372  
}

Author comment

from https://github.com/ontopia/ontopia/blob/HEAD/ontopia-engine/src/main/java/net/ontopia/utils/CompactHashSet.java

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #1012355
Snippet name: CompactHashSet - synchronized
Eternal ID of this version: #1012355/19
Text MD5: c5502feea19a5b462cb9bb9974c892eb
Transpilation MD5: 526cdbe5500028e4d02a4d9a6a3825ed
Author: stefan
Category: javax / collections
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-08-11 01:23:59
Source code size: 10536 bytes / 372 lines
Pitched / IR pitched: No / No
Views / Downloads: 624 / 1329
Version history: 18 change(s)
Referenced in: [show references]