1// 2// KTMutableMatrix 3// KTMatrix collection class cluster 4// 5// Extends the KTMatrix class cluster with mutator methods 6// 7// Copyright (c) 2002 Chris Purcell. All rights reserved. 8// 9// You may use this code for whatever purposes you wish. 10// This code comes with no warranties, implied or otherwise. 11// Using it may damage your data. It shouldn't, but save a copy first. 12// That's a good idea anyway, actually. 13// 14 15#import "KTMutableMatrix.h" 16#import "KTPlaceholderMutableMatrix.h" 17#import "KTMutableMatrixSparseImp.h" 18#import "KTMutableMatrixDenseImp.h" 19#import "KTCuboidHash.h" 20 21@implementation KTMutableMatrix 22 23//// Allocators 24+ (id)alloc 25{ 26 if ([self isEqual:[KTMutableMatrix class]]) 27 return [KTPlaceholderMutableMatrix alloc]; 28 else 29 return [super alloc]; 30} 31+ (id)allocWithZone:(NSZone *)zone 32{ 33 if ([self isEqual:[KTMutableMatrix class]]) 34 return [KTPlaceholderMutableMatrix allocWithZone:zone]; 35 else 36 return [super allocWithZone:zone]; 37} 38 39//// Constructors 40+ (id)matrixWithMatrix:(KTMatrix *)matrix 41{ 42 if (([[matrix locationHash] hashBound] == 0) || 43 ([matrix count] < [[matrix locationHash] hashBound]/3)) 44 return [KTMutableMatrixSparseImp matrixWithMatrix:matrix]; 45 else 46 return [KTMutableMatrixDenseImp matrixWithMatrix:matrix]; 47} 48+ (id)matrixWithLocationHash:(id<KTLocationHash>)hash; 49{ 50 return [self matrixWithCapacity:0 51 locationHash:hash]; 52} 53+ (id)matrixWithLocationHash:(id<KTLocationHash>)hash 54 objects:(NSArray *)objects 55 atLocations:(NSArray *)loc1s 56 byLocations:(NSArray *)loc2s 57{ 58 if (([hash hashBound] == 0) || ([objects count] < [hash hashBound]/3)) 59 return [KTMutableMatrixSparseImp matrixWithLocationHash:hash 60 objects:objects 61 atLocations:loc1s 62 byLocations:loc2s]; 63 else 64 return [KTMutableMatrixDenseImp matrixWithLocationHash:hash 65 objects:objects 66 atLocations:loc1s 67 byLocations:loc2s]; 68} 69+ (id)matrixWithCapacity:(unsigned)numItems 70 locationHash:(id<KTLocationHash>)hash 71{ 72 if (([hash hashBound] == 0) || (numItems < [hash hashBound]/3)) 73 return [KTMutableMatrixSparseImp matrixWithCapacity:numItems 74 locationHash:hash]; 75 else 76 return [KTMutableMatrixDenseImp matrixWithCapacity:numItems 77 locationHash:hash]; 78} 79+ (id)matrixWithCapacity:(unsigned)numItems 80 cuboidBoundArray:(NSArray *)bounds 81{ 82 id<KTLocationHash> hash = [[KTCuboidHash allocWithZone:NULL] 83 initWithBounds:bounds]; 84 id ret = [self matrixWithCapacity:numItems 85 locationHash:hash]; 86 [hash release]; 87 return ret; 88} 89+ (id)matrixWithCapacity:(unsigned)numItems 90 cuboidBounds:(unsigned)bound1,... 91{ 92 NSMutableArray *array 93 = [NSMutableArray arrayWithObject:[NSNumber numberWithInt:bound1]]; 94 unsigned bound; 95 va_list args; 96 if (bound1 == 0) 97 { // Creating a 0-dimensional array. Riiiight... 98 [array removeLastObject]; 99 } 100 else 101 { 102 va_start(args, bound1); 103 104 while (bound = va_arg(args, unsigned)) 105 [array addObject:[NSNumber numberWithInt:bound]]; 106 107 va_end(args); 108 } 109 return [self matrixWithCapacity:numItems 110 cuboidBoundArray:array]; 111} 112+ (id)matrixWithCuboidBoundsObjectAtCoordinates:(unsigned)bound1,... 113{ 114 KTCuboidHash *hash; // The hashing object to use 115 va_list args; // To trawl through the arguments 116 id ret; // The object being returned 117 id object; // Used to store the object in the arguments 118 119 va_start(args, bound1); 120 hash = [[KTCuboidHash alloc] initWithBoundsList:bound1 :&args]; 121 object = va_arg(args, id); 122 123 if ([self isEqual:[KTMutableMatrix class]]) 124 { // Can optimize away some inefficiencies 125 unsigned loc = [hash hashForCoordinatesList:&args]; 126 127 if (([hash hashBound] != 0) && ([hash hashBound] <= 3)) 128 ret = [KTMutableMatrixDenseImp alloc]; 129 else 130 ret = [KTMutableMatrixSparseImp alloc]; 131 ret = [[ret initWithLocationHash:hash 132 object:object 133 atHashedLocation:loc] autorelease]; 134 } 135 else 136 { 137 unsigned i, dimension = [hash dimension]; 138 NSMutableArray *coord = [[NSMutableArray alloc] init]; 139 NSNumber *number; 140 141 for (i = 0; i < dimension; i++) 142 { 143 number = [[NSNumber alloc] initWithInt:va_arg(args, unsigned)]; 144 [coord addObject:number]; 145 [number release]; 146 } 147 148 ret = [self matrixWithLocationHash:hash 149 object:object 150 atCoordinateArray:coord]; 151 [coord release]; 152 } 153 154 [hash release]; 155 va_end(args); 156 return ret; 157} 158+ (id)matrixWithCuboidBoundsObjectsAtCoordinates:(unsigned)bound1,... 159{ 160 KTCuboidHash *hash; // The hashing object to use 161 va_list args; // To trawl through the arguments 162 id object; // Used to store the objects in the arguments 163 id ret; // The object being returned 164 165 // Read in data for the cuboid hash 166 va_start(args, bound1); 167 hash = [[KTCuboidHash alloc] initWithBoundsList:bound1 :&args]; 168 169 if ([self isEqual:[KTMutableMatrix class]]) 170 { // Can optimize away some inefficiencies 171 // Need a mutable temporary to store all the objects 172 KTMutableMatrixSparseImp *temp; 173 // SELs/IMPs to speed up repeated method calls 174 SEL hashListSEL = @selector(hashForCoordinatesList:); 175 SEL setObjSEL = @selector(setObject:atHashedLocation:); 176 unsigned (*hashListIMP)(id, SEL, ...); 177 void (*setObjIMP)(id, SEL, ...); 178 179 // Allocate the temporary mutable matrix 180 temp = [[KTMutableMatrixSparseImp alloc] initWithCapacity:0 181 locationHash:hash]; 182 183 // Read in objects and coordinates 184 hashListIMP = (unsigned (*)(id, SEL, ...)) 185 [hash methodForSelector:hashListSEL]; 186 setObjIMP = (void (*)(id, SEL, ...)) 187 [temp methodForSelector:setObjSEL]; 188 while (object = va_arg(args, id)) 189 setObjIMP(temp, setObjSEL, object, 190 hashListIMP(hash,hashListSEL,&args)); 191 192 // Make a mutable copy of the object 193 if (([hash hashBound] == 0) || 194 ([temp count] < [hash hashBound]/3)) 195 ret = [temp retain]; 196 else 197 ret = [temp mutableCopyWithZone:NULL]; 198 [temp release]; 199 [ret autorelease]; 200 } 201 else 202 { // Version for derived classes 203 unsigned dimension = [hash dimension]; 204 NSMutableArray *objects = [[NSMutableArray alloc] init]; 205 NSMutableArray *coords = [[NSMutableArray alloc] init]; 206 NSNumber *number; 207 unsigned i; 208 NSMutableArray *coord; 209 210 // Fill a couple of arrays with the objects and coordinates 211 while (object = va_arg(args, id)) 212 { 213 [objects addObject:object]; 214 coord = [NSMutableArray array]; 215 for (i = 0; i < dimension; i++) 216 { 217 number = [[NSNumber alloc] initWithInt:va_arg(args, unsigned)]; 218 [coord addObject:number]; 219 [number release]; 220 } 221 [coords addObject:coord]; 222 } 223 224 ret = [self matrixWithLocationHash:hash 225 objects:objects 226 atCoordinateArrays:coords]; 227 [objects release]; 228 [coords release]; 229 } 230 231 [hash release]; 232 va_end(args); 233 return ret; 234} 235 236- (id)init 237{ 238 return (self = [super init]); 239} 240- (id)initWithMatrix:(KTMatrix *)matrix 241{ 242 [NSException raise:NSGenericException 243 format: 244 @"Must implement a complete subclass of KTMutableMatrix!"]; 245 [self release]; 246 return NULL; 247} 248- (id)initWithLocationHash:(id<KTLocationHash>)hash 249{ return (self = [self initWithCapacity:0 locationHash:hash]); } 250- (id)initWithCapacity:(unsigned)numItems 251 locationHash:(id<KTLocationHash>)hash 252{ 253 [NSException raise:NSGenericException 254 format: 255 @"Must implement a complete subclass of KTMutableMatrix!"]; 256 [self release]; 257 return NULL; 258} 259- (id)initWithCapacity:(unsigned)numItems 260 cuboidBoundArray:(NSArray *)bounds; 261{ 262 id<KTLocationHash> hash = [[KTCuboidHash allocWithZone:[self zone]] 263 initWithBounds:bounds]; 264 self = [self initWithCapacity:numItems 265 locationHash:hash]; 266 [hash release]; 267 return self; 268} 269- (id)initWithCapacity:(unsigned)numItems 270 cuboidBounds:(unsigned)bound1,... 271{ 272 va_list args; 273 id<KTLocationHash> hash; 274 275 va_start(args, bound1); 276 hash = [[KTCuboidHash allocWithZone:[self zone]] 277 initWithBoundsList:bound1 :&args]; 278 self = [self initWithCapacity:numItems locationHash:hash]; 279 [hash release]; 280 va_end(args); 281 282 return self; 283} 284 285//// Accessor methods 286- (id)objectAtLocation:(NSDictionary *)loc1 287 byLocation:(NSDictionary *)loc2; 288{ 289 [NSException raise:NSGenericException 290 format: 291 @"Must implement a complete subclass of KTMutableMatrix!"]; 292 return NULL; 293} 294- (id<KTLocationHash>)locationHash 295{ 296 [NSException raise:NSGenericException 297 format: 298 @"Must implement a complete subclass of KTMutableMatrix!"]; 299 return NULL; 300} 301 302//// Internal use accessors 303- (NSDictionary *)matrixData 304{ 305 [NSException raise:NSGenericException 306 format: 307 @"Must implement a complete subclass of KTMutableMatrix!"]; 308 return NULL; 309} 310 311//// Object methods 312- (NSEnumerator *)objectEnumerator 313{ 314 [NSException raise:NSGenericException 315 format: 316 @"Must implement a complete subclass of KTMutableMatrix!"]; 317 return NULL; 318} 319 320//// Mutator methods 321- (void)setMatrix:(KTMatrix *)matrix 322{ 323 [NSException raise:NSGenericException 324 format: 325 @"Must implement a complete subclass of KTMutableMatrix!"]; 326} 327- (void)setObject:(id)object 328 atLocation:(NSDictionary *)loc1; 329{ 330 [self setObject:object 331 atLocation:loc1 332 byLocation:[NSDictionary dictionary]]; 333} 334- (void)setObject:(id)object 335 atLocation:(NSDictionary *)loc1 336 byLocation:(NSDictionary *)loc2; 337{ 338 [NSException raise:NSGenericException 339 format: 340 @"Must implement a complete subclass of KTMutableMatrix!"]; 341} 342- (void) setObject:(id)object 343 atCoordinateArray:(NSArray *)coords 344{ 345 NSMutableDictionary *loc = [NSMutableDictionary dictionaryWithCapacity: 346 [coords count]]; 347 unsigned axis = 0; 348 349 for (; axis < [coords count]; axis++) 350 [loc setObject:[coords objectAtIndex:axis] 351 forKey:[NSNumber numberWithInt:axis]]; 352 [self setObject:object 353 atLocation:loc 354 byLocation:[NSDictionary dictionary]]; 355 return; 356} 357- (void) setObject:(id)object 358 atCoordinates:(unsigned)x,... 359{ 360 NSMutableArray *array 361 = [NSMutableArray arrayWithObject:[NSNumber numberWithInt:x]]; 362 unsigned axes = [self dimension]; 363 va_list args; 364 365 va_start(args, x); 366 367 while ([array count] < axes) 368 [array addObject:[NSNumber numberWithInt:va_arg(args, unsigned)]]; 369 370 va_end(args); 371 372 [self setObject:object 373 atCoordinateArray:array]; 374} 375- (void)setObjects:(NSArray *)objects 376 atLocations:(NSArray *)locs 377{ 378 NSEnumerator *i = [objects objectEnumerator]; 379 NSEnumerator *j = [locs objectEnumerator]; 380 id object; 381 NSDictionary *loc1; 382 NSDictionary *loc2 = [[NSDictionary alloc] init]; 383 384 if ([objects count] != [locs count]) 385 [NSException raise:NSInvalidArgumentException 386 format: 387 @"Objects and locations arrays not of equal length"]; 388 while ((object = [i nextObject]) && (loc1 = [j nextObject])) 389 [self setObject:object 390 atLocation:loc1 391 byLocation:loc2]; 392 [loc2 release]; 393} 394- (void)setObjects:(NSArray *)objects 395 atLocations:(NSArray *)loc1s 396 byLocation:(NSDictionary *)loc2 397{ 398 NSEnumerator *i = [objects objectEnumerator]; 399 NSEnumerator *j = [loc1s objectEnumerator]; 400 id object; 401 NSDictionary *loc1; 402 403 if ([objects count] != [loc1s count]) 404 [NSException raise:NSInvalidArgumentException 405 format: 406 @"Objects and locations arrays not of equal length"]; 407 while ((object = [i nextObject]) && (loc1 = [j nextObject])) 408 [self setObject:object 409 atLocation:loc1 410 byLocation:loc2]; 411} 412- (void)setObjects:(NSArray *)objects 413 atLocations:(NSArray *)loc1s 414 byLocations:(NSArray *)loc2s 415{ 416 NSEnumerator *i = [objects objectEnumerator]; 417 NSEnumerator *j = [loc1s objectEnumerator]; 418 NSEnumerator *k = [loc2s objectEnumerator]; 419 id object; 420 NSDictionary *loc1; 421 NSDictionary *loc2; 422 423 if ([objects count] != [loc1s count]) 424 [NSException raise:NSInvalidArgumentException 425 format: 426 @"Objects and locations arrays not of equal length"]; 427 if ([objects count] != [loc1s count]) 428 [NSException raise:NSInvalidArgumentException 429 format: 430 @"Locations arrays not of equal length"]; 431 while ((object = [i nextObject]) && (loc1 = [j nextObject]) && 432 (loc2 = [k nextObject])) 433 [self setObject:object 434 atLocation:loc1 435 byLocation:loc2]; 436} 437- (void)setObjectsAtLocations:(id)object1,... 438{ 439 NSDictionary *empty = [NSDictionary dictionary]; 440 NSMutableArray *objects = [NSMutableArray array]; 441 NSMutableArray *loc1s = [NSMutableArray array]; 442 NSMutableArray *loc2s = [NSMutableArray array]; 443 id object = object1; 444 va_list args; 445 446 if (object1 != 0) 447 { 448 va_start(args, object1); 449 450 do 451 { 452 [objects addObject:object]; 453 [loc1s addObject:va_arg(args, id)]; 454 [loc2s addObject:empty]; 455 } 456 while (object = va_arg(args, id)); 457 458 va_end(args); 459 } 460 [self setObjects:objects 461 atLocations:loc1s 462 byLocations:loc2s]; 463} 464- (void)setObjectsAtLocationsByLocations:(id)object1,... 465{ 466 NSMutableArray *objects = [NSMutableArray array]; 467 NSMutableArray *loc1s = [NSMutableArray array]; 468 NSMutableArray *loc2s = [NSMutableArray array]; 469 id object = object1; 470 va_list args; 471 472 if (object1 != 0) 473 { 474 va_start(args, object1); 475 476 do 477 { 478 [objects addObject:object]; 479 [loc1s addObject:va_arg(args, id)]; 480 [loc2s addObject:va_arg(args, id)]; 481 } 482 while (object = va_arg(args, id)); 483 484 va_end(args); 485 } 486 [self setObjects:objects 487 atLocations:loc1s 488 byLocations:loc2s]; 489} 490- (void) setObjects:(NSArray *)objects 491 atCoordinateArrays:(NSArray *)coords 492{ 493 NSArray *dims = [self axes]; 494 NSMutableArray *loc1s = [[NSMutableArray alloc] initWithCapacity: 495 [coords count]]; 496 NSMutableArray *loc2s = [[NSMutableArray alloc] initWithCapacity: 497 [coords count]]; 498 NSMutableDictionary *loc; 499 NSDictionary *empty = [[NSDictionary alloc] init]; 500 501 NSEnumerator *axes; 502 NSEnumerator *coordArrays = [coords objectEnumerator]; 503 NSEnumerator *vals; 504 id axis; 505 NSArray *coord; 506 507 while ((coord = [coordArrays nextObject])) 508 { 509 if ([dims count] != [coord count]) 510 [NSException raise:NSInvalidArgumentException 511 format: 512 @"Dimensions of hash and number of coordinates not equal"]; 513 axes = [dims objectEnumerator]; 514 vals = [coord objectEnumerator]; 515 loc = [[NSMutableDictionary alloc] init]; 516 while ((axis = [axes nextObject])) 517 [loc setObject:[vals nextObject] 518 forKey:axis]; 519 [loc1s addObject:loc]; 520 [loc2s addObject:empty]; 521 [loc release]; 522 } 523 [self setObjects:objects 524 atLocations:loc1s 525 byLocations:loc2s]; 526 [loc1s release]; 527 [loc2s release]; 528 [empty release]; 529} 530- (void)setObjectsAtCoordinates:(id)object1,... 531{ 532 NSMutableArray *objects = [NSMutableArray array]; 533 NSMutableArray *coords = [NSMutableArray array]; 534 unsigned dimension = [self dimension]; 535 id object = object1; 536 va_list args; 537 538 if (object1 != 0) 539 { 540 va_start(args, object1); 541 542 do 543 { 544 NSMutableArray *coord = [NSMutableArray arrayWithCapacity: 545 dimension]; 546 [objects addObject:object]; 547 while ([coord count] < dimension) 548 [coord addObject:[NSNumber numberWithInt: 549 va_arg(args, unsigned)]]; 550 [coords addObject:coord]; 551 } 552 while (object = va_arg(args, id)); 553 554 va_end(args); 555 } 556 [self setObjects:objects 557 atCoordinateArrays:coords]; 558} 559 560- (void)removeObjectAtLocation:(NSDictionary *)loc 561{ 562 NSDictionary *empty = [[NSDictionary alloc] init]; 563 [self removeObjectAtLocation:loc 564 byLocation:empty]; 565} 566- (void)removeObjectAtLocation:(NSDictionary *)loc1 567 byLocation:(NSDictionary *)loc2 568{ 569 [NSException raise:NSGenericException 570 format: 571 @"Must implement a complete subclass of KTMutableMatrix!"]; 572} 573- (void)removeObjectAtCoordinateArray:(NSArray *)coords 574{ 575 NSMutableDictionary *loc = [NSMutableDictionary dictionaryWithCapacity: 576 [coords count]]; 577 unsigned axis = 0; 578 for (; axis < [coords count]; axis++) 579 [loc setObject:[coords objectAtIndex:axis] 580 forKey:[NSNumber numberWithInt:axis]]; 581 [self removeObjectAtLocation:loc 582 byLocation:[NSDictionary dictionary]]; 583} 584- (void)removeObjectAtCoordinates:(unsigned)x,... 585{ 586 NSMutableArray *array = [NSMutableArray arrayWithObject: 587 [NSNumber numberWithInt:x]]; 588 unsigned axes = [self dimension]; 589 va_list args; 590 591 va_start(args, x); 592 593 while ([array count] < axes) 594 [array addObject:[NSNumber numberWithInt:va_arg(args, unsigned)]]; 595 596 va_end(args); 597 598 [self removeObjectAtCoordinateArray:array]; 599} 600- (void)removeObjectsAtLocations:(NSArray *)locs 601{ 602 NSDictionary *loc1; 603 NSDictionary *loc2 = [[NSDictionary alloc] init]; 604 NSEnumerator *i = [locs objectEnumerator]; 605 while ((loc1 = [i nextObject])) 606 [self removeObjectAtLocation:loc1 607 byLocation:loc2]; 608 [loc2 release]; 609} 610- (void)removeObjectsAtLocations:(NSArray *)loc1s 611 byLocation:(NSDictionary *)loc2 612{ 613 NSDictionary *loc1; 614 NSEnumerator *i = [loc1s objectEnumerator]; 615 while ((loc1 = [i nextObject])) 616 [self removeObjectAtLocation:loc1 617 byLocation:loc2]; 618} 619- (void)removeObjectsAtLocations:(NSArray *)loc1s 620 byLocations:(NSArray *)loc2s 621{ 622 NSDictionary *loc1, *loc2; 623 NSEnumerator *i = [loc1s objectEnumerator], 624 *j = [loc2s objectEnumerator]; 625 626 if ([loc1s count] != [loc2s count]) 627 [NSException raise:NSInvalidArgumentException 628 format: 629@"Inputs to removeObjectsAtLocations:byLocations: not of equal count"]; 630 while ((loc1 = [i nextObject]) && (loc2 = [j nextObject])) 631 [self removeObjectAtLocation:loc1 632 byLocation:loc2]; 633} 634- (void)removeObjectsAtCoordinateArrays:(NSArray *)coords 635{ 636 NSArray *dims = [self axes]; 637 NSMutableArray *loc1s = [[NSMutableArray alloc] initWithCapacity: 638 [coords count]]; 639 NSMutableArray *loc2s = [[NSMutableArray alloc] initWithCapacity: 640 [coords count]]; 641 NSMutableDictionary *loc; 642 NSDictionary *empty = [[NSDictionary alloc] init]; 643 644 NSEnumerator *axes; 645 NSEnumerator *coordArrays = [coords objectEnumerator]; 646 NSEnumerator *vals; 647 id axis; 648 NSArray *coord; 649 650 while ((coord = [coordArrays nextObject])) 651 { 652 if ([dims count] != [coord count]) 653 [NSException raise:NSInvalidArgumentException 654 format: 655 @"Dimensions of hash and number of coordinates not equal"]; 656 axes = [dims objectEnumerator]; 657 vals = [coord objectEnumerator]; 658 loc = [[NSMutableDictionary alloc] init]; 659 while ((axis = [axes nextObject])) 660 [loc setObject:[vals nextObject] 661 forKey:axis]; 662 [loc1s addObject:loc]; 663 [loc2s addObject:empty]; 664 [loc release]; 665 } 666 [self removeObjectsAtLocations:loc1s 667 byLocations:loc2s]; 668 [loc1s release]; 669 [loc2s release]; 670 [empty release]; 671} 672 673- (void)removeAllObjects 674{ 675 [NSException raise:NSGenericException 676 format: 677 @"Must implement a complete subclass of KTMutableMatrix!"]; 678} 679 680 681@end 682