]> err.no Git - sope/blob - sope-gdl1/GDLAccess/EOPrimaryKeyDictionary.m
fixed build with gstep-make 1.9.2
[sope] / sope-gdl1 / GDLAccess / EOPrimaryKeyDictionary.m
1 /* 
2    EOPrimaryKeyDictionary.m
3
4    Copyright (C) 1996 Free Software Foundation, Inc.
5
6    Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro>
7    Date: 1996
8
9    This file is part of the GNUstep Database Library.
10
11    This library is free software; you can redistribute it and/or
12    modify it under the terms of the GNU Library General Public
13    License as published by the Free Software Foundation; either
14    version 2 of the License, or (at your option) any later version.
15
16    This library is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    Library General Public License for more details.
20
21    You should have received a copy of the GNU Library General Public
22    License along with this library; see the file COPYING.LIB.
23    If not, write to the Free Software Foundation,
24    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27 #import "common.h"
28 #import "EOPrimaryKeyDictionary.h"
29 #import <EOControl/EONull.h>
30
31 /*
32  * Concrete Classes declaration
33  */
34
35 @interface EOSinglePrimaryKeyDictionary : EOPrimaryKeyDictionary
36 {
37   id key;
38   id value;
39 }
40 - (id)initWithObject:(id)anObject forKey:(id)aKey;
41 - (id)key;
42 @end
43
44 @interface EOSinglePrimaryKeyDictionaryEnumerator : NSEnumerator
45 {
46     id key;
47 }
48
49 - (id)iniWithObject:(id)_key;
50
51 @end
52
53 @interface EOMultiplePrimaryKeyDictionary : EOPrimaryKeyDictionary
54 {
55   int     count;
56   NSArray *keys;
57   id      values[0];
58 }
59
60 + (id)allocWithZone:(NSZone *)_zone capacity:(int)_capacity;
61 - (id)initWithKeys:(NSArray *)_keys fromDictionary:(NSDictionary *)_dict;
62
63 @end
64
65 /*
66  * Single key dictionary 
67  */
68
69 @implementation EOSinglePrimaryKeyDictionary
70
71 - (id)initWithObject:(id)_object forKey:(id)_key {
72   NSAssert(_key,     @"provided invalid key (is nil)");
73   NSAssert1(_object, @"provided invalid value (is nil), key=%@", _key);
74
75   if ([_object isKindOfClass:[EONull class]]) {
76     NSLog(@"value of primary key %@ is null ..", _key);
77     RELEASE(self);
78     return nil;
79   }
80   
81   NSAssert(![_object isKindOfClass:[EONull class]],
82            @"value of primary key may not be null !");
83   
84   self->key      = RETAIN(_key);
85   self->value    = RETAIN(_object);
86   self->fastHash = [_object hash];
87   return self;
88 }
89
90 - (void)dealloc {
91     RELEASE(self->key);
92     RELEASE(self->value);
93     [super dealloc];
94 }
95
96 /* operations */
97
98 - (NSEnumerator *)keyEnumerator {
99     return AUTORELEASE([[EOSinglePrimaryKeyDictionaryEnumerator alloc]
100                            iniWithObject:self->key]);
101 }
102
103 - (id)objectForKey:(id)_key {
104     return [key isEqual:_key] ? value : nil;
105 }
106
107 - (unsigned int)count {
108     return 1;
109 }
110
111 - (unsigned int)hash {
112     return 1;
113 }
114
115 - (id)key {
116     return self->key;
117 }
118
119 - (NSArray *)allKeys {
120     return [NSArray arrayWithObject:key];
121 }
122
123 - (NSArray *)allValues {
124     return [NSArray arrayWithObject:value];
125 }
126
127 - (BOOL)isEqualToDictionary:(NSDictionary *)other {
128     if (self == (EOSinglePrimaryKeyDictionary*)other)
129         return YES;
130     if (self->isa == ((EOSinglePrimaryKeyDictionary*)other)->isa) {
131         if (fastHash == ((EOSinglePrimaryKeyDictionary*)other)->fastHash &&
132             [key isEqual:((EOSinglePrimaryKeyDictionary*)other)->key] &&
133             [value isEqual:((EOSinglePrimaryKeyDictionary*)other)->value])
134                 return YES;
135         else
136                 return NO;
137     }
138     if ([other count] != 1)
139         return NO;
140     return [value isEqual:[other objectForKey:key]];
141 }
142
143 - (id)copyWithZone:(NSZone*)zone {
144     if ([self zone] == (zone ? zone : NSDefaultMallocZone()))
145         return RETAIN(self);
146     else
147         return [[[self class] allocWithZone:zone] 
148                    initWithObject:value forKey:key];
149 }
150 - (id)copy {
151     return [self copyWithZone:NULL];
152 }
153
154 - (BOOL)fastIsEqual:(id)other {
155     if (self == other)
156         return YES;
157     if (self->isa == ((EOSinglePrimaryKeyDictionary*)other)->isa) {
158         if (fastHash == ((EOSinglePrimaryKeyDictionary*)other)->fastHash &&
159             key == ((EOSinglePrimaryKeyDictionary*)other)->key &&
160             [value isEqual:((EOSinglePrimaryKeyDictionary*)other)->value])
161                 return YES;
162         else
163             return NO;
164     }
165     [NSException raise:NSInvalidArgumentException
166                  format:
167                    @"fastIsEqual: compares only "
168                    @"EOPrimaryKeyDictionary instances !"];
169     return NO;
170 }
171
172 @end /* EOSinglePrimaryKeyDictionary */
173
174 @implementation EOSinglePrimaryKeyDictionaryEnumerator
175
176 - (id)iniWithObject:(id)aKey {
177     self->key = RETAIN(aKey);
178     return self;
179 }
180
181 - (void)dealloc {
182     RELEASE(self->key);
183     [super dealloc];
184 }
185
186 /* operations */
187
188 - (id)nextObject {
189     id tmp = self->key;
190     self->key = nil;
191     return AUTORELEASE(tmp);
192 }
193
194 @end /* EOSinglePrimaryKeyDictionaryEnumerator */
195
196 /*
197  * Multiple key dictionary is very time-memory efficient
198  */
199
200 @implementation EOMultiplePrimaryKeyDictionary
201
202 + (id)allocWithZone:(NSZone *)zone capacity:(int)capacity {
203     return NSAllocateObject(self, sizeof(id)*capacity, zone);
204 }
205
206 - (id)initWithKeys:(NSArray*)theKeys fromDictionary:(NSDictionary*)dict; {
207     int i;
208     
209     self->count    = [theKeys count];
210     self->keys     = RETAIN(theKeys);
211     self->fastHash = 0;
212     
213     for (i = 0; i < count; i++) {
214         self->values[i] = [dict objectForKey:[keys objectAtIndex:i]];
215         RETAIN(self->values[i]);
216
217         NSAssert(![values[i] isKindOfClass:[EONull class]],
218                  @"primary key values may not be null !");
219         
220         if (self->values[i] == nil) {
221             AUTORELEASE(self);
222             return nil;
223         }
224         self->fastHash += [self->values[i] hash];
225     }
226     
227     return self;
228 }
229
230 - (void)dealloc {
231     int i;
232     
233     for (i = 0; i < count; i++)
234         RELEASE(self->values[i]);
235     RELEASE(self->keys);
236     [super dealloc];
237 }
238
239 /* operations */
240
241 - (NSEnumerator *)keyEnumerator {
242     return [self->keys objectEnumerator];
243 }
244
245 - (id)objectForKey:(id)aKey {
246     int max, min, mid;
247     // Binary search for key's index
248     for (min = 0, max = count-1; min <= max; ) {
249         NSComparisonResult ord;
250         
251         mid = (min+max) >> 1;
252         ord = [(NSString*)aKey compare:(NSString*)[keys objectAtIndex:mid]];
253         if (ord == NSOrderedSame)
254             return values[mid];
255         if (ord == NSOrderedDescending) 
256             min = mid+1;
257         else
258             max = mid-1;
259     }
260     return nil;
261 }
262
263 - (unsigned int)count {
264     return self->count;
265 }
266
267 - (unsigned int)hash {
268     return self->count;
269 }
270
271 - (NSArray *)allKeys {
272     return self->keys;
273 }
274
275 - (NSArray *)allValues {
276     return AUTORELEASE([[NSArray alloc] initWithObjects:values count:count]);
277 }
278
279 - (BOOL)isEqualToDictionary:(NSDictionary *)other {
280     int i;
281     
282     if (self == (EOMultiplePrimaryKeyDictionary*)other)
283         return YES;
284     if ((unsigned)self->count != [other count])
285         return NO;
286     for (i = 0; i < self->count; i++) {
287         if (![values[i] isEqual:[other objectForKey:[keys objectAtIndex:i]]])
288             return NO;
289     }
290     return YES;
291 }
292
293 - (id)copyWithZone:(NSZone *)zone {
294     if ([self zone] == (zone ? zone : NSDefaultMallocZone()))
295         return RETAIN(self);
296     else {
297         return [[[self class]
298                        allocWithZone:zone capacity:count] 
299                        initWithKeys:keys fromDictionary:self];
300     }
301 }
302 - (id)copy {
303     return [self copyWithZone:NULL];
304 }
305
306 - (unsigned)fastHash {
307     return self->fastHash;
308 }
309
310 - (BOOL)fastIsEqual:(id)aDict {
311     int i;
312     
313     if (self->isa != ((EOMultiplePrimaryKeyDictionary*)aDict)->isa) {
314       [NSException raise:NSInvalidArgumentException
315                    format:@"fastIsEqual: can compare only "
316                            @"EOPrimaryKeyDictionary instances"];
317     }
318     if (self->count != ((EOMultiplePrimaryKeyDictionary*)aDict)->count ||
319         self->fastHash != ((EOMultiplePrimaryKeyDictionary*)aDict)->fastHash ||
320         self->keys != ((EOMultiplePrimaryKeyDictionary*)aDict)->keys)
321         return NO;
322     
323     for (i = count - 1; i >= 0; i--) {
324       if (![values[i] isEqual:
325             ((EOMultiplePrimaryKeyDictionary*)aDict)->values[i]])
326         return NO;
327     }
328     return YES;
329 }
330
331 @end /* EOMultiplePrimaryKeyDictionary */
332
333 /*
334  * Cluster Abstract class
335  */
336
337 @implementation EOPrimaryKeyDictionary
338
339 + (id)allocWithZone:(NSZone *)_zone {
340   return NSAllocateObject(self, 0, _zone);
341 }
342
343 + (id)dictionaryWithKeys:(NSArray *)keys fromDictionary:(NSDictionary *)dict {
344     if ([dict count] == 0)
345         return nil;
346     
347     if ([keys count] == 1) {
348         id key      = [keys objectAtIndex:0];
349         id keyValue = [dict objectForKey:key];
350         
351         NSAssert2(keyValue, @"dictionary %@ contained no value for key %@ ..",
352                   dict, key);
353         
354         // Check if already an EOSinglePrimaryKeyDictionary from same entity
355         // return it since the new one will be identical to it; we have
356         // no problem regarding its correctness since it was built by this
357         // method !
358         if ([dict isKindOfClass:[EOSinglePrimaryKeyDictionary class]]) {
359           if ([(EOSinglePrimaryKeyDictionary*)dict key]==key)
360             return dict;
361         }
362         
363         //HH:
364         // Check if the keyValue is EONull. If this is the case, return nil.
365         // Primary keys are always 'not null'.
366         if ([keyValue isKindOfClass:[EONull class]])
367           return nil;
368         
369         // Alloc single key dictionary
370         return AUTORELEASE([[EOSinglePrimaryKeyDictionary alloc]
371                                                           initWithObject:keyValue
372                                                           forKey:key]);
373     }
374     else {
375         // Check if already an EOMultiplePrimaryKeyDictionary from same entity
376         // return it since the new one will be identical to it; we have
377         // no problem regarding its correctness since it was built by this
378         // method !
379         if ([dict isKindOfClass:[EOMultiplePrimaryKeyDictionary class]] &&
380             [dict allKeys] == keys)
381                 return dict;
382         // Alloc multi-key dictionary
383         return AUTORELEASE([[EOMultiplePrimaryKeyDictionary 
384                                 allocWithZone:NULL capacity:[keys count]]
385                                initWithKeys:keys fromDictionary:dict]);
386     }
387 }
388
389 + (id)dictionaryWithObject:(id)object forKey:(id)key {
390     return AUTORELEASE([[EOSinglePrimaryKeyDictionary alloc]
391                            initWithObject:object forKey:key]);
392 }
393
394 - (unsigned)fastHash {
395     return self->fastHash;
396 }
397
398 - (BOOL)fastIsEqual:aDict {
399     // TODO - request concrete implementation
400     return NO;
401 }
402
403 @end /* EOPrimaryKeyDictionary */