mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-25 09:41:15 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@3496 72102866-910b-0410-8b05-ffd578937521
408 lines
10 KiB
Objective-C
408 lines
10 KiB
Objective-C
/* Implementation for Objective-C LinkedList collection object
|
||
Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
|
||
|
||
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
||
Date: May 1993
|
||
|
||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
*/
|
||
|
||
#include <config.h>
|
||
#include <base/LinkedList.h>
|
||
#include <base/IndexedCollectionPrivate.h>
|
||
#include <base/Coder.h>
|
||
|
||
@implementation LinkedList
|
||
|
||
/* This is the designated initializer of this class */
|
||
- init
|
||
{
|
||
_count = 0;
|
||
_first_link = nil;
|
||
_last_link = nil;
|
||
return self;
|
||
}
|
||
|
||
- initWithObjects: (id*)objs count: (unsigned)c
|
||
{
|
||
[self init];
|
||
while (c--)
|
||
[self prependObject: objs[c]];
|
||
return self;
|
||
}
|
||
|
||
/* Archiving must mimic the above designated initializer */
|
||
|
||
- (void) encodeWithCoder: coder
|
||
{
|
||
id l;
|
||
|
||
[super encodeWithCoder: coder];
|
||
[coder encodeValueOfCType: @encode (typeof (_count))
|
||
at: &_count
|
||
withName: @"LinkedList count"];
|
||
FOR_COLLECTION (self, l)
|
||
{
|
||
[coder encodeObject: l
|
||
withName: @"LinkedList element"];
|
||
}
|
||
END_FOR_COLLECTION (self);
|
||
[coder encodeObjectReference: _first_link
|
||
withName: @"LinkedList first link"];
|
||
[coder encodeObjectReference: _last_link
|
||
withName: @"LinkedList last link"];
|
||
}
|
||
|
||
- initWithCoder: coder
|
||
{
|
||
int i;
|
||
// id link;
|
||
|
||
self = [super initWithCoder: coder];
|
||
[coder decodeValueOfCType: @encode (typeof (_count))
|
||
at: &_count
|
||
withName: NULL];
|
||
/* We don't really care about storing the elements decoded, because
|
||
we access them through their own link pointers. */
|
||
for (i = 0; i < _count; i++)
|
||
[coder decodeObjectAt: NULL
|
||
withName: NULL];
|
||
[coder decodeObjectAt: &_first_link
|
||
withName: NULL];
|
||
[coder decodeObjectAt: &_last_link
|
||
withName: NULL];
|
||
#if 0
|
||
/* xxx Not necessary, since the links encode this?
|
||
But should we rely on the links encoding this?
|
||
BUT! Look out: the next link pointers may not be set until
|
||
the last finishDecoding... method is run... */
|
||
FOR_COLLECTION (self, link)
|
||
{
|
||
[link setLinkedList: self];
|
||
}
|
||
END_FOR_COLLECTION (self);
|
||
#endif
|
||
return self;
|
||
}
|
||
|
||
/* Empty copy must empty an allocCopy'ed version of self */
|
||
- emptyCopy
|
||
{
|
||
LinkedList *copy = [super emptyCopy];
|
||
copy->_first_link = nil;
|
||
copy->_last_link = nil;
|
||
copy->_count = 0;
|
||
return copy;
|
||
}
|
||
|
||
/* This must work without sending any messages to content objects */
|
||
- (void) _empty
|
||
{
|
||
_count = 0;
|
||
_first_link = nil;
|
||
_last_link = nil;
|
||
}
|
||
|
||
/* These next four methods are the only ones that change the values of
|
||
the instance variables _count, _first_link, except for
|
||
"-init". */
|
||
|
||
- (void) removeObject: oldObject
|
||
{
|
||
NSAssert([oldObject linkedList] == self, NSInternalInconsistencyException);
|
||
if (_first_link == oldObject)
|
||
{
|
||
if (_count > 1)
|
||
_first_link = [oldObject nextLink];
|
||
else
|
||
_first_link = nil;
|
||
}
|
||
else
|
||
[[oldObject prevLink] setNextLink:[oldObject nextLink]];
|
||
if (_last_link == oldObject)
|
||
{
|
||
if (_count > 1)
|
||
_last_link = [oldObject prevLink];
|
||
else
|
||
_first_link = nil;
|
||
}
|
||
else
|
||
[[oldObject nextLink] setPrevLink:[oldObject prevLink]];
|
||
_count--;
|
||
[oldObject setNextLink: NO_OBJECT];
|
||
[oldObject setPrevLink: NO_OBJECT];
|
||
[oldObject setLinkedList: NO_OBJECT];
|
||
[oldObject release];
|
||
}
|
||
|
||
- (void) insertObject: newObject after: oldObject
|
||
{
|
||
/* Make sure we actually own the oldObject. */
|
||
NSAssert([oldObject linkedList] == self, NSInternalInconsistencyException);
|
||
|
||
/* Make sure no one else already owns the newObject. */
|
||
NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException);
|
||
|
||
/* Claim ownership of the newObject. */
|
||
[newObject retain];
|
||
[newObject setLinkedList: self];
|
||
|
||
/* Insert it. */
|
||
if (_count == 0)
|
||
{
|
||
_first_link = newObject;
|
||
_last_link = newObject;
|
||
_count = 1;
|
||
[newObject setNextLink: NO_OBJECT];
|
||
[newObject setPrevLink: NO_OBJECT];
|
||
}
|
||
else
|
||
{
|
||
if (oldObject == _last_link)
|
||
_last_link = newObject;
|
||
[newObject setNextLink: [oldObject nextLink]];
|
||
[newObject setPrevLink: oldObject];
|
||
[[oldObject nextLink] setPrevLink: newObject];
|
||
[oldObject setNextLink: newObject];
|
||
}
|
||
_count++;
|
||
}
|
||
|
||
- (void) insertObject: newObject before: oldObject
|
||
{
|
||
/* Make sure we actually own the oldObject. */
|
||
NSAssert([oldObject linkedList] == self, NSInternalInconsistencyException);
|
||
|
||
/* Make sure no one else already owns the newObject. */
|
||
NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException);
|
||
|
||
/* Claim ownership of the newObject. */
|
||
[newObject retain];
|
||
[newObject setLinkedList: self];
|
||
|
||
/* Insert it. */
|
||
if (_count == 0)
|
||
{
|
||
_first_link = newObject;
|
||
_last_link = newObject;
|
||
_count = 1;
|
||
[newObject setNextLink: NO_OBJECT];
|
||
[newObject setPrevLink: NO_OBJECT];
|
||
}
|
||
else
|
||
{
|
||
if (oldObject == _first_link)
|
||
_first_link = newObject;
|
||
[newObject setPrevLink: [oldObject prevLink]];
|
||
[newObject setNextLink: oldObject];
|
||
[[oldObject prevLink] setNextLink: newObject];
|
||
[oldObject setPrevLink: newObject];
|
||
}
|
||
_count++;
|
||
}
|
||
|
||
- (void) replaceObject: oldObject with: newObject
|
||
{
|
||
/* Make sure we actually own the oldObject. */
|
||
NSAssert([oldObject linkedList] == self, NSInternalInconsistencyException);
|
||
|
||
/* Make sure no one else already owns the newObject. */
|
||
NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException);
|
||
|
||
/* Claim ownership of the newObject. */
|
||
[newObject retain];
|
||
[newObject setLinkedList: self];
|
||
|
||
/* Do the replacement. */
|
||
if (oldObject == _first_link)
|
||
_first_link = newObject;
|
||
[newObject setNextLink:[oldObject nextLink]];
|
||
[newObject setPrevLink:[oldObject prevLink]];
|
||
[[oldObject prevLink] setNextLink:newObject];
|
||
[[oldObject nextLink] setPrevLink:newObject];
|
||
|
||
/* Release ownership of the oldObject. */
|
||
[oldObject setNextLink: NO_OBJECT];
|
||
[oldObject setPrevLink: NO_OBJECT];
|
||
[oldObject setLinkedList: NO_OBJECT];
|
||
[oldObject release];
|
||
}
|
||
|
||
/* End of methods that change the instance variables. */
|
||
|
||
|
||
- (void) appendObject: newObject
|
||
{
|
||
/* Make sure no one else already owns the newObject. */
|
||
NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException);
|
||
|
||
/* Insert it. */
|
||
if (_count == 0)
|
||
{
|
||
/* Claim ownership of the newObject. */
|
||
[newObject retain];
|
||
[newObject setLinkedList: self];
|
||
|
||
/* Put it in as the only node. */
|
||
_first_link = newObject;
|
||
_last_link = newObject;
|
||
_count = 1;
|
||
[newObject setNextLink: NO_OBJECT];
|
||
[newObject setPrevLink: NO_OBJECT];
|
||
}
|
||
else
|
||
[self insertObject: newObject after: _last_link];
|
||
}
|
||
|
||
- (void) prependObject: newObject
|
||
{
|
||
/* Make sure no one else already owns the newObject. */
|
||
NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException);
|
||
|
||
/* Insert it. */
|
||
if (_count == 0)
|
||
{
|
||
/* Claim ownership of the newObject. */
|
||
[newObject retain];
|
||
[newObject setLinkedList: self];
|
||
|
||
/* Put it in as the only node. */
|
||
_first_link = newObject;
|
||
_last_link = newObject;
|
||
_count = 1;
|
||
[newObject setNextLink: NO_OBJECT];
|
||
[newObject setPrevLink: NO_OBJECT];
|
||
}
|
||
else
|
||
[self insertObject: newObject before: _first_link];
|
||
}
|
||
|
||
- (void) insertObject: newObject atIndex: (unsigned)index
|
||
{
|
||
CHECK_INDEX_RANGE_ERROR(index, (_count+1));
|
||
|
||
/* Make sure no one else already owns the newObject. */
|
||
NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException);
|
||
|
||
/* Insert it. */
|
||
if (_count == 0)
|
||
{
|
||
/* Claim ownership of the newObject. */
|
||
[newObject retain];
|
||
[newObject setLinkedList: self];
|
||
|
||
/* Put it in as the only node. */
|
||
_first_link = newObject;
|
||
_last_link = newObject;
|
||
_count = 1;
|
||
[newObject setNextLink: NO_OBJECT];
|
||
[newObject setPrevLink: NO_OBJECT];
|
||
}
|
||
else if (index == _count)
|
||
[self insertObject: newObject after: _last_link];
|
||
else
|
||
[self insertObject:newObject before: [self objectAtIndex: index]];
|
||
}
|
||
|
||
- (void) removeObjectAtIndex: (unsigned)index
|
||
{
|
||
CHECK_INDEX_RANGE_ERROR(index, _count);
|
||
[self removeObject: [self objectAtIndex: index]];
|
||
}
|
||
|
||
- objectAtIndex: (unsigned)index
|
||
{
|
||
id <LinkedListComprising> link;
|
||
|
||
CHECK_INDEX_RANGE_ERROR(index, _count);
|
||
|
||
if (index < _count / 2)
|
||
for (link = _first_link;
|
||
index;
|
||
link = [link nextLink], index--)
|
||
;
|
||
else
|
||
for (link = _last_link, index = _count - index - 1;
|
||
index;
|
||
link = [link prevLink], index--)
|
||
;
|
||
return link;
|
||
}
|
||
|
||
- firstObject
|
||
{
|
||
return _first_link;
|
||
}
|
||
|
||
- lastObject
|
||
{
|
||
return _last_link;
|
||
}
|
||
|
||
- successorOfObject: oldObject
|
||
{
|
||
/* Make sure we actually own the oldObject. */
|
||
NSAssert([oldObject linkedList] == self, NSInternalInconsistencyException);
|
||
|
||
return [oldObject nextLink];
|
||
}
|
||
|
||
- predecessorOfObject: oldObject
|
||
{
|
||
/* Make sure we actually own the oldObject. */
|
||
NSAssert([oldObject linkedList] == self, NSInternalInconsistencyException);
|
||
|
||
return [oldObject prevLink];
|
||
}
|
||
|
||
- (void*) newEnumState
|
||
{
|
||
return _first_link;
|
||
}
|
||
|
||
- nextObjectWithEnumState: (void**)enumState
|
||
{
|
||
id ret;
|
||
|
||
if (!*enumState)
|
||
return nil;
|
||
ret = *enumState;
|
||
*enumState = [(id)(*enumState) nextLink];
|
||
/* *enumState points to the next object to be returned. */
|
||
return ret;
|
||
}
|
||
|
||
- prevObjectWithEnumState: (void**)enumState
|
||
{
|
||
/* *enumState points to the object returned last time. */
|
||
if (!*enumState)
|
||
return nil;
|
||
if (*enumState == _first_link)
|
||
/* enumState was just initialized from -newEnumState. */
|
||
return *enumState = _last_link;
|
||
return (id) *enumState = [(id)(*enumState) prevLink];
|
||
}
|
||
|
||
- (unsigned) count
|
||
{
|
||
return _count;
|
||
}
|
||
|
||
@end
|
||
|
||
|
||
|