mirror of
https://github.com/gnustep/libs-performance.git
synced 2025-02-24 04:11:19 +00:00
improve linked list api
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/performance/trunk@31440 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
0c664e3100
commit
dd2dc9ef19
5 changed files with 641 additions and 317 deletions
|
@ -1,3 +1,12 @@
|
|||
2010-09-29 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* GSLinkedList.h:
|
||||
* GSLinkedList.m:
|
||||
Revise structure and API for greater flexibility.
|
||||
* GSThreadPool.h
|
||||
* GSThreadPool.m
|
||||
Modify for new linked list api.
|
||||
|
||||
2010-09-23 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* performance/GSThreadPool.h:
|
||||
|
|
266
GSLinkedList.h
266
GSLinkedList.h
|
@ -24,107 +24,247 @@
|
|||
*/
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/** GSLinkedList provides simple doubly linked list functionality to
|
||||
@class GSLinkedList;
|
||||
|
||||
/** GSListLink provides simple doubly linked list functionality to
|
||||
* avoid the need to constantly re-invent it (as the OpenStep/Cocoa
|
||||
* APIs do not provide this). The emphasis is on speed of operation
|
||||
* so instance variables are directly accessible and functions are
|
||||
* provided to manipulate them, but you can/should avoid these direct
|
||||
* access features unless speed is really critical.<br />
|
||||
* A list is handled simply as a pointer to the link whose 'prev'
|
||||
* pointer is nil. <br />
|
||||
* While the item value of a link is retaned by the link, links in a
|
||||
* list are not retained, so you must manage retain/relase yourself.
|
||||
* so instance variables are directly accessible and inline functions
|
||||
* are provided to manipulate them (without error cehcking), but you
|
||||
* can/should avoid these direct access features unless speed is
|
||||
* really critical.<br />
|
||||
* A list may either be 'normal' ... (where the head/tail ends of
|
||||
* the list have a nil pointer to the previous/next link) or 'circular'
|
||||
* in which case the list is not terminated. <br />
|
||||
* The GSListLink item carries a minimal payload of a single item which
|
||||
* is retained by the link.<br />
|
||||
* The GSListLink owner is an optional pointer to an object which 'owns'
|
||||
* the link ... a GSLinkedList instance may use this to check link
|
||||
* ownership when manipulating links.
|
||||
*/
|
||||
@interface GSListLink : NSObject
|
||||
{
|
||||
@public
|
||||
GSListLink *next; // Not retained
|
||||
GSListLink *previous; // Not retained
|
||||
GSLinkedList *owner; // Not retained
|
||||
NSObject *item;
|
||||
}
|
||||
|
||||
/** Initialise the receiver as a link for a circular linked list.
|
||||
*/
|
||||
- (id) initCircular;
|
||||
|
||||
/** Return the next item in the list containing the receiver,
|
||||
* or nil if there are no more items.
|
||||
*/
|
||||
- (GSListLink*) next;
|
||||
|
||||
/** Return the list which owns the receiver or nil if the receiver is
|
||||
* not in a list.
|
||||
*/
|
||||
- (GSLinkedList*) owner;
|
||||
|
||||
/** Return the previous item in the list containing the receiver,
|
||||
* or nil if there are no more items.
|
||||
*/
|
||||
- (GSListLink*) previous;
|
||||
|
||||
/** Set an item value by retaining it and releasing any previous value.
|
||||
*/
|
||||
- (void) setItem: (NSObject*)anItem;
|
||||
@end
|
||||
|
||||
/** Inserts link after at in a circular list.<br />
|
||||
* Arguments must not be nil and link must not be in a list
|
||||
* (ie its next and previous pointers must point to itsself).
|
||||
*/
|
||||
static inline void
|
||||
GSLinkCircularInsertAfter(GSListLink *link, GSListLink *at)
|
||||
{
|
||||
link->next = at->next;
|
||||
link->previous = at;
|
||||
link->next->previous = link;
|
||||
link->previous->next = link;
|
||||
}
|
||||
|
||||
/** Inserts link before at in a circular list.<br />
|
||||
* Arguments must not be nil and link must not be in a list
|
||||
* (ie its next and previous pointers must point to itsself).
|
||||
*/
|
||||
static inline void
|
||||
GSLinkCircularInsertBefore(GSListLink *link, GSListLink *at)
|
||||
{
|
||||
link->next = at;
|
||||
link->previous = at->previous;
|
||||
link->next->previous = link;
|
||||
link->previous->next = link;
|
||||
}
|
||||
|
||||
/** Removes link from any list it is in.<br />
|
||||
* The link argument must not be nil.
|
||||
*/
|
||||
static inline void
|
||||
GSLinkCircularRemove(GSListLink *link)
|
||||
{
|
||||
link->next->previous = link->previous;
|
||||
link->previous->next = link->next;
|
||||
link->next = link->previous = link;
|
||||
}
|
||||
|
||||
/** Inserts link after at in a normal list.<br />
|
||||
* Arguments must not be nil and link must not be in a list
|
||||
* (ie its next and previous pointers must both be nil).
|
||||
*/
|
||||
static inline void
|
||||
GSLinkInsertAfter(GSListLink *link, GSListLink *at)
|
||||
{
|
||||
if (nil != at->next)
|
||||
{
|
||||
at->next->previous = link;
|
||||
}
|
||||
link->previous = at;
|
||||
at->next = link;
|
||||
}
|
||||
|
||||
/** Inserts link before at in a normal list.<br />
|
||||
* Arguments must not be nil and link must not be in a list
|
||||
* (ie its next and previous pointers must both be nil).
|
||||
*/
|
||||
static inline void
|
||||
GSLinkInsertBefore(GSListLink *link, GSListLink *at)
|
||||
{
|
||||
if (nil != at->previous)
|
||||
{
|
||||
at->previous->next = link;
|
||||
}
|
||||
link->next = at;
|
||||
at->previous = link;
|
||||
}
|
||||
|
||||
/** Removes link from the list it is in.<br />
|
||||
* The link argument must not be nil.
|
||||
*/
|
||||
static inline void
|
||||
GSLinkRemove(GSListLink *link)
|
||||
{
|
||||
if (nil != link->next)
|
||||
{
|
||||
link->next->previous = link->previous;
|
||||
}
|
||||
if (nil != link->previous)
|
||||
{
|
||||
link->previous->next = link->next;
|
||||
}
|
||||
link->next = link->previous = nil;
|
||||
}
|
||||
|
||||
|
||||
/** GSLinkedList manages a list of GSListLink objects.
|
||||
*/
|
||||
@interface GSLinkedList : NSObject
|
||||
{
|
||||
@public
|
||||
GSLinkedList *next; // Not retained
|
||||
GSLinkedList *prev; // Not retained
|
||||
NSObject *item;
|
||||
GSListLink *head; // First link in the list.
|
||||
GSListLink *tail; // Last link in the list.
|
||||
NSUInteger count; // Number of links in the list.
|
||||
}
|
||||
|
||||
/** Appends other at the end of the linked list contining the receiver.
|
||||
/** Appends link at the end of the linked list managed by the receiver.<br />
|
||||
* Retains the link.
|
||||
*/
|
||||
- (void) append: (GSLinkedList*)other;
|
||||
- (void) append: (GSListLink*)link;
|
||||
|
||||
/** Searches the linked list containing the receiver from the
|
||||
* receiver onwards, returning the link containing object or nil
|
||||
/** Returns the number of links in the list.
|
||||
*/
|
||||
- (NSUInteger) count;
|
||||
|
||||
/** Remove all links from the list and release them all.
|
||||
*/
|
||||
- (void) empty;
|
||||
|
||||
/** Searches the linked list returning the link containing object or nil
|
||||
* if it is not found.<br />
|
||||
* The comparison is performed using the -isEqual: method of object.<br />
|
||||
* This method will <em>not</em> find links containins nil items.
|
||||
* The comparison is performed using the [NSObject-isEqual:] method
|
||||
* of object.<br />
|
||||
* If start is nil then the whole list is searched.<br />
|
||||
* This method will <em>not</em> find links containing nil items.
|
||||
*/
|
||||
- (id) findEqual: (NSObject*)object;
|
||||
- (GSListLink*) findEqual: (NSObject*)object
|
||||
from: (GSListLink*)start
|
||||
back: (BOOL)aFlag;
|
||||
|
||||
/** Searches the linked list containing the receiver, from the receiver
|
||||
* onwards, returning the link containing object or nil if it is not found.
|
||||
/** Searches the linked list returning the link containing object or nil
|
||||
* if it is not found.<br />
|
||||
* If start is nil then the whole list is searched.<br />
|
||||
* A direct pointer comparison is used to determine equality.
|
||||
*/
|
||||
- (id) findIdentical: (NSObject*)object;
|
||||
- (GSListLink*) findIdentical: (NSObject*)object
|
||||
from: (GSListLink*)start
|
||||
back: (BOOL)aFlag;
|
||||
|
||||
/** Returns the first link in the list.
|
||||
*/
|
||||
- (id) head;
|
||||
- (GSListLink*) head;
|
||||
|
||||
/** Inserts other immediately before the receiver.
|
||||
/** Inserts other immediately after the receiver.<br />
|
||||
* Retains the link.
|
||||
*/
|
||||
- (void) insert: (GSLinkedList*)other;
|
||||
- (void) insert: (GSListLink*)link after: (GSListLink*)at;
|
||||
|
||||
/** Returns the item in the link represented by the receiver.<br />
|
||||
* The item may be nil.
|
||||
/** Inserts other immediately before the receiver.<br />
|
||||
* Retains the link.
|
||||
*/
|
||||
- (NSObject*) item;
|
||||
- (void) insert: (GSListLink*)link before: (GSListLink*)at;
|
||||
|
||||
/** Returns the next link in the list, or nil if the receiver is at the tail.
|
||||
/** Removes the link from the receiver.<br />
|
||||
* releases the link.
|
||||
*/
|
||||
- (id) next;
|
||||
|
||||
/** Returns the previous link in the list, or nil if the receiver is at the
|
||||
* head.
|
||||
*/
|
||||
- (id) previous;
|
||||
|
||||
/** Removes the receiver from the linked list containing it.<br />
|
||||
* Returns the link which was next after the receiver.
|
||||
*/
|
||||
- (id) remove;
|
||||
|
||||
/** Replaces any existing item in the receiver with the supplied object.<br />
|
||||
* The item may be nil.
|
||||
*/
|
||||
- (void) setItem: (NSObject*)object;
|
||||
- (void) removeLink: (GSListLink*)link;
|
||||
|
||||
/** Returns the last link in the list.
|
||||
*/
|
||||
- (id) tail;
|
||||
- (GSListLink*) tail;
|
||||
|
||||
@end
|
||||
|
||||
/** Appends link at the end of the list.
|
||||
/** Searches from list to the end looking for the first link containing
|
||||
* object (as determined by using object's [NSObject-isEqual:] method).<br />
|
||||
* If from is nil the list is search from head or tail as appropriate
|
||||
* to the direction in which it is searched.
|
||||
*/
|
||||
extern void
|
||||
GSLinkedListAppend(GSLinkedList *link, GSLinkedList *list);
|
||||
extern GSListLink*
|
||||
GSLinkedListFindEqual(NSObject *object, GSLinkedList *list,
|
||||
GSListLink *from, BOOL back);
|
||||
|
||||
/** Searches from list to the end looking for the first link containing
|
||||
* object (as determiend by using object's -isEqual: method).
|
||||
* object (as determined by direct pointer comparison).<br />
|
||||
* If from is nil the list is search from head or tail as appropriate
|
||||
* to the direction in which it is searched.
|
||||
*/
|
||||
extern id
|
||||
GSLinkedListFindEqual(NSObject *object, GSLinkedList *list);
|
||||
extern GSListLink*
|
||||
GSLinkedListFindIdentical(NSObject *object, GSLinkedList *list,
|
||||
GSListLink *from, BOOL back);
|
||||
|
||||
/** Searches from list to the end looking for the first link containing
|
||||
* object (as determiend by direct pointer comparison).
|
||||
*/
|
||||
extern id
|
||||
GSLinkedListFindIdentical(NSObject *object, GSLinkedList *list);
|
||||
|
||||
/** Inserts link immediately before at.
|
||||
/** Inserts link immediately after at.<br />
|
||||
* Updates the head, tail and count variables of list.<br />
|
||||
* Does not retain link.
|
||||
*/
|
||||
extern void
|
||||
GSLinkedListInsert(GSLinkedList *link, GSLinkedList *at);
|
||||
GSLinkedListInsertAfter(GSListLink *link, GSLinkedList *list, GSListLink *at);
|
||||
|
||||
/** Removes link from it list and returns the next item in the list
|
||||
* or nil if there is no next item.
|
||||
/** Inserts link immediately before at.<br />
|
||||
* Updates the head, tail and count variables of list.<br />
|
||||
* Does not retain link.
|
||||
*/
|
||||
extern id
|
||||
GSLinkedListRemove(GSLinkedList *link);
|
||||
extern void
|
||||
GSLinkedListInsertBefore(GSListLink *link, GSLinkedList *list, GSListLink *at);
|
||||
|
||||
/** Removes link from the list.<br />
|
||||
* Updates the head, tail and count variables of list.<br />
|
||||
* Does not release link.
|
||||
*/
|
||||
extern void
|
||||
GSLinkedListRemove(GSListLink *link, GSLinkedList *list);
|
||||
|
||||
#endif
|
||||
|
|
476
GSLinkedList.m
476
GSLinkedList.m
|
@ -23,186 +23,430 @@
|
|||
#import <Foundation/NSException.h>
|
||||
#import "GSLinkedList.h"
|
||||
|
||||
@implementation GSLinkedList
|
||||
- (void) append: (GSLinkedList*)other
|
||||
{
|
||||
if (nil == other)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] nil argument",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
if (other->next || other->prev)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] other link is still in a list",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
GSLinkedListAppend(other, self);
|
||||
}
|
||||
@implementation GSListLink
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
if (next || prev)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"[%@-%@] receiver is still in a list",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
NSAssert(nil != owner, NSInternalInconsistencyException);
|
||||
[item release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) findEqual: (NSObject*)object;
|
||||
- (id) initCircular
|
||||
{
|
||||
return GSLinkedListFindEqual(object, self);
|
||||
}
|
||||
|
||||
- (id) findIdentical: (NSObject*)object;
|
||||
{
|
||||
return GSLinkedListFindIdentical(object, self);
|
||||
}
|
||||
|
||||
- (id) head
|
||||
{
|
||||
GSLinkedList *link = self;
|
||||
|
||||
while (nil != link->prev)
|
||||
if ((self = [super init]) != nil)
|
||||
{
|
||||
link = link->prev;
|
||||
next = previous = self;
|
||||
}
|
||||
return link;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) insert: (GSLinkedList*)other
|
||||
- (id) item
|
||||
{
|
||||
if (nil == other)
|
||||
return item;
|
||||
}
|
||||
|
||||
- (GSListLink*) next
|
||||
{
|
||||
if (next == self)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
- (GSLinkedList*) owner
|
||||
{
|
||||
return owner;
|
||||
}
|
||||
|
||||
- (GSListLink*) previous
|
||||
{
|
||||
if (previous == self)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
return previous;
|
||||
}
|
||||
|
||||
- (void) setItem: (NSObject*)anItem
|
||||
{
|
||||
id o = item;
|
||||
|
||||
item = [anItem retain];
|
||||
[o release];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation GSLinkedList
|
||||
- (void) append: (GSListLink*)link
|
||||
{
|
||||
if (nil == link)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] nil argument",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
if (other->next || other->prev)
|
||||
if (self == link->owner)
|
||||
{
|
||||
if (link != tail)
|
||||
{
|
||||
GSLinkedListRemove(link, self);
|
||||
GSLinkedListInsertAfter(link, self, tail);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nil != link->owner || nil != link->next || nil != link->previous)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] other link is still in a list",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
GSLinkedListInsert(other, self);
|
||||
}
|
||||
|
||||
- (NSObject*) item
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
- (id) next
|
||||
{
|
||||
return next;
|
||||
}
|
||||
|
||||
- (id) previous
|
||||
{
|
||||
return prev;
|
||||
}
|
||||
|
||||
- (id) remove
|
||||
{
|
||||
return GSLinkedListRemove(self);
|
||||
}
|
||||
|
||||
- (void) setItem: (NSObject*)object
|
||||
{
|
||||
id o = item;
|
||||
|
||||
item = [object retain];
|
||||
[o release];
|
||||
}
|
||||
|
||||
- (id) tail
|
||||
{
|
||||
GSLinkedList *link = self;
|
||||
|
||||
while (nil != link->next)
|
||||
{
|
||||
link = link->next;
|
||||
GSLinkedListInsertAfter(link, self, tail);
|
||||
[link retain];
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
||||
- (NSUInteger) count
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
count = 0;
|
||||
tail = nil;
|
||||
while (nil != head)
|
||||
{
|
||||
GSListLink *link = head;
|
||||
|
||||
head = link->next;
|
||||
head->next = head->previous = nil;
|
||||
head->owner = nil;
|
||||
[head release];
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) empty
|
||||
{
|
||||
GSListLink *link;
|
||||
|
||||
while (nil != (link = head))
|
||||
{
|
||||
head = link->next;
|
||||
link->owner = nil;
|
||||
link->next = link->previous = nil;
|
||||
[link release];
|
||||
}
|
||||
tail = nil;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
- (GSListLink*) findEqual: (NSObject*)object
|
||||
from: (GSListLink*)start
|
||||
back: (BOOL)aFlag
|
||||
{
|
||||
if (nil != start && start->owner != self)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] start link is not in this list",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
return GSLinkedListFindEqual(object, self, start, aFlag);
|
||||
}
|
||||
|
||||
- (GSListLink*) findIdentical: (NSObject*)object
|
||||
from: (GSListLink*)start
|
||||
back: (BOOL)aFlag
|
||||
{
|
||||
if (nil != start && start->owner != self)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] start link is not in this list",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
return GSLinkedListFindIdentical(object, self, start, aFlag);
|
||||
}
|
||||
|
||||
- (GSListLink*) head
|
||||
{
|
||||
return head;
|
||||
}
|
||||
|
||||
- (void) insert: (GSListLink*)link after: (GSListLink*)at
|
||||
{
|
||||
if (nil == link)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] nil link argument",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
if (nil == at)
|
||||
{
|
||||
at = tail;
|
||||
}
|
||||
if (at->owner != self)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] 'at' link is not in this list",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
if (at == link)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (link->owner == self)
|
||||
{
|
||||
GSLinkedListRemove(link, self);
|
||||
GSLinkedListInsertAfter(link, self, at);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nil != link->owner || nil != link->next || nil != link->previous)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] other link is still in a list",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
GSLinkedListInsertAfter(link, self, at);
|
||||
[link retain];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) insert: (GSListLink*)link before: (GSListLink*)at
|
||||
{
|
||||
if (nil == link)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] nil link argument",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
if (nil == at)
|
||||
{
|
||||
at = head;
|
||||
}
|
||||
if (at->owner != self)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] 'at' link is not in this list",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
if (at == link)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (link->owner == self)
|
||||
{
|
||||
GSLinkedListRemove(link, self);
|
||||
GSLinkedListInsertBefore(link, self, at);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nil != link->owner || nil != link->next || nil != link->previous)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] other link is still in a list",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
GSLinkedListInsertBefore(link, self, at);
|
||||
[link retain];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) removeLink: (GSListLink*)link
|
||||
{
|
||||
if (nil == link)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] nil link argument",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
if (link->owner != self)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] link is not in this list",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
GSLinkedListRemove(link, self);
|
||||
[link release];
|
||||
}
|
||||
|
||||
- (GSListLink*) tail
|
||||
{
|
||||
return tail;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
void
|
||||
GSLinkedListAppend(GSLinkedList *link, GSLinkedList *list)
|
||||
GSLinkedListInsertBefore(GSListLink *link, GSLinkedList *list, GSListLink *at)
|
||||
{
|
||||
while (nil != list->next)
|
||||
if (nil == list->head)
|
||||
{
|
||||
list = list->next;
|
||||
list->head = list->tail = link;
|
||||
}
|
||||
link->prev = list;
|
||||
list->next = link;
|
||||
else
|
||||
{
|
||||
link->previous = at->previous;
|
||||
if (nil == link->previous)
|
||||
{
|
||||
list->head = link;
|
||||
}
|
||||
else
|
||||
{
|
||||
link->previous->next = link;
|
||||
}
|
||||
at->previous = link;
|
||||
link->next = at;
|
||||
}
|
||||
link->owner = list;
|
||||
list->count++;
|
||||
}
|
||||
|
||||
void
|
||||
GSLinkedListInsert(GSLinkedList *link, GSLinkedList *at)
|
||||
GSLinkedListInsertAfter(GSListLink *link, GSLinkedList *list, GSListLink *at)
|
||||
{
|
||||
link->next = at;
|
||||
if (nil != at->prev)
|
||||
if (nil == list->head)
|
||||
{
|
||||
at->prev->next = link;
|
||||
link->prev = at->prev;
|
||||
list->head = list->tail = link;
|
||||
}
|
||||
at->prev = link;
|
||||
else
|
||||
{
|
||||
link->next = at->next;
|
||||
if (nil == link->next)
|
||||
{
|
||||
list->tail = link;
|
||||
}
|
||||
else
|
||||
{
|
||||
link->next->previous = link;
|
||||
}
|
||||
at->next = link;
|
||||
link->previous = at;
|
||||
}
|
||||
link->owner = list;
|
||||
list->count++;
|
||||
}
|
||||
|
||||
id
|
||||
GSLinkedListRemove(GSLinkedList *link)
|
||||
void
|
||||
GSLinkedListRemove(GSListLink *link, GSLinkedList *list)
|
||||
{
|
||||
GSLinkedList *next = link->next;
|
||||
|
||||
if (nil != link->next)
|
||||
if (list->head == link)
|
||||
{
|
||||
link->next->prev = link->prev;
|
||||
}
|
||||
if (nil != link->prev)
|
||||
list->head = link->next;
|
||||
if (nil != list->head)
|
||||
{
|
||||
link->prev->next = link->next;
|
||||
list->head->previous = nil;
|
||||
}
|
||||
link->next = nil;
|
||||
link->prev = nil;
|
||||
return next;
|
||||
}
|
||||
else
|
||||
{
|
||||
link->previous->next = link->next;
|
||||
}
|
||||
if (list->tail == link)
|
||||
{
|
||||
list->tail = link->previous;
|
||||
if (nil != list->tail)
|
||||
{
|
||||
list->tail->next = nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
link->next->previous = link->previous;
|
||||
}
|
||||
link->next = link->previous = nil;
|
||||
link->owner = nil;
|
||||
list->count--;
|
||||
}
|
||||
|
||||
id
|
||||
GSLinkedListFindEqual(NSObject *object, GSLinkedList *list)
|
||||
GSListLink*
|
||||
GSLinkedListFindEqual(NSObject *object, GSLinkedList *list,
|
||||
GSListLink *from, BOOL back)
|
||||
{
|
||||
if (nil == from)
|
||||
{
|
||||
if (YES == back)
|
||||
{
|
||||
from = list->tail;
|
||||
}
|
||||
else
|
||||
{
|
||||
from = list->head;
|
||||
}
|
||||
}
|
||||
if (nil != object)
|
||||
{
|
||||
BOOL (*imp)(id, SEL, id);
|
||||
|
||||
imp = (BOOL(*)(id,SEL,id))[object methodForSelector: @selector(isEqual:)];
|
||||
while (nil != list)
|
||||
if (YES == back)
|
||||
{
|
||||
if (YES == (*imp)(object, @selector(isEqual:), list->item))
|
||||
while (nil != from)
|
||||
{
|
||||
return list;
|
||||
if (YES == (*imp)(object, @selector(isEqual:), from->item))
|
||||
{
|
||||
return from;
|
||||
}
|
||||
from = from->previous;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (nil != from)
|
||||
{
|
||||
if (YES == (*imp)(object, @selector(isEqual:), from->item))
|
||||
{
|
||||
return from;
|
||||
}
|
||||
from = from->next;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
id
|
||||
GSLinkedListFindIdentical(NSObject *object, GSLinkedList *list)
|
||||
|
||||
GSListLink*
|
||||
GSLinkedListFindIdentical(NSObject *object, GSLinkedList *list,
|
||||
GSListLink *from, BOOL back)
|
||||
{
|
||||
while (nil != list)
|
||||
if (nil == from)
|
||||
{
|
||||
if (object == list->item)
|
||||
if (YES == back)
|
||||
{
|
||||
return list;
|
||||
from = list->tail;
|
||||
}
|
||||
else
|
||||
{
|
||||
from = list->head;
|
||||
}
|
||||
}
|
||||
if (YES == back)
|
||||
{
|
||||
while (nil != from)
|
||||
{
|
||||
if (object == from->item)
|
||||
{
|
||||
return from;
|
||||
}
|
||||
from = from->previous;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (nil != from)
|
||||
{
|
||||
if (object == from->item)
|
||||
{
|
||||
return from;
|
||||
}
|
||||
from = from->next;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
|
|
@ -24,8 +24,7 @@
|
|||
*/
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class GSOperation;
|
||||
@class GSThreadLink;
|
||||
@class GSLinkedList;
|
||||
@class NSLock;
|
||||
|
||||
/** This class provides a thread pool for performing methods
|
||||
|
@ -41,16 +40,11 @@
|
|||
BOOL shutdown;
|
||||
BOOL suspended;
|
||||
NSUInteger maxThreads;
|
||||
NSUInteger threadCount;
|
||||
NSUInteger activeCount;
|
||||
GSThreadLink *idle;
|
||||
GSThreadLink *live;
|
||||
GSLinkedList *idle;
|
||||
GSLinkedList *live;
|
||||
NSUInteger maxOperations;
|
||||
NSUInteger operationCount;
|
||||
GSOperation *operations;
|
||||
GSOperation *lastOperation;
|
||||
NSUInteger unusedCount;
|
||||
GSOperation *unused;
|
||||
GSLinkedList *operations;
|
||||
GSLinkedList *unused;
|
||||
NSUInteger processed;
|
||||
}
|
||||
|
||||
|
|
177
GSThreadPool.m
177
GSThreadPool.m
|
@ -5,7 +5,7 @@
|
|||
|
||||
@class GSThreadPool;
|
||||
|
||||
@interface GSOperation : GSLinkedList
|
||||
@interface GSOperation : GSListLink
|
||||
{
|
||||
@public
|
||||
SEL sel;
|
||||
|
@ -20,7 +20,7 @@
|
|||
}
|
||||
@end
|
||||
|
||||
@interface GSThreadLink : GSLinkedList
|
||||
@interface GSThreadLink : GSListLink
|
||||
{
|
||||
@public
|
||||
GSThreadPool *pool; // Not retained
|
||||
|
@ -28,6 +28,7 @@
|
|||
GSOperation *op;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GSThreadLink
|
||||
- (void) dealloc
|
||||
{
|
||||
|
@ -44,7 +45,7 @@
|
|||
return self;
|
||||
}
|
||||
@end
|
||||
;
|
||||
|
||||
@interface GSThreadPool (Internal)
|
||||
- (void) _any;
|
||||
- (void) _dead: (GSThreadLink*)link;
|
||||
|
@ -58,36 +59,34 @@
|
|||
|
||||
- (void) dealloc
|
||||
{
|
||||
GSThreadLink *link;
|
||||
|
||||
[poolLock lock];
|
||||
while (nil != operations)
|
||||
[operations release];
|
||||
operations = nil;
|
||||
[unused release];
|
||||
unused = nil;
|
||||
if (nil != idle)
|
||||
{
|
||||
id link = operations;
|
||||
|
||||
operations = [link remove];
|
||||
[link release];
|
||||
}
|
||||
while (nil != unused)
|
||||
while (nil != (link = (GSThreadLink*)idle->head))
|
||||
{
|
||||
id link = operations;
|
||||
|
||||
unused = [link remove];
|
||||
[link release];
|
||||
}
|
||||
while (nil != idle)
|
||||
{
|
||||
GSThreadLink *link = idle;
|
||||
|
||||
idle = [link remove];
|
||||
GSLinkedListRemove(link, idle);
|
||||
[link->lock lock];
|
||||
[link->lock unlockWithCondition: 1];
|
||||
}
|
||||
while (nil != live)
|
||||
[idle release];
|
||||
idle = nil;
|
||||
}
|
||||
if (nil != live)
|
||||
{
|
||||
GSThreadLink *link = live;
|
||||
|
||||
live = [link remove];
|
||||
while (nil != (link = (GSThreadLink*)live->head))
|
||||
{
|
||||
GSLinkedListRemove(link, live);
|
||||
link->pool = nil;
|
||||
}
|
||||
[live release];
|
||||
live = nil;
|
||||
}
|
||||
[poolLock unlock];
|
||||
[poolLock release];
|
||||
[super dealloc];
|
||||
|
@ -100,8 +99,8 @@
|
|||
[poolLock lock];
|
||||
result = [NSString stringWithFormat:
|
||||
@"%@ queue: %u(%u) threads: %u(%u) active: %u processed: %u",
|
||||
[super description], operationCount, maxOperations,
|
||||
threadCount, maxThreads, activeCount, processed];
|
||||
[super description], operations->count, maxOperations,
|
||||
idle->count + live->count, maxThreads, live->count, processed];
|
||||
[poolLock unlock];
|
||||
return result;
|
||||
}
|
||||
|
@ -123,15 +122,8 @@
|
|||
NSUInteger counter;
|
||||
|
||||
[poolLock lock];
|
||||
counter = operationCount;
|
||||
while (nil != operations)
|
||||
{
|
||||
id o = operations;
|
||||
|
||||
operations = [o remove];
|
||||
operationCount--;
|
||||
[o release];
|
||||
}
|
||||
counter = operations->count;
|
||||
[operations empty];
|
||||
[poolLock unlock];
|
||||
return counter;
|
||||
}
|
||||
|
@ -141,6 +133,10 @@
|
|||
if ((self = [super init]) != nil)
|
||||
{
|
||||
poolLock = [NSRecursiveLock new];
|
||||
idle = [GSLinkedList new];
|
||||
live = [GSLinkedList new];
|
||||
operations = [GSLinkedList new];
|
||||
unused = [GSLinkedList new];
|
||||
[self setOperations: 100];
|
||||
[self setThreads: 2];
|
||||
}
|
||||
|
@ -149,12 +145,12 @@
|
|||
|
||||
- (BOOL) isEmpty
|
||||
{
|
||||
return (nil == operations) ? YES : NO;
|
||||
return (0 == operations->count) ? YES : NO;
|
||||
}
|
||||
|
||||
- (BOOL) isIdle
|
||||
{
|
||||
return (nil == live) ? YES : NO;
|
||||
return (0 == live->count) ? YES : NO;
|
||||
}
|
||||
|
||||
- (BOOL) isSuspended
|
||||
|
@ -201,9 +197,9 @@
|
|||
format: @"Nil receiver"];
|
||||
}
|
||||
[poolLock lock];
|
||||
if (operationCount < maxOperations && maxThreads > 0)
|
||||
if (operations->count < maxOperations && maxThreads > 0)
|
||||
{
|
||||
GSOperation *op = unused;
|
||||
GSOperation *op = (GSOperation*)unused->head;
|
||||
|
||||
if (nil == op)
|
||||
{
|
||||
|
@ -211,23 +207,13 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
unused = [op remove]; // Re-use an old one
|
||||
unusedCount--;
|
||||
GSLinkedListRemove(op, unused); // Re-use an old one
|
||||
}
|
||||
[op setItem: aReceiver];
|
||||
op->sel = aSelector;
|
||||
op->arg = [anArgument retain];
|
||||
|
||||
if (nil == operations)
|
||||
{
|
||||
operations = lastOperation = op;
|
||||
}
|
||||
else
|
||||
{
|
||||
[lastOperation append: op];
|
||||
}
|
||||
lastOperation = op;
|
||||
operationCount++;
|
||||
GSLinkedListInsertAfter(op, operations, operations->tail);
|
||||
[self _any];
|
||||
[poolLock unlock];
|
||||
}
|
||||
|
@ -276,17 +262,16 @@
|
|||
}
|
||||
[poolLock lock];
|
||||
}
|
||||
while (maxThreads < threadCount && idle != nil)
|
||||
while (maxThreads < idle->count + live->count && idle->count > 0)
|
||||
{
|
||||
GSThreadLink *link = idle;
|
||||
GSThreadLink *link = (GSThreadLink*)idle->head;
|
||||
|
||||
/* Remove thread link from the idle list, then start up the
|
||||
* thread using the condition lock ... the thread will see
|
||||
* that it has no operation to work with and will terminate
|
||||
* itsself and release the link.
|
||||
*/
|
||||
idle = [idle remove];
|
||||
threadCount--;
|
||||
GSLinkedListRemove(link, idle);
|
||||
[link->lock lock];
|
||||
[link->lock unlockWithCondition: 1];
|
||||
}
|
||||
|
@ -313,30 +298,27 @@
|
|||
{
|
||||
GSOperation *op;
|
||||
|
||||
while (nil != (op = operations))
|
||||
while (nil != (op = (GSOperation*)operations->head))
|
||||
{
|
||||
GSThreadLink *link = idle;
|
||||
GSThreadLink *link = (GSThreadLink*)idle->head;
|
||||
|
||||
if (nil == link)
|
||||
{
|
||||
if (maxThreads > threadCount)
|
||||
if (maxThreads > idle->count + live->count)
|
||||
{
|
||||
NSThread *thread;
|
||||
|
||||
/* Create a new link, add it to the idle list, and start the
|
||||
* thread which will work withn it.
|
||||
*/
|
||||
threadCount++;
|
||||
link = [GSThreadLink new];
|
||||
link->pool = self;
|
||||
thread = [[NSThread alloc] initWithTarget: self
|
||||
selector: @selector(_run:)
|
||||
object: link];
|
||||
[link release]; // Retained by thread
|
||||
[link setItem: thread];
|
||||
[thread release]; // Retained by link
|
||||
[idle insert: link];
|
||||
idle = link;
|
||||
GSLinkedListInsertAfter(link, idle, idle->tail);
|
||||
[thread start];
|
||||
}
|
||||
else
|
||||
|
@ -344,16 +326,9 @@
|
|||
break; // No idle thread to perform operation
|
||||
}
|
||||
}
|
||||
operations = [op remove];
|
||||
operationCount--;
|
||||
if (nil == operations)
|
||||
{
|
||||
lastOperation = nil;
|
||||
}
|
||||
idle = [link remove];
|
||||
[live insert: link];
|
||||
live = link;
|
||||
activeCount++;
|
||||
GSLinkedListRemove(op, operations);
|
||||
GSLinkedListRemove(link, idle);
|
||||
GSLinkedListInsertAfter(link, live, live->tail);
|
||||
link->op = op;
|
||||
[link->lock lock];
|
||||
[link->lock unlockWithCondition: 1];
|
||||
|
@ -364,29 +339,9 @@
|
|||
- (void) _dead: (GSThreadLink*)link
|
||||
{
|
||||
[poolLock lock];
|
||||
if (nil == link->next)
|
||||
if (link->owner != nil)
|
||||
{
|
||||
if (link == live)
|
||||
{
|
||||
live = [link remove];
|
||||
threadCount--;
|
||||
}
|
||||
else if (link == idle)
|
||||
{
|
||||
idle = [link remove];
|
||||
threadCount--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Already dead ... don't change threadCount.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (link == live) live = [link remove];
|
||||
else if (link == idle) idle = [link remove];
|
||||
else [link remove];
|
||||
threadCount--;
|
||||
GSLinkedListRemove(link, link->owner);
|
||||
}
|
||||
[poolLock unlock];
|
||||
}
|
||||
|
@ -399,28 +354,17 @@
|
|||
BOOL madeIdle = YES;
|
||||
|
||||
[poolLock lock];
|
||||
if (link == live)
|
||||
if (link->owner != nil)
|
||||
{
|
||||
live = [link remove];
|
||||
GSLinkedListRemove(link, link->owner);
|
||||
}
|
||||
else if (link == idle)
|
||||
if (idle->count + live->count > maxThreads)
|
||||
{
|
||||
idle = [link remove];
|
||||
}
|
||||
else
|
||||
{
|
||||
[link remove];
|
||||
}
|
||||
activeCount--;
|
||||
if (threadCount > maxThreads)
|
||||
{
|
||||
threadCount--;
|
||||
madeIdle = NO; // Made dead instead
|
||||
}
|
||||
else
|
||||
{
|
||||
[idle insert: link];
|
||||
idle = link;
|
||||
GSLinkedListInsertAfter(link, idle, idle->tail);
|
||||
}
|
||||
[poolLock unlock];
|
||||
return madeIdle;
|
||||
|
@ -437,7 +381,7 @@
|
|||
|
||||
[poolLock lock];
|
||||
processed++;
|
||||
if (unusedCount < maxOperations)
|
||||
if (unused->count < maxOperations)
|
||||
{
|
||||
if (nil != op->arg)
|
||||
{
|
||||
|
@ -445,23 +389,16 @@
|
|||
op->arg = nil;
|
||||
}
|
||||
[op setItem: nil];
|
||||
[unused insert: op];
|
||||
unused = op;
|
||||
unusedCount++;
|
||||
GSLinkedListInsertAfter(op, unused, unused->tail);
|
||||
}
|
||||
else
|
||||
{
|
||||
[op release];
|
||||
}
|
||||
link->op = operations;
|
||||
link->op = (GSOperation*)operations->head;
|
||||
if (nil != link->op)
|
||||
{
|
||||
operations = [operations remove];
|
||||
operationCount--;
|
||||
if (nil == operations)
|
||||
{
|
||||
lastOperation = nil;
|
||||
}
|
||||
GSLinkedListRemove(link->op, operations);
|
||||
more = YES;
|
||||
}
|
||||
[poolLock unlock];
|
||||
|
|
Loading…
Reference in a new issue