LCOV - code coverage report
Current view: top level - Core - OOPriorityQueue.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 24 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OOPriorityQueue.m
       4             : 
       5             : 
       6             : Copyright (C) 2007-2013 Jens Ayton
       7             : 
       8             : Permission is hereby granted, free of charge, to any person obtaining a copy
       9             : of this software and associated documentation files (the "Software"), to deal
      10             : in the Software without restriction, including without limitation the rights
      11             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12             : copies of the Software, and to permit persons to whom the Software is
      13             : furnished to do so, subject to the following conditions:
      14             : 
      15             : The above copyright notice and this permission notice shall be included in all
      16             : copies or substantial portions of the Software.
      17             : 
      18             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      24             : SOFTWARE.
      25             : 
      26             : */
      27             : 
      28             : #include <assert.h>
      29             : 
      30             : #import "OOPriorityQueue.h"
      31             : #import "OOFunctionAttributes.h"
      32             : 
      33             : 
      34             : /*      Capacity grows by 50% each time. kMinCapacity must be at least 2 or Bad
      35             :         Things will happen. Some examples of growth patterns based on kMinCapacity:
      36             :         2:      2  3  4  6  9  13  19  28  42  63  94  141  211  316  474  711  1066...
      37             :         4:      4  6  9  13  19  28  42  63  94  141  211  316  474  711  1066  1599...
      38             :         8:      8  12  18  27  40  60  90  135  202  303  454  681  1021  1531  2296...
      39             :         16:     16  24  36  54  81  121  181  271  406  609  913  1369  2053  3079...
      40             :         32:     32  48  72  108  162  243  364  546  819  1228  1842  2763  4144...
      41             :         
      42             :         Special cases: when an OOPriorityQueue is copied, the copy's capacity is
      43             :         set to the same as its count, which may be less than kMinCapacity. However,
      44             :         when it is grown, it will be set to at least kMinCapacity (except in the
      45             :         case of a reallocation failure, in which case an attempt will be made to
      46             :         grow capacity by one element).
      47             : */
      48           0 : enum
      49             : {
      50             :         kMinCapacity                            = 16
      51             : };
      52             : 
      53             : 
      54             : /*      Functions to navigate the binary heap.
      55             :         Using one-based indices, the following hold:
      56             :         * The left child of a node, L(n), is 2n.
      57             :         * The right child of a node, R(n), is 2n + 1.
      58             :         * The parent of a node, P(n), is n/2 for n > 1.
      59             :         
      60             :         Using zero-based indices, we must convert to and from one-based indices to
      61             :         perform these calculations, giving:
      62             :         * Lz(n) = L(n+1)-1 = (2(n+1))-1 = 2n+1
      63             :         * Rz(n) = R(n+1)-1 = (2(n+1)+1)-1 = 2n+2
      64             :         * Pz(n) = P(n+1)-1 = ((n+1)/2)-1
      65             : */
      66             : 
      67             : 
      68             : OOINLINE NSUInteger PQLeftChild(NSUInteger n) INLINE_CONST_FUNC;
      69             : OOINLINE NSUInteger PQRightChild(NSUInteger n) INLINE_CONST_FUNC;
      70             : OOINLINE NSUInteger PQParent(NSUInteger n) INLINE_CONST_FUNC;
      71             : 
      72           0 : OOINLINE NSUInteger PQLeftChild(NSUInteger n)
      73             : {
      74             :         return (n << 1) + 1;
      75             : }
      76             : 
      77           0 : OOINLINE NSUInteger PQRightChild(NSUInteger n)
      78             : {
      79             :         return (n << 1) + 2;
      80             : }
      81             : 
      82             : 
      83           0 : OOINLINE NSUInteger PQParent(NSUInteger n)
      84             : {
      85             :         return ((n + 1) >> 1) - 1;
      86             : }
      87             : 
      88             : 
      89           0 : typedef NSComparisonResult (*CompareIMP)(id self, SEL _cmd, id other);
      90             : 
      91             : 
      92           0 : OOINLINE NSComparisonResult PQCompare(id a, id b, SEL comparator)
      93             : {
      94             :         CompareIMP                              compare = NULL;
      95             :         NSComparisonResult              result;
      96             :         
      97             :         // This is equivalent to [a performSelector:comparator withObject:b], except the resulting value isn't an object.
      98             :         compare = (CompareIMP)[a methodForSelector:comparator];
      99             :         result = compare(a, comparator, b);
     100             :         return result;
     101             : }
     102             : 
     103             : 
     104             : // Private priority queue methods.
     105             : @interface OOPriorityQueue (Private)
     106             : 
     107           0 : - (void) makeObjectsPerformSelector:(SEL)selector;
     108             : 
     109           0 : - (void) bubbleUpFrom:(NSUInteger)i;
     110           0 : - (void) bubbleDownFrom:(NSUInteger)i;
     111             : 
     112           0 : - (void) growBuffer;
     113           0 : - (void) shrinkBuffer;
     114             : 
     115           0 : - (void)removeObjectAtIndex:(NSUInteger)i;
     116             : 
     117             : #if OO_DEBUG
     118             : - (void) appendDebugDataToString:(NSMutableString *)string index:(NSUInteger)i depth:(NSUInteger)depth;
     119             : #endif
     120             : 
     121             : @end
     122             : 
     123             : 
     124             : // NSEnumerator subclass to pull objects from queue.
     125           0 : @interface OOPriorityQueueEnumerator: NSEnumerator
     126             : {
     127             : @private
     128           0 :         OOPriorityQueue                 *_queue;
     129             : }
     130             : 
     131           0 : - (id) initWithPriorityQueue:(OOPriorityQueue *)queue;
     132             : 
     133             : @end
     134             : 
     135             : 
     136             : @implementation OOPriorityQueue
     137             : 
     138             : + (instancetype) queueWithComparator:(SEL)comparator
     139             : {
     140             :         return [[[self alloc] initWithComparator:comparator] autorelease];
     141             : }
     142             : 
     143             : 
     144             : - (id) initWithComparator:(SEL)comparator
     145             : {
     146             :         if (comparator == NULL)
     147             :         {
     148             :                 [self release];
     149             :                 return nil;
     150             :         }
     151             :         
     152             :         self = [super init];
     153             :         if (self != nil)
     154             :         {
     155             :                 _comparator = comparator;
     156             :         }
     157             :         
     158             :         return self;
     159             : }
     160             : 
     161             : 
     162           0 : - (id) init
     163             : {
     164             :         return [self initWithComparator:@selector(compare:)];
     165             : }
     166             : 
     167             : 
     168           0 : - (void) dealloc
     169             : {
     170             :         [self makeObjectsPerformSelector:@selector(release)];
     171             :         free(_heap);
     172             :         
     173             :         [super dealloc];
     174             : }
     175             : 
     176             : 
     177           0 : - (NSString *) description
     178             : {
     179             :         return [NSString stringWithFormat:@"<%@ %p>{count=%lu, capacity=%lu}", [self class], self, _count, _capacity];
     180             : }
     181             : 
     182             : 
     183             : #if OO_DEBUG
     184             : - (NSString *) debugDescription
     185             : {
     186             :         NSMutableString                         *result = nil;
     187             :         
     188             :         result = [NSMutableString string];
     189             :         [result appendFormat:@"<%@ %p> (count=%lu, capacity=%lu, comparator=%@)", [self class], self, _count, _capacity, NSStringFromSelector(_comparator)];
     190             :         
     191             :         if (_count != 0)
     192             :         {
     193             :                 [result appendString:@"\n{\n"];
     194             :                 [self appendDebugDataToString:result index:0 depth:0];
     195             :                 [result appendString:@"}"];
     196             :         }
     197             :         else
     198             :         {
     199             :                 [result appendString:@" {}"];
     200             :         }
     201             :         return result;
     202             : }
     203             : #endif
     204             : 
     205             : 
     206           0 : - (BOOL) isEqual:(id)object
     207             : {
     208             :         NSUInteger                                      i;
     209             :         OOPriorityQueue                         *selfCopy = nil, *otherCopy = nil;
     210             :         BOOL                                            identical = YES;
     211             :         
     212             :         if (object == self)  return YES;
     213             :         if (![object isKindOfClass:[self class]])  return NO;
     214             :         
     215             :         if (_count != [object count])  return NO;
     216             :         if (_count == 0)  return YES;
     217             :         
     218             :         selfCopy = [self copy];
     219             :         otherCopy = [object copy];
     220             :         i = _count;
     221             :         while (i--)
     222             :         {
     223             :                 if (![[selfCopy nextObject] isEqual:[otherCopy nextObject]])
     224             :                 {
     225             :                         identical = NO;
     226             :                         break;
     227             :                 }
     228             :         }
     229             :         [selfCopy release];
     230             :         [otherCopy release];
     231             :         
     232             :         return identical;
     233             : }
     234             : 
     235             : 
     236           0 : - (NSUInteger) hash
     237             : {
     238             :         if (_count == 0)  return NSNotFound;
     239             :         return _count ^ [_heap[0] hash];
     240             : }
     241             : 
     242             : 
     243           0 : - (id) copyWithZone:(NSZone *)zone
     244             : {
     245             :         OOPriorityQueue                         *copy = nil;
     246             :         
     247             :         copy = [[self class] allocWithZone:zone];
     248             :         if (copy != nil)
     249             :         {
     250             :                 copy->_comparator = _comparator;
     251             :                 copy->_count = _count;
     252             :                 copy->_capacity = _count;
     253             :                 
     254             :                 copy->_heap = malloc(_count * sizeof(id));
     255             :                 if (copy->_heap != NULL)
     256             :                 {
     257             :                         memcpy(copy->_heap, _heap, _count * sizeof(id));
     258             :                         [copy makeObjectsPerformSelector:@selector(retain)];
     259             :                 }
     260             :                 else  if (_count != 0)
     261             :                 {
     262             :                         [copy release];
     263             :                         copy = nil;
     264             :                 }
     265             :         }
     266             :         
     267             :         return copy;
     268             : }
     269             : 
     270             : 
     271             : - (void) addObject:(id)object
     272             : {
     273             :         NSUInteger                      i;
     274             :         
     275             :         // Validate object
     276             :         if (object == nil)
     277             :         {
     278             :                 [NSException raise:NSInvalidArgumentException
     279             :                                         format:@"Attempt to insert nil into OOPriorityQueue."];
     280             :         }
     281             :         
     282             :         if (![object respondsToSelector:_comparator])
     283             :         {
     284             :                 [NSException raise:NSInvalidArgumentException
     285             :                                         format:@"Attempt to insert object (%@) which does not support comparator %@ into OOPriorityQueue.",
     286             :                                                    object, NSStringFromSelector(_comparator)];
     287             :         }
     288             :         
     289             :         // Ensure there is sufficent space.
     290             :         if (_count == _capacity)  [self growBuffer];
     291             :         
     292             :         // insert object at end of buffer.
     293             :         i = _count++;
     294             :         _heap[i] = object;
     295             :         
     296             :         [self bubbleUpFrom:i];
     297             :         [object retain];
     298             : }
     299             : 
     300             : 
     301             : - (void) removeObject:(id)object
     302             : {
     303             :         NSUInteger                              i;
     304             :         
     305             :         /*      Perform linear search for object (using comparator). A depth-first
     306             :                 search could skip leaves of lower priority, but I don't expect this to
     307             :                 be called very often.
     308             :         */
     309             :         
     310             :         if (object == nil)  return;
     311             :         
     312             :         for (i = 0; i < _count; ++i)
     313             :         {
     314             :                 if (PQCompare(object, _heap[i], _comparator) == 0)
     315             :                 {
     316             :                         [self removeObjectAtIndex:i];
     317             :                 }
     318             :         }
     319             : }
     320             : 
     321             : 
     322             : - (void) removeExactObject:(id)object
     323             : {
     324             :         NSUInteger                              i;
     325             :         
     326             :         if (object == nil)  return;
     327             :         
     328             :         for (i = 0; i < _count; ++i)
     329             :         {
     330             :                 if (object == _heap[i])
     331             :                 {
     332             :                         [self removeObjectAtIndex:i];
     333             :                 }
     334             :         }
     335             : }
     336             : 
     337             : 
     338             : - (NSUInteger) count
     339             : {
     340             :         return _count;
     341             : }
     342             : 
     343             : 
     344             : - (id) nextObject
     345             : {
     346             :         id result = [self peekAtNextObject];
     347             :         [self removeNextObject];
     348             :         return result;
     349             : }
     350             : 
     351             : 
     352             : - (id) peekAtNextObject
     353             : {
     354             :         if (_count == 0)  return nil;
     355             : //      return [[_heap[0] retain] autorelease];
     356             :         return _heap[0];
     357             : }
     358             : 
     359             : 
     360             : - (void) removeNextObject
     361             : {
     362             :         [self removeObjectAtIndex:0];
     363             : }
     364             : 
     365             : 
     366             : - (void) addObjects:(id)collection
     367             : {
     368             :         id                                      value = nil;
     369             :         
     370             :         if ([collection respondsToSelector:@selector(objectEnumerator)])  collection = [collection objectEnumerator];
     371             :         if (![collection respondsToSelector:@selector(nextObject)])  return;
     372             :         
     373             :         while ((value = [collection nextObject]))  [self addObject:value];
     374             : }
     375             : 
     376             : 
     377             : - (NSArray *) sortedObjects
     378             : {
     379             :         return [[self objectEnumerator] allObjects];
     380             : }
     381             : 
     382             : 
     383             : - (NSEnumerator *) objectEnumerator
     384             : {
     385             :         return [[[OOPriorityQueueEnumerator alloc] initWithPriorityQueue:self] autorelease];
     386             : }
     387             : 
     388             : @end
     389             : 
     390             : 
     391             : @implementation OOPriorityQueue (Private)
     392             : 
     393             : - (void) makeObjectsPerformSelector:(SEL)selector
     394             : {
     395             :         NSUInteger                              i;
     396             :         
     397             :         if (selector == NULL)  return;
     398             :         
     399             :         for (i = 0; i != _count; ++i)
     400             :         {
     401             :                 [_heap[i] performSelector:selector];
     402             :         }
     403             : }
     404             : 
     405             : 
     406             : - (void) bubbleUpFrom:(NSUInteger)i
     407             : {
     408             :         NSUInteger                              pi;
     409             :         id                                              obj = nil, par = nil;
     410             :         
     411             :         while (0 < i)
     412             :         {
     413             :                 pi = PQParent(i);
     414             :                 obj = _heap[i];
     415             :                 par = _heap[pi];
     416             :                 
     417             :                 if (PQCompare(obj, par, _comparator) < 0)
     418             :                 {
     419             :                         _heap[i] = par;
     420             :                         _heap[pi] = obj;
     421             :                         i = pi;
     422             :                 }
     423             :                 else  break;
     424             :         }
     425             : }
     426             : 
     427             : 
     428             : - (void) bubbleDownFrom:(NSUInteger)i
     429             : {
     430             :         NSUInteger                              end = _count - 1;
     431             :         NSUInteger                              li, ri, next;
     432             :         id                                              obj = nil;
     433             :         
     434             :         obj = _heap[i];
     435             :         while (PQLeftChild(i) <= end)
     436             :         {
     437             :                 li = PQLeftChild(i);
     438             :                 ri = PQRightChild(i);
     439             :                 
     440             :                 // If left child has lower priority than right child, or there is only one child...
     441             :                 if (li == end || PQCompare(_heap[li], _heap[ri], _comparator) < 0)
     442             :                 {
     443             :                         next = li;
     444             :                 }
     445             :                 else
     446             :                 {
     447             :                         next = ri;
     448             :                 }
     449             :                 
     450             :                 if (PQCompare(_heap[next], obj, _comparator) < 0)
     451             :                 {
     452             :                         // Exchange parent with lowest-priority child
     453             :                         _heap[i] = _heap[next];
     454             :                         _heap[next] = obj;
     455             :                         i = next;
     456             :                 }
     457             :                 else  break;
     458             :         }
     459             : }
     460             : 
     461             : 
     462             : - (void) growBuffer
     463             : {
     464             :         id                                      *newBuffer = NULL;
     465             :         NSUInteger                      newCapacity;
     466             :         
     467             :         newCapacity = _capacity * 3 / 2;
     468             :         if (newCapacity < kMinCapacity)  newCapacity = kMinCapacity;
     469             :         
     470             :         // Note: realloc(NULL, size) with non-zero size is equivalent to malloc(size), so this is OK starting from a NULL buffer.
     471             :         newBuffer = realloc(_heap, newCapacity * sizeof(id));
     472             :         if (newBuffer == NULL)
     473             :         {
     474             :                 // Attempt to grow by just one waffer-thin slot.
     475             :                 newCapacity = _capacity + 1;
     476             :                 newBuffer = realloc(_heap, newCapacity * sizeof(id));
     477             :                 
     478             :                 if (newBuffer == NULL)
     479             :                 {
     480             :                         // Failed to grow.
     481             :                         [NSException raise:NSMallocException
     482             :                                                 format:@"Could not expand capacity of OOPriorityQueue."];
     483             :                 }
     484             :         }
     485             :         
     486             :         _heap = newBuffer;
     487             :         _capacity = newCapacity;
     488             :         
     489             :         assert(_count < _capacity);
     490             : }
     491             : 
     492             : 
     493             : - (void)shrinkBuffer
     494             : {
     495             :         NSUInteger                      amountToRemove;
     496             :         id                                      *newBuffer = NULL;
     497             :         NSUInteger                      newCapacity;
     498             :         
     499             :         if (kMinCapacity < _capacity)
     500             :         {
     501             :                 // Remove two thirds of free space, if at least three slots are free.
     502             :                 amountToRemove = (_capacity - _count) * 2 / 3;
     503             :                 if (2 < amountToRemove)
     504             :                 {
     505             :                         newCapacity = _capacity - amountToRemove;
     506             :                         newBuffer = realloc(_heap, newCapacity * sizeof(id));
     507             :                         if (newBuffer != NULL)
     508             :                         {
     509             :                                 _heap = newBuffer;
     510             :                                 _capacity = newCapacity;
     511             :                         }
     512             :                 }
     513             :         }
     514             : }
     515             : 
     516             : 
     517             : - (void)removeObjectAtIndex:(NSUInteger)i
     518             : {
     519             :         id                                      object = nil;
     520             :         
     521             :         if (_count <= i)  return;
     522             :         
     523             :         object = _heap[i];
     524             :         if (i < --_count)
     525             :         {
     526             :                 // Overwrite object with last object in array
     527             :                 _heap[i] = _heap[_count];
     528             :                 
     529             :                 // Push previously-last object down until tree is partially ordered.
     530             :                 [self bubbleDownFrom:i];
     531             :         }
     532             :         else
     533             :         {
     534             :                 // Special case: removing last (or only) object. No bubbling needed.
     535             :         }
     536             :         
     537             :         [object autorelease];
     538             :         if (_count * 2 <= _capacity)  [self shrinkBuffer];
     539             : }
     540             : 
     541             : 
     542             : #if OO_DEBUG
     543             : - (void) appendDebugDataToString:(NSMutableString *)string index:(NSUInteger)i depth:(NSUInteger)depth
     544             : {
     545             :         NSUInteger                              spaces;
     546             :         
     547             :         if (_count <= i)  return;
     548             :         
     549             :         spaces = 2 + depth;
     550             :         while (spaces--)  [string appendString:@"  "];
     551             :         [string appendString:[_heap[i] description]];
     552             :         [string appendString:@"\n"];
     553             :         
     554             :         [self appendDebugDataToString:string index:PQLeftChild(i) depth:depth + 1];
     555             :         [self appendDebugDataToString:string index:PQRightChild(i) depth:depth + 1];
     556             : }
     557             : #endif
     558             : 
     559             : @end
     560             : 
     561             : 
     562             : @implementation OOPriorityQueueEnumerator
     563             : 
     564             : - (id) initWithPriorityQueue:(OOPriorityQueue *)queue
     565             : {
     566             :         if (queue == nil)
     567             :         {
     568             :                 [self release];
     569             :                 return nil;
     570             :         }
     571             :         
     572             :         self = [super init];
     573             :         if (self != nil)
     574             :         {
     575             :                 _queue = [queue retain];
     576             :         }
     577             :         return self;
     578             : }
     579             : 
     580             : 
     581           0 : - (void) dealloc
     582             : {
     583             :         [_queue release];
     584             :         
     585             :         [super dealloc];
     586             : }
     587             : 
     588             : 
     589           0 : - (id) nextObject
     590             : {
     591             :         id value = [_queue nextObject];
     592             :         if (value == nil)
     593             :         {
     594             :                 // Maintain enumerator semantics by ensuring we don't start returning new values after returning nil.
     595             :                 [_queue release];
     596             :                 _queue = nil;
     597             :         }
     598             :         return value;
     599             : }
     600             : 
     601             : @end
     602             : 
     603             : 
     604             : #if DEBUG_GRAPHVIZ
     605             : @implementation OOPriorityQueue (DebugGraphViz)
     606             : 
     607             : 
     608             : static NSString *EscapedString(NSString *string)
     609             : {
     610             :         NSString                                *srcStrings[] =
     611             :         {
     612             :                 //Note: backslash must be first.
     613             :                 @"\\", @"\"", @"\'", @"\r", @"\n", @"\t", nil
     614             :         };
     615             :         NSString                                *subStrings[] =
     616             :         {
     617             :                 //Note: must be same order.
     618             :                 @"\\\\", @"\\\"", @"\\\'", @"\\r", @"\\n", @"\\t", nil
     619             :         };
     620             :         
     621             :         NSString                                **src = srcStrings, **sub = subStrings;
     622             :         NSMutableString                 *mutable = nil;
     623             :         NSString                                *result = nil;
     624             :         
     625             :         mutable = [string mutableCopy];
     626             :         while (*src != nil)
     627             :         {
     628             :                 [mutable replaceOccurrencesOfString:*src++
     629             :                                                                 withString:*sub++
     630             :                                                                    options:0
     631             :                                                                          range:NSMakeRange(0, [mutable length])];
     632             :         }
     633             :         
     634             :         if ([mutable length] == [string length])
     635             :         {
     636             :                 result = string;
     637             :         }
     638             :         else
     639             :         {
     640             :                 result = [[mutable copy] autorelease];
     641             :         }
     642             :         [mutable release];
     643             :         return result;
     644             : }
     645             : 
     646             : 
     647             : - (NSString *) generateGraphViz
     648             : {
     649             :         NSMutableString                 *result = nil;
     650             :         NSUInteger                              i;
     651             :         id                                              node = nil;
     652             :         NSString                                *desc = nil;
     653             :         
     654             :         result = [NSMutableString string];
     655             :         
     656             :         // Header
     657             :         [result appendString:
     658             :                 @"// OOPriorityQueue partially ordered tree dump\n\n"
     659             :                 "digraph heap\n"
     660             :                 "{\n"
     661             :                 "\tgraph [charset=\"UTF-8\", label=\"OOPriorityQueue heap dump\", labelloc=t, labeljust=l];\n"
     662             :                 "\tnode [shape=record];\n\t\n\t"];
     663             :         
     664             :         // Nodes
     665             :         for (i = 0; i < _count; ++i)
     666             :         {
     667             :                 node = _heap[i];
     668             :                 desc = [node description];
     669             :                 if ([desc length] > 70)
     670             :                 {
     671             :                         desc = [[desc substringToIndex:64] stringByAppendingString:@"..."];
     672             :                 }
     673             :                 
     674             :                 [result appendFormat:@"\tnode_%lu [label=\"<f0> | <f1> %@ | <f2>\"];\n", i, EscapedString(desc)];
     675             :         }
     676             :         
     677             :         // Arcs
     678             :         for (i = 0; PQLeftChild(i) < _count; ++i)
     679             :                 {
     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)];
     682             :         }
     683             :         
     684             :         [result appendString:@"}\n"];
     685             :         
     686             :         return result;
     687             : }
     688             : 
     689             : 
     690             : - (void) writeGraphVizToURL:(NSURL *)url
     691             : {
     692             :         NSString                        *graphViz = nil;
     693             :         NSData                          *data = nil;
     694             :         
     695             :         graphViz = [self generateGraphViz];
     696             :         data = [graphViz dataUsingEncoding:NSUTF8StringEncoding];
     697             :         
     698             :         if (data != nil)
     699             :         {
     700             :                 [data writeToURL:url atomically:YES];
     701             :         }
     702             : }
     703             : 
     704             : 
     705             : - (void) writeGraphVizToPath:(NSString *)path
     706             : {
     707             :         [self writeGraphVizToURL:[NSURL fileURLWithPath:path]];
     708             : }
     709             : 
     710             : @end
     711             : #endif

Generated by: LCOV version 1.14