]> err.no Git - sope/blob - sope-gdl1/GDLAccess/EORecordDictionary.m
fixed bug in GDL adaptor lookup
[sope] / sope-gdl1 / GDLAccess / EORecordDictionary.m
1 /* 
2    EOAdaptorChannel.m
3
4    Copyright (C) 1996 Free Software Foundation, Inc.
5
6    Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
7    Date: October 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 #include <stdarg.h>
28 #include <math.h>
29
30 #import <Foundation/NSObject.h>
31 #import <Foundation/NSDictionary.h>
32 #import <Foundation/NSArray.h>
33 #import <Foundation/NSString.h>
34 #import <Foundation/NSException.h>
35
36 #if LIB_FOUNDATION_LIBRARY
37 #  include <extensions/objc-runtime.h>
38 #else
39 #  include <NGExtensions/NGObjectMacros.h>
40 #endif
41
42 #include "EORecordDictionary.h"
43
44 @implementation EORecordDictionary
45
46 static NSDictionary *emptyDict = nil;
47
48 - (id)init  {
49   RELEASE(self);
50   if (emptyDict == nil) emptyDict = [[NSDictionary alloc] init];
51   return [emptyDict retain];
52 }
53
54 - (id)initWithObjects:(id *)_objects forKeys:(id *)_keys 
55   count:(unsigned int)_count
56 {
57   if (_count == 0) {
58         RELEASE(self);
59         if (emptyDict == nil) emptyDict = [[NSDictionary alloc] init];
60         return [emptyDict retain];
61   }
62   
63   if (_count == 1) {
64         RELEASE(self);
65         return [[NSDictionary alloc]
66                               initWithObjects:_objects forKeys:_keys
67                               count:_count];
68   }
69   
70   self->count = _count;
71   while(_count--) {
72         if ((_keys[_count] == nil) || (_objects[_count] == nil)) {
73           [NSException raise:NSInvalidArgumentException
74                        format:@"Nil object to be added in dictionary"];
75         }
76         self->entries[_count].key   = RETAIN(_keys[_count]);
77         self->entries[_count].hash  = [_keys[_count] hash];
78         self->entries[_count].value = RETAIN(_objects[_count]);
79   }
80   return self;
81 }
82
83 - (id)initWithDictionary:(NSDictionary *)dictionary {
84   // TODO: who calls this method?
85   NSEnumerator  *keys;
86   unsigned char i;
87     
88   keys = [dictionary keyEnumerator];
89   self->count = [dictionary count];
90
91   for (i = 0; i < self->count; i++) {
92     id key = [keys nextObject];
93     
94     self->entries[i].key   = RETAIN(key);
95     self->entries[i].hash  = [key hash];
96     self->entries[i].value = RETAIN([dictionary objectForKey:key]);
97   }
98   return self;
99 }
100
101 - (void)dealloc {
102   /* keys are always NSString keys?! */
103 #if GNU_RUNTIME
104   static Class LastKeyClass = Nil;
105   static IMP   keyRelease   = 0;
106   static unsigned misses = 0, hits = 0;
107 #endif
108   register unsigned char i;
109     
110   for (i = 0; i < self->count; i++) {
111       register NSString *key = self->entries[i].key;
112 #if GNU_RUNTIME      
113       if (*(id *)key != LastKeyClass) {
114         LastKeyClass = *(id *)key;
115         keyRelease = 
116           method_get_imp(class_get_instance_method(LastKeyClass, 
117                                                    @selector(release)));
118         misses++;
119       }
120       else
121         hits++;
122       
123       keyRelease(key, NULL /* dangerous? */);
124
125 #if PROF_METHOD_CACHE
126       if (hits % 1000 == 0 && hits != 0)
127         NSLog(@"%s: DB HITS: %d MISSES: %d", __PRETTY_FUNCTION__,hits, misses);
128 #endif
129 #else
130       [key release];
131 #endif
132
133       RELEASE(self->entries[i].value);
134   }
135   [super dealloc];
136 }
137
138 /* operations */
139
140 - (id)objectForKey:(id)aKey {
141   register EORecordDictionaryEntry *e = self->entries;
142   register signed char i;
143   register unsigned hash;
144 #if GNU_RUNTIME
145   static Class LastKeyClass = Nil;
146   static unsigned (*keyHash)(id,SEL)  = 0;
147   static BOOL     (*keyEq)(id,SEL,id) = 0;
148 #if PROF_METHOD_CACHE
149   static unsigned misses = 0, hits = 0;
150 #endif
151 #endif
152   
153 #if GNU_RUNTIME      
154   if (aKey == nil)
155     return nil;
156   
157   if (*(id *)aKey != LastKeyClass) {
158     LastKeyClass = *(id *)aKey;
159     keyHash = (void *)
160       method_get_imp(class_get_instance_method(LastKeyClass, 
161                                                @selector(hash)));
162     keyEq = (void *)
163       method_get_imp(class_get_instance_method(LastKeyClass, 
164                                                @selector(isEqual:)));
165   }
166   
167   hash = keyHash(aKey, NULL /* dangerous? */);
168 #else  
169   hash = [aKey hash];
170 #endif
171
172   for (i = (self->count - 1); i >= 0; i--, e++) {
173     if (e->hash != hash)
174       continue;
175     if (e->key == aKey)
176       return e->value;
177     
178 #if GNU_RUNTIME
179     if (keyEq(e->key, NULL /* dangerous? */, aKey))
180       return e->value;
181 #else
182     if ([e->key isEqual:aKey]) 
183       return e->value;
184 #endif
185   }
186   return nil;
187 }
188
189 - (unsigned int)count {
190   return self->count;
191 }
192 - (NSEnumerator *)keyEnumerator {
193   return AUTORELEASE([[_EORecordDictionaryKeyEnumerator alloc]
194                             initWithDictionary:self
195                             firstEntry:self->entries count:self->count]);
196 }
197
198 @end /* NSConcreteSmallDictionary */
199
200 @implementation _EORecordDictionaryKeyEnumerator
201
202 - (id)initWithDictionary:(EORecordDictionary *)_dict
203   firstEntry:(EORecordDictionaryEntry *)_firstEntry
204   count:(unsigned char)_count
205 {
206     self->dict         = RETAIN(_dict);
207     self->currentEntry = _firstEntry;
208     self->count        = _count;
209     return self;
210 }
211
212 - (void)dealloc {
213     RELEASE(self->dict);
214     [super dealloc];
215 }
216
217 - (id)nextObject {
218   if (self->count > 0) {
219         id obj;
220         obj = self->currentEntry->key;
221         self->currentEntry++;
222         self->count--;
223         return obj;
224   }
225     
226   return nil;
227 }
228
229 @end /* _NSConcreteSmallDictionaryKeyEnumerator */