KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > avalon > excalibur > collections > BucketMap


1 /*
2
3  ============================================================================
4                    The Apache Software License, Version 1.1
5  ============================================================================
6  
7  Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
8  
9  Redistribution and use in source and binary forms, with or without modifica-
10  tion, are permitted provided that the following conditions are met:
11  
12  1. Redistributions of source code must retain the above copyright notice,
13     this list of conditions and the following disclaimer.
14  
15  2. Redistributions in binary form must reproduce the above copyright notice,
16     this list of conditions and the following disclaimer in the documentation
17     and/or other materials provided with the distribution.
18  
19  3. The end-user documentation included with the redistribution, if any, must
20     include the following acknowledgment: "This product includes software
21     developed by the Apache Software Foundation (http://www.apache.org/)."
22     Alternately, this acknowledgment may appear in the software itself, if
23     and wherever such third-party acknowledgments normally appear.
24  
25  4. The names "Jakarta", "Avalon", "Excalibur" and "Apache Software Foundation"
26     must not be used to endorse or promote products derived from this software
27     without prior written permission. For written permission, please contact
28     apache@apache.org.
29  
30  5. Products derived from this software may not be called "Apache", nor may
31     "Apache" appear in their name, without prior written permission of the
32     Apache Software Foundation.
33  
34  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
35  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
36  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
37  APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
38  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
39  DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
40  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
41  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
43  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44  
45  This software consists of voluntary contributions made by many individuals
46  on behalf of the Apache Software Foundation. For more information on the
47  Apache Software Foundation, please see <http://www.apache.org/>.
48  
49 */

50 package org.apache.avalon.excalibur.collections;
51
52 import java.util.Collection JavaDoc;
53 import java.util.HashSet JavaDoc;
54 import java.util.Iterator JavaDoc;
55 import java.util.Map JavaDoc;
56 import java.util.Set JavaDoc;
57
58 /**
59  * A BucketMap is an efficient thread-safe implementation of the
60  * <code>java.util.Map</code>. The map supports <code>get</code>,
61  * <code>put</code>, and <code>contains</code> methods most efficiently.
62  * The other methods are supported, but are ver inneficient compared to
63  * other <code>java.util.Map</code> implementations.
64  *
65  * @deprecated use org.apache.commons.collections.StaticBucketMap instead
66  *
67  * @author <a HREF="bloritsch@apache.org">Berin Loritsch</a>
68  * @author <a HREF="g-froehlich@gmx.de">Gerhard Froehlich</a>
69  * @version CVS $Revision: 1.4 $ $Date: 2003/03/22 12:46:22 $
70  * @since 4.0
71  */

72 public final class BucketMap implements Map JavaDoc
73 {
74     private static final int DEFAULT_BUCKETS = 256;
75     private final Node[] m_buckets;
76     private volatile int m_size = 0;
77
78     /**
79      * Initializes the map with the default number of buckets.
80      */

81     public BucketMap()
82     {
83         this( DEFAULT_BUCKETS );
84     }
85
86     /**
87      * Initializes the map with a specified number of buckets. The number
88      * of buckets is never below 17, and is always an odd number (BucketMap
89      * ensures this). The number of buckets is inversely proportional to the
90      * chances for thread contention. The fewer buckets, the more chances for
91      * thread contention. The more buckets the fewer chances for thread
92      * contention.
93      */

94     public BucketMap( int numBuckets )
95     {
96         int size = Math.max( 17, numBuckets );
97
98         m_buckets = new Node[ size ];
99
100         for( int i = 0; i < size; i++ )
101         {
102             m_buckets[ i ] = new Node();
103         }
104     }
105
106     /**
107      * Determine the exact hash entry for the key. The hash algorithm
108      * is rather simplistic, but it does the job:
109      *
110      * <pre>
111      * He = |Hk mod n|
112      * </pre>
113      *
114      * <p>
115      * He is the entry's hashCode, Hk is the key's hashCode, and n is
116      * the number of buckets.
117      * </p>
118      */

119     private final int getHash( Object JavaDoc key )
120     {
121         int hash = key.hashCode();
122         
123         hash += ~(hash << 9);
124         hash ^= (hash >>> 14);
125         hash += (hash << 4);
126         hash ^= (hash >>> 10);
127         
128         hash %= m_buckets.length;
129
130         return ( hash < 0 ) ? hash * -1 : hash;
131     }
132
133     /**
134      * Obtain a Set for the keys. This operation crosses bucket boundaries,
135      * so it is less efficient, and greatly increases the chance for thread
136      * contention.
137      */

138     public Set JavaDoc keySet()
139     {
140         Set JavaDoc keySet = new HashSet JavaDoc();
141
142         for( int i = 0; i < m_buckets.length; i++ )
143         {
144             synchronized( m_buckets[ i ] )
145             {
146                 Node n = m_buckets[ i ];
147
148                 while( n != null && n.key != null )
149                 {
150                     keySet.add( n.key );
151                     n = n.next;
152                 }
153             }
154         }
155
156         return keySet;
157     }
158
159     /**
160      * Returns the current number of key, value pairs.
161      */

162     public int size()
163     {
164         return m_size;
165     }
166
167     /**
168      * Put a reference in the Map.
169      */

170     public Object JavaDoc put( final Object JavaDoc key, final Object JavaDoc value )
171     {
172         if( null == key || null == value )
173         {
174             return null;
175         }
176
177         int hash = getHash( key );
178
179         synchronized( m_buckets[ hash ] )
180         {
181             Node n = m_buckets[ hash ];
182
183             if( n.key == null )
184             {
185                 n.key = key;
186                 n.value = value;
187                 m_size++;
188                 return value;
189             }
190
191             // Set n to the last node in the linked list. Check each key along the way
192
// If the key is found, then change the value of that node and return
193
// the old value.
194
for( Node next = n; next != null; next = next.next )
195             {
196                 n = next;
197
198                 if( ( n.key == key ) || ( n.key.equals( key ) ) )
199                 {
200                     // do not adjust size because nothing was added
201
Object JavaDoc returnVal = n.value;
202                     n.value = value;
203                     return returnVal;
204                 }
205             }
206
207             // The key was not found in the current list of nodes, add it to the end
208
// in a new node.
209
Node newNode = new Node();
210             newNode.key = key;
211             newNode.value = value;
212             n.next = newNode;
213             m_size++;
214         }
215
216         return null;
217     }
218
219     /**
220      * Get an object from the Map by the key
221      */

222     public Object JavaDoc get( final Object JavaDoc key )
223     {
224         if( null == key )
225         {
226             return null;
227         }
228
229         int hash = getHash( key );
230
231         synchronized( m_buckets[ hash ] )
232         {
233             Node n = m_buckets[ hash ];
234
235             while( n != null && n.key != null )
236             {
237                 if( ( n.key == key ) || ( n.key.equals( key ) ) )
238                 {
239                     return n.value;
240                 }
241
242                 n = n.next;
243             }
244         }
245
246         return null;
247     }
248
249     /**
250      * Checks to see if the provided key exists in the Map.
251      */

252     public boolean containsKey( final Object JavaDoc key )
253     {
254         if( null == key )
255         {
256             return false;
257         }
258
259         int hash = getHash( key );
260
261         synchronized( m_buckets[ hash ] )
262         {
263             Node n = m_buckets[ hash ];
264
265             while( n != null && n.key != null )
266             {
267                 if( ( n.key == key ) || ( n.key.equals( key ) ) )
268                 {
269                     return true;
270                 }
271
272                 n = n.next;
273             }
274         }
275
276         return false;
277     }
278
279     /**
280      * Checks to see if a value exists. This operation crosses bucket
281      * boundaries, so it is less efficient, and greatly increases the chance
282      * for thread contention.
283      */

284     public boolean containsValue( final Object JavaDoc value )
285     {
286         if( null == value )
287         {
288             return false;
289         }
290
291         for( int i = 0; i < m_buckets.length; i++ )
292         {
293             synchronized( m_buckets[ i ] )
294             {
295                 Node n = m_buckets[ i ];
296
297                 while( n != null && n.key != null )
298                 {
299                     if( ( n.value == value ) || ( n.value.equals( value ) ) )
300                     {
301                         return true;
302                     }
303
304                     n = n.next;
305                 }
306             }
307         }
308
309         return false;
310     }
311
312     /**
313      * Obtain a Set for the values. This operation crosses bucket boundaries,
314      * so it is less efficient, and greatly increases the chance for thread
315      * contention.
316      */

317     public Collection JavaDoc values()
318     {
319         Set JavaDoc valueSet = new HashSet JavaDoc();
320
321         for( int i = 0; i < m_buckets.length; i++ )
322         {
323             synchronized( m_buckets[ i ] )
324             {
325                 Node n = m_buckets[ i ];
326
327                 while( n != null && n.key != null )
328                 {
329                     valueSet.add( n.value );
330                     n = n.next;
331                 }
332             }
333         }
334
335         return valueSet;
336     }
337
338     /**
339      * Obtain a Set for the entries. This operation crosses bucket boundaries,
340      * so it is less efficient, and greatly increases the chance for thread
341      * contention.
342      */

343     public Set JavaDoc entrySet()
344     {
345         Set JavaDoc entrySet = new HashSet JavaDoc();
346
347         for( int i = 0; i < m_buckets.length; i++ )
348         {
349             synchronized( m_buckets[ i ] )
350             {
351                 Node n = m_buckets[ i ];
352
353                 while( n != null && n.key != null )
354                 {
355                     entrySet.add( n );
356                     n = n.next;
357                 }
358             }
359         }
360
361         return entrySet;
362     }
363
364     /**
365      * Add all the contents of one Map into this one.
366      */

367     public void putAll( Map JavaDoc other )
368     {
369         Iterator JavaDoc i = other.keySet().iterator();
370
371         while( i.hasNext() )
372         {
373             Object JavaDoc key = i.next();
374             put( key, other.get( key ) );
375         }
376     }
377
378     /**
379      * Removes the object from the Map based on the key.
380      */

381     public Object JavaDoc remove( Object JavaDoc key )
382     {
383         if( null == key )
384         {
385             return null;
386         }
387
388         int hash = getHash( key );
389
390         synchronized( m_buckets[ hash ] )
391         {
392             Node n = m_buckets[ hash ];
393             Node prev = null;
394
395             while( n != null && n.key != null )
396             {
397                 if( ( n.key == key ) || ( n.key.equals( key ) ) )
398                 {
399                     // Remove this node from the linked list of nodes.
400
if( null == prev )
401                     {
402                         // This node was the head, set the next node to be the new head.
403
m_buckets[ hash ] = ( n.next == null ? new Node() : n.next );
404                     }
405                     else
406                     {
407                         // Set the next node of the previous node to be the node after this one.
408
prev.next = n.next;
409                     }
410
411                     m_size--;
412                     return n.value;
413                 }
414
415                 prev = n;
416                 n = n.next;
417             }
418         }
419
420         return null;
421     }
422
423     /**
424      * Tests if the Map is empty.
425      */

426     public final boolean isEmpty()
427     {
428         return m_size == 0;
429     }
430
431     /**
432      * Removes all the entries from the Map.
433      */

434     public final void clear()
435     {
436         for( int i = 0; i < m_buckets.length; i++ )
437         {
438             m_buckets[ i ] = null; // be explicit
439
m_buckets[ i ] = new Node();
440         }
441     }
442
443     /**
444      * The Map.Entry for the BucketMap.
445      */

446     private final class Node implements Map.Entry JavaDoc
447     {
448         protected Object JavaDoc key;
449         protected Object JavaDoc value;
450         protected Node next;
451
452         public Object JavaDoc getKey()
453         {
454             return key;
455         }
456
457         public Object JavaDoc getValue()
458         {
459             return value;
460         }
461
462         public int hashCode()
463         {
464             return getHash( key );
465         }
466
467         public Object JavaDoc setValue( Object JavaDoc val )
468         {
469             Object JavaDoc retVal = value;
470             value = val;
471             return retVal;
472         }
473     }
474 }
475
Popular Tags