#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