New class

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/performance/trunk@38845 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2015-07-29 08:07:44 +00:00
parent e2d66ee254
commit 08cf714574
3 changed files with 264 additions and 25 deletions

View file

@ -1,3 +1,11 @@
2015-07-29 Richard Frith-Macdonald <rfm@gnu.org>
* GSLinkedList.h:
* GSLinkedList.m:
Add GSLinkedStore for a list which controls its own links and stores
unused links to avoid having to create/destroy link objects
repeatedly.
2015-07-17 Niels Grewe <niels.grewe@halbordnung.de>
* GSFIFO.m: Implement methods that allow waiting on an empty

View file

@ -254,7 +254,18 @@ extern GSListLink*
GSLinkedListFindIdentical(NSObject *object, GSLinkedList *list,
GSListLink *from, BOOL back);
/** Returns the first object in the list.
*/
static inline id
GSLinkedListFirstObject(GSLinkedList *list)
{
if (nil == list->head)
return nil;
return list->head->item;
}
/** Inserts link immediately after at.<br />
* If at is nil, inserts at the end of the list (link becomes tail).<br />
* Updates the head, tail and count variables of list.<br />
* Does not retain link.
*/
@ -262,12 +273,23 @@ extern void
GSLinkedListInsertAfter(GSListLink *link, GSLinkedList *list, GSListLink *at);
/** Inserts link immediately before at.<br />
* If at is nil, inserts at the start of the list (link becomes head).<br />
* Updates the head, tail and count variables of list.<br />
* Does not retain link.
*/
extern void
GSLinkedListInsertBefore(GSListLink *link, GSLinkedList *list, GSListLink *at);
/** Returns the last object in the list.
*/
static inline id
GSLinkedListLastObject(GSLinkedList *list)
{
if (nil == list->tail)
return nil;
return list->tail->item;
}
/** Moves the link to the head of the list if it is not already there.
*/
extern void
@ -285,4 +307,80 @@ GSLinkedListMoveToTail(GSListLink *link, GSLinkedList *list);
extern void
GSLinkedListRemove(GSListLink *link, GSLinkedList *list);
/** This class extends GSLinkedList by providing storage for unused links
* and re-using those links when a new link is needed.<br />
* This avoids the overhead of allocating/deallocating links and provides
* an API more like a mutable array.
*/
@interface GSLinkStore : GSLinkedList
{
@public
GSListLink *free; /** The unused links */
}
/** Adds an object at the end of the list (calls -insertObject:after:).
*/
- (void) addObject: (id)anObject;
/** Returns the first object in the list or nil if the list is empty.
*/
- (id) firstObject;
/** Inserts anObject immediately after the specified link. If at is nil
* the object is inserted at the end of the list.
*/
- (void) insertObject: (id)anObject after: (GSListLink*)at;
/** Inserts anObject immediately before the specified link. If at is nil
* the object is inserted at the start of the list.
*/
- (void) insertObject: (id)anObject before: (GSListLink*)at;
/** Returns the last object in the list or nil if the list is empty.
*/
- (id) lastObject;
/** Removes any unused links from the list (to release the memory they
* occupied).
*/
- (void) purge;
/** Removes the first object from the list (or does nothing if the list
* is empty).
*/
- (void) removeFirstObject;
/** Removes the last object from the list (or does nothing if the list
* is empty).
*/
- (void) removeLastObject;
@end
/** Adds the object at the end of the list.
*/
extern void
GSLinkStoreAddObject(GSLinkStore *list, NSObject *anObject);
/** Adds the object to the list after the specified link.<br />
* Calls GSLinkedListInsertAfter().
*/
extern void
GSLinkStoreInsertObjectAfter(
NSObject *anObject, GSLinkStore *list, GSListLink *at);
/** Adds the object to the list before the specified link.<br />
* Calls GSLinkedListInsertBefore().
*/
extern void
GSLinkStoreInsertObjectBefore(
NSObject *anObject, GSLinkStore *list, GSListLink *at);
/** Removes the object held in the specified link.<br />
* If at is nil or is not owned by the list, this does nothing.
*/
extern void
GSLinkStoreRemoveObjectAt(GSLinkStore *list, GSListLink *at);
#endif

View file

@ -361,31 +361,6 @@ GSLinkedListFindIdentical(NSObject *object, GSLinkedList *list,
return nil;
}
void
GSLinkedListInsertBefore(GSListLink *link, GSLinkedList *list, GSListLink *at)
{
if (nil == list->head)
{
list->head = list->tail = 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
GSLinkedListInsertAfter(GSListLink *link, GSLinkedList *list, GSListLink *at)
{
@ -395,6 +370,10 @@ GSLinkedListInsertAfter(GSListLink *link, GSLinkedList *list, GSListLink *at)
}
else
{
if (nil == at)
{
at = list->tail;
}
link->next = at->next;
if (nil == link->next)
{
@ -411,6 +390,35 @@ GSLinkedListInsertAfter(GSListLink *link, GSLinkedList *list, GSListLink *at)
list->count++;
}
void
GSLinkedListInsertBefore(GSListLink *link, GSLinkedList *list, GSListLink *at)
{
if (nil == list->head)
{
list->head = list->tail = link;
}
else
{
if (nil == at)
{
at = list->head;
}
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
GSLinkedListRemove(GSListLink *link, GSLinkedList *list)
{
@ -487,3 +495,128 @@ GSLinkedListMoveToTail(GSListLink *link, GSLinkedList *list)
}
}
@implementation GSLinkStore
- (void) addObject: (id)anObject
{
GSLinkStoreInsertObjectAfter(anObject, self, tail);
}
- (void) dealloc
{
[self empty];
[self purge];
[super dealloc];
}
- (void) empty
{
while (nil != head)
{
GSLinkStoreRemoveObjectAt(self, head);
}
}
- (id) firstObject
{
return GSLinkedListFirstObject(self);
}
- (void) insertObject: (id)anObject after: (GSListLink*)at
{
GSLinkStoreInsertObjectAfter(anObject, self, at);
}
- (void) insertObject: (id)anObject before: (GSListLink*)at
{
GSLinkStoreInsertObjectBefore(anObject, self, at);
}
- (id) lastObject
{
return GSLinkedListLastObject(self);
}
- (void) purge
{
while (nil != free)
{
GSListLink *link = free;
free = link->next;
link->next = nil;
link->owner = nil;
[link release];
}
}
- (void) removeFirstObject
{
if (nil != head)
{
GSLinkStoreRemoveObjectAt(self, head);
}
}
- (void) removeLastObject
{
if (nil != tail)
{
GSLinkStoreRemoveObjectAt(self, tail);
}
}
@end
void
GSLinkStoreInsertObjectAfter(
NSObject *anObject, GSLinkStore *list, GSListLink *at)
{
GSListLink *link = list->free;
if (nil == link)
{
link = [GSListLink new];
link->owner = list;
}
else
{
list->free = link->next;
link->next = nil;
}
link->item = [anObject retain];
GSLinkedListInsertAfter(link, list, list->tail);
}
void
GSLinkStoreInsertObjectBefore(
NSObject *anObject, GSLinkStore *list, GSListLink *at)
{
GSListLink *link = list->free;
if (nil == link)
{
link = [GSListLink new];
link->owner = list;
}
else
{
list->free = link->next;
link->next = nil;
}
link->item = [anObject retain];
GSLinkedListInsertBefore(link, list, list->head);
}
void
GSLinkStoreRemoveObjectAt(GSLinkStore *list, GSListLink *at)
{
if (nil != at && at->owner == list)
{
GSLinkedListRemove(at, list);
[at->item release];
at->next = list->free;
list->free = at;
}
}