1//
2//  KTPlaceholderMatrix
3//  KTMatrix collection class cluster
4//
5//  KTMatrix class cluster initialisation subclass
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 "KTPlaceholderMatrix.h"
16#import "KTCuboidHash.h"
17#import "KTMatrixSparseImp.h"
18#import "KTMatrixDenseImp.h"
19#import "KTMutableMatrixSparseImp.h"
20
21@implementation KTPlaceholderMatrix
22
23//// Primitive methods
24- (id)init
25{
26    NSZone *zone = [self zone];
27    KTCuboidHash *hash = [[KTCuboidHash alloc] init];
28    [self release];
29    self = [[KTMatrixSparseImp allocWithZone:zone]
30        initWithLocationHash:hash];
31    [hash release];
32    return self;
33}
34- (id)initWithMatrix:(KTMatrix *)matrix
35{
36    NSZone *zone = [self zone];
37    [self release];
38    if (([[matrix locationHash] hashBound] == 0) ||
39        ([matrix count] < [[matrix locationHash] hashBound]/3))
40        self = [KTMatrixSparseImp allocWithZone:zone];
41    else
42        self = [KTMatrixDenseImp allocWithZone:zone];
43    self = [self initWithMatrix:matrix];
44    return self;
45}
46- (id)initWithLocationHash:(id<KTLocationHash>)hash
47{
48    NSZone *zone = [self zone];
49    [self release];
50    return [[KTMatrixSparseImp allocWithZone:zone] initWithLocationHash:hash];
51}
52- (id)initWithLocationHash:(id<KTLocationHash>)hash
53                   objects:(NSArray *)objects
54               atLocations:(NSArray *)loc1s
55               byLocations:(NSArray *)loc2s
56{
57    NSZone *zone = [self zone];
58    [self release];
59    if (([hash hashBound] == 0) || ([objects count] < [hash hashBound]/3))
60        self = [KTMatrixSparseImp allocWithZone:zone];
61    else
62        self = [KTMatrixDenseImp allocWithZone:zone];
63    self = [self initWithLocationHash:hash
64                              objects:objects
65                          atLocations:loc1s
66                          byLocations:loc2s];
67    return self;
68}
69
70//// Efficient implementations of other methods
71- (id)initWithCuboidBoundsObjectAtCoordinates:(unsigned)bound1,...
72{
73    NSZone *zone = [self zone];
74    KTCuboidHash *hash;
75    id object = nil;
76    va_list args;
77
78    [self release];
79
80    va_start(args, bound1);
81    hash = [[KTCuboidHash allocWithZone:zone]
82                initWithBoundsList:bound1 :&args];
83
84    object = va_arg(args, id);
85
86    if (([hash hashBound] != 0) && ([hash hashBound] <= 3))
87        self = [KTMatrixDenseImp alloc];
88    else
89        self = [KTMatrixSparseImp alloc];
90    self = [(id)self initWithLocationHash:hash
91                                   object:object
92                         atHashedLocation:[hash hashForCoordinatesList:&args]];
93
94    va_end(args);
95    [hash release];
96    return self;
97}
98- (id)initWithCuboidBoundsObjectsAtCoordinates:(unsigned)bound1,...
99{   // Can optimize away some inefficiencies
100    NSZone *zone = [self zone];
101    KTCuboidHash *hash; // The hashing object to use
102    va_list args;       // To trawl through the arguments
103    id object;          // Used to store the objects in the arguments
104
105    // Need a mutable temporary to store all the objects
106    KTMutableMatrixSparseImp *temp;
107    // SELs/IMPs to speed up repeated method calls
108    SEL hashListSEL = @selector(hashForCoordinatesList:);
109    SEL setObjSEL = @selector(setObject:atHashedLocation:);
110    unsigned (*hashListIMP)(id, SEL, ...);
111    void (*setObjIMP)(id, SEL, ...);
112
113    [self release];
114
115    // Read in data for the cuboid hash
116    va_start(args, bound1);
117    hash = [[KTCuboidHash allocWithZone:zone]
118                initWithBoundsList:bound1 :&args];
119
120    // Allocate the temporary mutable matrix
121    temp = [[KTMutableMatrixSparseImp allocWithZone:zone]
122                initWithCapacity:0
123                    locationHash:hash];
124
125    // Read in objects and coordinates
126    hashListIMP = (unsigned (*)(id, SEL, ...))
127        [hash methodForSelector:hashListSEL];
128    setObjIMP = (void (*)(id, SEL, ...))
129        [temp methodForSelector:setObjSEL];
130    while (object = va_arg(args, id))
131        setObjIMP(temp, setObjSEL, object,
132                  hashListIMP(hash,hashListSEL,&args));
133
134    // Make an immutable copy of the object
135    self = [temp copyWithZone:zone];
136    [temp release];
137
138    [hash release];
139    va_end(args);
140    return self;
141}
142@end
143