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

364
LINES

< > BotCompany Repo | #1028522 // UnsynchronizedCompactHashSet

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

Libraryless. Click here for Pure Java version (3422L/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  
// Note: equals is always called on the _stored_ object, not the one
27  
// passed as an argument to find(), contains() etc.
28  
// (In case you want to put special magic in your equals() function)
29  
30  
sclass UnsynchronizedCompactHashSet<A> extends java.util.AbstractSet<A> {
31  
  protected final static int INITIAL_SIZE = 3;
32  
  public final static double LOAD_FACTOR = 0.75;
33  
34  
  protected final static Object nullObject = new Object();
35  
  protected final static Object deletedObject = new Object();
36  
  protected int elements;
37  
  protected int freecells;
38  
  protected A[] objects;
39  
  ifndef NoModCount
40  
  protected int modCount;
41  
  endifndef
42  
  
43  
  UnsynchronizedCompactHashSet() {
44  
    this(INITIAL_SIZE);
45  
  }
46  
47  
  *(int size) {
48  
    // NOTE: If array size is 0, we get a
49  
    // "java.lang.ArithmeticException: / by zero" in add(Object).
50  
    objects = (A[]) new Object[(size==0 ? 1 : size)];
51  
    elements = 0;
52  
    freecells = objects.length;
53  
    ifndef NoModCount
54  
      modCount = 0;
55  
    endifndef
56  
  }
57  
58  
  *(Collection<A> c) {
59  
    this(c.size());
60  
    addAll(c);
61  
  }
62  
63  
  @Override
64  
  public Iterator<A> iterator() {
65  
    return new CompactHashIterator<A>();
66  
  }
67  
68  
  @Override
69  
  public int size() {
70  
    return elements;
71  
  }
72  
73  
  @Override
74  
  public boolean isEmpty() {
75  
    return elements == 0;
76  
  }
77  
78  
  @Override
79  
  public boolean contains(Object o) {
80  
    ret find(o) != null;
81  
  }
82  
  
83  
  A find(O o) {
84  
    if (o == null) o = nullObject;
85  
    
86  
    int hash = o.hashCode();
87  
    int index = (hash & 0x7FFFFFFF) % objects.length;
88  
    int offset = 1;
89  
90  
    // search for the object (continue while !null and !this object)
91  
    while(objects[index] != null &&
92  
          !(objects[index].hashCode() == hash &&
93  
            objects[index].equals(o))) {
94  
      index = ((index + offset) & 0x7FFFFFFF) % objects.length;
95  
      offset = offset*2 + 1;
96  
97  
      if (offset == -1)
98  
        offset = 2;
99  
    }
100  
101  
    ret objects[index];
102  
  }
103  
  
104  
  bool removeIfSame(O o) {
105  
    A value = find(o);
106  
    if (value == o) {
107  
      remove(value);
108  
      true;
109  
    }
110  
    false;
111  
  }
112  
113  
  @Override
114  
  public boolean add(Object o) {
115  
    if (o == null) o = nullObject;
116  
117  
    int hash = o.hashCode();
118  
    int index = (hash & 0x7FFFFFFF) % objects.length;
119  
    int offset = 1;
120  
    int deletedix = -1;
121  
    
122  
    // search for the object (continue while !null and !this object)
123  
    while(objects[index] != null &&
124  
          !(objects[index].hashCode() == hash &&
125  
            objects[index].equals(o))) {
126  
127  
      // if there's a deleted object here we can put this object here,
128  
      // provided it's not in here somewhere else already
129  
      if (objects[index] == deletedObject)
130  
        deletedix = index;
131  
      
132  
      index = ((index + offset) & 0x7FFFFFFF) % objects.length;
133  
      offset = offset*2 + 1;
134  
135  
      if (offset == -1)
136  
        offset = 2;
137  
    }
138  
    
139  
    if (objects[index] == null) { // wasn't present already
140  
      if (deletedix != -1) // reusing a deleted cell
141  
        index = deletedix;
142  
      else
143  
        freecells--;
144  
145  
      ifndef NoModCount
146  
        modCount++;
147  
      endifndef
148  
      elements++;
149  
150  
      // here we face a problem regarding generics:
151  
      // add(A o) is not possible because of the null Object. We cant do 'new A()' or '(A) new Object()'
152  
      // so adding an empty object is a problem here
153  
      // If (! o instanceof A) : This will cause a class cast exception
154  
      // If (o instanceof A) : This will work fine
155  
156  
      objects[index] = (A) o;
157  
      
158  
      // do we need to rehash?
159  
      if (1 - (freecells / (double) objects.length) > LOAD_FACTOR)
160  
        rehash();
161  
      return true;
162  
    } else // was there already 
163  
      return false;
164  
  }
165  
  
166  
  @Override
167  
  public boolean remove(Object o) {
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  
  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  
  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  
  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  
        for (index = 0; index < objects.length &&
298  
                        (objects[index] == null ||
299  
                        objects[index] == deletedObject); index++)
300  
          ;
301  
        ifndef NoModCount
302  
          expectedModCount = modCount;
303  
        endifndef
304  
    }
305  
306  
    @Override
307  
    public boolean hasNext() {
308  
        return index < objects.length;
309  
    }
310  
311  
    @SuppressWarnings("empty-statement")
312  
    @Override
313  
    public T next() {
314  
        /*if (modCount != expectedModCount)
315  
          throw new ConcurrentModificationException();*/
316  
        int length = objects.length;
317  
        if (index >= length) {
318  
          lastReturned = -2;
319  
          throw new NoSuchElementException();
320  
        }
321  
  
322  
        lastReturned = index;
323  
        for (index += 1; index < length &&
324  
                         (objects[index] == null ||
325  
                          objects[index] == deletedObject); index++)
326  
          ;
327  
        if (objects[lastReturned] == nullObject)
328  
          return null;
329  
        else
330  
          return (T) objects[lastReturned];
331  
    }
332  
333  
    @Override
334  
    public void remove() {
335  
        ifndef NoModCount
336  
          if (modCount != expectedModCount)
337  
            throw new ConcurrentModificationException();
338  
        endifndef
339  
        if (lastReturned == -1 || lastReturned == -2)
340  
          throw new IllegalStateException();
341  
        // delete object
342  
        if (objects[lastReturned] != null && objects[lastReturned] != deletedObject) {
343  
          objects[lastReturned] = (A) deletedObject;
344  
          elements--;
345  
          ifndef NoModCount
346  
            modCount++;
347  
            expectedModCount = modCount; // this is expected; we made the change
348  
          endifndef
349  
        }
350  
    }
351  
  }
352  
  
353  
  int capacity() { ret objects.length; }
354  
  
355  
  // returns true if there was a shrink
356  
  bool shrinkToFactor(double factor) {
357  
    if (factor > LOAD_FACTOR)
358  
      fail("Shrink factor must be equal to or smaller than load factor: " + factor + " / " + LOAD_FACTOR);
359  
    int newCapacity = max(INITIAL_SIZE, iround(size()/factor);
360  
    if (newCapacity >= capacity()) false;
361  
    rehash(newCapacity);
362  
    true;
363  
  }
364  
}

Author comment

Began life as a copy of #1012355

download  show line numbers  debug dex  old transpilations   

Travelled to 12 computer(s): bhatertpkbcr, ekrmjmnbrukm, elmgxqgtpvxh, mowyntqkapby, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt, wnsclhtenguj, xrpafgyirdlv

No comments. add comment

Snippet ID: #1028522
Snippet name: UnsynchronizedCompactHashSet
Eternal ID of this version: #1028522/3
Text MD5: 2b57ce7d3600efb650167f10cb1f0e3b
Transpilation MD5: ec00f26395e432c3786334092a70bf8a
Author: stefan
Category: javax / collections
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-08-03 22:17:18
Source code size: 10337 bytes / 364 lines
Pitched / IR pitched: No / No
Views / Downloads: 178 / 2663
Version history: 2 change(s)
Referenced in: [show references]