Coverage Report - jaggregate.AbstractDictionaryImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractDictionaryImpl
100%
144/144
100%
13/13
0
AbstractDictionaryImpl$1
100%
3/3
N/A
0
AbstractDictionaryImpl$10
100%
5/5
100%
1/1
0
AbstractDictionaryImpl$11
100%
2/2
100%
1/1
0
AbstractDictionaryImpl$12
100%
5/5
100%
1/1
0
AbstractDictionaryImpl$13
100%
5/5
100%
1/1
0
AbstractDictionaryImpl$14
100%
4/4
100%
1/1
0
AbstractDictionaryImpl$15
100%
3/3
N/A
0
AbstractDictionaryImpl$16
100%
2/2
N/A
0
AbstractDictionaryImpl$17
100%
7/7
N/A
0
AbstractDictionaryImpl$18
67%
4/6
N/A
0
AbstractDictionaryImpl$2
100%
3/3
N/A
0
AbstractDictionaryImpl$3
100%
5/5
100%
1/1
0
AbstractDictionaryImpl$4
100%
3/3
N/A
0
AbstractDictionaryImpl$5
100%
3/3
N/A
0
AbstractDictionaryImpl$6
100%
3/3
N/A
0
AbstractDictionaryImpl$7
100%
4/4
100%
1/1
0
AbstractDictionaryImpl$8
100%
3/3
N/A
0
AbstractDictionaryImpl$9
100%
5/5
100%
1/1
0
AbstractDictionaryImpl$DictionaryEqualityTester
100%
11/11
100%
3/3
0
 
 1  
 /*
 2  
  Copyright 2004-2008 Paul R. Holser, Jr.  All rights reserved.
 3  
  Licensed under the Academic Free License version 3.0
 4  
  */
 5  
 
 6  
 package jaggregate;
 7  
 
 8  
 import java.io.IOException;
 9  
 import java.io.ObjectInputStream;
 10  
 import java.io.ObjectOutputStream;
 11  
 
 12  
 import jaggregate.internal.Casting;
 13  
 import jaggregate.internal.EquivalenceTester;
 14  
 import jaggregate.internal.HashingContainer;
 15  
 import jaggregate.internal.NonLocalReturnException;
 16  
 import static jaggregate.internal.ArgumentChecks.*;
 17  
 import static jaggregate.internal.Casting.*;
 18  
 
 19  
 /**
 20  
  * Implementation of the <dfn>dictionary</dfn> concept that should be common for most
 21  
  * concrete implementations.
 22  
  *
 23  
  * @param <K> a restriction on the types of the keys that may be contained in the
 24  
  * dictionary
 25  
  * @param <V> a restriction on the types of the values that may be contained in the
 26  
  * dictionary
 27  
  *
 28  
  * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
 29  
  * @version $Id: AbstractDictionaryImpl.java,v 1.10 2008/10/03 19:01:23 pholser Exp $
 30  
  */
 31  2587
 public abstract class AbstractDictionaryImpl<K, V>
 32  
     extends AbstractExtensibleCollection<Pair<K, V>>
 33  
     implements AbstractDictionary<K, V> {
 34  
 
 35  
     private transient HashingContainer<K, V> hash;
 36  
 
 37  
     /**
 38  
      * For subclasses, so they can serialize themselves.
 39  
      */
 40  6
     protected AbstractDictionaryImpl() {
 41  
         // nothing to do
 42  6
     }
 43  
 
 44  
     /**
 45  
      * Creates an empty dictionary that uses the given strategy to determine key
 46  
      * equivalence.
 47  
      *
 48  
      * @param equivalenceTester a key equivalence strategy
 49  
      */
 50  2329
     protected AbstractDictionaryImpl( EquivalenceTester equivalenceTester ) {
 51  2329
         hash = new HashingContainer<K, V>( equivalenceTester );
 52  2329
     }
 53  
 
 54  
     /**
 55  
      * Creates a dictionary that contains the given associations and uses the given
 56  
      * strategy to determine key equivalence.
 57  
      *
 58  
      * @param associations the associations for the new dictionary to have
 59  
      * @param equivalenceTester a key equivalence strategy
 60  
      */
 61  
     protected AbstractDictionaryImpl(
 62  
         AbstractDictionary<? extends K, ? extends V> associations,
 63  
         EquivalenceTester equivalenceTester ) {
 64  
 
 65  11
         this( equivalenceTester );
 66  11
         putAll( associations );
 67  9
     }
 68  
 
 69  
     /**
 70  
      * {@inheritDoc}
 71  
      */
 72  
     public void add( Pair<K, V> newElement ) {
 73  468
         if ( newElement == null )
 74  6
             throw new IllegalArgumentException( "cannot add a null pair" );
 75  
 
 76  462
         putAt( newElement.key(), newElement.value() );
 77  462
     }
 78  
 
 79  
     /**
 80  
      * {@inheritDoc}
 81  
      */
 82  
     @Override
 83  
     public <R> AbstractBag<R> collect(
 84  
         UnaryFunctor<? super Pair<K, V>, ? extends R> transformer ) {
 85  
 
 86  5
         return (AbstractBag<R>) super.collect( transformer );
 87  
     }
 88  
 
 89  
     /**
 90  
      * {@inheritDoc}
 91  
      */
 92  
     public void forEachDo( UnaryFunctor<? super Pair<K, V>, ?> operation ) {
 93  2706
         ensureNotNull( operation, OPERATION );
 94  
 
 95  2704
         hash.forEachDo( operation );
 96  2417
     }
 97  
 
 98  
     /**
 99  
      * {@inheritDoc}
 100  
      */
 101  
     @Override
 102  
     public boolean includes( Pair<K, V> target ) {
 103  300
         if ( target == null )
 104  6
             return false;
 105  
 
 106  294
         K key = target.key();
 107  294
         return includesKey( key ) && hash.areEqual( at( key ), target.value() );
 108  
     }
 109  
 
 110  
     /**
 111  
      * {@inheritDoc}
 112  
      */
 113  
     @Override
 114  
     public int occurrencesOf( Pair<K, V> target ) {
 115  11
         return includes( target ) ? 1 : 0;
 116  
     }
 117  
 
 118  
     /**
 119  
      * {@inheritDoc}
 120  
      */
 121  
     @Override
 122  
     public void rehash() {
 123  11
         hash.rehash();
 124  11
     }
 125  
 
 126  
     /**
 127  
      * {@inheritDoc}
 128  
      */
 129  
     @Override
 130  
     public AbstractDictionary<K, V> reject(
 131  
         UnaryCondition<? super Pair<K, V>> discriminator ) {
 132  
 
 133  10
         return (AbstractDictionary<K, V>) super.reject( discriminator );
 134  
     }
 135  
 
 136  
     /**
 137  
      * {@inheritDoc}
 138  
      */
 139  
     @Override
 140  
     public AbstractDictionary<K, V> select(
 141  
         UnaryCondition<? super Pair<K, V>> discriminator ) {
 142  
 
 143  10
         return (AbstractDictionary<K, V>) super.select( discriminator );
 144  
     }
 145  
 
 146  
     /**
 147  
      * {@inheritDoc}
 148  
      */
 149  
     public int size() {
 150  3572
         return hash.size();
 151  
     }
 152  
 
 153  
     /**
 154  
      * {@inheritDoc}
 155  
      */
 156  
     public void putAll( AbstractDictionary<? extends K, ? extends V> newPairs ) {
 157  35
         newPairs.keysAndValuesDo( new BinaryFunctor<K, V, Void>() {
 158  136
             public Void evaluate( K first, V second ) {
 159  101
                 putAt( first, second );
 160  101
                 return null;
 161  
             }
 162  
         } );
 163  31
     }
 164  
 
 165  
     /**
 166  
      * {@inheritDoc}
 167  
      */
 168  
     public V at( K key ) {
 169  6574
         return hash.get( key );
 170  
     }
 171  
 
 172  
     /**
 173  
      * {@inheritDoc}
 174  
      */
 175  
     public <R> AbstractDictionary<K, R> collectValues(
 176  
         final UnaryFunctor<? super V, ? extends R> transformer ) {
 177  
 
 178  9
         ensureNotNull( transformer, TRANSFORMER );
 179  
 
 180  7
         final AbstractDictionary<K, R> results = newEmptyDictionary();
 181  
 
 182  7
         keysAndValuesDo( new BinaryFunctor<K, V, Void>() {
 183  21
             public Void evaluate( K first, V second ) {
 184  14
                 results.putAt( first, transformer.evaluate( second ) );
 185  14
                 return null;
 186  
             }
 187  
         } );
 188  
 
 189  7
         return results;
 190  
     }
 191  
 
 192  
     /**
 193  
      * {@inheritDoc}
 194  
      */
 195  
     public boolean includesKey( K key ) {
 196  2827
         return hash.hasKey( key );
 197  
     }
 198  
 
 199  
     /**
 200  
      * {@inheritDoc}
 201  
      */
 202  
     public K keyAt( final V value ) {
 203  6
         final Object[] correspondingKey = new Object[] { null };
 204  
 
 205  
         try {
 206  6
             keysAndValuesDo( new BinaryFunctor<K, V, Void>() {
 207  11
                 public Void evaluate( K first, V second ) {
 208  5
                     if ( hash.areEqual( value, second ) ) {
 209  4
                         correspondingKey[ 0 ] = first;
 210  4
                         throw new NonLocalReturnException();
 211  
                     }
 212  
 
 213  1
                     return null;
 214  
                 }
 215  
             } );
 216  
 
 217  2
             return null;
 218  
         }
 219  4
         catch ( NonLocalReturnException ignored ) {
 220  4
             return Casting.<K>cast( correspondingKey[ 0 ] );
 221  
         }
 222  
     }
 223  
 
 224  
     /**
 225  
      * {@inheritDoc}
 226  
      */
 227  
     public AbstractSet<K> keys() {
 228  22
         final AbstractSet<K> keys = newEmptySet();
 229  
 
 230  22
         keysDo( new UnaryFunctor<K, Void>() {
 231  106
             public Void evaluate( K argument ) {
 232  84
                 keys.add( argument );
 233  84
                 return null;
 234  
             }
 235  
         } );
 236  
 
 237  22
         return keys;
 238  
     }
 239  
 
 240  
     /**
 241  
      * {@inheritDoc}
 242  
      */
 243  
     public void keysAndValuesDo(
 244  
         final BinaryFunctor<? super K, ? super V, ?> operation ) {
 245  
 
 246  1593
         ensureNotNull( operation, OPERATION );
 247  
 
 248  1591
         forEachDo( new UnaryFunctor<Pair<K, V>, Void>() {
 249  6324
             public Void evaluate( Pair<K, V> argument ) {
 250  4733
                 operation.evaluate( argument.key(), argument.value() );
 251  4467
                 return null;
 252  
             }
 253  
         } );
 254  1325
     }
 255  
 
 256  
     /**
 257  
      * {@inheritDoc}
 258  
      */
 259  
     public <R> void keysDo( final UnaryFunctor<? super K, ? extends R> operation ) {
 260  431
         ensureNotNull( operation, OPERATION );
 261  
 
 262  427
         forEachDo( new UnaryFunctor<Pair<K, V>, Void>() {
 263  1837
             public Void evaluate( Pair<K, V> argument ) {
 264  1410
                 operation.evaluate( argument.key() );
 265  1401
                 return null;
 266  
             }
 267  
         } );
 268  418
     }
 269  
 
 270  
     /**
 271  
      * {@inheritDoc}
 272  
      */
 273  
     public V putAt( K key, V newElement ) {
 274  8069
         return hash.put( key, newElement );
 275  
     }
 276  
 
 277  
     /**
 278  
      * {@inheritDoc}
 279  
      */
 280  
     public AbstractDictionary<K, V> rejectValues(
 281  
         final UnaryCondition<? super V> discriminator ) {
 282  
 
 283  9
         ensureNotNull( discriminator, DISCRIMINATOR );
 284  
 
 285  7
         final AbstractDictionary<K, V> rejects = newEmptyDictionary();
 286  
 
 287  7
         keysAndValuesDo( new BinaryFunctor<K, V, Void>() {
 288  21
             public Void evaluate( K first, V second ) {
 289  14
                 if ( !discriminator.matches( second ) )
 290  11
                     rejects.putAt( first, second );
 291  
 
 292  14
                 return null;
 293  
             }
 294  
         } );
 295  
 
 296  7
         return rejects;
 297  
     }
 298  
 
 299  
     /**
 300  
      * {@inheritDoc}
 301  
      */
 302  
     public boolean remove( Pair<K, V> oldElement ) {
 303  279
         if ( includes( oldElement ) ) {
 304  226
             removeKey( oldElement.key() );
 305  226
             return true;
 306  
         }
 307  
 
 308  53
         return false;
 309  
     }
 310  
 
 311  
     /**
 312  
      * {@inheritDoc}
 313  
      */
 314  
     public V removeKey( K key ) {
 315  1403
         return hash.remove( key );
 316  
     }
 317  
 
 318  
     /**
 319  
      * {@inheritDoc}
 320  
      */
 321  
     public void removeAllKeys( Collection<? extends K> oldKeys ) {
 322  7
         oldKeys.forEachDo( new UnaryFunctor<K, Void>() {
 323  22
             public Void evaluate( K argument ) {
 324  15
                 removeKey( argument );
 325  15
                 return null;
 326  
             }
 327  
         } );
 328  5
     }
 329  
 
 330  
     /**
 331  
      * {@inheritDoc}
 332  
      */
 333  
     public void removeAllKeys( K[] oldKeys ) {
 334  69
         for ( K each : oldKeys )
 335  44
             removeKey( each );
 336  23
     }
 337  
 
 338  
     /**
 339  
      * {@inheritDoc}
 340  
      */
 341  
     public void removeAllKeys( K oldKey, K... restOfOldKeys ) {
 342  22
         removeKey( oldKey );
 343  22
         removeAllKeys( restOfOldKeys );
 344  22
     }
 345  
 
 346  
     /**
 347  
      * {@inheritDoc}
 348  
      */
 349  
     public void removeAllKeys( Iterable<? extends K> oldKeys ) {
 350  22
         for ( K each : oldKeys )
 351  60
             removeKey( each );
 352  20
     }
 353  
 
 354  
     /**
 355  
      * {@inheritDoc}
 356  
      */
 357  
     public boolean removeIfKey( final UnaryCondition<? super K> discriminator ) {
 358  50
         ensureNotNull( discriminator, DISCRIMINATOR );
 359  
 
 360  48
         final boolean[] removalOccurred = new boolean[] { false };
 361  
 
 362  48
         keysDo( new UnaryFunctor<K, Void>() {
 363  366
             public Void evaluate( K argument ) {
 364  318
                 if ( discriminator.matches( argument ) ) {
 365  222
                     removalOccurred[ 0 ] = true;
 366  222
                     removeKey( argument );
 367  
                 }
 368  
 
 369  318
                 return null;
 370  
             }
 371  
         } );
 372  
 
 373  48
         return removalOccurred[ 0 ];
 374  
     }
 375  
 
 376  
     /**
 377  
      * {@inheritDoc}
 378  
      */
 379  
     public boolean removeIfValue( final UnaryCondition<? super V> discriminator ) {
 380  18
         ensureNotNull( discriminator, DISCRIMINATOR );
 381  
 
 382  16
         final boolean[] removalOccurred = new boolean[] { false };
 383  
 
 384  16
         keysAndValuesDo( new BinaryFunctor<K, V, Void>() {
 385  136
             public Void evaluate( K first, V second ) {
 386  120
                 if ( discriminator.matches( second ) ) {
 387  48
                     removalOccurred[ 0 ] = true;
 388  48
                     removeKey( first );
 389  
                 }
 390  
 
 391  120
                 return null;
 392  
             }
 393  
         } );
 394  
 
 395  16
         return removalOccurred[ 0 ];
 396  
     }
 397  
 
 398  
     private boolean retainAllKeysFrom( final Collection<Object> keepers ) {
 399  36
         return removeIfKey( new UnaryCondition<K>() {
 400  36
             public boolean matches( K target ) {
 401  228
                 return !keepers.includes( target );
 402  
             }
 403  
         } );
 404  
     }
 405  
 
 406  
     /**
 407  
      * {@inheritDoc}
 408  
      */
 409  
     public boolean retainAllKeys( Collection<? extends K> keepers ) {
 410  10
         AbstractSet<Object> setOfKeepers = newEmptySet();
 411  10
         setOfKeepers.addAll( keepers );
 412  
 
 413  8
         return retainAllKeysFrom( setOfKeepers );
 414  
     }
 415  
 
 416  
     /**
 417  
      * {@inheritDoc}
 418  
      */
 419  
     public boolean retainAllKeys( K[] keepers ) {
 420  4
         AbstractSet<Object> setOfKeepers = newEmptySet();
 421  4
         setOfKeepers.addAll( keepers );
 422  
 
 423  2
         return retainAllKeysFrom( setOfKeepers );
 424  
     }
 425  
 
 426  
     /**
 427  
      * {@inheritDoc}
 428  
      */
 429  
     public boolean retainAllKeys( K keeper, K... restOfKeepers ) {
 430  12
         AbstractSet<Object> setOfKeepers = newEmptySet();
 431  12
         setOfKeepers.add( keeper );
 432  12
         setOfKeepers.addAll( restOfKeepers );
 433  
 
 434  12
         return retainAllKeysFrom( setOfKeepers );
 435  
     }
 436  
 
 437  
     /**
 438  
      * {@inheritDoc}
 439  
      */
 440  
     public boolean retainAllKeys( Iterable<? extends K> keepers ) {
 441  16
         AbstractSet<Object> setOfKeepers = newEmptySet();
 442  16
         setOfKeepers.addAll( keepers );
 443  
 
 444  14
         return retainAllKeysFrom( setOfKeepers );
 445  
     }
 446  
 
 447  
     /**
 448  
      * {@inheritDoc}
 449  
      */
 450  
     public boolean retainIfKey( final UnaryCondition<? super K> discriminator ) {
 451  18
         ensureNotNull( discriminator, DISCRIMINATOR );
 452  
 
 453  16
         final boolean[] removalOccurred = new boolean[] { false };
 454  
 
 455  16
         keysDo( new UnaryFunctor<K, Void>() {
 456  136
             public Void evaluate( K argument ) {
 457  120
                 if ( !discriminator.matches( argument ) ) {
 458  48
                     removalOccurred[ 0 ] = true;
 459  48
                     removeKey( argument );
 460  
                 }
 461  
 
 462  120
                 return null;
 463  
             }
 464  
         } );
 465  
 
 466  16
         return removalOccurred[ 0 ];
 467  
     }
 468  
 
 469  
     /**
 470  
      * {@inheritDoc}
 471  
      */
 472  
     public boolean retainIfValue( final UnaryCondition<? super V> discriminator ) {
 473  14
         ensureNotNull( discriminator, DISCRIMINATOR );
 474  
 
 475  12
         final boolean[] removalOccurred = new boolean[] { false };
 476  
 
 477  12
         keysAndValuesDo( new BinaryFunctor<K, V, Void>() {
 478  102
             public Void evaluate( K first, V second ) {
 479  90
                 if ( !discriminator.matches( second ) ) {
 480  54
                     removalOccurred[ 0 ] = true;
 481  54
                     removeKey( first );
 482  
                 }
 483  
 
 484  90
                 return null;
 485  
             }
 486  
         } );
 487  
 
 488  12
         return removalOccurred[ 0 ];
 489  
     }
 490  
 
 491  
     /**
 492  
      * {@inheritDoc}
 493  
      */
 494  
     public AbstractDictionary<K, V> selectValues(
 495  
         final UnaryCondition<? super V> discriminator ) {
 496  
 
 497  34
         ensureNotNull( discriminator, DISCRIMINATOR );
 498  
 
 499  32
         final AbstractDictionary<K, V> matches = newEmptyDictionary();
 500  
 
 501  32
         keysAndValuesDo( new BinaryFunctor<K, V, Void>() {
 502  194
             public Void evaluate( K first, V second ) {
 503  162
                 if ( discriminator.matches( second ) )
 504  51
                     matches.putAt( first, second );
 505  
 
 506  162
                 return null;
 507  
             }
 508  
         } );
 509  
 
 510  32
         return matches;
 511  
     }
 512  
 
 513  
     /**
 514  
      * {@inheritDoc}
 515  
      */
 516  
     public AbstractBag<V> values() {
 517  7
         final AbstractBag<V> values = newEmptyExtensibleResultCollection();
 518  
 
 519  7
         keysAndValuesDo( new BinaryFunctor<K, V, Void>() {
 520  21
             public Void evaluate( K first, V second ) {
 521  14
                 values.add( second );
 522  14
                 return null;
 523  
             }
 524  
         } );
 525  
 
 526  7
         return values;
 527  
     }
 528  
 
 529  
     /**
 530  
      * {@inheritDoc}
 531  
      * <p/>
 532  
      * An object is considered equivalent to this dictionary if the object is assignable
 533  
      * to this dictionary's class and has equivalent contents, as defined by this
 534  
      * dictionary's notion of equivalence.
 535  
      */
 536  
     @Override
 537  
     public boolean equals( Object that ) {
 538  1821
         if ( this == that )
 539  168
             return true;
 540  
 
 541  1653
         if ( !getImplementationClass().isInstance( that ) )
 542  2
             return false;
 543  
 
 544  1651
         final AbstractDictionary<Object, Object> other = cast( that );
 545  
 
 546  1651
         if ( size() != other.size() )
 547  504
             return false;
 548  
 
 549  
         try {
 550  1147
             keysAndValuesDo( new DictionaryEqualityTester( other ) );
 551  888
             return true;
 552  
         }
 553  259
         catch ( NonLocalReturnException ignored ) {
 554  259
             return false;
 555  
         }
 556  
     }
 557  
 
 558  
     /**
 559  
      * Subclasses implement this method to answer the root of its true runtime class,
 560  
      * for purposes of determining {@linkplain #equals(Object) equivalence}.
 561  
      *
 562  
      * @return this dictionary's implementation class
 563  
      */
 564  
     protected abstract Class<? extends AbstractDictionary> getImplementationClass();
 565  
 
 566  
     /**
 567  
      * {@inheritDoc}
 568  
      */
 569  
     @Override
 570  
     public int hashCode() {
 571  541
         return inject( 0, new BinaryFunctor<Integer, Pair<K, V>, Integer>() {
 572  2077
             public Integer evaluate( Integer first, Pair<K, V> second ) {
 573  1536
                 return first + second.hashCode();
 574  
             }
 575  
         } );
 576  
     }
 577  
 
 578  
     /**
 579  
      * {@inheritDoc}
 580  
      */
 581  
     @Override
 582  
     public String toString() {
 583  12
         final StringBuilder buffer = new StringBuilder( "{" );
 584  
 
 585  12
         if ( !isEmpty() ) {
 586  10
             hash.forEachDo( new UnaryFunctor<Pair<K, V>, Void>() {
 587  22
                 public Void evaluate( Pair<K, V> argument ) {
 588  12
                     buffer.append( '[' );
 589  12
                     buffer.append( asStringOrThis( argument.key() ) );
 590  12
                     buffer.append( '=' );
 591  12
                     buffer.append( asStringOrThis( argument.value() ) );
 592  12
                     buffer.append( "]," );
 593  12
                     return null;
 594  
                 }
 595  
             } );
 596  
 
 597  10
             buffer.deleteCharAt( buffer.length() - 1 );
 598  
         }
 599  
 
 600  12
         buffer.append( '}' );
 601  
 
 602  12
         return buffer.toString();
 603  
     }
 604  
 
 605  
     /**
 606  
      * Answers a new, empty dictionary for internal use.
 607  
      *
 608  
      * @param <T> a restriction on the types of keys allowed in the returned
 609  
      * dictionary
 610  
      * @param <U> a restriction on the types of values allowed in the returned
 611  
      * dictionary
 612  
      * @return a new, empty dictionary
 613  
      */
 614  
     protected abstract <T, U> AbstractDictionaryImpl<T, U> newEmptyDictionary();
 615  
 
 616  
     /**
 617  
      * {@inheritDoc}
 618  
      */
 619  
     @Override
 620  
     protected final AbstractDictionaryImpl<K, V> newEmptyExtensibleCollection() {
 621  16
         return newEmptyDictionary();
 622  
     }
 623  
 
 624  
     /**
 625  
      * {@inheritDoc}
 626  
      */
 627  
     @Override
 628  
     protected abstract <R> AbstractBag<R> newEmptyExtensibleResultCollection();
 629  
 
 630  
     /**
 631  
      * Tells how the given key or value will show up in this dictionary's string
 632  
      * representation.
 633  
      *
 634  
      * @param keyOrValue an element of this collection
 635  
      * @return a string representation of {@code keyOrValue} to be used in this bag's
 636  
      * string representation
 637  
      */
 638  
     protected abstract String asString( Object keyOrValue );
 639  
 
 640  
     private String asStringOrThis( Object keyOrValue ) {
 641  24
         return keyOrValue == this ? "this" : asString( keyOrValue );
 642  
     }
 643  
 
 644  
     private int capacity() {
 645  6
         return hash.capacity();
 646  
     }
 647  
 
 648  
     private void initialize( int capacity, EquivalenceTester tester ) {
 649  6
         hash = new HashingContainer<K, V>( capacity, tester );
 650  6
     }
 651  
 
 652  
     /**
 653  
      * Serialization helper method.
 654  
      *
 655  
      * @param output stream to write object state to
 656  
      * @throws IOException if an I/O problem occurs during serialization
 657  
      */
 658  
     protected final void serializeTo( final ObjectOutputStream output )
 659  
         throws IOException {
 660  
 
 661  6
         output.defaultWriteObject();
 662  6
         output.writeInt( capacity() );
 663  6
         output.writeInt( size() );
 664  
 
 665  6
         hash.forEachDo( new UnaryFunctor<Pair<K, V>, Void>() {
 666  30
             public Void evaluate( Pair<K, V> argument ) {
 667  
                 try {
 668  24
                     output.writeObject( argument.key() );
 669  24
                     output.writeObject( argument.value() );
 670  24
                     return null;
 671  
                 }
 672  0
                 catch ( IOException ex ) {
 673  0
                     throw new RuntimeException( ex );
 674  
                 }
 675  
             }
 676  
         } );
 677  6
     }
 678  
 
 679  
     /**
 680  
      * De-serialization helper method.
 681  
      *
 682  
      * @param input stream to read object state from
 683  
      * @param tester equivalence tester to give the reconstituted dictionary
 684  
      * @throws IOException if an I/O problem occurs during de-serialization
 685  
      * @throws ClassNotFoundException if a class that is necessary for de-serialization
 686  
      * cannot be found
 687  
      */
 688  
     protected final void deserializeFrom( ObjectInputStream input,
 689  
         EquivalenceTester tester ) throws IOException, ClassNotFoundException {
 690  
 
 691  6
         input.defaultReadObject();
 692  
 
 693  6
         int capacity = input.readInt();
 694  6
         initialize( capacity, tester );
 695  
 
 696  6
         int size = input.readInt();
 697  30
         for ( int i = 0; i < size; ++i ) {
 698  24
             K key = Casting.<K>cast( input.readObject() );
 699  24
             V value = Casting.<V>cast( input.readObject() );
 700  
 
 701  24
             putAt( key, value );
 702  
         }
 703  6
     }
 704  
 
 705  3041
     private class DictionaryEqualityTester
 706  
         implements BinaryFunctor<Object, Object, Void> {
 707  
 
 708  
         private final AbstractDictionary<Object, Object> other;
 709  
 
 710  1147
         public DictionaryEqualityTester( AbstractDictionary<Object, Object> other ) {
 711  1147
             this.other = other;
 712  1147
         }
 713  
 
 714  
         public Void evaluate( Object first, Object second ) {
 715  3041
             Object valueAtKey = other.at( first );
 716  
 
 717  3041
             if ( second == null ) {
 718  849
                 if ( !( valueAtKey == null && other.includesKey( first ) ) )
 719  3
                     throw new NonLocalReturnException();
 720  
             }
 721  
             else {
 722  2192
                 if ( !hash.areEqual( second, valueAtKey ) )
 723  256
                     throw new NonLocalReturnException();
 724  
             }
 725  
 
 726  2782
             return null;
 727  
         }
 728  
     }
 729  
 }