85 return ((n + 1) >> 1) - 1;
89typedef NSComparisonResult (*
CompareIMP)(
id self,
SEL _cmd,
id other);
95 NSComparisonResult result;
98 compare = (
CompareIMP)[a methodForSelector:comparator];
99 result = compare(a, comparator, b);
105@interface OOPriorityQueue (Private)
107- (void) makeObjectsPerformSelector:(
SEL)selector;
109- (void) bubbleUpFrom:(NSUInteger)i;
110- (void) bubbleDownFrom:(NSUInteger)i;
115- (void)removeObjectAtIndex:(NSUInteger)i;
118- (void) appendDebugDataToString:(NSMutableString *)string index:(NSUInteger)i depth:(NSUInteger)depth;
138+ (instancetype) queueWithComparator:(
SEL)comparator
140 return [[[
self alloc] initWithComparator:comparator] autorelease];
144- (id) initWithComparator:(
SEL)comparator
146 if (comparator == NULL)
155 _comparator = comparator;
164 return [
self initWithComparator:@selector(compare:)];
170 [
self makeObjectsPerformSelector:@selector(release)];
177- (NSString *) description
179 return [NSString stringWithFormat:@"<%@ %p>{count=%lu, capacity=%lu}", [
self class], self, _count, _capacity];
184- (NSString *) debugDescription
186 NSMutableString *result =
nil;
188 result = [NSMutableString string];
189 [result appendFormat:@"<%@ %p> (count=%lu, capacity=%lu, comparator=%@)", [
self class], self, _count, _capacity, NSStringFromSelector(_comparator)];
193 [result appendString:@"\n{\n"];
194 [
self appendDebugDataToString:result index:0 depth:0];
195 [result appendString:@"}"];
199 [result appendString:@" {}"];
206- (BOOL) isEqual:(
id)object
210 BOOL identical = YES;
212 if (
object ==
self)
return YES;
213 if (![
object isKindOfClass:[
self class]])
return NO;
215 if (_count != [
object count])
return NO;
216 if (_count == 0)
return YES;
218 selfCopy = [
self copy];
219 otherCopy = [object copy];
223 if (![[selfCopy nextObject] isEqual:[otherCopy nextObject]])
238 if (_count == 0)
return NSNotFound;
239 return _count ^ [_heap[0] hash];
243- (id) copyWithZone:(NSZone *)zone
247 copy = [[
self class] allocWithZone:zone];
254 copy->
_heap = malloc(_count *
sizeof(
id));
255 if (copy->
_heap != NULL)
257 memcpy(copy->
_heap, _heap, _count *
sizeof(
id));
260 else if (_count != 0)
271- (void) addObject:(
id)object
278 [NSException raise:NSInvalidArgumentException
279 format:@"Attempt to insert nil into OOPriorityQueue."];
282 if (![
object respondsToSelector:_comparator])
284 [NSException raise:NSInvalidArgumentException
285 format:@"Attempt to insert object (%@) which does not support comparator %@ into OOPriorityQueue.",
286 object, NSStringFromSelector(_comparator)];
290 if (_count == _capacity) [
self growBuffer];
296 [
self bubbleUpFrom:i];
301- (void) removeObject:(
id)object
310 if (
object ==
nil)
return;
312 for (i = 0; i < _count; ++i)
314 if (
PQCompare(
object, _heap[i], _comparator) == 0)
316 [
self removeObjectAtIndex:i];
322- (void) removeExactObject:(
id)object
326 if (
object ==
nil)
return;
328 for (i = 0; i < _count; ++i)
330 if (
object == _heap[i])
332 [
self removeObjectAtIndex:i];
346 id result = [
self peekAtNextObject];
347 [
self removeNextObject];
352- (id) peekAtNextObject
354 if (_count == 0)
return nil;
360- (void) removeNextObject
362 [
self removeObjectAtIndex:0];
366- (void) addObjects:(
id)collection
370 if ([collection respondsToSelector:
@selector(objectEnumerator)]) collection = [collection objectEnumerator];
371 if (![collection respondsToSelector:
@selector(nextObject)])
return;
373 while ((value = [collection nextObject])) [
self addObject:value];
377- (NSArray *) sortedObjects
379 return [[
self objectEnumerator] allObjects];
383- (NSEnumerator *) objectEnumerator
391@implementation OOPriorityQueue (Private)
393- (void) makeObjectsPerformSelector:(
SEL)selector
397 if (selector == NULL)
return;
399 for (i = 0; i != _count; ++i)
401 [_heap[i] performSelector:selector];
406- (void) bubbleUpFrom:(NSUInteger)i
417 if (
PQCompare(obj, par, _comparator) < 0)
428- (void) bubbleDownFrom:(NSUInteger)i
430 NSUInteger end = _count - 1;
431 NSUInteger li, ri, next;
441 if (li == end ||
PQCompare(_heap[li], _heap[ri], _comparator) < 0)
450 if (
PQCompare(_heap[next], obj, _comparator) < 0)
453 _heap[i] = _heap[next];
464 id *newBuffer = NULL;
465 NSUInteger newCapacity;
467 newCapacity = _capacity * 3 / 2;
471 newBuffer = realloc(_heap, newCapacity *
sizeof(
id));
472 if (newBuffer == NULL)
475 newCapacity = _capacity + 1;
476 newBuffer = realloc(_heap, newCapacity *
sizeof(
id));
478 if (newBuffer == NULL)
481 [NSException raise:NSMallocException
482 format:@"Could not expand capacity of OOPriorityQueue."];
487 _capacity = newCapacity;
489 assert(_count < _capacity);
495 NSUInteger amountToRemove;
496 id *newBuffer = NULL;
497 NSUInteger newCapacity;
502 amountToRemove = (_capacity - _count) * 2 / 3;
503 if (2 < amountToRemove)
505 newCapacity = _capacity - amountToRemove;
506 newBuffer = realloc(_heap, newCapacity *
sizeof(
id));
507 if (newBuffer != NULL)
510 _capacity = newCapacity;
517- (void)removeObjectAtIndex:(NSUInteger)i
521 if (_count <= i)
return;
527 _heap[i] = _heap[_count];
530 [
self bubbleDownFrom:i];
537 [object autorelease];
538 if (_count * 2 <= _capacity) [
self shrinkBuffer];
543- (void) appendDebugDataToString:(NSMutableString *)string index:(NSUInteger)i depth:(NSUInteger)depth
547 if (_count <= i)
return;
550 while (spaces--) [string appendString:@" "];
551 [string appendString:[_heap[i] description]];
552 [string appendString:@"\n"];
554 [
self appendDebugDataToString:string index:PQLeftChild(i) depth:depth + 1];
555 [
self appendDebugDataToString:string index:PQRightChild(i) depth:depth + 1];
575 _queue = [queue retain];
591 id value = [_queue nextObject];
605@implementation OOPriorityQueue (DebugGraphViz)
608static NSString *EscapedString(NSString *
string)
610 NSString *srcStrings[] =
613 @"\\",
@"\"", @"\
'", @"\r", @"\n", @"\t", nil
615 NSString *subStrings[] =
617 //Note: must be same order.
618 @"\\\\", @"\\\"", @"\\\'", @"\\r", @"\\n", @"\\t", nil
621 NSString **src = srcStrings, **sub = subStrings;
622 NSMutableString *mutable = nil;
623 NSString *result = nil;
625 mutable = [string mutableCopy];
628 [mutable replaceOccurrencesOfString:*src++
631 range:NSMakeRange(0, [mutable length])];
634 if ([mutable length] == [string length])
640 result = [[mutable copy] autorelease];
647- (NSString *) generateGraphViz
649 NSMutableString *result = nil;
652 NSString *desc = nil;
654 result = [NSMutableString string];
657 [result appendString:
658 @"// OOPriorityQueue partially ordered tree dump\n\n"
661 "\tgraph [charset=\"UTF-8\", label=\"OOPriorityQueue heap dump\", labelloc=t, labeljust=l];\n"
662 "\tnode [shape=record];\n\t\n\t"];
665 for (i = 0; i < _count; ++i)
668 desc = [node description];
669 if ([desc length] > 70)
671 desc = [[desc substringToIndex:64] stringByAppendingString:@"..."];
674 [result appendFormat:@"\tnode_%lu [label=\"<f0> | <f1> %@ | <f2>\"];\n", i, EscapedString(desc)];
678 for (i = 0; PQLeftChild(i) < _count; ++i)
680 [result appendFormat:@"\tnode_%lu:f0 -> node_%lu:f1;\n", i, PQLeftChild(i)];
681 if (PQRightChild(i) < _count) [result appendFormat:@"\tnode_%lu:f2 -> node_%lu:f1;\n", i, PQRightChild(i)];
684 [result appendString:@"}\n"];
690- (void) writeGraphVizToURL:(NSURL *)url
692 NSString *graphViz = nil;
695 graphViz = [self generateGraphViz];
696 data = [graphViz dataUsingEncoding:NSUTF8StringEncoding];
700 [data writeToURL:url atomically:YES];
705- (void) writeGraphVizToPath:(NSString *)path
707 [self writeGraphVizToURL:[NSURL fileURLWithPath:path]];
#define INLINE_CONST_FUNC
OOINLINE NSComparisonResult PQCompare(id a, id b, SEL comparator)
OOINLINE NSUInteger PQLeftChild(NSUInteger n) INLINE_CONST_FUNC
OOINLINE NSUInteger PQRightChild(NSUInteger n) INLINE_CONST_FUNC
OOINLINE NSUInteger PQParent(NSUInteger n) INLINE_CONST_FUNC
NSComparisonResult(* CompareIMP)(id self, SEL _cmd, id other)
void makeObjectsPerformSelector:(SEL selector)