KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > util > ObjectIDSet2


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.util;
5
6 import com.tc.exception.ImplementMe;
7 import com.tc.object.ObjectID;
8
9 import java.util.AbstractSet JavaDoc;
10 import java.util.ArrayList JavaDoc;
11 import java.util.Collection JavaDoc;
12 import java.util.Iterator JavaDoc;
13 import java.util.NoSuchElementException JavaDoc;
14
15 /**
16  * This class is a an attempt to meet the shortcomings of ObjectIDSet. Mainly the performance of adds and removes when
17  * the ObjectIDs are non-contiguous. It uses a balanced tree internally to store ranges instead of an arraylist
18  */

19 public class ObjectIDSet2 extends AbstractSet JavaDoc {
20
21   private final AATree ranges;
22   private int size = 0;
23
24   public ObjectIDSet2() {
25     ranges = new AATree();
26   }
27
28   public ObjectIDSet2(Collection JavaDoc c) {
29     this();
30     if (c instanceof ObjectIDSet2) {
31       ObjectIDSet2 other = (ObjectIDSet2) c;
32       // fast way to clone
33
this.size = other.size();
34       for (Iterator JavaDoc i = other.ranges.iterator(); i.hasNext();) {
35         this.ranges.insert((Range) ((Range) i.next()).clone());
36       }
37       return;
38     } else {
39       addAll(c);
40     }
41   }
42
43   public Iterator JavaDoc iterator() {
44     return new ObjectIDSetIterator();
45   }
46
47   public int size() {
48     return size;
49   }
50
51   public boolean contains(ObjectID id) {
52     long lid = id.toLong();
53     return (ranges.find(new MyLong(lid)) != null);
54   }
55
56   public boolean remove(ObjectID id) {
57     long lid = id.toLong();
58
59     Range current = (Range) ranges.find(new MyLong(lid));
60     if (current == null) {
61       // Not found
62
return false;
63     }
64     Range newRange = current.remove(lid);
65     if (newRange != null) {
66       ranges.insert(newRange);
67     } else if (current.isNull()) {
68       ranges.remove(current);
69     }
70     size--;
71     return true;
72   }
73
74   public boolean add(ObjectID id) {
75     long lid = id.toLong();
76
77     // Step 1 : Check if the previous number is present, if so add to the same Range.
78
Range prev = (Range) ranges.find(new MyLong(lid - 1));
79     if (prev != null) {
80       boolean isAdded = prev.add(lid);
81       if (isAdded) {
82         Range next = (Range) ranges.remove((new MyLong(lid + 1)));
83         if (next != null) prev.merge(next);
84         size++;
85       }
86       return isAdded;
87     }
88
89     // Step 2 : Check if the next number is present, if so add to the same Range.
90
Range next = (Range) ranges.find((new MyLong(lid + 1)));
91     if (next != null) {
92       boolean isAdded = next.add(lid);
93       if (isAdded) size++;
94       return isAdded;
95     }
96
97     // Step 3: Add a new range for just this number.
98
boolean isAdded = ranges.insert(new Range(lid, lid));
99     if (isAdded) size++;
100     return isAdded;
101   }
102
103   public String JavaDoc toString() {
104     StringBuffer JavaDoc sb = new StringBuffer JavaDoc("ObjectIDSet2 [");
105     for (Iterator JavaDoc i = ranges.iterator(); i.hasNext();) {
106       sb.append(' ').append(i.next());
107     }
108     return sb.append(']').toString();
109   }
110
111   /**
112    * Ranges store the elements stored in the tree. The range is inclusive.
113    */

114   private static class Range implements Cloneable JavaDoc, Comparable JavaDoc {
115     public long start;
116     public long end;
117
118     public String JavaDoc toString() {
119       return "Range(" + start + "," + end + ")";
120     }
121
122     public boolean isNull() {
123       return start > end;
124     }
125
126     public Range remove(long lid) {
127       if (lid < start || lid > end) { throw new AssertionError JavaDoc("Ranges : Illegal value passed to remove : " + this
128                                                                + " remove called for : " + lid); }
129       if (start == lid) {
130         start++;
131         return null;
132       } else if (end == lid) {
133         end--;
134         return null;
135       } else {
136         Range newRange = new Range(lid + 1, end);
137         end = lid - 1;
138         return newRange;
139       }
140     }
141
142     public void merge(Range other) {
143       if (start == other.end + 1) {
144         start = other.start;
145       } else if (end == other.start - 1) {
146         end = other.end;
147       } else {
148         throw new AssertionError JavaDoc("Ranges : Merge is called on non contigues value : " + this + " and other Range is "
149                                  + other);
150       }
151     }
152
153     public boolean add(long lid) {
154       if (lid == start - 1) {
155         start--;
156         return true;
157       } else if (lid == end + 1) {
158         end++;
159         return true;
160       } else if (lid >= start && lid <= end) {
161         return false;
162       } else {
163         throw new AssertionError JavaDoc("Ranges : Add is called on non contigues value : " + this + " but trying to add "
164                                  + lid);
165       }
166     }
167
168     public Range(long start, long end) {
169       this.start = start;
170       this.end = end;
171     }
172
173     public Object JavaDoc clone() {
174       return new Range(start, end);
175     }
176
177     public int compareTo(Object JavaDoc o) {
178       if (o instanceof Range) {
179         Range other = (Range) o;
180         if (start < other.start) return -1;
181         else if (start == other.start) return 0;
182         else return 1;
183       } else {
184         long n = ((MyLong) o).longValue();
185         if (end < n) return -1;
186         else if (n < start) return 1;
187         else return 0;
188       }
189     }
190   }
191
192   // This class is used as a key for lookup.
193
private static final class MyLong implements Comparable JavaDoc {
194     final long number;
195
196     public MyLong(long number) {
197       this.number = number;
198     }
199
200     public long longValue() {
201       return number;
202     }
203
204     public int compareTo(Object JavaDoc o) {
205       if (o instanceof Range) {
206         Range r = (Range) o;
207         if (number < r.start) return -1;
208         else if (number > r.end) return 1;
209         else return 0;
210       } else {
211         long other = ((MyLong) o).longValue();
212         if (number < other) return -1;
213         else if (number > other) return 1;
214         else return 0;
215       }
216     }
217     
218     public String JavaDoc toString() {
219       return "MyLong@" + System.identityHashCode(this) + "(" + number +")" ;
220     }
221   }
222
223   private class ObjectIDSetIterator implements Iterator JavaDoc {
224
225     Iterator JavaDoc nodes;
226     Range current;
227     int idx = 0;
228
229     public ObjectIDSetIterator() {
230       nodes = ranges.iterator();
231       if (nodes.hasNext()) current = (Range) nodes.next();
232     }
233
234     public boolean hasNext() {
235       return nodes.hasNext() || (current != null && (current.start + idx) <= current.end);
236     }
237
238     public Object JavaDoc next() {
239       if (current == null) throw new NoSuchElementException JavaDoc();
240       ObjectID oid = new ObjectID(current.start + idx);
241       if (current.start + idx == current.end) {
242         idx = 0;
243         if (nodes.hasNext()) {
244           current = (Range) nodes.next();
245         } else {
246           current = null;
247         }
248       } else {
249         idx++;
250       }
251       return oid;
252     }
253
254     // This is a little tricky as the tree might balance itself.
255
public void remove() {
256       throw new ImplementMe();
257     }
258   }
259
260   /*
261    * Because of the short comings of the iterator (it cant perform remove), this method is overridden
262    */

263   public boolean removeAll(Collection JavaDoc c) {
264     boolean modified = false;
265     if (size() > c.size()) {
266       for (Iterator JavaDoc i = c.iterator(); i.hasNext();)
267         modified |= remove(i.next());
268     } else {
269       // XXX :; yuck !!
270
ArrayList JavaDoc toRemove = new ArrayList JavaDoc();
271       for (Iterator JavaDoc i = iterator(); i.hasNext();) {
272         Object JavaDoc o = i.next();
273         if (c.contains(o)) {
274           toRemove.add(o);
275           modified = true;
276         }
277       }
278       for (Iterator JavaDoc i = toRemove.iterator(); i.hasNext();) {
279         remove(i.next());
280       }
281     }
282     return modified;
283   }
284
285   /*
286    * Because of the short comings of the iterator (it cant perform remove), this method is overridden
287    */

288   public boolean retainAll(Collection JavaDoc c) {
289     boolean modified = false;
290       // XXX :; yuck !!
291
ArrayList JavaDoc toRemove = new ArrayList JavaDoc(c.size());
292     Iterator JavaDoc e = iterator();
293     while (e.hasNext()) {
294       Object JavaDoc o = e.next();
295       if (!c.contains(o)) {
296         toRemove.add(o);
297         modified = true;
298       }
299     }
300     for (Iterator JavaDoc i = toRemove.iterator(); i.hasNext();) {
301       remove(i.next());
302     }
303     return modified;
304   }
305
306   public boolean contains(Object JavaDoc o) {
307     if (o instanceof ObjectID) {
308       return contains((ObjectID) o);
309     } else {
310       return false;
311     }
312   }
313
314   public boolean add(Object JavaDoc arg0) {
315     return add((ObjectID) arg0);
316   }
317
318   public boolean remove(Object JavaDoc o) {
319     if (o instanceof ObjectID) {
320       return remove((ObjectID) o);
321     } else {
322       return false;
323     }
324   }
325
326   public void clear() {
327     this.size = 0;
328     ranges.clear();
329   }
330
331 }
332
Popular Tags