add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / contrib / facet / src / java / org / apache / lucene / util / collections / IntToDoubleMap.java
1 package org.apache.lucene.util.collections;
2
3 import java.util.Arrays;
4
5 /**
6  * Licensed to the Apache Software Foundation (ASF) under one or more
7  * contributor license agreements.  See the NOTICE file distributed with
8  * this work for additional information regarding copyright ownership.
9  * The ASF licenses this file to You under the Apache License, Version 2.0
10  * (the "License"); you may not use this file except in compliance with
11  * the License.  You may obtain a copy of the License at
12  *
13  *     http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21
22 /**
23  * An Array-based hashtable which maps primitive int to a primitive double.<br>
24  * The hashtable is constracted with a given capacity, or 16 as a default. In
25  * case there's not enough room for new pairs, the hashtable grows. <br>
26  * Capacity is adjusted to a power of 2, and there are 2 * capacity entries for
27  * the hash.
28  * 
29  * The pre allocated arrays (for keys, values) are at length of capacity + 1,
30  * when index 0 is used as 'Ground' or 'NULL'.<br>
31  * 
32  * The arrays are allocated ahead of hash operations, and form an 'empty space'
33  * list, to which the key,value pair is allocated.
34  * 
35  * @lucene.experimental
36  */
37 public class IntToDoubleMap {
38
39   public static final double GROUND = Double.NaN;
40
41   /**
42    * Implements an IntIterator which iterates over all the allocated indexes.
43    */
44   private final class IndexIterator implements IntIterator {
45     /**
46      * The last used baseHashIndex. Needed for "jumping" from one hash entry
47      * to another.
48      */
49     private int baseHashIndex = 0;
50
51     /**
52      * The next not-yet-visited index.
53      */
54     private int index = 0;
55
56     /**
57      * Index of the last visited pair. Used in {@link #remove()}.
58      */
59     private int lastIndex = 0;
60
61     /**
62      * Create the Iterator, make <code>index</code> point to the "first"
63      * index which is not empty. If such does not exist (eg. the map is
64      * empty) it would be zero.
65      */
66     public IndexIterator() {
67       for (baseHashIndex = 0; baseHashIndex < baseHash.length; ++baseHashIndex) {
68         index = baseHash[baseHashIndex];
69         if (index != 0) {
70           break;
71         }
72       }
73     }
74
75     public boolean hasNext() {
76       return (index != 0);
77     }
78
79     public int next() {
80       // Save the last index visited
81       lastIndex = index;
82
83       // next the index
84       index = next[index];
85
86       // if the next index points to the 'Ground' it means we're done with
87       // the current hash entry and we need to jump to the next one. This
88       // is done until all the hash entries had been visited.
89       while (index == 0 && ++baseHashIndex < baseHash.length) {
90         index = baseHash[baseHashIndex];
91       }
92
93       return lastIndex;
94     }
95
96     public void remove() {
97       IntToDoubleMap.this.remove(keys[lastIndex]);
98     }
99
100   }
101
102   /**
103    * Implements an IntIterator, used for iteration over the map's keys.
104    */
105   private final class KeyIterator implements IntIterator {
106     private IntIterator iterator = new IndexIterator();
107
108     KeyIterator() { }
109     
110     public boolean hasNext() {
111       return iterator.hasNext();
112     }
113
114     public int next() {
115       return keys[iterator.next()];
116     }
117
118     public void remove() {
119       iterator.remove();
120     }
121   }
122
123   /**
124    * Implements an Iterator of a generic type T used for iteration over the
125    * map's values.
126    */
127   private final class ValueIterator implements DoubleIterator {
128     private IntIterator iterator = new IndexIterator();
129
130     ValueIterator() { }
131     
132     public boolean hasNext() {
133       return iterator.hasNext();
134     }
135
136     public double next() {
137       return values[iterator.next()];
138     }
139
140     public void remove() {
141       iterator.remove();
142     }
143   }
144
145   /**
146    * Default capacity - in case no capacity was specified in the constructor
147    */
148   private static int defaultCapacity = 16;
149
150   /**
151    * Holds the base hash entries. if the capacity is 2^N, than the base hash
152    * holds 2^(N+1). It can hold
153    */
154   int[] baseHash;
155
156   /**
157    * The current capacity of the map. Always 2^N and never less than 16. We
158    * never use the zero index. It is needed to improve performance and is also
159    * used as "ground".
160    */
161   private int capacity;
162   /**
163    * All objects are being allocated at map creation. Those objects are "free"
164    * or empty. Whenever a new pair comes along, a pair is being "allocated" or
165    * taken from the free-linked list. as this is just a free list.
166    */
167   private int firstEmpty;
168
169   /**
170    * hashFactor is always (2^(N+1)) - 1. Used for faster hashing.
171    */
172   private int hashFactor;
173
174   /**
175    * This array holds the unique keys
176    */
177   int[] keys;
178
179   /**
180    * In case of collisions, we implement a double linked list of the colliding
181    * hash's with the following next[] and prev[]. Those are also used to store
182    * the "empty" list.
183    */
184   int[] next;
185
186   private int prev;
187
188   /**
189    * Number of currently objects in the map.
190    */
191   private int size;
192
193   /**
194    * This array holds the values
195    */
196   double[] values;
197
198   /**
199    * Constructs a map with default capacity.
200    */
201   public IntToDoubleMap() {
202     this(defaultCapacity);
203   }
204
205   /**
206    * Constructs a map with given capacity. Capacity is adjusted to a native
207    * power of 2, with minimum of 16.
208    * 
209    * @param capacity
210    *            minimum capacity for the map.
211    */
212   public IntToDoubleMap(int capacity) {
213     this.capacity = 16;
214     // Minimum capacity is 16..
215     while (this.capacity < capacity) {
216       // Multiply by 2 as long as we're still under the requested capacity
217       this.capacity <<= 1;
218     }
219
220     // As mentioned, we use the first index (0) as 'Ground', so we need the
221     // length of the arrays to be one more than the capacity
222     int arrayLength = this.capacity + 1;
223
224     this.values = new double[arrayLength];
225     this.keys = new int[arrayLength];
226     this.next = new int[arrayLength];
227
228     // Hash entries are twice as big as the capacity.
229     int baseHashSize = this.capacity << 1;
230
231     this.baseHash = new int[baseHashSize];
232
233     this.values[0] = GROUND;
234
235     // The has factor is 2^M - 1 which is used as an "AND" hashing operator.
236     // {@link #calcBaseHash()}
237     this.hashFactor = baseHashSize - 1;
238
239     this.size = 0;
240
241     clear();
242   }
243
244   /**
245    * Adds a pair to the map. Takes the first empty position from the
246    * empty-linked-list's head - {@link firstEmpty}.
247    * 
248    * New pairs are always inserted to baseHash, and are followed by the old
249    * colliding pair.
250    * 
251    * @param key
252    *            integer which maps the given Object
253    * @param v
254    *            double value which is being mapped using the given key
255    */
256   private void prvt_put(int key, double v) {
257     // Hash entry to which the new pair would be inserted
258     int hashIndex = calcBaseHashIndex(key);
259
260     // 'Allocating' a pair from the "Empty" list.
261     int objectIndex = firstEmpty;
262
263     // Setting data
264     firstEmpty = next[firstEmpty];
265     values[objectIndex] = v;
266     keys[objectIndex] = key;
267
268     // Inserting the new pair as the first node in the specific hash entry
269     next[objectIndex] = baseHash[hashIndex];
270     baseHash[hashIndex] = objectIndex;
271
272     // Announcing a new pair was added!
273     ++size;
274   }
275
276   /**
277    * Calculating the baseHash index using the internal <code>hashFactor</code>
278    * .
279    * 
280    * @param key
281    */
282   protected int calcBaseHashIndex(int key) {
283     return key & hashFactor;
284   }
285
286   /**
287    * Empties the map. Generates the "Empty" space list for later allocation.
288    */
289   public void clear() {
290     // Clears the hash entries
291     Arrays.fill(this.baseHash, 0);
292
293     // Set size to zero
294     size = 0;
295
296     // Mark all array entries as empty. This is done with
297     // <code>firstEmpty</code> pointing to the first valid index (1 as 0 is
298     // used as 'Ground').
299     firstEmpty = 1;
300
301     // And setting all the <code>next[i]</code> to point at
302     // <code>i+1</code>.
303     for (int i = 1; i < this.capacity;) {
304       next[i] = ++i;
305     }
306
307     // Surly, the last one should point to the 'Ground'.
308     next[this.capacity] = 0;
309   }
310
311   /**
312    * Checks if a given key exists in the map.
313    * 
314    * @param key
315    *            that is checked against the map data.
316    * @return true if the key exists in the map. false otherwise.
317    */
318   public boolean containsKey(int key) {
319     return find(key) != 0;
320   }
321
322   /**
323    * Checks if the given value exists in the map.<br>
324    * This method iterates over the collection, trying to find an equal object.
325    * 
326    * @param value
327    *            double value that is checked against the map data.
328    * @return true if the value exists in the map, false otherwise.
329    */
330   public boolean containsValue(double value) {
331     for (DoubleIterator iterator = iterator(); iterator.hasNext();) {
332       double d = iterator.next();
333       if (d == value) {
334         return true;
335       }
336     }
337     return false;
338   }
339
340   /**
341    * Find the actual index of a given key.
342    * 
343    * @param key
344    * @return index of the key. zero if the key wasn't found.
345    */
346   protected int find(int key) {
347     // Calculate the hash entry.
348     int baseHashIndex = calcBaseHashIndex(key);
349
350     // Start from the hash entry.
351     int localIndex = baseHash[baseHashIndex];
352
353     // while the index does not point to the 'Ground'
354     while (localIndex != 0) {
355       // returns the index found in case of of a matching key.
356       if (keys[localIndex] == key) {
357         return localIndex;
358       }
359         
360       // next the local index
361       localIndex = next[localIndex];
362     }
363
364     // If we got this far, it could only mean we did not find the key we
365     // were asked for. return 'Ground' index.
366     return 0;
367   }
368
369   /**
370    * Find the actual index of a given key with it's baseHashIndex.<br>
371    * Some methods use the baseHashIndex. If those call {@link #find()} there's
372    * no need to re-calculate that hash.
373    * 
374    * @param key
375    * @param baseHashIndex
376    * @return the index of the given key, or 0 as 'Ground' if the key wasn't
377    *         found.
378    */
379   private int findForRemove(int key, int baseHashIndex) {
380     // Start from the hash entry.
381     this.prev = 0;
382     int index = baseHash[baseHashIndex];
383
384     // while the index does not point to the 'Ground'
385     while (index != 0) {
386       // returns the index found in case of of a matching key.
387       if (keys[index] == key) {
388         return index;
389       }
390
391       // next the local index
392       prev = index;
393       index = next[index];
394     }
395
396     // If we got this far, it could only mean we did not find the key we
397     // were asked for. return 'Ground' index.
398     this.prev = 0;
399     return 0;
400   }
401
402   /**
403    * Returns the value mapped with the given key.
404    * 
405    * @param key
406    *            int who's mapped object we're interested in.
407    * @return a double value mapped by the given key. Double.NaN if the key wasn't found.
408    */
409   public double get(int key) {
410     return values[find(key)];
411   }
412
413   /**
414    * Grows the map. Allocates a new map of double the capacity, and
415    * fast-insert the old key-value pairs.
416    */
417   protected void grow() {
418     IntToDoubleMap that = new IntToDoubleMap(
419         this.capacity * 2);
420
421     // Iterates fast over the collection. Any valid pair is put into the new
422     // map without checking for duplicates or if there's enough space for
423     // it.
424     for (IndexIterator iterator = new IndexIterator(); iterator.hasNext();) {
425       int index = iterator.next();
426       that.prvt_put(this.keys[index], this.values[index]);
427     }
428
429     // Copy that's data into this.
430     this.capacity = that.capacity;
431     this.size = that.size;
432     this.firstEmpty = that.firstEmpty;
433     this.values = that.values;
434     this.keys = that.keys;
435     this.next = that.next;
436     this.baseHash = that.baseHash;
437     this.hashFactor = that.hashFactor;
438   }
439
440   /**
441    * 
442    * @return true if the map is empty. false otherwise.
443    */
444   public boolean isEmpty() {
445     return size == 0;
446   }
447
448   /**
449    * Returns a new iterator for the mapped double values.
450    */
451   public DoubleIterator iterator() {
452     return new ValueIterator();
453   }
454
455   /** Returns an iterator on the map keys. */
456   public IntIterator keyIterator() {
457     return new KeyIterator();
458   }
459
460   /**
461    * Prints the baseHash array, used for debug purposes.
462    */
463   @SuppressWarnings("unused")
464   private void printBaseHash() {
465     for (int i = 0; i < this.baseHash.length; i++) {
466       System.out.println(i + ".\t" + baseHash[i]);
467     }
468   }
469
470   /**
471    * Inserts the &lt;key,value&gt; pair into the map. If the key already exists,
472    * this method updates the mapped value to the given one, returning the old
473    * mapped value.
474    * 
475    * @return the old mapped value, or {@link Double#NaN} if the key didn't exist.
476    */
477   public double put(int key, double v) {
478     // Does key exists?
479     int index = find(key);
480
481     // Yes!
482     if (index != 0) {
483       // Set new data and exit.
484       double old = values[index];
485       values[index] = v;
486       return old;
487     }
488
489     // Is there enough room for a new pair?
490     if (size == capacity) {
491       // No? Than grow up!
492       grow();
493     }
494
495     // Now that everything is set, the pair can be just put inside with no
496     // worries.
497     prvt_put(key, v);
498
499     return Double.NaN;
500   }
501
502   /**
503    * Removes a &lt;key,value&gt; pair from the map and returns the mapped value,
504    * or {@link Double#NaN} if the none existed.
505    * 
506    * @param key used to find the value to remove
507    * @return the removed value or {@link Double#NaN} if none existed.
508    */
509   public double remove(int key) {
510     int baseHashIndex = calcBaseHashIndex(key);
511     int index = findForRemove(key, baseHashIndex);
512     if (index != 0) {
513       // If it is the first in the collision list, we should promote its
514       // next colliding element.
515       if (prev == 0) {
516         baseHash[baseHashIndex] = next[index];
517       }
518
519       next[prev] = next[index];
520       next[index] = firstEmpty;
521       firstEmpty = index;
522       --size;
523       return values[index];
524     }
525
526     return Double.NaN;
527   }
528
529   /**
530    * @return number of pairs currently in the map
531    */
532   public int size() {
533     return this.size;
534   }
535
536   /**
537    * Translates the mapped pairs' values into an array of Objects
538    * 
539    * @return a double array of all the values currently in the map.
540    */
541   public double[] toArray() {
542     int j = -1;
543     double[] array = new double[size];
544
545     // Iterates over the values, adding them to the array.
546     for (DoubleIterator iterator = iterator(); iterator.hasNext();) {
547       array[++j] = iterator.next();
548     }
549     return array;
550   }
551
552   /**
553    * Translates the mapped pairs' values into an array of T
554    * 
555    * @param a
556    *            the array into which the elements of the list are to be
557    *            stored. If it is big enough use whatever space we need,
558    *            setting the one after the true data as {@link Double#NaN}.
559    * 
560    * @return an array containing the elements of the list, using the given
561    *         parameter if big enough, otherwise allocate an appropriate array
562    *         and return it.
563    * 
564    */
565   public double[] toArray(double[] a) {
566     int j = 0;
567     if (a.length < this.size()) {
568       a = new double[this.size()];
569     }
570
571     // Iterates over the values, adding them to the array.
572     for (DoubleIterator iterator = iterator(); iterator.hasNext(); ++j) {
573       a[j] = iterator.next();
574     }
575
576     if (j < a.length) {
577       a[j] = Double.NaN;
578     }
579
580     return a;
581   }
582
583   @Override
584   public String toString() {
585     StringBuffer sb = new StringBuffer();
586     sb.append('{');
587     IntIterator keyIterator = keyIterator();
588     while (keyIterator.hasNext()) {
589       int key = keyIterator.next();
590       sb.append(key);
591       sb.append('=');
592       sb.append(get(key));
593       if (keyIterator.hasNext()) {
594         sb.append(',');
595         sb.append(' ');
596       }
597     }
598     sb.append('}');
599     return sb.toString();
600   }
601   
602   @Override
603   public int hashCode() {
604     return getClass().hashCode() ^ size();
605   }
606   
607   @Override
608   public boolean equals(Object o) {
609     IntToDoubleMap that = (IntToDoubleMap)o;
610     if (that.size() != this.size()) {
611       return false;
612     }
613     
614     IntIterator it = keyIterator();
615     while (it.hasNext()) {
616       int key = it.next();
617       if (!that.containsKey(key)) {
618         return false;
619       }
620
621       double v1 = this.get(key);
622       double v2 = that.get(key);
623       if (Double.compare(v1, v2) != 0) {
624         return false;
625       }
626     }
627     return true;
628   }
629 }