Garbage collecting updates and moved more gnustep specifiec code to the

Additions library


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@15016 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2002-11-19 05:37:42 +00:00
parent 8b29e69fab
commit bfeb8dbf69
11 changed files with 1279 additions and 4 deletions

View file

@ -1,3 +1,13 @@
2002-11-19 Richard Frith-Macdonald <rfm@gnu.org>
* Source/behavior.m: Moved to Source/Additions/behavior.m
* Source/Unicode.m: Moved to Source/Additions/Unicode.m
* Source/Additions/GCObject.m: new experimental GC class.
* Source/Additions/GCArray.m: ditto
* Source/Additions/GCDictionary.m: ditto
* Headers/gnustep/base/GCObject.h: Garbage collection classes intended
for use by gdl2 and gsweb.
2002-11-18 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSCompatibility.m: Fix for case where a non property list

View file

@ -0,0 +1,109 @@
/** Interface for simple garbage collected classes
Copyright (C) 2002 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <rfm@gnu.org>
Inspired by gc classes of Ovidiu Predescu and Mircea Oancea
This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
AutogsdocSource: Additions/GCObject.m
AutogsdocSource: Additions/GCArray.m
AutogsdocSource: Additions/GCDictionary.m
*/
#ifndef __INCLUDED_GCOBJECT_H
#define __INCLUDED_GCOBJECT_H
#include <Foundation/NSObject.h>
#include <Foundation/NSArray.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSMapTable.h>
@class GCObject;
typedef struct {
GCObject *next;
GCObject *previous;
struct {
unsigned visited:1;
unsigned refCount:31;
} flags;
} gcInfo;
@interface GCObject : NSObject
{
gcInfo gc;
}
+ (void) gcCollectGarbage;
+ (BOOL) gcIsCollecting;
+ (void) gcObjectWillBeDeallocated: (GCObject*)anObject;
- (void) gcDecrementRefCount;
- (void) gcDecrementRefCountOfContainedObjects;
- (void) gcIncrementRefCount;
- (BOOL) gcIncrementRefCountOfContainedObjects;
@end
@interface GCObject (Extra)
- (GCObject*) gcNextObject;
- (GCObject*) gcPreviousObject;
- (GCObject*) gcSetNextObject: (GCObject*)anObject;
- (GCObject*) gcSetPreviousObject: (GCObject*)anObject;
- (BOOL) gcAlreadyVisited;
- (void) gcSetVisited: (BOOL)flag;
@end
@interface GCArray : NSArray
{
gcInfo gc;
id *_contents; // C array of content objects
BOOL *_isGCObject; // Is content object collectable?
unsigned int _count; // Number of content objects.
}
@end
@interface GCMutableArray : NSMutableArray
{
gcInfo gc;
id *_contents;
BOOL *_isGCObject;
unsigned _count;
unsigned _maxCount; // Maximum number of content objects.
}
@end
@interface GCDictionary : NSDictionary
{
gcInfo gc;
NSMapTable *_map;
}
@end
@interface GCMutableDictionary : NSMutableDictionary
{
gcInfo gc;
NSMapTable *_map;
}
@end
#endif /* __INCLUDED_GCOBJECT_H */

View file

@ -1,4 +1,4 @@
/* Interface for behaviors for Obj-C, "for Protocols with implementations".
/** Interface for behaviors for Obj-C, "for Protocols with implementations".
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
@ -19,6 +19,9 @@
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
AutogsdocSource: Additions/behavior.m
*/
#ifndef __behavior_h_GNUSTEP_BASE_INCLUDE

405
Source/Additions/GCArray.m Normal file
View file

@ -0,0 +1,405 @@
/* Implementation of garbage collecting array classes.
Copyright (C) 2002 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <rfm@gnu.org>
Inspired by gc classes of Ovidiu Predescu and Mircea Oancea
This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/
#include <Foundation/NSException.h>
#include <Foundation/NSRange.h>
#include <Foundation/NSString.h>
#include <gnustep/base/behavior.h>
#include <gnustep/base/GCObject.h>
@implementation GCArray
static Class gcClass = 0;
+ (void) initialize
{
if (gcClass == 0)
{
gcClass = [GCObject class];
behavior_class_add_class(self, gcClass);
}
}
- (Class) classForCoder
{
return [GCArray class];
}
- (id) copyWithZone: (NSZone*)zone
{
if (NSShouldRetainWithZone(self, zone))
{
return [self retain];
}
return [[GCArray allocWithZone: zone] initWithArray: self copyItems: YES];
}
- (unsigned int) count
{
return _count;
}
- (void) dealloc
{
unsigned int c = _count;
[GCObject gcObjectWillBeDeallocated: (GCObject*)self];
if ([GCObject gcIsCollecting])
{
while (c-- > 0)
{
if (_isGCObject[c] == NO)
{
[_contents[c] release];
}
}
}
else
{
while (c-- > 0)
{
[_contents[c] release];
}
}
NSZoneFree([self zone], _contents);
[super dealloc];
}
- (void) gcDecrementRefCountOfContainedObjects
{
unsigned int c = _count;
gc.flags.visited = 0;
while (c-- > 0)
{
if (_isGCObject[c])
{
[_contents[c] gcDecrementRefCount];
}
}
}
- (BOOL) gcIncrementRefCountOfContainedObjects
{
if (gc.flags.visited == 1)
{
return NO;
}
else
{
unsigned int c = _count;
gc.flags.visited = 1;
while (c-- > 0)
{
if (_isGCObject[c])
{
[_contents[c] gcIncrementRefCount];
[_contents[c] gcIncrementRefCountOfContainedObjects];
}
}
return YES;
}
}
- (id) initWithObjects: (id*)objects count: (unsigned int)count
{
unsigned int i;
_contents = NSZoneMalloc([self zone], count * (sizeof(id) + sizeof(BOOL)));
_isGCObject = (BOOL*)&_contents[count];
_count = count;
for (i = 0; i < count; i++)
{
_contents[i] = [objects[i] retain];
if (_contents[i] == nil)
{
[self release];
[NSException raise: NSInvalidArgumentException
format: @"Nil object to be added in array"];
}
else
{
_isGCObject[i] = [objects[i] isKindOfClass: gcClass];
}
}
return self;
}
- (id) initWithArray: (NSArray*)anotherArray
{
unsigned int i;
unsigned int count = [anotherArray count];
_contents = NSZoneMalloc([self zone], count * (sizeof(id) + sizeof(BOOL)));
_isGCObject = (BOOL*)&_contents[count];
_count = count;
for (i = 0; i < _count; i++)
{
_contents[i] = [[anotherArray objectAtIndex: i] retain];
_isGCObject[i] = [_contents[i] isKindOfClass: gcClass];
}
return self;
}
/**
* We use the same initial instance variable layout as a GCObject and
* ue the <em>behavior</em> mechanism to inherit methods from that class
* to implement a form of multiple inheritance. We need to implement
* this method to make this apparent at runtime.
*/
- (BOOL) isKindOfClass: (Class)c
{
if (c == gcClass)
{
return YES;
}
return [super isKindOfClass: c];
}
- (id) mutableCopyWithZone: (NSZone*)zone
{
return [[GCMutableArray allocWithZone: zone]
initWithArray: self copyItems: YES];
}
- (id) objectAtIndex: (unsigned int)index
{
if (index >= _count)
{
[NSException raise: NSRangeException
format: @"[%@-%@]: index: %u",
NSStringFromClass([self class]), NSStringFromSelector(_cmd), index];
}
return _contents[index];
}
@end
@implementation GCMutableArray
+ (void)initialize
{
static BOOL beenHere = NO;
if (beenHere == NO)
{
beenHere = YES;
behavior_class_add_class(self, [GCArray class]);
}
}
- (void) addObject: (id)anObject
{
[self insertObject: anObject atIndex: _count];
}
- (Class) classForCoder
{
return [GCMutableArray class];
}
- (id) copyWithZone: (NSZone*)zone
{
return [[GCArray allocWithZone: zone]
initWithArray: self copyItems: YES];
}
- (id) init
{
return [self initWithCapacity: 1];
}
- (id) initWithCapacity: (unsigned int)aNumItems
{
if (aNumItems < 1)
{
aNumItems = 1;
}
_contents = NSZoneMalloc([self zone], aNumItems * (sizeof(id) + sizeof(BOOL)));
_isGCObject = (BOOL*)&_contents[aNumItems];
_maxCount = aNumItems;
_count = 0;
return self;
}
- (id) initWithObjects: (id *)objects count: (unsigned int)count
{
self = [self initWithCapacity: count];
if (self != nil)
{
unsigned int i;
for (i = 0; i < count; i++)
{
_contents[i] = [objects[i] retain];
if (_contents[i] == nil)
{
[self release];
[NSException raise: NSInvalidArgumentException
format: @"Nil object to be added in array"];
}
else
{
_isGCObject[i] = [objects[i] isKindOfClass: gcClass];
}
}
}
return self;
}
- (id) initWithArray: (NSArray*)anotherArray
{
unsigned int count = [anotherArray count];
self = [self initWithCapacity: count];
if (self != nil)
{
unsigned int i;
for (i = 0; i < _count; i++)
{
_contents[i] = [[anotherArray objectAtIndex: i] retain];
_isGCObject[i] = [_contents[i] isKindOfClass: gcClass];
}
}
return self;
}
- (void) insertObject: (id)anObject atIndex: (unsigned int)index
{
unsigned int i;
if (anObject == nil)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@]: nil argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
if (index > _count)
{
[NSException raise: NSRangeException
format: @"[%@-%@]: bad index %u",
NSStringFromClass([self class]), NSStringFromSelector(_cmd), index];
}
if (_count == _maxCount)
{
unsigned old = _maxCount;
BOOL *optr;
if (_maxCount > 0)
{
_maxCount += (_maxCount >> 1) ? (_maxCount >> 1) : 1;
}
else
{
_maxCount = 1;
}
_contents = (id*)NSZoneRealloc([self zone], _contents,
_maxCount * (sizeof(id) + sizeof(BOOL)));
optr = (BOOL*)&_contents[old];
_isGCObject = (BOOL*)&_contents[_maxCount];
memmove(_isGCObject, optr, sizeof(BOOL)*old);
}
for(i = _count; i > index; i--)
{
_contents[i] = _contents[i - 1];
_isGCObject[i] = _isGCObject[i - 1];
}
_contents[index] = [anObject retain];
_isGCObject[index] = [anObject isKindOfClass: gcClass];
_count++;
}
- (id) mutableCopyWithZone: (NSZone*)zone
{
return [[GCMutableArray allocWithZone: zone]
initWithArray: self copyItems: YES];
}
- (void) removeAllObjects
{
[self removeObjectsInRange: NSMakeRange(0, _count)];
}
- (void) removeObjectAtIndex: (unsigned int)index
{
[self removeObjectsInRange: NSMakeRange(index, 1)];
}
- (void) removeObjectsInRange: (NSRange)range
{
unsigned int i;
if (NSMaxRange(range) > _count)
{
[NSException raise: NSRangeException
format: @"[%@-%@]: bad range %@",
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
NSStringFromRange(range)];
}
if (range.length == 0)
{
return;
}
for (i = range.location; i < NSMaxRange(range); i++)
{
[_contents[i] release];
}
for (i = NSMaxRange(range); i < _count; i++, range.location++)
{
_contents[range.location] = _contents[i];
_isGCObject[range.location] = _isGCObject[i];
}
_count -= range.length;
}
- (void) replaceObjectAtIndex: (unsigned int)index withObject: (id)anObject
{
if (anObject == nil)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@]: nil argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
if (index >= _count)
{
[NSException raise: NSRangeException
format: @"[%@-%@]: bad index %u",
NSStringFromClass([self class]), NSStringFromSelector(_cmd), index];
}
[anObject retain];
[_contents[index] release];
_contents[index] = anObject;
_isGCObject[index] = [anObject isKindOfClass: gcClass];
}
@end

View file

@ -0,0 +1,403 @@
/* Implementation of garbage collecting dictionary classes
Copyright (C) 2002 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <rfm@gnu.org>
Inspired by gc classes of Ovidiu Predescu and Mircea Oancea
This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/
#include <Foundation/NSException.h>
#include <Foundation/NSString.h>
#include <gnustep/base/behavior.h>
#include <gnustep/base/GCObject.h>
typedef struct {
id object;
BOOL isGCObject;
} GCInfo;
@interface _GCDictionaryKeyEnumerator : NSObject
{
@public
GCDictionary *dict;
NSMapEnumerator enumerator;
}
- (id) nextObject;
@end
@interface _GCDictionaryObjectEnumerator : _GCDictionaryKeyEnumerator
- (id) nextObject;
@end
@implementation _GCDictionaryKeyEnumerator
- (id) copyWithZone: (NSZone*)z
{
return [self retain];
}
- (void) dealloc
{
NSEndMapTableEnumeration(&enumerator);
[dict release];
[super dealloc];
}
- (id) nextObject
{
GCInfo *keyStruct;
GCInfo *valueStruct;
return NSNextMapEnumeratorPair(&enumerator,
(void**)&keyStruct, (void**)&valueStruct) ? keyStruct->object : nil;
}
@end
@implementation _GCDictionaryObjectEnumerator
- (id) nextObject
{
GCInfo *keyStruct;
GCInfo *valueStruct;
return NSNextMapEnumeratorPair(&enumerator,
(void**)&keyStruct, (void**)&valueStruct) ? valueStruct->object : nil;
}
@end
@implementation GCDictionary
static unsigned
_GCHashObject(NSMapTable *table, const GCInfo *objectStruct)
{
return [objectStruct->object hash];
}
static BOOL
_GCCompareObjects(NSMapTable *table, const GCInfo *o1, const GCInfo *o2)
{
return [o1->object isEqual: o2->object];
}
static void
_GCRetainObjects(NSMapTable *table, const void *ptr)
{
GCInfo *objectStruct = (GCInfo*)ptr;
[objectStruct->object retain];
}
static void
_GCReleaseObjects(NSMapTable *table, const void *ptr)
{
GCInfo *objectStruct = (GCInfo*)ptr;
if ([GCObject gcIsCollecting])
{
if (objectStruct->isGCObject == NO)
{
[objectStruct->object release];
}
}
else
{
[objectStruct->object release];
}
NSZoneFree(NSDefaultMallocZone(), objectStruct);
}
static NSString*
_GCDescribeObjects(NSMapTable *table, const GCInfo *objectStruct)
{
return [objectStruct->object description];
}
static const NSMapTableKeyCallBacks GCInfoMapKeyCallBacks = {
(unsigned(*)(NSMapTable *, const void *))_GCHashObject,
(BOOL(*)(NSMapTable *, const void *, const void *))_GCCompareObjects,
(void (*)(NSMapTable *, const void *))_GCRetainObjects,
(void (*)(NSMapTable *, const void *))_GCReleaseObjects,
(NSString *(*)(NSMapTable *, const void *))_GCDescribeObjects,
(const void *)NULL
};
static const NSMapTableValueCallBacks GCInfoValueCallBacks = {
(void (*)(NSMapTable *, const void *))_GCRetainObjects,
(void (*)(NSMapTable *, const void *))_GCReleaseObjects,
(NSString *(*)(NSMapTable *, const void *))_GCDescribeObjects
};
static Class gcClass = 0;
+ (void) initialize
{
if (gcClass == 0)
{
gcClass = [GCObject class];
behavior_class_add_class(self, gcClass);
}
}
- (id) copyWithZone: (NSZone*)zone
{
if (NSShouldRetainWithZone(self, zone))
{
return [self retain];
}
return [[GCDictionary allocWithZone: zone] initWithDictionary: self];
}
- (unsigned int) count
{
return NSCountMapTable(_map);
}
- (void) dealloc
{
[GCObject gcObjectWillBeDeallocated: (GCObject*)self];
NSFreeMapTable(_map);
[super dealloc];
}
- (void) gcDecrementRefCountOfContainedObjects
{
NSMapEnumerator enumerator = NSEnumerateMapTable(_map);
GCInfo *keyStruct;
GCInfo *valueStruct;
gc.flags.visited = 0;
while (NSNextMapEnumeratorPair(&enumerator,
(void**)&keyStruct, (void**)&valueStruct))
{
if (keyStruct->isGCObject)
{
[keyStruct->object gcDecrementRefCount];
}
if (valueStruct->isGCObject)
{
[valueStruct->object gcDecrementRefCount];
}
}
NSEndMapTableEnumeration(&enumerator);
}
- (BOOL) gcIncrementRefCountOfContainedObjects
{
NSMapEnumerator enumerator;
GCInfo *keyStruct;
GCInfo *valueStruct;
if (gc.flags.visited == 1)
{
return NO;
}
gc.flags.visited = 1;
enumerator = NSEnumerateMapTable(_map);
while (NSNextMapEnumeratorPair(&enumerator,
(void**)&keyStruct, (void**)&valueStruct))
{
if (keyStruct->isGCObject)
{
[keyStruct->object gcIncrementRefCount];
[keyStruct->object gcIncrementRefCountOfContainedObjects];
}
if (valueStruct->isGCObject)
{
[valueStruct->object gcIncrementRefCount];
[valueStruct->object gcIncrementRefCountOfContainedObjects];
}
}
NSEndMapTableEnumeration(&enumerator);
return YES;
}
- (id) initWithDictionary: (NSDictionary*)dictionary
{
id keys = [dictionary keyEnumerator];
id key;
unsigned int size = ([dictionary count] * 4) / 3;
NSZone *z = NSDefaultMallocZone();
_map = NSCreateMapTableWithZone(GCInfoMapKeyCallBacks,
GCInfoValueCallBacks, size, z);
while ((key = [keys nextObject]) != nil)
{
GCInfo *keyStruct;
GCInfo *valueStruct;
id value;
keyStruct = NSZoneMalloc(z, sizeof(GCInfo));
valueStruct = NSZoneMalloc(z, sizeof(GCInfo));
value = [dictionary objectForKey: key];
keyStruct->object = key;
keyStruct->isGCObject = [key isKindOfClass: gcClass];
valueStruct->object = value;
valueStruct->isGCObject = [value isKindOfClass: gcClass];
NSMapInsert(_map, keyStruct, valueStruct);
}
return self;
}
- (id) initWithObjects: (id*)objects
forKeys: (id*)keys
count: (unsigned int)count
{
unsigned int size = (count * 4) / 3;
NSZone *z = NSDefaultMallocZone();
_map = NSCreateMapTableWithZone(GCInfoMapKeyCallBacks,
GCInfoValueCallBacks, size, z);
while (count-- > 0)
{
GCInfo *keyStruct;
GCInfo *valueStruct;
if (!keys[count] || !objects[count])
{
[self release];
[NSException raise: NSInvalidArgumentException
format: @"Nil object added in dictionary"];
}
keyStruct = NSZoneMalloc(z, sizeof(GCInfo));
valueStruct = NSZoneMalloc(z, sizeof(GCInfo));
keyStruct->object = keys[count];
keyStruct->isGCObject = [keys[count] isKindOfClass: gcClass];
valueStruct->object = objects[count];
valueStruct->isGCObject
= [objects[count] isKindOfClass: gcClass];
NSMapInsert(_map, keyStruct, valueStruct);
}
return self;
}
/**
* We use the same initial instance variable layout as a GCObject and
* ue the <em>behavior</em> mechanism to inherit methods from that class
* to implement a form of multiple inheritance. We need to implement
* this method to make this apparent at runtime.
*/
- (BOOL) isKindOfClass: (Class)c
{
if (c == gcClass)
{
return YES;
}
return [super isKindOfClass: c];
}
- (NSEnumerator*) keyEnumerator
{
_GCDictionaryKeyEnumerator *e;
e = [_GCDictionaryKeyEnumerator alloc];
e->dict = [self retain];
e->enumerator = NSEnumerateMapTable(_map);
return [e autorelease];
}
- (NSEnumerator*) objectEnumerator
{
_GCDictionaryObjectEnumerator *e;
e = [_GCDictionaryObjectEnumerator alloc];
e->dict = [self retain];
e->enumerator = NSEnumerateMapTable(_map);
return [e autorelease];
}
- (id) mutableCopyWithZone: (NSZone*)zone
{
return [[GCMutableDictionary allocWithZone: zone] initWithDictionary: self];
}
- (id) objectForKey: (id)key
{
GCInfo keyStruct = { key, 0 };
GCInfo *valueStruct;
valueStruct = NSMapGet(_map, (void**)&keyStruct);
return valueStruct ? valueStruct->object : nil;
}
@end
@implementation GCMutableDictionary
+ (void) initialize
{
static BOOL beenHere = NO;
if (beenHere == NO)
{
beenHere = YES;
behavior_class_add_class(self, [GCDictionary class]);
}
}
- (id) init
{
return [self initWithCapacity: 0];
}
- (id) initWithCapacity: (unsigned int)aNumItems
{
unsigned int size = (aNumItems * 4) / 3;
_map = NSCreateMapTableWithZone(GCInfoMapKeyCallBacks,
GCInfoValueCallBacks, size, [self zone]);
return self;
}
- (id) copyWithZone: (NSZone*)zone
{
return [[GCDictionary allocWithZone: zone] initWithDictionary: self];
}
- (void) setObject: (id)anObject forKey: (id)aKey
{
GCInfo *keyStruct;
GCInfo *valueStruct;
NSZone *z = NSDefaultMallocZone();
keyStruct = NSZoneMalloc(z, sizeof(GCInfo));
valueStruct = NSZoneMalloc(z, sizeof(GCInfo));
keyStruct->object = aKey;
keyStruct->isGCObject = [aKey isKindOfClass: gcClass];
valueStruct->object = anObject;
valueStruct->isGCObject = [anObject isKindOfClass: gcClass];
NSMapInsert(_map, keyStruct, valueStruct);
}
- (void) removeObjectForKey: (id)key
{
GCInfo keyStruct = { key, 0 };
NSMapRemove(_map, (void**)&keyStruct);
}
- (void) removeAllObjects
{
NSResetMapTable(_map);
}
@end

338
Source/Additions/GCObject.m Normal file
View file

@ -0,0 +1,338 @@
/* Implementation of garbage collecting classe framework
Copyright (C) 2002 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <rfm@gnu.org>
Inspired by gc classes of Ovidiu Predescu and Mircea Oancea
This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
AutogsdocSource: Additions/GCObject.m
AutogsdocSource: Additions/GCArray.m
AutogsdocSource: Additions/GCDictionary.m
*/
#include <Foundation/NSAutoreleasePool.h>
#include <Foundation/NSString.h>
#include <gnustep/base/GCObject.h>
/*
* The head of a linked list of all garbage collecting objects is a
* special object which is never deallocated.
*/
@interface _GCObjectList : GCObject
@end
@implementation _GCObjectList
- (void) dealloc
{
}
@end
/**
* The GCObject class is both the base class for all garbage collected
* objects, and an infrastructure for handling garbage collection.<br />
* It maintains a list of all garbage collectable objects and provides
* a method to run a garbage collection pass on those objects.
*/
@implementation GCObject
static GCObject *allObjects = nil;
static BOOL isCollecting = NO;
+ (id) allocWithZone: (NSZone*)zone
{
GCObject *o = [super allocWithZone: zone];
o->gc.next = allObjects;
o->gc.previous = allObjects->gc.previous;
allObjects->gc.previous->gc.next = o;
allObjects->gc.previous = o;
o->gc.flags.refCount = 1;
return o;
}
/**
* <p>This method runs a garbage collection, causing unreferenced objects to
* be deallocated. This is done using a simple three pass algorithm -
* </p>
* <deflist>
* <term>Pass 1</term>
* <desc>
* All the garbage collectable objects are sent a
* -gcDecrementRefCountOfContainedObjects message.
* </desc>
* <term>Pass 2</term>
* <desc>
* All objects having a refCount greater than 0 are sent an
* -gcIncrementRefCountOfContainedObjects message.
* </desc>
* <term>Pass 3</term>
* <desc>
* All the objects that still have the refCount of 0
* are part of cyclic graphs and none of the objects from this graph
* are held by some object outside graph. These objects receive the
* -dealloc message. In this method they should send the -dealloc message
* to any garbage collectable (GCObject and subclass) instances they
* contain.
* </desc>
* </deflist>
* <p>During garbage collection, the +gcIsCollecting method returns YES.
* </p>
*/
+ (void) gcCollectGarbage
{
GCObject *object;
GCObject *last;
if (isCollecting == YES)
{
return; // Don't allow recursion.
}
isCollecting = YES;
// Pass 1
object = allObjects->gc.next;
while (object != allObjects)
{
[object gcDecrementRefCountOfContainedObjects];
// object->gc.flags.visited = 0;
// object = object->gc.next;
[object gcSetVisited: NO];
object = [object gcNextObject];
}
// Pass 2
object = allObjects->gc.next;
while (object != allObjects)
{
if ([object retainCount] > 0)
{
[object gcIncrementRefCountOfContainedObjects];
}
// object = object->gc.next;
object = [object gcNextObject];
}
last = allObjects;
object = last->gc.next;
while (object != allObjects)
{
if ([object retainCount] == 0)
{
GCObject *next;
// next = object->gc.next;
// next->gc.previous = last;
// last->gc.next = next;
// object->gc.next = object;
// object->gc.previous = object;
next = [object gcNextObject];
[next gcSetPreviousObject: last];
[last gcSetNextObject: next];
[object gcSetNextObject: object];
[object gcSetPreviousObject: object];
[object dealloc];
object = next;
}
else
{
last = object;
// object = object->gc.next;
object = [object gcNextObject];
}
}
isCollecting = NO;
}
+ (void) initialize
{
if (self == [GCObject class])
{
allObjects = (_GCObjectList*)
NSAllocateObject([_GCObjectList class], 0, NSDefaultMallocZone());
}
}
/**
* Returns a flag to indicate whether a garbage collection is in progress.
*/
+ (BOOL) gcIsCollecting
{
return isCollecting;
}
/**
* Called to remove anObject from the list of garbage collectable objects.
* Subclasses should call this is their -dealloc methods.
*/
+ (void) gcObjectWillBeDeallocated: (GCObject*)anObject
{
GCObject *p;
GCObject *n;
// p = anObject->gc.previous;
// n = anObject->gc.next;
// p->gc.next = n;
// n->gc.previous = p;
p = [anObject gcPreviousObject];
n = [anObject gcNextObject];
[p gcSetNextObject: n];
[n gcSetPreviousObject: p];
}
- (id) copyWithZone: (NSZone*)zone
{
GCObject *o = (GCObject*)NSCopyObject(self, 0, zone);
o->gc.next = allObjects;
o->gc.previous = allObjects->gc.previous;
allObjects->gc.previous->gc.next = o;
allObjects->gc.previous = o;
o->gc.flags.refCount = 1;
return o;
}
/*
* Decrements the garbage collection reference count for the receiver.<br />
*/
- (void) gcDecrementRefCount
{
gc.flags.refCount--;
}
/*
* <p>Marks the receiver as not having been visited in the current garbage
* collection process (first pass of collection).
* </p>
* <p>All container subclasses should override this method to call the super
* implementation then decrement the ref counts of their contents as well as
* sending the -gcDecrementRefCountOfContainedObjects
* message to each of them.
* </p>
*/
- (void) gcDecrementRefCountOfContainedObjects
{
gc.flags.visited = 0;
}
/*
* Increments the garbage collection reference count for the receiver.<br />
*/
- (void) gcIncrementRefCount
{
gc.flags.refCount++;
}
/*
* <p>Checks to see if the receiver has already been visited in the
* current garbage collection process, and either marks the receiver as
* visited (and returns YES) or returns NO to indicate that it had already
* been visited.
* </p>
* <p>All container subclasses should override this method to call the super
* implementation then, if the method returns YES, increment the reference
* count of any contained objects and send the
* -gcIncrementRefCountOfContainedObjects
* to each of the contained objects too.
* </p>
*/
- (BOOL) gcIncrementRefCountOfContainedObjects
{
if (gc.flags.visited == 1)
{
return NO;
}
gc.flags.visited = 1;
return YES;
}
- (oneway void) release
{
if (gc.flags.refCount > 0 && gc.flags.refCount-- == 1)
{
[GCObject gcObjectWillBeDeallocated: self];
[self dealloc];
}
}
- (id) retain
{
gc.flags.refCount++;
return self;
}
- (unsigned int) retainCount
{
return gc.flags.refCount;
}
@end
@implementation GCObject (Extra)
- (BOOL) gcAlreadyVisited
{
if (gc.flags.visited == 1)
{
return YES;
}
else
{
return NO;
}
}
- (GCObject*) gcNextObject
{
return gc.next;
}
- (GCObject*) gcPreviousObject
{
return gc.previous;
}
- (GCObject*) gcSetNextObject: (GCObject*)anObject
{
gc.next = anObject;
return self;
}
- (GCObject*) gcSetPreviousObject: (GCObject*)anObject
{
gc.previous = anObject;
return self;
}
- (void) gcSetVisited: (BOOL)flag
{
if (flag == YES)
{
gc.flags.visited = 1;
}
else
{
gc.flags.visited = 0;
}
}
@end

View file

@ -31,8 +31,13 @@ include $(GNUSTEP_MAKEFILES)/common.make
SUBPROJECT_NAME=Additions
Additions_OBJC_FILES =\
GCObject.m \
GCArray.m \
GCDictionary.m \
GSMime.m \
GSXML.m
GSXML.m \
Unicode.m \
behavior.m
-include Makefile.preamble

View file

@ -36,6 +36,9 @@ Base_AGSDOC_FILES = \
../Documentation/Base.gsdoc \
GSMime.h \
GSXML.h \
behavior.h \
Unicode.h \
GCObject.h \
NSArchiver.h \
NSArray.h \
NSAttributedString.h \

View file

@ -88,8 +88,6 @@ endif
GNU_MFILES = \
GSCompatibility.m \
GSLocale.m \
Unicode.m \
behavior.m \
preface.m \
mframe.m
@ -118,6 +116,7 @@ libgnustep-base.def
GNU_HEADERS = \
DistributedObjects.h \
GCObject.h \
GSFileHandle.h \
GSLocale.h \
GSUnion.h \