1*16467b97STreehugger Robot#import <Foundation/Foundation.h> 2*16467b97STreehugger Robot#import "AMutableArray.h" 3*16467b97STreehugger Robot#import "LinkedHashMap.h" 4*16467b97STreehugger Robot#import "RuntimeException.h" 5*16467b97STreehugger Robot 6*16467b97STreehugger Robotextern NSInteger const DEFAULT_INITIAL_CAPACITY; 7*16467b97STreehugger Robotextern float const DEFAULT_LOAD_FACTOR; 8*16467b97STreehugger Robot 9*16467b97STreehugger Robot@implementation LHMEntry 10*16467b97STreehugger Robot 11*16467b97STreehugger Robot@synthesize before; 12*16467b97STreehugger Robot@synthesize after; 13*16467b97STreehugger Robot@synthesize accessOrder; 14*16467b97STreehugger Robot 15*16467b97STreehugger Robot- (id) newEntry:(NSInteger)aHash key:(NSString *)aKey value:(id)aValue next:(LHMEntry *)aNext 16*16467b97STreehugger Robot{ 17*16467b97STreehugger Robot return [[LHMEntry alloc] init:aHash key:aKey value:aValue next:aNext]; 18*16467b97STreehugger Robot} 19*16467b97STreehugger Robot 20*16467b97STreehugger Robot- (id) init:(NSInteger)aHash key:(NSString *)aKey value:(id)aValue next:(LHMEntry *)aNext 21*16467b97STreehugger Robot{ 22*16467b97STreehugger Robot self = [super init:aHash key:aKey value:aValue next:aNext]; 23*16467b97STreehugger Robot if (self) { 24*16467b97STreehugger Robot } 25*16467b97STreehugger Robot return self; 26*16467b97STreehugger Robot} 27*16467b97STreehugger Robot 28*16467b97STreehugger Robot 29*16467b97STreehugger Robot- (void) dealloc 30*16467b97STreehugger Robot{ 31*16467b97STreehugger Robot [before release]; 32*16467b97STreehugger Robot [after release]; 33*16467b97STreehugger Robot [super dealloc]; 34*16467b97STreehugger Robot} 35*16467b97STreehugger Robot 36*16467b97STreehugger Robot/** 37*16467b97STreehugger Robot * Removes this entry from the linked list. 38*16467b97STreehugger Robot */ 39*16467b97STreehugger Robot- (void) removeEntry 40*16467b97STreehugger Robot{ 41*16467b97STreehugger Robot before.after = after; 42*16467b97STreehugger Robot after.before = before; 43*16467b97STreehugger Robot} 44*16467b97STreehugger Robot 45*16467b97STreehugger Robot 46*16467b97STreehugger Robot/** 47*16467b97STreehugger Robot * Inserts this entry before the specified existing entry in the list. 48*16467b97STreehugger Robot */ 49*16467b97STreehugger Robot- (void) addBefore:(LHMEntry *)existingEntry 50*16467b97STreehugger Robot{ 51*16467b97STreehugger Robot after = [existingEntry retain]; 52*16467b97STreehugger Robot before = [existingEntry.before retain]; 53*16467b97STreehugger Robot before.after = [self retain]; 54*16467b97STreehugger Robot after.before = [self retain]; 55*16467b97STreehugger Robot} 56*16467b97STreehugger Robot 57*16467b97STreehugger Robot 58*16467b97STreehugger Robot/** 59*16467b97STreehugger Robot * This method is invoked by the superclass whenever the value 60*16467b97STreehugger Robot * of a pre-existing entry is read by Map.get or modified by Map.set. 61*16467b97STreehugger Robot * If the enclosing Map is access-ordered, it moves the entry 62*16467b97STreehugger Robot * to the end of the list; otherwise, it does nothing. 63*16467b97STreehugger Robot */ 64*16467b97STreehugger Robot- (void) recordAccess:(LinkedHashMap *)m 65*16467b97STreehugger Robot{ 66*16467b97STreehugger Robot LinkedHashMap *lhm = (LinkedHashMap *)m; 67*16467b97STreehugger Robot if (lhm.accessOrder) { 68*16467b97STreehugger Robot lhm.modCount++; 69*16467b97STreehugger Robot [self removeEntry]; 70*16467b97STreehugger Robot [self addBefore:lhm.header]; 71*16467b97STreehugger Robot } 72*16467b97STreehugger Robot} 73*16467b97STreehugger Robot 74*16467b97STreehugger Robot- (void) recordRemoval:(LinkedHashMap *)m 75*16467b97STreehugger Robot{ 76*16467b97STreehugger Robot [self removeEntry]; 77*16467b97STreehugger Robot} 78*16467b97STreehugger Robot 79*16467b97STreehugger Robot@end 80*16467b97STreehugger Robot 81*16467b97STreehugger Robot@implementation LinkedHashIterator 82*16467b97STreehugger Robot 83*16467b97STreehugger Robot@synthesize nextEntry; 84*16467b97STreehugger Robot@synthesize lastReturned; 85*16467b97STreehugger Robot@synthesize lhm; 86*16467b97STreehugger Robot 87*16467b97STreehugger Robot+ (LinkedHashIterator *) newIterator:(LinkedHashMap *)aLHM 88*16467b97STreehugger Robot{ 89*16467b97STreehugger Robot return [[LinkedHashIterator alloc] init:aLHM]; 90*16467b97STreehugger Robot} 91*16467b97STreehugger Robot 92*16467b97STreehugger Robot- (id) init:(LinkedHashMap *)aLHM 93*16467b97STreehugger Robot{ 94*16467b97STreehugger Robot self = [super init]; 95*16467b97STreehugger Robot if ( self ) { 96*16467b97STreehugger Robot lhm = aLHM; 97*16467b97STreehugger Robot nextEntry = lhm.header.after; 98*16467b97STreehugger Robot lastReturned = nil; 99*16467b97STreehugger Robot expectedModCount = lhm.modCount; 100*16467b97STreehugger Robot/* 101*16467b97STreehugger Robot AMutableArray *a = [AMutableArray arrayWithCapacity:lhm.Capacity]; 102*16467b97STreehugger Robot LHMEntry *tmp = lhm.header.after; 103*16467b97STreehugger Robot while ( tmp != lhm.header ) { 104*16467b97STreehugger Robot [a addObject:tmp]; 105*16467b97STreehugger Robot tmp = tmp.after; 106*16467b97STreehugger Robot } 107*16467b97STreehugger Robot anArray = [NSArray arrayWithArray:a]; 108*16467b97STreehugger Robot */ 109*16467b97STreehugger Robot } 110*16467b97STreehugger Robot return self; 111*16467b97STreehugger Robot} 112*16467b97STreehugger Robot 113*16467b97STreehugger Robot- (BOOL) hasNext 114*16467b97STreehugger Robot{ 115*16467b97STreehugger Robot return nextEntry != lhm.header; 116*16467b97STreehugger Robot} 117*16467b97STreehugger Robot 118*16467b97STreehugger Robot- (void) remove 119*16467b97STreehugger Robot{ 120*16467b97STreehugger Robot if (lastReturned == nil) 121*16467b97STreehugger Robot @throw [[IllegalStateException newException] autorelease]; 122*16467b97STreehugger Robot if (lhm.modCount != expectedModCount) 123*16467b97STreehugger Robot @throw [[ConcurrentModificationException newException:@"Unexpected modCount"] autorelease]; 124*16467b97STreehugger Robot [lhm remove:(NSString *)(lastReturned.key)]; 125*16467b97STreehugger Robot lastReturned = nil; 126*16467b97STreehugger Robot expectedModCount = lhm.modCount; 127*16467b97STreehugger Robot} 128*16467b97STreehugger Robot 129*16467b97STreehugger Robot- (LHMEntry *) nextEntry 130*16467b97STreehugger Robot{ 131*16467b97STreehugger Robot if (lhm.modCount != expectedModCount) 132*16467b97STreehugger Robot @throw [[ConcurrentModificationException newException:@"Unexpected modCount"] autorelease]; 133*16467b97STreehugger Robot if (nextEntry == lhm.header) 134*16467b97STreehugger Robot @throw [[[NoSuchElementException alloc] init] autorelease]; 135*16467b97STreehugger Robot LHMEntry * e = lastReturned = nextEntry; 136*16467b97STreehugger Robot nextEntry = e.after; 137*16467b97STreehugger Robot return e; 138*16467b97STreehugger Robot} 139*16467b97STreehugger Robot 140*16467b97STreehugger Robot- (void) dealloc 141*16467b97STreehugger Robot{ 142*16467b97STreehugger Robot [nextEntry release]; 143*16467b97STreehugger Robot [lastReturned release]; 144*16467b97STreehugger Robot [super dealloc]; 145*16467b97STreehugger Robot} 146*16467b97STreehugger Robot 147*16467b97STreehugger Robot@end 148*16467b97STreehugger Robot 149*16467b97STreehugger Robot@implementation LHMKeyIterator 150*16467b97STreehugger Robot+ (LHMKeyIterator *)newIterator:(LinkedHashMap *)aLHM 151*16467b97STreehugger Robot{ 152*16467b97STreehugger Robot return [[LHMKeyIterator alloc] init:aLHM]; 153*16467b97STreehugger Robot} 154*16467b97STreehugger Robot 155*16467b97STreehugger Robot- (id) init:(LinkedHashMap *)aLHM 156*16467b97STreehugger Robot{ 157*16467b97STreehugger Robot self = [super init:aLHM]; 158*16467b97STreehugger Robot if ( self ) { 159*16467b97STreehugger Robot } 160*16467b97STreehugger Robot return self; 161*16467b97STreehugger Robot} 162*16467b97STreehugger Robot 163*16467b97STreehugger Robot- (NSString *) next 164*16467b97STreehugger Robot{ 165*16467b97STreehugger Robot return [self nextEntry].key; 166*16467b97STreehugger Robot} 167*16467b97STreehugger Robot 168*16467b97STreehugger Robot@end 169*16467b97STreehugger Robot 170*16467b97STreehugger Robot@implementation LHMValueIterator 171*16467b97STreehugger Robot+ (LHMValueIterator *)newIterator:(LinkedHashMap *)aLHM 172*16467b97STreehugger Robot{ 173*16467b97STreehugger Robot return [[LHMValueIterator alloc] init:aLHM]; 174*16467b97STreehugger Robot} 175*16467b97STreehugger Robot 176*16467b97STreehugger Robot- (id) init:(LinkedHashMap *)aLHM 177*16467b97STreehugger Robot{ 178*16467b97STreehugger Robot self = [super init:aLHM]; 179*16467b97STreehugger Robot if ( self ) { 180*16467b97STreehugger Robot } 181*16467b97STreehugger Robot return self; 182*16467b97STreehugger Robot} 183*16467b97STreehugger Robot 184*16467b97STreehugger Robot- (id) next 185*16467b97STreehugger Robot{ 186*16467b97STreehugger Robot return [self nextEntry].value; 187*16467b97STreehugger Robot} 188*16467b97STreehugger Robot 189*16467b97STreehugger Robot@end 190*16467b97STreehugger Robot 191*16467b97STreehugger Robot@implementation LHMEntryIterator 192*16467b97STreehugger Robot+ (LHMEntryIterator *)newIterator:(LinkedHashMap *)aLHM 193*16467b97STreehugger Robot{ 194*16467b97STreehugger Robot return [[LHMEntryIterator alloc] init:aLHM]; 195*16467b97STreehugger Robot} 196*16467b97STreehugger Robot 197*16467b97STreehugger Robot- (id) init:(LinkedHashMap *)aLHM 198*16467b97STreehugger Robot{ 199*16467b97STreehugger Robot self = [super init:aLHM]; 200*16467b97STreehugger Robot if ( self ) { 201*16467b97STreehugger Robot } 202*16467b97STreehugger Robot return self; 203*16467b97STreehugger Robot} 204*16467b97STreehugger Robot 205*16467b97STreehugger Robot- (LHMEntry *) next 206*16467b97STreehugger Robot{ 207*16467b97STreehugger Robot return [self nextEntry]; 208*16467b97STreehugger Robot} 209*16467b97STreehugger Robot 210*16467b97STreehugger Robot@end 211*16467b97STreehugger Robot 212*16467b97STreehugger Robot//long const serialVersionUID = 3801124242820219131L; 213*16467b97STreehugger Robot 214*16467b97STreehugger Robot@implementation LinkedHashMap 215*16467b97STreehugger Robot 216*16467b97STreehugger Robot@synthesize header; 217*16467b97STreehugger Robot@synthesize accessOrder; 218*16467b97STreehugger Robot 219*16467b97STreehugger Robot/** 220*16467b97STreehugger Robot * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance 221*16467b97STreehugger Robot * with the specified initial capacity and load factor. 222*16467b97STreehugger Robot * 223*16467b97STreehugger Robot * @param initialCapacity the initial capacity 224*16467b97STreehugger Robot * @param loadFactor the load factor 225*16467b97STreehugger Robot * @throws IllegalArgumentException if the initial capacity is negative 226*16467b97STreehugger Robot * or the load factor is nonpositive 227*16467b97STreehugger Robot */ 228*16467b97STreehugger Robot+ (id) newLinkedHashMap:(NSInteger)anInitialCapacity 229*16467b97STreehugger Robot loadFactor:(float)loadFactor 230*16467b97STreehugger Robot accessOrder:(BOOL)anAccessOrder 231*16467b97STreehugger Robot{ 232*16467b97STreehugger Robot return [[LinkedHashMap alloc] init:anInitialCapacity 233*16467b97STreehugger Robot loadFactor:loadFactor 234*16467b97STreehugger Robot accessOrder:(BOOL)anAccessOrder]; 235*16467b97STreehugger Robot} 236*16467b97STreehugger Robot 237*16467b97STreehugger Robot+ (id) newLinkedHashMap:(NSInteger)anInitialCapacity loadFactor:(float)loadFactor 238*16467b97STreehugger Robot{ 239*16467b97STreehugger Robot return [[LinkedHashMap alloc] init:anInitialCapacity loadFactor:loadFactor]; 240*16467b97STreehugger Robot} 241*16467b97STreehugger Robot 242*16467b97STreehugger Robot+ (id) newLinkedHashMap:(NSInteger)anInitialCapacity 243*16467b97STreehugger Robot{ 244*16467b97STreehugger Robot return [[LinkedHashMap alloc] init:anInitialCapacity loadFactor:DEFAULT_LOAD_FACTOR]; 245*16467b97STreehugger Robot} 246*16467b97STreehugger Robot 247*16467b97STreehugger Robot/** 248*16467b97STreehugger Robot * Constructs an empty <tt>LinkedHashMap</tt> instance with the 249*16467b97STreehugger Robot * specified initial capacity, load factor and ordering mode. 250*16467b97STreehugger Robot * 251*16467b97STreehugger Robot * @param initialCapacity the initial capacity 252*16467b97STreehugger Robot * @param loadFactor the load factor 253*16467b97STreehugger Robot * @param accessOrder the ordering mode - <tt>true</tt> for 254*16467b97STreehugger Robot * access-order, <tt>false</tt> for insertion-order 255*16467b97STreehugger Robot * @throws IllegalArgumentException if the initial capacity is negative 256*16467b97STreehugger Robot * or the load factor is nonpositive 257*16467b97STreehugger Robot */ 258*16467b97STreehugger Robot- (id) init:(NSInteger)anInitialCapacity loadFactor:(float)aLoadFactor accessOrder:(BOOL)anAccessOrder 259*16467b97STreehugger Robot{ 260*16467b97STreehugger Robot self = [super init:anInitialCapacity loadFactor:aLoadFactor]; 261*16467b97STreehugger Robot if ( self ) { 262*16467b97STreehugger Robot accessOrder = anAccessOrder; 263*16467b97STreehugger Robot header = [[[LHMEntry alloc] init:-1 key:nil value:nil next:nil] retain]; 264*16467b97STreehugger Robot header.before = header.after = header; 265*16467b97STreehugger Robot } 266*16467b97STreehugger Robot return self; 267*16467b97STreehugger Robot} 268*16467b97STreehugger Robot 269*16467b97STreehugger Robot- (id) init:(NSInteger)anInitialCapacity loadFactor:(float)aLoadFactor 270*16467b97STreehugger Robot{ 271*16467b97STreehugger Robot self = [super init:anInitialCapacity loadFactor:aLoadFactor]; 272*16467b97STreehugger Robot if ( self ) { 273*16467b97STreehugger Robot accessOrder = NO; 274*16467b97STreehugger Robot header = [[[LHMEntry alloc] init:-1 key:nil value:nil next:nil] retain]; 275*16467b97STreehugger Robot header.before = header.after = header; 276*16467b97STreehugger Robot } 277*16467b97STreehugger Robot return self; 278*16467b97STreehugger Robot} 279*16467b97STreehugger Robot 280*16467b97STreehugger Robot/** 281*16467b97STreehugger Robot * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance 282*16467b97STreehugger Robot * with the specified initial capacity and a default load factor (0.75). 283*16467b97STreehugger Robot * 284*16467b97STreehugger Robot * @param initialCapacity the initial capacity 285*16467b97STreehugger Robot * @throws IllegalArgumentException if the initial capacity is negative 286*16467b97STreehugger Robot */ 287*16467b97STreehugger Robot- (id) init:(NSInteger)initialCapacity 288*16467b97STreehugger Robot{ 289*16467b97STreehugger Robot self = [super init:initialCapacity loadFactor:DEFAULT_LOAD_FACTOR]; 290*16467b97STreehugger Robot if ( self ) { 291*16467b97STreehugger Robot accessOrder = NO; 292*16467b97STreehugger Robot header = [[[LHMEntry alloc] init:-1 key:nil value:nil next:nil] retain]; 293*16467b97STreehugger Robot header.before = header.after = header; 294*16467b97STreehugger Robot } 295*16467b97STreehugger Robot return self; 296*16467b97STreehugger Robot} 297*16467b97STreehugger Robot 298*16467b97STreehugger Robot/** 299*16467b97STreehugger Robot * Constructs an insertion-ordered <tt>LinkedHashMap</tt> instance with 300*16467b97STreehugger Robot * the same mappings as the specified map. The <tt>LinkedHashMap</tt> 301*16467b97STreehugger Robot * instance is created with a default load factor (0.75) and an initial 302*16467b97STreehugger Robot * capacity sufficient to hold the mappings in the specified map. 303*16467b97STreehugger Robot * 304*16467b97STreehugger Robot * @param m the map whose mappings are to be placed in this map 305*16467b97STreehugger Robot * @throws NullPointerException if the specified map is null 306*16467b97STreehugger Robot */ 307*16467b97STreehugger Robot- (id) initWithM:(LinkedHashMap *)m 308*16467b97STreehugger Robot{ 309*16467b97STreehugger Robot self = [super initWithM:m]; 310*16467b97STreehugger Robot if ( self ) { 311*16467b97STreehugger Robot accessOrder = NO; 312*16467b97STreehugger Robot header = [[[LHMEntry alloc] init:-1 key:nil value:nil next:nil] retain]; 313*16467b97STreehugger Robot header.before = header.after = header; 314*16467b97STreehugger Robot } 315*16467b97STreehugger Robot return self; 316*16467b97STreehugger Robot} 317*16467b97STreehugger Robot 318*16467b97STreehugger Robot/** 319*16467b97STreehugger Robot * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance 320*16467b97STreehugger Robot * with the default initial capacity (16) and load factor (0.75). 321*16467b97STreehugger Robot */ 322*16467b97STreehugger Robot- (id) init 323*16467b97STreehugger Robot{ 324*16467b97STreehugger Robot self = [super init]; 325*16467b97STreehugger Robot if ( self ) { 326*16467b97STreehugger Robot accessOrder = NO; 327*16467b97STreehugger Robot header = [[[LHMEntry alloc] init:-1 key:nil value:nil next:nil] retain]; 328*16467b97STreehugger Robot header.before = header.after = header; 329*16467b97STreehugger Robot } 330*16467b97STreehugger Robot return self; 331*16467b97STreehugger Robot} 332*16467b97STreehugger Robot 333*16467b97STreehugger Robot 334*16467b97STreehugger Robot/** 335*16467b97STreehugger Robot * Transfers all entries to new table array. This method is called 336*16467b97STreehugger Robot * by superclass resize. It is overridden for performance, as it is 337*16467b97STreehugger Robot * faster to iterate using our linked list. 338*16467b97STreehugger Robot */ 339*16467b97STreehugger Robot- (void) transfer:(AMutableArray *)newTable 340*16467b97STreehugger Robot{ 341*16467b97STreehugger Robot NSInteger newCapacity = [newTable count]; 342*16467b97STreehugger Robot 343*16467b97STreehugger Robot for (LHMEntry * e = header.after; e != header; e = e.after) { 344*16467b97STreehugger Robot NSInteger index = [self indexFor:e.hash length:newCapacity]; 345*16467b97STreehugger Robot e.next = [newTable objectAtIndex:index]; 346*16467b97STreehugger Robot [newTable replaceObjectAtIndex:index withObject:e]; 347*16467b97STreehugger Robot } 348*16467b97STreehugger Robot 349*16467b97STreehugger Robot} 350*16467b97STreehugger Robot 351*16467b97STreehugger Robot/** 352*16467b97STreehugger Robot * Returns <tt>true</tt> if this map maps one or more keys to the 353*16467b97STreehugger Robot * specified value. 354*16467b97STreehugger Robot * 355*16467b97STreehugger Robot * @param value value whose presence in this map is to be tested 356*16467b97STreehugger Robot * @return <tt>true</tt> if this map maps one or more keys to the 357*16467b97STreehugger Robot * specified value 358*16467b97STreehugger Robot */ 359*16467b97STreehugger Robot- (BOOL) containsValue:(id)value 360*16467b97STreehugger Robot{ 361*16467b97STreehugger Robot if (value == nil) { 362*16467b97STreehugger Robot 363*16467b97STreehugger Robot for (LHMEntry * e = header.after; e != header; e = e.after) 364*16467b97STreehugger Robot if (e.value == nil) 365*16467b97STreehugger Robot return YES; 366*16467b97STreehugger Robot 367*16467b97STreehugger Robot } 368*16467b97STreehugger Robot else { 369*16467b97STreehugger Robot 370*16467b97STreehugger Robot for (LHMEntry * e = header.after; e != header; e = e.after) 371*16467b97STreehugger Robot if ([value isEqualTo:e.value]) 372*16467b97STreehugger Robot return YES; 373*16467b97STreehugger Robot 374*16467b97STreehugger Robot } 375*16467b97STreehugger Robot return NO; 376*16467b97STreehugger Robot} 377*16467b97STreehugger Robot 378*16467b97STreehugger Robot/** 379*16467b97STreehugger Robot * Returns the value to which the specified key is mapped, 380*16467b97STreehugger Robot * or {@code null} if this map contains no mapping for the key. 381*16467b97STreehugger Robot * 382*16467b97STreehugger Robot * <p>More formally, if this map contains a mapping from a key 383*16467b97STreehugger Robot * {@code k} to a value {@code v} such that {@code (key==null ? k==null : 384*16467b97STreehugger Robot * key.equals(k))}, then this method returns {@code v}; otherwise 385*16467b97STreehugger Robot * it returns {@code null}. (There can be at most one such mapping.) 386*16467b97STreehugger Robot * 387*16467b97STreehugger Robot * <p>A return value of {@code null} does not <i>necessarily</i> 388*16467b97STreehugger Robot * indicate that the map contains no mapping for the key; it's also 389*16467b97STreehugger Robot * possible that the map explicitly maps the key to {@code null}. 390*16467b97STreehugger Robot * The {@link #containsKey containsKey} operation may be used to 391*16467b97STreehugger Robot * distinguish these two cases. 392*16467b97STreehugger Robot */ 393*16467b97STreehugger Robot- (id) get:(NSString *)aKey 394*16467b97STreehugger Robot{ 395*16467b97STreehugger Robot LHMEntry * e = (LHMEntry *)[self getEntry:aKey]; 396*16467b97STreehugger Robot if (e == nil) 397*16467b97STreehugger Robot return nil; 398*16467b97STreehugger Robot [e recordAccess:self]; 399*16467b97STreehugger Robot return e.value; 400*16467b97STreehugger Robot} 401*16467b97STreehugger Robot 402*16467b97STreehugger Robot 403*16467b97STreehugger Robot/** 404*16467b97STreehugger Robot * Removes all of the mappings from this map. 405*16467b97STreehugger Robot * The map will be empty after this call returns. 406*16467b97STreehugger Robot */ 407*16467b97STreehugger Robot- (void) clear 408*16467b97STreehugger Robot{ 409*16467b97STreehugger Robot [super clear]; 410*16467b97STreehugger Robot header.before = header.after = header; 411*16467b97STreehugger Robot} 412*16467b97STreehugger Robot 413*16467b97STreehugger Robot- (void) dealloc { 414*16467b97STreehugger Robot [header release]; 415*16467b97STreehugger Robot [super dealloc]; 416*16467b97STreehugger Robot} 417*16467b97STreehugger Robot 418*16467b97STreehugger Robot- (LHMEntryIterator *) newEntryIterator 419*16467b97STreehugger Robot{ 420*16467b97STreehugger Robot return [LHMEntryIterator newIterator:self]; 421*16467b97STreehugger Robot} 422*16467b97STreehugger Robot 423*16467b97STreehugger Robot- (LHMKeyIterator *) newKeyIterator 424*16467b97STreehugger Robot{ 425*16467b97STreehugger Robot return [LHMKeyIterator newIterator:self]; 426*16467b97STreehugger Robot} 427*16467b97STreehugger Robot 428*16467b97STreehugger Robot- (LHMValueIterator *) newValueIterator 429*16467b97STreehugger Robot{ 430*16467b97STreehugger Robot return [LHMValueIterator newIterator:self]; 431*16467b97STreehugger Robot} 432*16467b97STreehugger Robot 433*16467b97STreehugger Robot 434*16467b97STreehugger Robot/** 435*16467b97STreehugger Robot * This override alters behavior of superclass put method. It causes newly 436*16467b97STreehugger Robot * allocated entry to get inserted at the end of the linked list and 437*16467b97STreehugger Robot * removes the eldest entry if appropriate. 438*16467b97STreehugger Robot */ 439*16467b97STreehugger Robot- (void) addEntry:(NSInteger)aHash key:(NSString *)aKey value:(id)aValue bucketIndex:(NSInteger)aBucketIndex 440*16467b97STreehugger Robot{ 441*16467b97STreehugger Robot [self createEntry:aHash key:aKey value:aValue bucketIndex:aBucketIndex]; 442*16467b97STreehugger Robot LHMEntry * eldest = header.after; 443*16467b97STreehugger Robot if ([self removeEldestEntry:eldest]) { 444*16467b97STreehugger Robot [self removeEntryForKey:eldest.key]; 445*16467b97STreehugger Robot } 446*16467b97STreehugger Robot else { 447*16467b97STreehugger Robot if (count >= threshold) 448*16467b97STreehugger Robot [self resize:2 * [buffer length]]; 449*16467b97STreehugger Robot } 450*16467b97STreehugger Robot} 451*16467b97STreehugger Robot 452*16467b97STreehugger Robot 453*16467b97STreehugger Robot/** 454*16467b97STreehugger Robot * This override differs from addEntry in that it doesn't resize the 455*16467b97STreehugger Robot * table or remove the eldest entry. 456*16467b97STreehugger Robot */ 457*16467b97STreehugger Robot- (void) createEntry:(NSInteger)aHash key:(NSString *)aKey value:(id)aValue bucketIndex:(NSInteger)bucketIndex 458*16467b97STreehugger Robot{ 459*16467b97STreehugger Robot LHMEntry *old = (LHMEntry *)ptrBuffer[bucketIndex]; 460*16467b97STreehugger Robot LHMEntry *e = [[[LHMEntry alloc] init:aHash key:aKey value:aValue next:old] retain]; 461*16467b97STreehugger Robot ptrBuffer[bucketIndex] = (id)e; 462*16467b97STreehugger Robot [e addBefore:header]; 463*16467b97STreehugger Robot count++; 464*16467b97STreehugger Robot} 465*16467b97STreehugger Robot 466*16467b97STreehugger Robot 467*16467b97STreehugger Robot/** 468*16467b97STreehugger Robot * Returns <tt>true</tt> if this map should remove its eldest entry. 469*16467b97STreehugger Robot * This method is invoked by <tt>put</tt> and <tt>putAll</tt> after 470*16467b97STreehugger Robot * inserting a new entry into the map. It provides the implementor 471*16467b97STreehugger Robot * with the opportunity to remove the eldest entry each time a new one 472*16467b97STreehugger Robot * is added. This is useful if the map represents a cache: it allows 473*16467b97STreehugger Robot * the map to reduce memory consumption by deleting stale entries. 474*16467b97STreehugger Robot * 475*16467b97STreehugger Robot * <p>Sample use: this override will allow the map to grow up to 100 476*16467b97STreehugger Robot * entries and then delete the eldest entry each time a new entry is 477*16467b97STreehugger Robot * added, maintaining a steady state of 100 entries. 478*16467b97STreehugger Robot * <pre> 479*16467b97STreehugger Robot * private static final NSInteger MAX_ENTRIES = 100; 480*16467b97STreehugger Robot * 481*16467b97STreehugger Robot * protected boolean removeEldestEntry(Map.LHMEntry eldest) { 482*16467b97STreehugger Robot * return count() > MAX_ENTRIES; 483*16467b97STreehugger Robot * } 484*16467b97STreehugger Robot * </pre> 485*16467b97STreehugger Robot * 486*16467b97STreehugger Robot * <p>This method typically does not modify the map in any way, 487*16467b97STreehugger Robot * instead allowing the map to modify itself as directed by its 488*16467b97STreehugger Robot * return value. It <i>is</i> permitted for this method to modify 489*16467b97STreehugger Robot * the map directly, but if it does so, it <i>must</i> return 490*16467b97STreehugger Robot * <tt>false</tt> (indicating that the map should not attempt any 491*16467b97STreehugger Robot * further modification). The effects of returning <tt>true</tt> 492*16467b97STreehugger Robot * after modifying the map from within this method are unspecified. 493*16467b97STreehugger Robot * 494*16467b97STreehugger Robot * <p>This implementation merely returns <tt>false</tt> (so that this 495*16467b97STreehugger Robot * map acts like a normal map - the eldest element is never removed). 496*16467b97STreehugger Robot * 497*16467b97STreehugger Robot * @param eldest The least recently inserted entry in the map, or if 498*16467b97STreehugger Robot * this is an access-ordered map, the least recently accessed 499*16467b97STreehugger Robot * entry. This is the entry that will be removed it this 500*16467b97STreehugger Robot * method returns <tt>true</tt>. If the map was empty prior 501*16467b97STreehugger Robot * to the <tt>put</tt> or <tt>putAll</tt> invocation resulting 502*16467b97STreehugger Robot * in this invocation, this will be the entry that was just 503*16467b97STreehugger Robot * inserted; in other words, if the map contains a single 504*16467b97STreehugger Robot * entry, the eldest entry is also the newest. 505*16467b97STreehugger Robot * @return <tt>true</tt> if the eldest entry should be removed 506*16467b97STreehugger Robot * from the map; <tt>false</tt> if it should be retained. 507*16467b97STreehugger Robot */ 508*16467b97STreehugger Robot- (BOOL) removeEldestEntry:(LHMEntry *)eldest 509*16467b97STreehugger Robot{ 510*16467b97STreehugger Robot return NO; 511*16467b97STreehugger Robot} 512*16467b97STreehugger Robot 513*16467b97STreehugger Robot@end 514