2 EOPrimaryKeyDictionary.m
4 Copyright (C) 1996 Free Software Foundation, Inc.
6 Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro>
9 This file is part of the GNUstep Database Library.
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.
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.
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.
28 #import "EOPrimaryKeyDictionary.h"
29 #import <EOControl/EONull.h>
32 * Concrete Classes declaration
35 @interface EOSinglePrimaryKeyDictionary : EOPrimaryKeyDictionary
40 - (id)initWithObject:(id)anObject forKey:(id)aKey;
44 @interface EOSinglePrimaryKeyDictionaryEnumerator : NSEnumerator
49 - (id)iniWithObject:(id)_key;
53 @interface EOMultiplePrimaryKeyDictionary : EOPrimaryKeyDictionary
60 + (id)allocWithZone:(NSZone *)_zone capacity:(int)_capacity;
61 - (id)initWithKeys:(NSArray *)_keys fromDictionary:(NSDictionary *)_dict;
66 * Single key dictionary
69 @implementation EOSinglePrimaryKeyDictionary
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);
75 if ([_object isKindOfClass:[EONull class]]) {
76 NSLog(@"value of primary key %@ is null ..", _key);
81 NSAssert(![_object isKindOfClass:[EONull class]],
82 @"value of primary key may not be null !");
84 self->key = RETAIN(_key);
85 self->value = RETAIN(_object);
86 self->fastHash = [_object hash];
98 - (NSEnumerator *)keyEnumerator {
99 return AUTORELEASE([[EOSinglePrimaryKeyDictionaryEnumerator alloc]
100 iniWithObject:self->key]);
103 - (id)objectForKey:(id)_key {
104 return [key isEqual:_key] ? value : nil;
107 - (unsigned int)count {
114 - (unsigned int)hash {
122 - (NSArray *)allKeys {
123 return [NSArray arrayWithObject:key];
126 - (NSArray *)allValues {
127 return [NSArray arrayWithObject:value];
130 - (BOOL)isEqualToDictionary:(NSDictionary *)other {
131 if (self == (EOSinglePrimaryKeyDictionary*)other)
133 if (self->isa == ((EOSinglePrimaryKeyDictionary*)other)->isa) {
134 if (fastHash == ((EOSinglePrimaryKeyDictionary*)other)->fastHash &&
135 [key isEqual:((EOSinglePrimaryKeyDictionary*)other)->key] &&
136 [value isEqual:((EOSinglePrimaryKeyDictionary*)other)->value])
141 if ([other count] != 1)
143 return [value isEqual:[other objectForKey:key]];
146 - (id)copyWithZone:(NSZone*)zone {
147 if ([self zone] == (zone ? zone : NSDefaultMallocZone()))
150 return [[[self class] allocWithZone:zone]
151 initWithObject:value forKey:key];
154 return [self copyWithZone:NULL];
157 - (BOOL)fastIsEqual:(id)other {
160 if (self->isa == ((EOSinglePrimaryKeyDictionary*)other)->isa) {
161 if (fastHash == ((EOSinglePrimaryKeyDictionary*)other)->fastHash &&
162 key == ((EOSinglePrimaryKeyDictionary*)other)->key &&
163 [value isEqual:((EOSinglePrimaryKeyDictionary*)other)->value])
168 [NSException raise:NSInvalidArgumentException
170 @"fastIsEqual: compares only "
171 @"EOPrimaryKeyDictionary instances !"];
175 @end /* EOSinglePrimaryKeyDictionary */
177 @implementation EOSinglePrimaryKeyDictionaryEnumerator
179 - (id)iniWithObject:(id)aKey {
180 self->key = RETAIN(aKey);
194 return AUTORELEASE(tmp);
197 @end /* EOSinglePrimaryKeyDictionaryEnumerator */
200 * Multiple key dictionary is very time-memory efficient
203 @implementation EOMultiplePrimaryKeyDictionary
205 + (id)allocWithZone:(NSZone *)zone capacity:(int)capacity {
206 return NSAllocateObject(self, sizeof(id)*capacity, zone);
209 - (id)initWithKeys:(NSArray*)theKeys fromDictionary:(NSDictionary*)dict; {
212 self->count = [theKeys count];
213 self->keys = RETAIN(theKeys);
216 for (i = 0; i < count; i++) {
217 self->values[i] = [dict objectForKey:[keys objectAtIndex:i]];
218 RETAIN(self->values[i]);
220 NSAssert(![values[i] isKindOfClass:[EONull class]],
221 @"primary key values may not be null !");
223 if (self->values[i] == nil) {
227 self->fastHash += [self->values[i] hash];
236 for (i = 0; i < count; i++)
237 RELEASE(self->values[i]);
244 - (NSEnumerator *)keyEnumerator {
245 return [self->keys objectEnumerator];
248 - (id)objectForKey:(id)aKey {
250 // Binary search for key's index
251 for (min = 0, max = count-1; min <= max; ) {
252 NSComparisonResult ord;
254 mid = (min+max) >> 1;
255 ord = [(NSString*)aKey compare:(NSString*)[keys objectAtIndex:mid]];
256 if (ord == NSOrderedSame)
258 if (ord == NSOrderedDescending)
266 - (unsigned int)count {
270 return self->count > 0 ? YES : NO;
273 - (unsigned int)hash {
277 - (NSArray *)allKeys {
281 - (NSArray *)allValues {
282 return AUTORELEASE([[NSArray alloc] initWithObjects:values count:count]);
285 - (BOOL)isEqualToDictionary:(NSDictionary *)other {
288 if (self == (EOMultiplePrimaryKeyDictionary*)other)
290 if ((unsigned)self->count != [other count])
292 for (i = 0; i < self->count; i++) {
293 if (![values[i] isEqual:[other objectForKey:[keys objectAtIndex:i]]])
299 - (id)copyWithZone:(NSZone *)zone {
300 if ([self zone] == (zone ? zone : NSDefaultMallocZone()))
303 return [[[self class]
304 allocWithZone:zone capacity:count]
305 initWithKeys:keys fromDictionary:self];
309 return [self copyWithZone:NULL];
312 - (unsigned)fastHash {
313 return self->fastHash;
316 - (BOOL)fastIsEqual:(id)aDict {
319 if (self->isa != ((EOMultiplePrimaryKeyDictionary*)aDict)->isa) {
320 [NSException raise:NSInvalidArgumentException
321 format:@"fastIsEqual: can compare only "
322 @"EOPrimaryKeyDictionary instances"];
324 if (self->count != ((EOMultiplePrimaryKeyDictionary*)aDict)->count ||
325 self->fastHash != ((EOMultiplePrimaryKeyDictionary*)aDict)->fastHash ||
326 self->keys != ((EOMultiplePrimaryKeyDictionary*)aDict)->keys)
329 for (i = count - 1; i >= 0; i--) {
330 if (![values[i] isEqual:
331 ((EOMultiplePrimaryKeyDictionary*)aDict)->values[i]])
337 @end /* EOMultiplePrimaryKeyDictionary */
340 * Cluster Abstract class
343 @implementation EOPrimaryKeyDictionary
345 + (id)allocWithZone:(NSZone *)_zone {
346 return NSAllocateObject(self, 0, _zone);
349 + (id)dictionaryWithKeys:(NSArray *)keys fromDictionary:(NSDictionary *)dict {
350 if ([dict count] == 0)
353 if ([keys count] == 1) {
354 id key = [keys objectAtIndex:0];
355 id keyValue = [dict objectForKey:key];
357 NSAssert2(keyValue, @"dictionary %@ contained no value for key %@ ..",
360 // Check if already an EOSinglePrimaryKeyDictionary from same entity
361 // return it since the new one will be identical to it; we have
362 // no problem regarding its correctness since it was built by this
364 if ([dict isKindOfClass:[EOSinglePrimaryKeyDictionary class]]) {
365 if ([(EOSinglePrimaryKeyDictionary*)dict key]==key)
370 // Check if the keyValue is EONull. If this is the case, return nil.
371 // Primary keys are always 'not null'.
372 if ([keyValue isKindOfClass:[EONull class]])
375 // Alloc single key dictionary
376 return AUTORELEASE([[EOSinglePrimaryKeyDictionary alloc]
377 initWithObject:keyValue
381 // Check if already an EOMultiplePrimaryKeyDictionary from same entity
382 // return it since the new one will be identical to it; we have
383 // no problem regarding its correctness since it was built by this
385 if ([dict isKindOfClass:[EOMultiplePrimaryKeyDictionary class]] &&
386 [dict allKeys] == keys)
388 // Alloc multi-key dictionary
389 return AUTORELEASE([[EOMultiplePrimaryKeyDictionary
390 allocWithZone:NULL capacity:[keys count]]
391 initWithKeys:keys fromDictionary:dict]);
395 + (id)dictionaryWithObject:(id)object forKey:(id)key {
396 return AUTORELEASE([[EOSinglePrimaryKeyDictionary alloc]
397 initWithObject:object forKey:key]);
400 - (unsigned)fastHash {
401 return self->fastHash;
404 - (BOOL)fastIsEqual:aDict {
405 // TODO - request concrete implementation
409 @end /* EOPrimaryKeyDictionary */