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 {
111 - (unsigned int)hash {
119 - (NSArray *)allKeys {
120 return [NSArray arrayWithObject:key];
123 - (NSArray *)allValues {
124 return [NSArray arrayWithObject:value];
127 - (BOOL)isEqualToDictionary:(NSDictionary *)other {
128 if (self == (EOSinglePrimaryKeyDictionary*)other)
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])
138 if ([other count] != 1)
140 return [value isEqual:[other objectForKey:key]];
143 - (id)copyWithZone:(NSZone*)zone {
144 if ([self zone] == (zone ? zone : NSDefaultMallocZone()))
147 return [[[self class] allocWithZone:zone]
148 initWithObject:value forKey:key];
151 return [self copyWithZone:NULL];
154 - (BOOL)fastIsEqual:(id)other {
157 if (self->isa == ((EOSinglePrimaryKeyDictionary*)other)->isa) {
158 if (fastHash == ((EOSinglePrimaryKeyDictionary*)other)->fastHash &&
159 key == ((EOSinglePrimaryKeyDictionary*)other)->key &&
160 [value isEqual:((EOSinglePrimaryKeyDictionary*)other)->value])
165 [NSException raise:NSInvalidArgumentException
167 @"fastIsEqual: compares only "
168 @"EOPrimaryKeyDictionary instances !"];
172 @end /* EOSinglePrimaryKeyDictionary */
174 @implementation EOSinglePrimaryKeyDictionaryEnumerator
176 - (id)iniWithObject:(id)aKey {
177 self->key = RETAIN(aKey);
191 return AUTORELEASE(tmp);
194 @end /* EOSinglePrimaryKeyDictionaryEnumerator */
197 * Multiple key dictionary is very time-memory efficient
200 @implementation EOMultiplePrimaryKeyDictionary
202 + (id)allocWithZone:(NSZone *)zone capacity:(int)capacity {
203 return NSAllocateObject(self, sizeof(id)*capacity, zone);
206 - (id)initWithKeys:(NSArray*)theKeys fromDictionary:(NSDictionary*)dict; {
209 self->count = [theKeys count];
210 self->keys = RETAIN(theKeys);
213 for (i = 0; i < count; i++) {
214 self->values[i] = [dict objectForKey:[keys objectAtIndex:i]];
215 RETAIN(self->values[i]);
217 NSAssert(![values[i] isKindOfClass:[EONull class]],
218 @"primary key values may not be null !");
220 if (self->values[i] == nil) {
224 self->fastHash += [self->values[i] hash];
233 for (i = 0; i < count; i++)
234 RELEASE(self->values[i]);
241 - (NSEnumerator *)keyEnumerator {
242 return [self->keys objectEnumerator];
245 - (id)objectForKey:(id)aKey {
247 // Binary search for key's index
248 for (min = 0, max = count-1; min <= max; ) {
249 NSComparisonResult ord;
251 mid = (min+max) >> 1;
252 ord = [(NSString*)aKey compare:(NSString*)[keys objectAtIndex:mid]];
253 if (ord == NSOrderedSame)
255 if (ord == NSOrderedDescending)
263 - (unsigned int)count {
267 - (unsigned int)hash {
271 - (NSArray *)allKeys {
275 - (NSArray *)allValues {
276 return AUTORELEASE([[NSArray alloc] initWithObjects:values count:count]);
279 - (BOOL)isEqualToDictionary:(NSDictionary *)other {
282 if (self == (EOMultiplePrimaryKeyDictionary*)other)
284 if ((unsigned)self->count != [other count])
286 for (i = 0; i < self->count; i++) {
287 if (![values[i] isEqual:[other objectForKey:[keys objectAtIndex:i]]])
293 - (id)copyWithZone:(NSZone *)zone {
294 if ([self zone] == (zone ? zone : NSDefaultMallocZone()))
297 return [[[self class]
298 allocWithZone:zone capacity:count]
299 initWithKeys:keys fromDictionary:self];
303 return [self copyWithZone:NULL];
306 - (unsigned)fastHash {
307 return self->fastHash;
310 - (BOOL)fastIsEqual:(id)aDict {
313 if (self->isa != ((EOMultiplePrimaryKeyDictionary*)aDict)->isa) {
314 [NSException raise:NSInvalidArgumentException
315 format:@"fastIsEqual: can compare only "
316 @"EOPrimaryKeyDictionary instances"];
318 if (self->count != ((EOMultiplePrimaryKeyDictionary*)aDict)->count ||
319 self->fastHash != ((EOMultiplePrimaryKeyDictionary*)aDict)->fastHash ||
320 self->keys != ((EOMultiplePrimaryKeyDictionary*)aDict)->keys)
323 for (i = count - 1; i >= 0; i--) {
324 if (![values[i] isEqual:
325 ((EOMultiplePrimaryKeyDictionary*)aDict)->values[i]])
331 @end /* EOMultiplePrimaryKeyDictionary */
334 * Cluster Abstract class
337 @implementation EOPrimaryKeyDictionary
339 + (id)allocWithZone:(NSZone *)_zone {
340 return NSAllocateObject(self, 0, _zone);
343 + (id)dictionaryWithKeys:(NSArray *)keys fromDictionary:(NSDictionary *)dict {
344 if ([dict count] == 0)
347 if ([keys count] == 1) {
348 id key = [keys objectAtIndex:0];
349 id keyValue = [dict objectForKey:key];
351 NSAssert2(keyValue, @"dictionary %@ contained no value for key %@ ..",
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
358 if ([dict isKindOfClass:[EOSinglePrimaryKeyDictionary class]]) {
359 if ([(EOSinglePrimaryKeyDictionary*)dict key]==key)
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]])
369 // Alloc single key dictionary
370 return AUTORELEASE([[EOSinglePrimaryKeyDictionary alloc]
371 initWithObject:keyValue
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
379 if ([dict isKindOfClass:[EOMultiplePrimaryKeyDictionary class]] &&
380 [dict allKeys] == keys)
382 // Alloc multi-key dictionary
383 return AUTORELEASE([[EOMultiplePrimaryKeyDictionary
384 allocWithZone:NULL capacity:[keys count]]
385 initWithKeys:keys fromDictionary:dict]);
389 + (id)dictionaryWithObject:(id)object forKey:(id)key {
390 return AUTORELEASE([[EOSinglePrimaryKeyDictionary alloc]
391 initWithObject:object forKey:key]);
394 - (unsigned)fastHash {
395 return self->fastHash;
398 - (BOOL)fastIsEqual:aDict {
399 // TODO - request concrete implementation
403 @end /* EOPrimaryKeyDictionary */