]> err.no Git - sope/blob - sope-gdl1/GDLAccess/EOPrimaryKeyDictionary.m
Add libxml2-dev to libsope-xml4.7-dev deps
[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 - (BOOL)isNotEmpty {
111   return YES;
112 }
113
114 - (unsigned int)hash {
115     return 1;
116 }
117
118 - (id)key {
119     return self->key;
120 }
121
122 - (NSArray *)allKeys {
123     return [NSArray arrayWithObject:key];
124 }
125
126 - (NSArray *)allValues {
127     return [NSArray arrayWithObject:value];
128 }
129
130 - (BOOL)isEqualToDictionary:(NSDictionary *)other {
131     if (self == (EOSinglePrimaryKeyDictionary*)other)
132         return YES;
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])
137                 return YES;
138         else
139                 return NO;
140     }
141     if ([other count] != 1)
142         return NO;
143     return [value isEqual:[other objectForKey:key]];
144 }
145
146 - (id)copyWithZone:(NSZone*)zone {
147     if ([self zone] == (zone ? zone : NSDefaultMallocZone()))
148         return RETAIN(self);
149     else
150         return [[[self class] allocWithZone:zone] 
151                    initWithObject:value forKey:key];
152 }
153 - (id)copy {
154     return [self copyWithZone:NULL];
155 }
156
157 - (BOOL)fastIsEqual:(id)other {
158     if (self == other)
159         return YES;
160     if (self->isa == ((EOSinglePrimaryKeyDictionary*)other)->isa) {
161         if (fastHash == ((EOSinglePrimaryKeyDictionary*)other)->fastHash &&
162             key == ((EOSinglePrimaryKeyDictionary*)other)->key &&
163             [value isEqual:((EOSinglePrimaryKeyDictionary*)other)->value])
164                 return YES;
165         else
166             return NO;
167     }
168     [NSException raise:NSInvalidArgumentException
169                  format:
170                    @"fastIsEqual: compares only "
171                    @"EOPrimaryKeyDictionary instances !"];
172     return NO;
173 }
174
175 @end /* EOSinglePrimaryKeyDictionary */
176
177 @implementation EOSinglePrimaryKeyDictionaryEnumerator
178
179 - (id)iniWithObject:(id)aKey {
180     self->key = RETAIN(aKey);
181     return self;
182 }
183
184 - (void)dealloc {
185     RELEASE(self->key);
186     [super dealloc];
187 }
188
189 /* operations */
190
191 - (id)nextObject {
192     id tmp = self->key;
193     self->key = nil;
194     return AUTORELEASE(tmp);
195 }
196
197 @end /* EOSinglePrimaryKeyDictionaryEnumerator */
198
199 /*
200  * Multiple key dictionary is very time-memory efficient
201  */
202
203 @implementation EOMultiplePrimaryKeyDictionary
204
205 + (id)allocWithZone:(NSZone *)zone capacity:(int)capacity {
206     return NSAllocateObject(self, sizeof(id)*capacity, zone);
207 }
208
209 - (id)initWithKeys:(NSArray*)theKeys fromDictionary:(NSDictionary*)dict; {
210     int i;
211     
212     self->count    = [theKeys count];
213     self->keys     = RETAIN(theKeys);
214     self->fastHash = 0;
215     
216     for (i = 0; i < count; i++) {
217         self->values[i] = [dict objectForKey:[keys objectAtIndex:i]];
218         RETAIN(self->values[i]);
219
220         NSAssert(![values[i] isKindOfClass:[EONull class]],
221                  @"primary key values may not be null !");
222         
223         if (self->values[i] == nil) {
224             AUTORELEASE(self);
225             return nil;
226         }
227         self->fastHash += [self->values[i] hash];
228     }
229     
230     return self;
231 }
232
233 - (void)dealloc {
234     int i;
235     
236     for (i = 0; i < count; i++)
237         RELEASE(self->values[i]);
238     RELEASE(self->keys);
239     [super dealloc];
240 }
241
242 /* operations */
243
244 - (NSEnumerator *)keyEnumerator {
245     return [self->keys objectEnumerator];
246 }
247
248 - (id)objectForKey:(id)aKey {
249     int max, min, mid;
250     // Binary search for key's index
251     for (min = 0, max = count-1; min <= max; ) {
252         NSComparisonResult ord;
253         
254         mid = (min+max) >> 1;
255         ord = [(NSString*)aKey compare:(NSString*)[keys objectAtIndex:mid]];
256         if (ord == NSOrderedSame)
257             return values[mid];
258         if (ord == NSOrderedDescending) 
259             min = mid+1;
260         else
261             max = mid-1;
262     }
263     return nil;
264 }
265
266 - (unsigned int)count {
267     return self->count;
268 }
269 - (BOOL)isNotEmpty {
270   return self->count > 0 ? YES : NO;
271 }
272
273 - (unsigned int)hash {
274     return self->count;
275 }
276
277 - (NSArray *)allKeys {
278     return self->keys;
279 }
280
281 - (NSArray *)allValues {
282     return AUTORELEASE([[NSArray alloc] initWithObjects:values count:count]);
283 }
284
285 - (BOOL)isEqualToDictionary:(NSDictionary *)other {
286     int i;
287     
288     if (self == (EOMultiplePrimaryKeyDictionary*)other)
289         return YES;
290     if ((unsigned)self->count != [other count])
291         return NO;
292     for (i = 0; i < self->count; i++) {
293         if (![values[i] isEqual:[other objectForKey:[keys objectAtIndex:i]]])
294             return NO;
295     }
296     return YES;
297 }
298
299 - (id)copyWithZone:(NSZone *)zone {
300     if ([self zone] == (zone ? zone : NSDefaultMallocZone()))
301         return RETAIN(self);
302     else {
303         return [[[self class]
304                        allocWithZone:zone capacity:count] 
305                        initWithKeys:keys fromDictionary:self];
306     }
307 }
308 - (id)copy {
309     return [self copyWithZone:NULL];
310 }
311
312 - (unsigned)fastHash {
313     return self->fastHash;
314 }
315
316 - (BOOL)fastIsEqual:(id)aDict {
317     int i;
318     
319     if (self->isa != ((EOMultiplePrimaryKeyDictionary*)aDict)->isa) {
320       [NSException raise:NSInvalidArgumentException
321                    format:@"fastIsEqual: can compare only "
322                            @"EOPrimaryKeyDictionary instances"];
323     }
324     if (self->count != ((EOMultiplePrimaryKeyDictionary*)aDict)->count ||
325         self->fastHash != ((EOMultiplePrimaryKeyDictionary*)aDict)->fastHash ||
326         self->keys != ((EOMultiplePrimaryKeyDictionary*)aDict)->keys)
327         return NO;
328     
329     for (i = count - 1; i >= 0; i--) {
330       if (![values[i] isEqual:
331             ((EOMultiplePrimaryKeyDictionary*)aDict)->values[i]])
332         return NO;
333     }
334     return YES;
335 }
336
337 @end /* EOMultiplePrimaryKeyDictionary */
338
339 /*
340  * Cluster Abstract class
341  */
342
343 @implementation EOPrimaryKeyDictionary
344
345 + (id)allocWithZone:(NSZone *)_zone {
346   return NSAllocateObject(self, 0, _zone);
347 }
348
349 + (id)dictionaryWithKeys:(NSArray *)keys fromDictionary:(NSDictionary *)dict {
350     if ([dict count] == 0)
351         return nil;
352     
353     if ([keys count] == 1) {
354         id key      = [keys objectAtIndex:0];
355         id keyValue = [dict objectForKey:key];
356         
357         NSAssert2(keyValue, @"dictionary %@ contained no value for key %@ ..",
358                   dict, key);
359         
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
363         // method !
364         if ([dict isKindOfClass:[EOSinglePrimaryKeyDictionary class]]) {
365           if ([(EOSinglePrimaryKeyDictionary*)dict key]==key)
366             return dict;
367         }
368         
369         //HH:
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]])
373           return nil;
374         
375         // Alloc single key dictionary
376         return AUTORELEASE([[EOSinglePrimaryKeyDictionary alloc]
377                                                           initWithObject:keyValue
378                                                           forKey:key]);
379     }
380     else {
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
384         // method !
385         if ([dict isKindOfClass:[EOMultiplePrimaryKeyDictionary class]] &&
386             [dict allKeys] == keys)
387                 return dict;
388         // Alloc multi-key dictionary
389         return AUTORELEASE([[EOMultiplePrimaryKeyDictionary 
390                                 allocWithZone:NULL capacity:[keys count]]
391                                initWithKeys:keys fromDictionary:dict]);
392     }
393 }
394
395 + (id)dictionaryWithObject:(id)object forKey:(id)key {
396     return AUTORELEASE([[EOSinglePrimaryKeyDictionary alloc]
397                            initWithObject:object forKey:key]);
398 }
399
400 - (unsigned)fastHash {
401     return self->fastHash;
402 }
403
404 - (BOOL)fastIsEqual:aDict {
405     // TODO - request concrete implementation
406     return NO;
407 }
408
409 @end /* EOPrimaryKeyDictionary */