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

361
LINES

< > BotCompany Repo | #1028518 // CompactIdentityHashSet - CompactHashSet using object identity hashCode/equals

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

Libraryless. Click here for Pure Java version (2921L/19K).

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

Author comment

Began life as a copy of #1012816

download  show line numbers  debug dex  old transpilations   

Travelled to 7 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv

No comments. add comment

Snippet ID: #1028518
Snippet name: CompactIdentityHashSet - CompactHashSet using object identity hashCode/equals
Eternal ID of this version: #1028518/5
Text MD5: dee8d12db16126219ec8c9bbed01ea0c
Transpilation MD5: a220a4b3cff99631bd1a89fcbd118a06
Author: stefan
Category: javax / collections
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2020-06-24 00:09:29
Source code size: 10115 bytes / 361 lines
Pitched / IR pitched: No / No
Views / Downloads: 284 / 597
Version history: 4 change(s)
Referenced in: [show references]