]> err.no Git - sope/blob - sope-gdl1/GDLAccess/EOObjectUniquer.m
added missing inline pathes
[sope] / sope-gdl1 / GDLAccess / EOObjectUniquer.m
1 /* 
2    EOObjectUniquer.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 "EOEntity.h"
29 #import "EOObjectUniquer.h"
30 #import "EOPrimaryKeyDictionary.h"
31 #import "EODatabaseFault.h"
32 #import "EOGenericRecord.h"
33
34 static unsigned uniquerHash(NSMapTable* table, EOUniquerRecord* rec) {
35   // efficient hash for dictionaries is done in the concrete
36   // dictionaries implementation; dictionaries are allocated
37   // from EOPrimaryKeyDictionary concrete subclasses
38   return  ((unsigned)(rec->entity) >> 4) +
39           ((EOPrimaryKeyDictionary*)(rec->pkey))->fastHash;
40 }
41
42 static BOOL uniquerCompare(NSMapTable *table, EOUniquerRecord *rec1,
43                            EOUniquerRecord *rec2) {
44   // efficient compare between dictionaries is done in the concrete
45   // dictionaries implementation; dictionaries are allocated
46   // from EOPrimaryKeyDictionary concrete subclasses
47   return (rec1->entity == rec2->entity) &&  [rec1->pkey fastIsEqual:rec2->pkey];
48 }
49
50 static NSString* uniqDescription(NSMapTable *t, EOUniquerRecord* rec) {
51   return [NSString stringWithFormat:
52                      @"<<pkey:%08x entity:%08x object:%08x snapshot:%08x>>",
53                      rec->pkey, rec->entity, rec->object, rec->snapshot];
54 }
55
56 static void uniquerRetain(NSMapTable *table, EOUniquerRecord* rec) {
57   rec->refCount++;
58 }
59
60 static void uniquerRelease(NSMapTable *table, EOUniquerRecord *rec) {
61   rec->refCount--;
62   
63   if (rec->refCount <= 0) {
64     RELEASE(rec->pkey);     rec->pkey     = NULL;
65     RELEASE(rec->entity);   rec->entity   = NULL;
66     RELEASE(rec->snapshot); rec->snapshot = NULL;
67     Free(rec); rec = NULL;
68   }
69 }
70
71 static inline EOUniquerRecord *uniquerCreate(id pkey, id entity, id object,
72                                              id snapshot) {
73   EOUniquerRecord *rec = NULL;
74   
75   rec = (EOUniquerRecord *)Malloc(sizeof(EOUniquerRecord));
76   rec->refCount = 0;
77   rec->pkey     = RETAIN(pkey);
78   rec->entity   = RETAIN(entity);
79   rec->object   = object;
80   rec->snapshot = RETAIN(snapshot);
81     
82   return rec;
83 }
84
85 static void uniquerNoAction(NSMapTable * t, const void *_object) {
86 }
87
88 static NSMapTableKeyCallBacks uniquerKeyMapCallbacks = {
89     (unsigned(*)(NSMapTable *, const void *))uniquerHash,
90     (BOOL(*)(NSMapTable *, const void *, const void *))uniquerCompare,
91     (void (*)(NSMapTable *, const void *))uniquerNoAction,
92     (void (*)(NSMapTable *, void *))uniquerNoAction,
93     (NSString *(*)(NSMapTable *, const void *))uniqDescription,
94     (const void *)NULL
95 };
96
97 static NSMapTableValueCallBacks uniquerValueMapCallbacks = {
98     (void (*)(NSMapTable *, const void *))uniquerRetain,
99     (void (*)(NSMapTable *, void *))uniquerRelease,
100     (NSString *(*)(NSMapTable *, const void *))uniqDescription
101 }; 
102
103 static int initialHashSize = 1021;
104
105 @implementation EOObjectUniquer
106
107 static NSMutableArray  *uniquerExtent = nil;
108 static NSRecursiveLock *lock          = nil;
109
110 + (void)initialize {
111   static BOOL isInitialized = NO;
112   if (!isInitialized) {
113     isInitialized = YES;
114
115     uniquerExtent = [[NSMutableArray alloc] initWithCapacity:16];
116     // THREAD: lock = [[NSRecursiveLock alloc] init];
117   }
118 }
119
120 static inline void _addUniquerInstance(EOObjectUniquer *_uniquer) {
121   [lock lock];
122   [uniquerExtent addObject:[NSValue valueWithNonretainedObject:_uniquer]];
123   [lock unlock];
124 }
125 static inline void _removeUniquerInstance(EOObjectUniquer *_uniquer) {
126   [lock lock];
127   {
128     int i;
129     
130     for (i = [uniquerExtent count] - 1; i >= 0; i--) {
131       EOObjectUniquer *uniquer;
132
133       uniquer = [[uniquerExtent objectAtIndex:i] nonretainedObjectValue];
134       if (uniquer == _uniquer) {
135         [uniquerExtent removeObjectAtIndex:i];
136         break;
137       }
138     }
139   }
140   [lock unlock];
141 }
142
143 // Initializing a uniquing dictionary
144
145 - (id)init {
146   self->primaryKeyToRec = NSCreateMapTable(uniquerKeyMapCallbacks, 
147                                            uniquerValueMapCallbacks,
148                                            initialHashSize);
149 #if LIB_FOUNDATION_LIBRARY
150   self->objectsToRec    = NSCreateMapTableInvisibleKeysOrValues
151                             (NSNonOwnedPointerMapKeyCallBacks, 
152                              uniquerValueMapCallbacks, initialHashSize,
153                              YES, NO);
154 #else
155   self->objectsToRec = NSCreateMapTable
156                             (NSNonOwnedPointerMapKeyCallBacks, 
157                              uniquerValueMapCallbacks, initialHashSize);
158 #endif
159   self->keyRecord = uniquerCreate(nil, nil, nil, nil);
160
161   _addUniquerInstance(self);
162
163   return self;
164 }
165
166 - (void)dealloc {
167     [self forgetAllObjects];
168     _removeUniquerInstance(self);
169     
170     NSFreeMapTable(self->objectsToRec);
171     NSFreeMapTable(self->primaryKeyToRec);
172     if (self->keyRecord) {
173       Free(self->keyRecord);
174       self->keyRecord = NULL;
175     }
176     [super dealloc];
177 }
178
179 // Transfer self to parent
180
181 - (void)transferTo:(EOObjectUniquer *)_dest
182   objects:(BOOL)isKey andSnapshots:(BOOL)isSnap
183 {
184   EOUniquerRecord *key = NULL;
185   EOUniquerRecord *rec = NULL;
186   NSMapEnumerator enumerator = NSEnumerateMapTable(primaryKeyToRec);
187     
188   while(NSNextMapEnumeratorPair(&enumerator, (void**)(&key), (void**)(&rec))) {
189     [_dest recordObject:rec->object
190            primaryKey:  isKey  ? rec->pkey     : nil
191            entity:      isKey  ? rec->entity   : nil
192            snapshot:    isSnap ? rec->snapshot : nil];
193   }
194   [self forgetAllObjects];
195 }
196
197 // Handling objects
198
199 - (void)forgetObject:(id)_object {
200   EOUniquerRecord *rec = NULL;
201     
202   if (_object == nil)
203     return;
204   
205   rec = (EOUniquerRecord *)NSMapGet(self->objectsToRec, _object);
206   
207   if (rec == NULL)
208     return;
209   
210   /*
211   NSLog(@"Uniquer[0x%08X]: forget object 0x%08X<%s> entity=%@",
212         self, _object, class_get_class_name(*(Class *)_object),
213         [[_object entity] name]);
214   */
215   
216   if (rec->pkey)
217     NSMapRemove(self->primaryKeyToRec, rec);
218   NSMapRemove(self->objectsToRec, _object);
219 }
220
221 - (void)forgetAllObjects {
222   NSResetMapTable(self->primaryKeyToRec);
223   NSResetMapTable(self->objectsToRec);
224 }
225
226 - (void)forgetAllSnapshots {
227   NSMapEnumerator enumerator;
228   EOUniquerRecord *rec       = NULL;
229   id              key        = nil;
230   
231   NSLog(@"uniquer 0x%08X forgetAllSnapshots ..", self);
232   
233   enumerator = NSEnumerateMapTable(self->objectsToRec);
234   while (NSNextMapEnumeratorPair(&enumerator, (void**)(&key), (void**)(&rec))) {
235     RELEASE(rec->snapshot);
236     rec->snapshot = nil;
237   }
238 }
239
240 - (id)objectForPrimaryKey:(NSDictionary *)_key entity:(EOEntity *)_entity {
241   EOUniquerRecord *rec;
242     
243   if (_key == nil || _entity == nil)
244     return nil;
245   
246   if (![_key isKindOfClass:[EOPrimaryKeyDictionary class]]) {
247     [NSException raise:NSInvalidArgumentException
248                  format:
249                    @"attempt to record object with non "
250               @" EOPrimaryKeyDictionary class in EOObjectUniquer."
251               @"This is a bug in EODatabase/Context/Channel."];
252   }
253
254   keyRecord->pkey   = _key;
255   keyRecord->entity = _entity;
256     
257   rec = (EOUniquerRecord*)NSMapGet(primaryKeyToRec, keyRecord);
258     
259   return rec ? rec->object : nil;
260 }
261
262 - (EOUniquerRecord *)recordForObject:(id)_object {
263     return (_object == nil)
264       ? (EOUniquerRecord *)NULL
265       : (EOUniquerRecord *)NSMapGet(self->objectsToRec, _object);
266 }
267
268 - (void)recordObject:(id)_object
269   primaryKey:(NSDictionary *)_key
270   entity:(EOEntity *)_entity
271   snapshot:(NSDictionary *)_snapshot
272 {
273     EOUniquerRecord *rec = NULL;
274     EOUniquerRecord *orc = NULL;
275     
276     if (_object == nil)
277       return;
278
279     if ((_key == nil) || (_entity == nil)) {
280         _key    = nil;
281         _entity = nil;
282     }
283     
284     if ((_key == nil) && (_snapshot == nil))
285         return;
286     
287     if (_key && ![_key isKindOfClass:[EOPrimaryKeyDictionary class]]) {
288       [NSException raise:NSInvalidArgumentException
289                    format:
290                      @"attempt to record object with non "
291                      @" EOPrimaryKeyDictionary class in EOObjectUniquer."
292                      @"This is a bug in EODatabase/Context/Channel."];
293     }
294
295     keyRecord->pkey   = _key;
296     keyRecord->entity = _entity;
297     
298     rec = (EOUniquerRecord*)NSMapGet(objectsToRec, _object);
299     if (rec) {
300         if (_key && uniquerCompare(NULL, rec, keyRecord)) {
301             ASSIGN(rec->snapshot, _snapshot);
302             return;
303         }
304         if (_key) {
305             orc = (EOUniquerRecord*)NSMapGet(primaryKeyToRec, keyRecord);
306             if (orc && orc != rec) {
307                 if (orc->pkey)
308                     NSMapRemove(primaryKeyToRec, orc);
309
310                 NSMapRemove(objectsToRec, orc->object);
311             }
312             NSMapRemove(primaryKeyToRec, rec);
313         }
314         ASSIGN(rec->pkey, _key);
315         ASSIGN(rec->entity, _entity);
316         ASSIGN(rec->snapshot, _snapshot);
317
318         if (_key)
319             NSMapInsertKnownAbsent(primaryKeyToRec, rec, rec);
320         return;
321     }
322
323     if (_key)
324         rec = (EOUniquerRecord*)NSMapGet(primaryKeyToRec, keyRecord);
325     if (rec) {
326         if (rec->object == _object) {
327             ASSIGN(rec->snapshot, _snapshot);
328             return;
329         }
330
331         NSMapRemove(objectsToRec, rec->object);
332
333         ASSIGN(rec->snapshot, _snapshot);
334         rec->object = _object;
335         NSMapInsertKnownAbsent(objectsToRec, _object, rec);
336         return;
337     }
338     
339     rec = uniquerCreate(_key, _entity, _object, _snapshot);
340     if (_key)
341         NSMapInsertKnownAbsent(primaryKeyToRec, rec, rec);
342     NSMapInsertKnownAbsent(objectsToRec, _object, rec);
343 }
344
345
346 /* This method is called by the Boehm's garbage collector when an object
347    is finalized */
348 - (void)_objectWillFinalize:(id)_object {
349   //    printf ("_objectWillFinalize: %p (%s)\n",
350   //            _object, class_get_class_name ([_object class]));
351   [self forgetObject:_object];
352 }
353
354 + (void)forgetObject:(id)_object {
355   [lock lock];
356   {
357     int i;
358     
359     for (i = [uniquerExtent count] - 1; i >= 0; i--) {
360       EOObjectUniquer *uniquer;
361
362       uniquer = [[uniquerExtent objectAtIndex:i] nonretainedObjectValue];
363       [uniquer forgetObject:_object];
364     }
365   }
366   [lock unlock];
367 }
368
369 @end /* EOObjectUniquer */