ftp.nice.ch/Attic/openStep/implementation/gnustep/sources/libFoundation.0.7.tgz#/libFoundation-0.7/FoundationExtensions/extensions/GarbageCollector.m

This is GarbageCollector.m in view mode; [Download] [Up]

/* 
   Copyright (C) 1996 
	Ovidiu Predescu <ovidiu@bx.logicnet.ro>
	Mircea Oancea <mircea@jupiter.elcom.pub.ro>

   Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>

   This file is part of the FoundationExtensions 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; see the file COPYING.LIB.
   If not, write to the Free Software Foundation,
   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include <Foundation/NSArray.h>
#include <extensions/objc-runtime.h>
#include <extensions/GCObject.h>
#include <extensions/GarbageCollector.h>

@interface __DummyGCObject : GCObject
@end

@implementation __DummyGCObject
+ allocWithZone:(NSZone*)zone
{
    return NSAllocateObject(self, 0, zone);
}

- (void)dealloc
{
}
@end


/* The GCDoubleLinkedList is a double linked list which contains as the first
    element a dummy GCObject. This object is always the head of the list. A
    new element is introduced immediately after the head. This way we don't
    need to keep track of the head of the list when we remove an element. */
@interface GCDoubleLinkedList : NSObject
{
    id list;
}
- (void)addObject:(id)anObject;
- (void)removeObject:(id)anObject;
- (id)firstObject;
- (void)removeAllObjects;
@end

@implementation GCDoubleLinkedList
- init
{
    list = [__DummyGCObject new];
    return self;
}

- (void)addObject:(id)anObject
{
    id next = [list gcNextObject];

    [list gcSetNextObject:anObject];
    [anObject gcSetNextObject:next];
    [next gcSetPreviousObject:anObject];
    [anObject gcSetPreviousObject:list];
}

- (void)removeObject:(id)anObject
{
    id prev = [anObject gcPreviousObject];
    id next = [anObject gcNextObject];

    [prev gcSetNextObject:next];
    [next gcSetPreviousObject:prev];
}

- (id)firstObject
{
    return [list gcNextObject];
}

- (void)removeAllObjects
{
    [list gcSetNextObject:nil];
}
@end


@implementation GarbageCollector

static id gcObjectsToBeVisited;
static BOOL isGarbageCollecting = NO;

+ (void)initialize
{
    gcObjectsToBeVisited = [GCDoubleLinkedList new];
}

+ (void)collectGarbages
{
    id object;

    isGarbageCollecting = YES;

    /*  First pass. All the objects in the gcObjectsToBeVisited list
        receive the -decrementRefCount message. Each object should decrement
	the ref count of all objects contained. */
    object = [gcObjectsToBeVisited firstObject];
    while(object) {
	[object gcDecrementRefCountOfContainedObjects];
	[object gcSetVisited:NO];
	object = [object gcNextObject];
    };

    /*  Second pass. All the objects in the gcObjectsToBeVisited list that have
	the refCount greater than 0 receive the -incrementRefCount message.
	Each object should increment the ref count of all objects contained.
	Then it should send the -incrementRefCount message to all objects
	contained. */
    object = [gcObjectsToBeVisited firstObject];
    while(object) {
	if([object retainCount])
	    [object gcIncrementRefCountOfContainedObjects];
	object = [object gcNextObject];
    }

    /*  Third pass. All the objects that still have the refCount equal with 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 objects that are garbage collectable. An object could be asked if
	it is garbage collectable by sending it the -isGarbageCollectable
	message. */
    object = [gcObjectsToBeVisited firstObject];
    while(object) {
	if([object retainCount] == 0) {
	    id nextObject = [object gcNextObject];

	    /*  Remove object from gcObjectsToBeVisited list. We have to keep
		the old nextObject because after removing the object from list
		its nextObject is altered. */
	    [gcObjectsToBeVisited removeObject:object];
	    [object dealloc];
	    object = nextObject;
	}
	else object = [object gcNextObject];
    }

    isGarbageCollecting = NO;
}

+ (void)addObject:(id)anObject
{
    [gcObjectsToBeVisited addObject:anObject];
}

+ (void)objectWillBeDeallocated:(id)anObject
{
    /*  We can remove without fear the object from its list because the head of
	the list is always the same. */
    id prev = [anObject gcPreviousObject];
    id next = [anObject gcNextObject];
    [prev gcSetNextObject:next];
    [next gcSetPreviousObject:prev];
}

+ (BOOL)isGarbageCollecting		{ return isGarbageCollecting; }

@end

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.