298 lines
5.4 KiB
Objective-C
298 lines
5.4 KiB
Objective-C
#import "DDList.h"
|
|
|
|
#if ! __has_feature(objc_arc)
|
|
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
|
|
#endif
|
|
|
|
|
|
@interface DDListEnumerator (PrivateAPI)
|
|
|
|
- (id)initWithList:(DDListNode *)list reverse:(BOOL)reverse;
|
|
|
|
@end
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark -
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
@implementation DDList
|
|
|
|
- (id)init
|
|
{
|
|
if ((self = [super init]))
|
|
{
|
|
listHead = NULL;
|
|
listTail = NULL;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)add:(void *)element
|
|
{
|
|
if(element == NULL) return;
|
|
|
|
DDListNode *node = malloc(sizeof(DDListNode));
|
|
|
|
node->element = element;
|
|
|
|
// Remember: The list is a linked list of DDListNode objects.
|
|
// Each node object is allocated and placed in the list.
|
|
// It is not deallocated until it is later removed from the linked list.
|
|
|
|
if (listTail == NULL)
|
|
{
|
|
node->next = NULL;
|
|
node->prev = NULL;
|
|
}
|
|
else
|
|
{
|
|
node->next = NULL;
|
|
node->prev = listTail;
|
|
node->prev->next = node;
|
|
}
|
|
|
|
listTail = node;
|
|
|
|
if (listHead == NULL)
|
|
listHead = node;
|
|
}
|
|
|
|
- (void)remove:(void *)element allInstances:(BOOL)allInstances
|
|
{
|
|
if(element == NULL) return;
|
|
|
|
DDListNode *node = listHead;
|
|
while (node != NULL)
|
|
{
|
|
DDListNode *nextNode = node->next;
|
|
if (element == node->element)
|
|
{
|
|
// Remove the node from the list.
|
|
// This is done by editing the pointers of the node's neighbors to skip it.
|
|
//
|
|
// In other words:
|
|
// node->prev->next = node->next
|
|
// node->next->prev = node->prev
|
|
//
|
|
// We also want to properly update our list pointer,
|
|
// which always points to the "first" element in the list. (Most recently added.)
|
|
|
|
if (node->prev != NULL)
|
|
node->prev->next = node->next;
|
|
else
|
|
listHead = node->next;
|
|
|
|
if (node->next != NULL)
|
|
node->next->prev = node->prev;
|
|
else
|
|
listTail = node->prev;
|
|
|
|
free(node);
|
|
|
|
if (!allInstances) break;
|
|
}
|
|
node = nextNode;
|
|
}
|
|
}
|
|
|
|
- (void)remove:(void *)element
|
|
{
|
|
[self remove:element allInstances:NO];
|
|
}
|
|
|
|
- (void)removeAll:(void *)element
|
|
{
|
|
[self remove:element allInstances:YES];
|
|
}
|
|
|
|
- (void)removeAllElements
|
|
{
|
|
DDListNode *node = listHead;
|
|
while (node != NULL)
|
|
{
|
|
DDListNode *next = node->next;
|
|
|
|
free(node);
|
|
node = next;
|
|
}
|
|
|
|
listHead = NULL;
|
|
listTail = NULL;
|
|
}
|
|
|
|
- (BOOL)contains:(void *)element
|
|
{
|
|
DDListNode *node;
|
|
for (node = listHead; node != NULL; node = node->next)
|
|
{
|
|
if (node->element == element)
|
|
{
|
|
return YES;
|
|
}
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (NSUInteger)count
|
|
{
|
|
NSUInteger count = 0;
|
|
|
|
DDListNode *node;
|
|
for (node = listHead; node != NULL; node = node->next)
|
|
{
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
|
|
objects:(id __unsafe_unretained [])buffer
|
|
count:(NSUInteger)len
|
|
{
|
|
DDListNode *currentNode;
|
|
|
|
if (state->extra[0] == 1)
|
|
return 0;
|
|
|
|
if (state->state == 0)
|
|
currentNode = listHead;
|
|
else
|
|
currentNode = (DDListNode *)state->state;
|
|
|
|
NSUInteger batchCount = 0;
|
|
while (currentNode != NULL && batchCount < len)
|
|
{
|
|
buffer[batchCount] = (__bridge id)currentNode->element;
|
|
currentNode = currentNode->next;
|
|
batchCount++;
|
|
}
|
|
|
|
state->state = (unsigned long)currentNode;
|
|
state->itemsPtr = buffer;
|
|
state->mutationsPtr = (__bridge void *)self;
|
|
|
|
if (currentNode == NULL)
|
|
state->extra[0] = 1;
|
|
else
|
|
state->extra[0] = 0;
|
|
|
|
return batchCount;
|
|
}
|
|
|
|
- (DDListEnumerator *)listEnumerator
|
|
{
|
|
return [[DDListEnumerator alloc] initWithList:listHead reverse:NO];
|
|
}
|
|
|
|
- (DDListEnumerator *)reverseListEnumerator
|
|
{
|
|
return [[DDListEnumerator alloc] initWithList:listTail reverse:YES];
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[self removeAllElements];
|
|
}
|
|
|
|
@end
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark -
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
@implementation DDListEnumerator
|
|
|
|
- (id)initWithList:(DDListNode *)list reverse:(BOOL)reverse
|
|
{
|
|
if ((self = [super init]))
|
|
{
|
|
numElements = 0;
|
|
currentElementIndex = 0;
|
|
|
|
// First get a count of the number of elements in the given list.
|
|
|
|
if (reverse)
|
|
{
|
|
for (DDListNode *node = list; node != NULL; node = node->prev)
|
|
{
|
|
numElements++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (DDListNode *node = list; node != NULL; node = node->next)
|
|
{
|
|
numElements++;
|
|
}
|
|
|
|
}
|
|
|
|
// Now copy the list into a C array.
|
|
|
|
if (numElements > 0)
|
|
{
|
|
elements = malloc(numElements * sizeof(void *));
|
|
|
|
DDListNode *node = list;
|
|
|
|
if (reverse)
|
|
{
|
|
for (NSUInteger i = 0; i < numElements; i++)
|
|
{
|
|
elements[i] = node->element;
|
|
node = node->prev;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (NSUInteger i = 0; i < numElements; i++)
|
|
{
|
|
elements[i] = node->element;
|
|
node = node->next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (NSUInteger)numTotal
|
|
{
|
|
return numElements;
|
|
}
|
|
|
|
- (NSUInteger)numLeft
|
|
{
|
|
if (currentElementIndex < numElements)
|
|
return numElements - currentElementIndex;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
- (void *)nextElement
|
|
{
|
|
if (currentElementIndex < numElements)
|
|
{
|
|
void *element = elements[currentElementIndex];
|
|
currentElementIndex++;
|
|
|
|
return element;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
if (elements)
|
|
{
|
|
free(elements);
|
|
}
|
|
}
|
|
|
|
@end
|