git.y1.nz

SameBoy

Accurate GB/GBC emulator
download: https://git.y1.nz/archives/sameboy.tar.gz
README | Files | Log | Refs | LICENSE

HexFiend/HFFunctions.h

      1 /* Functions and convenience methods for working with HFTypes */
      2 
      3 #import <HexFiend/HFTypes.h>
      4 #import <libkern/OSAtomic.h>
      5 
      6 #define HFDEFAULT_FONT (@"Monaco")
      7 #define HFDEFAULT_FONTSIZE ((CGFloat)11.)
      8 
      9 #define HFZeroRange (HFRange){0, 0}
     10 
     11 /*!
     12   Makes an HFRange.  An HFRange is like an NSRange except it uses unsigned long longs.
     13 */
     14 static inline HFRange HFRangeMake(unsigned long long loc, unsigned long long len) {
     15     return (HFRange){loc, len};
     16 }
     17 
     18 /*!
     19   Returns true if a given location is within a given HFRange.  If the location is at the end of the range (range.location + range.length) this returns NO.
     20 */
     21 static inline BOOL HFLocationInRange(unsigned long long location, HFRange range) {
     22     return location >= range.location && location - range.location < range.length;
     23 }
     24 
     25 /*!
     26   Like NSRangeToString but for HFRanges
     27 */
     28 static inline NSString* HFRangeToString(HFRange range) {
     29     return [NSString stringWithFormat:@"{%llu, %llu}", range.location, range.length];
     30 }
     31 
     32 /*!
     33   Converts a given HFFPRange to a string.
     34 */
     35 static inline NSString* HFFPRangeToString(HFFPRange range) {
     36     return [NSString stringWithFormat:@"{%Lf, %Lf}", range.location, range.length];
     37 }
     38 
     39 /*!
     40   Returns true if two HFRanges are equal.
     41 */
     42 static inline BOOL HFRangeEqualsRange(HFRange a, HFRange b) {
     43     return a.location == b.location && a.length == b.length;
     44 }
     45 
     46 /*!
     47   Returns true if a + b does not overflow an unsigned long long.
     48 */
     49 static inline BOOL HFSumDoesNotOverflow(unsigned long long a, unsigned long long b) {
     50     return a + b >= a;
     51 }
     52 
     53 /*!
     54   Returns true if a * b does not overflow an unsigned long long.
     55 */
     56 static inline BOOL HFProductDoesNotOverflow(unsigned long long a, unsigned long long b) {
     57     if (b == 0) return YES;
     58     unsigned long long result = a * b;
     59     return result / b == a;
     60 }
     61 
     62 /*!
     63   Returns a * b as an NSUInteger.  This asserts on overflow, unless NDEBUG is defined.
     64 */
     65 static inline NSUInteger HFProductInt(NSUInteger a, NSUInteger b) {
     66     NSUInteger result = a * b;
     67     assert(a == 0 || result / a == b); //detect overflow
     68     return result;
     69 }
     70 
     71 /*!
     72   Returns a + b as an NSUInteger.  This asserts on overflow unless NDEBUG is defined.
     73 */
     74 static inline NSUInteger HFSumInt(NSUInteger a, NSUInteger b) {
     75 	assert(a + b >= a);
     76 	return a + b;
     77 }
     78 
     79 /*!
     80  Returns a + b as an NSUInteger, saturating at NSUIntegerMax
     81  */
     82 static inline NSUInteger HFSumIntSaturate(NSUInteger a, NSUInteger b) {
     83     NSUInteger result = a + b;
     84     return (result < a) ? NSUIntegerMax : result;
     85 }
     86 
     87 /*!
     88  Returns a + b as an unsigned long long, saturating at ULLONG_MAX
     89  */
     90 static inline unsigned long long HFSumULLSaturate(unsigned long long a, unsigned long long b) {
     91     unsigned long long result = a + b;
     92     return (result < a) ? ULLONG_MAX : result;
     93 }
     94 
     95 /*!
     96   Returns a * b as an unsigned long long.  This asserts on overflow, unless NDEBUG is defined.
     97 */
     98 static inline unsigned long long HFProductULL(unsigned long long a, unsigned long long b) {
     99     unsigned long long result = a * b;
    100     assert(HFProductDoesNotOverflow(a, b)); //detect overflow
    101     return result;
    102 }
    103 
    104 /*!
    105   Returns a + b as an unsigned long long.  This asserts on overflow, unless NDEBUG is defined.
    106 */
    107 static inline unsigned long long HFSum(unsigned long long a, unsigned long long b) {
    108     assert(HFSumDoesNotOverflow(a, b));
    109     return a + b;
    110 }
    111 
    112 /*!
    113  Returns a + b as an unsigned long long.  This asserts on overflow, unless NDEBUG is defined.
    114  */
    115 static inline unsigned long long HFMaxULL(unsigned long long a, unsigned long long b) {
    116     return a < b ? b : a;
    117 }
    118 
    119 /*!
    120   Returns a - b as an unsigned long long.  This asserts on underflow (if b > a), unless NDEBUG is defined.
    121 */
    122 static inline unsigned long long HFSubtract(unsigned long long a, unsigned long long b) {
    123     assert(a >= b);
    124     return a - b;
    125 }
    126 
    127 /*!
    128   Returns the smallest multiple of B that is equal to or larger than A, and asserts on overflow.
    129 */
    130 static inline unsigned long long HFRoundUpToMultiple(unsigned long long a, unsigned long long b) {
    131     // The usual approach of ((a + (b - 1)) / b) * b doesn't handle overflow correctly
    132     unsigned long long remainder = a % b;
    133     if (remainder == 0) return a;
    134     else return HFSum(a, b - remainder);
    135 }
    136 
    137 /*!
    138  Returns the smallest multiple of B that is equal to or larger than A, and asserts on overflow.
    139  */
    140 static inline NSUInteger HFRoundUpToMultipleInt(NSUInteger a, NSUInteger b) {
    141     // The usual approach of ((a + (b - 1)) / b) * b doesn't handle overflow correctly
    142     NSUInteger remainder = a % b;
    143     if (remainder == 0) return a;
    144     else return (NSUInteger)HFSum(a, b - remainder);
    145 }
    146 
    147 /*!
    148  Returns the least common multiple of A and B, and asserts on overflow or if A or B is zero.
    149  */
    150 static inline NSUInteger HFLeastCommonMultiple(NSUInteger a, NSUInteger b) {
    151     assert(a > 0);
    152     assert(b > 0);
    153     
    154     /* Compute GCD.  It ends up in U. */
    155     NSUInteger t, u = a, v = b;
    156     while (v > 0) {
    157         t = v;
    158         v = u % v;
    159         u = t;
    160     }
    161     
    162     /* Return the product divided by the GCD, in an overflow safe manner */
    163     return HFProductInt(a/u, b);
    164 }
    165 
    166 
    167 /*!
    168  Returns the smallest multiple of B strictly larger than A, or ULLONG_MAX if it would overflow
    169 */
    170 static inline unsigned long long HFRoundUpToNextMultipleSaturate(unsigned long long a, unsigned long long b) {
    171     assert(b > 0);
    172     unsigned long long result = a + (b - a % b);
    173     if (result < a) result = ULLONG_MAX; //the saturation...on overflow go to the max
    174     return result;
    175 }
    176 
    177 /*! Like NSMaxRange, but for an HFRange. */
    178 static inline unsigned long long HFMaxRange(HFRange a) {
    179     assert(HFSumDoesNotOverflow(a.location, a.length));
    180     return a.location + a.length;
    181 }
    182 
    183 /*! Returns YES if needle is fully contained within haystack.  Equal ranges are always considered to be subranges of each other (even if they are empty).  Furthermore, a zero length needle at the end of haystack is considered a subrange - for example, {6, 0} is a subrange of {3, 3}. */
    184 static inline BOOL HFRangeIsSubrangeOfRange(HFRange needle, HFRange haystack) {
    185     // If needle starts before haystack, or if needle is longer than haystack, it is not a subrange of haystack
    186     if (needle.location < haystack.location || needle.length > haystack.length) return NO;
    187     
    188     // Their difference in lengths determines the maximum difference in their start locations.  We know that these expressions cannot overflow because of the above checks.
    189     return haystack.length - needle.length >= needle.location - haystack.location;
    190 }
    191 
    192 /*! Splits a range about a subrange, returning by reference the prefix and suffix (which may have length zero). */
    193 static inline void HFRangeSplitAboutSubrange(HFRange range, HFRange subrange, HFRange *outPrefix, HFRange *outSuffix) {
    194     // Requires it to be a subrange
    195     assert(HFRangeIsSubrangeOfRange(subrange, range));
    196     outPrefix->location = range.location;
    197     outPrefix->length = HFSubtract(subrange.location, range.location);
    198     outSuffix->location = HFMaxRange(subrange);
    199     outSuffix->length = HFMaxRange(range) - outSuffix->location;
    200 }
    201 
    202 /*! Returns YES if the given ranges intersect. Two ranges are considered to intersect if they share at least one index in common.  Thus, zero-length ranges do not intersect anything. */
    203 static inline BOOL HFIntersectsRange(HFRange a, HFRange b) {
    204     // Ranges are said to intersect if they share at least one value.  Therefore, zero length ranges never intersect anything.
    205     if (a.length == 0 || b.length == 0) return NO;
    206     
    207     // rearrange (a.location < b.location + b.length && b.location < a.location + a.length) to not overflow
    208     // = ! (a.location >= b.location + b.length || b.location >= a.location + a.length)
    209     BOOL clause1 = (a.location >= b.location && a.location - b.location >= b.length);
    210     BOOL clause2 = (b.location >= a.location && b.location - a.location >= a.length);
    211     return ! (clause1 || clause2);
    212 }
    213 
    214 /*! Returns YES if the given ranges intersect. Two ranges are considered to intersect if any fraction overlaps; zero-length ranges do not intersect anything. */
    215 static inline BOOL HFFPIntersectsRange(HFFPRange a, HFFPRange b) {
    216     // Ranges are said to intersect if they share at least one value.  Therefore, zero length ranges never intersect anything.
    217     if (a.length == 0 || b.length == 0) return NO;
    218     
    219     if (a.location <= b.location && a.location + a.length >= b.location) return YES;
    220     if (b.location <= a.location && b.location + b.length >= a.location) return YES;
    221     return NO;
    222 }
    223 
    224 /*! Returns a range containing the union of the given ranges.  These ranges must either intersect or be adjacent: there cannot be any "holes" between them. */
    225 static inline HFRange HFUnionRange(HFRange a, HFRange b) {
    226     assert(HFIntersectsRange(a, b) || HFMaxRange(a) == b.location || HFMaxRange(b) == a.location);
    227     HFRange result;
    228     result.location = MIN(a.location, b.location);
    229     assert(HFSumDoesNotOverflow(a.location, a.length));
    230     assert(HFSumDoesNotOverflow(b.location, b.length));
    231     result.length = MAX(a.location + a.length, b.location + b.length) - result.location;
    232     return result;
    233 }
    234 
    235 
    236 /*! Returns whether a+b > c+d, as if there were no overflow (so ULLONG_MAX + 1 > 10 + 20) */
    237 static inline BOOL HFSumIsLargerThanSum(unsigned long long a, unsigned long long b, unsigned long long c, unsigned long long d) {
    238 #if 1
    239     // Theory: compare a/2 + b/2 to c/2 + d/2, and if they're equal, compare a%2 + b%2 to c%2 + d%2.  We may get into trouble if a and b are both even and c and d are both odd: e.g. a = 2, b = 2, c = 1, d = 3.  We would compare 1 + 1 vs 0 + 1, and therefore that 2 + 2 > 1 + 3.  To address this, if both remainders are 1, we add this to the sum.  We know this cannot overflow because ULLONG_MAX is odd, so (ULLONG_MAX/2) + (ULLONG_MAX/2) + 1 does not overflow.
    240     unsigned int rem1 = (unsigned)(a%2 + b%2);
    241     unsigned int rem2 = (unsigned)(c%2 + d%2);
    242     unsigned long long sum1 = a/2 + b/2 + rem1/2;
    243     unsigned long long sum2 = c/2 + d/2 + rem2/2;
    244     if (sum1 > sum2) return YES;
    245     else if (sum1 < sum2) return NO;
    246     else {
    247         // sum1 == sum2, so compare the remainders.  But we have already added in the remainder / 2, so compare the remainders mod 2.
    248         if (rem1%2 > rem2%2) return YES;
    249         else return NO;
    250     }
    251 #else
    252     /* Faster version, but not thoroughly tested yet. */
    253     unsigned long long xor1 = a^b;
    254     unsigned long long xor2 = c^d;
    255     unsigned long long avg1 = (a&b)+(xor1/2);
    256     unsigned long long avg2 = (c&d)+(xor2/2);
    257     unsigned s1l = avg1 > avg2;
    258     unsigned eq = (avg1 == avg2);
    259     return s1l | ((xor1 & ~xor2) & eq);
    260 #endif
    261 }
    262 
    263 /*! Returns the absolute value of a - b. */
    264 static inline unsigned long long HFAbsoluteDifference(unsigned long long a, unsigned long long b) {
    265     if (a > b) return a - b;
    266     else return b - a;
    267 }
    268 
    269 /*! Returns true if the end of A is larger than the end of B. */
    270 static inline BOOL HFRangeExtendsPastRange(HFRange a, HFRange b) {
    271     return HFSumIsLargerThanSum(a.location, a.length, b.location, b.length);
    272 }
    273 
    274 /*! Returns a range containing all indexes in common betwen the two ranges.  If there are no indexes in common, returns {0, 0}. */
    275 static inline HFRange HFIntersectionRange(HFRange range1, HFRange range2) {
    276     unsigned long long minend = HFRangeExtendsPastRange(range2, range1) ? range1.location + range1.length : range2.location + range2.length;
    277     if (range2.location <= range1.location && range1.location - range2.location < range2.length) {
    278 	return HFRangeMake(range1.location, minend - range1.location);
    279     }
    280     else if (range1.location <= range2.location && range2.location - range1.location < range1.length) {
    281 	return HFRangeMake(range2.location, minend - range2.location);
    282     }
    283     return HFRangeMake(0, 0);
    284 }
    285 
    286 /*! ceil() for a CGFloat, for compatibility with OSes that do not have the CG versions.  */
    287 static inline CGFloat HFCeil(CGFloat a) {
    288     if (sizeof(a) == sizeof(float)) return (CGFloat)ceilf((float)a);
    289     else return (CGFloat)ceil((double)a);
    290 }
    291 
    292 /*! floor() for a CGFloat, for compatibility with OSes that do not have the CG versions.  */
    293 static inline CGFloat HFFloor(CGFloat a) {
    294     if (sizeof(a) == sizeof(float)) return (CGFloat)floorf((float)a);
    295     else return (CGFloat)floor((double)a);
    296 }
    297 
    298 /*! round() for a CGFloat, for compatibility with OSes that do not have the CG versions.  */
    299 static inline CGFloat HFRound(CGFloat a) {
    300     if (sizeof(a) == sizeof(float)) return (CGFloat)roundf((float)a);
    301     else return (CGFloat)round((double)a);
    302 }
    303 
    304 /*! fmin() for a CGFloat, for compatibility with OSes that do not have the CG versions.  */
    305 static inline CGFloat HFMin(CGFloat a, CGFloat b) {
    306     if (sizeof(a) == sizeof(float)) return (CGFloat)fminf((float)a, (float)b);
    307     else return (CGFloat)fmin((double)a, (double)b);    
    308 }
    309 
    310 /*! fmax() for a CGFloat, for compatibility with OSes that do not have the CG versions.  */
    311 static inline CGFloat HFMax(CGFloat a, CGFloat b) {
    312     if (sizeof(a) == sizeof(float)) return (CGFloat)fmaxf((float)a, (float)b);
    313     else return (CGFloat)fmax((double)a, (double)b);    
    314 }
    315 
    316 /*! Returns true if the given HFFPRanges are equal.  */
    317 static inline BOOL HFFPRangeEqualsRange(HFFPRange a, HFFPRange b) {
    318     return a.location == b.location && a.length == b.length;
    319 }
    320 
    321 /*! copysign() for a CGFloat */
    322 static inline CGFloat HFCopysign(CGFloat a, CGFloat b) {
    323 #if CGFLOAT_IS_DOUBLE
    324     return copysign(a, b);
    325 #else
    326     return copysignf(a, b);
    327 #endif
    328 }
    329 
    330 /*! Atomically increments an NSUInteger, returning the new value.  Optionally invokes a memory barrier. */
    331 static inline NSUInteger HFAtomicIncrement(volatile NSUInteger *ptr, BOOL barrier) {
    332     return _Generic(ptr,
    333         volatile unsigned *:           (barrier ? OSAtomicIncrement32Barrier : OSAtomicIncrement32)((volatile int32_t *)ptr),
    334 #if ULONG_MAX == UINT32_MAX
    335         volatile unsigned long *:      (barrier ? OSAtomicIncrement32Barrier : OSAtomicIncrement32)((volatile int32_t *)ptr),
    336 #else
    337         volatile unsigned long *:      (barrier ? OSAtomicIncrement64Barrier : OSAtomicIncrement64)((volatile int64_t *)ptr),
    338 #endif
    339         volatile unsigned long long *: (barrier ? OSAtomicIncrement64Barrier : OSAtomicIncrement64)((volatile int64_t *)ptr));
    340 }
    341 
    342 /*! Atomically decrements an NSUInteger, returning the new value.  Optionally invokes a memory barrier. */
    343 static inline NSUInteger HFAtomicDecrement(volatile NSUInteger *ptr, BOOL barrier) {
    344     return _Generic(ptr,
    345         volatile unsigned *:           (barrier ? OSAtomicDecrement32Barrier : OSAtomicDecrement32)((volatile int32_t *)ptr),
    346 #if ULONG_MAX == UINT32_MAX
    347         volatile unsigned long *:      (barrier ? OSAtomicDecrement32Barrier : OSAtomicDecrement32)((volatile int32_t *)ptr),
    348 #else
    349         volatile unsigned long *:      (barrier ? OSAtomicDecrement64Barrier : OSAtomicDecrement64)((volatile int64_t *)ptr),
    350 #endif
    351         volatile unsigned long long *: (barrier ? OSAtomicDecrement64Barrier : OSAtomicDecrement64)((volatile int64_t *)ptr));
    352 }
    353 
    354 /*! Converts a long double to unsigned long long.  Assumes that val is already an integer - use floorl or ceill */
    355 static inline unsigned long long HFFPToUL(long double val) {
    356     assert(val >= 0);
    357     assert(val <= ULLONG_MAX);
    358     unsigned long long result = (unsigned long long)val;
    359     assert((long double)result == val);
    360     return result;
    361 }
    362 
    363 /*! Converts an unsigned long long to a long double. */
    364 static inline long double HFULToFP(unsigned long long val) {
    365     long double result = (long double)val;
    366     assert(HFFPToUL(result) == val);
    367     return result;
    368 }
    369 
    370 /*! Convenience to return information about a CGAffineTransform for logging. */
    371 static inline NSString *HFDescribeAffineTransform(CGAffineTransform t) {
    372     return [NSString stringWithFormat:@"%f %f 0\n%f %f 0\n%f %f 1", t.a, t.b, t.c, t.d, t.tx, t.ty];
    373 }
    374 
    375 /*! Returns 1 + floor(log base 10 of val).  If val is 0, returns 1. */
    376 static inline NSUInteger HFCountDigitsBase10(unsigned long long val) {
    377     const unsigned long long kValues[] = {0ULL, 9ULL, 99ULL, 999ULL, 9999ULL, 99999ULL, 999999ULL, 9999999ULL, 99999999ULL, 999999999ULL, 9999999999ULL, 99999999999ULL, 999999999999ULL, 9999999999999ULL, 99999999999999ULL, 999999999999999ULL, 9999999999999999ULL, 99999999999999999ULL, 999999999999999999ULL, 9999999999999999999ULL};
    378     NSUInteger low = 0, high = sizeof kValues / sizeof *kValues;
    379     while (high > low) {
    380         NSUInteger mid = (low + high)/2; //low + high cannot overflow
    381         if (val > kValues[mid]) {
    382             low = mid + 1;
    383         }
    384         else {
    385             high = mid;
    386         }
    387     }
    388     return MAX(1u, low);
    389 }
    390 
    391 /*! Returns 1 + floor(log base 16 of val).  If val is 0, returns 1.  This works by computing the log base 2 based on the number of leading zeros, and then dividing by 4. */
    392 static inline NSUInteger HFCountDigitsBase16(unsigned long long val) {
    393     /* __builtin_clzll doesn't like being passed 0 */
    394     if (val == 0) return 1;
    395     
    396     /* Compute the log base 2 */
    397     NSUInteger leadingZeros = (NSUInteger)__builtin_clzll(val);
    398     NSUInteger logBase2 = (CHAR_BIT * sizeof val) - leadingZeros - 1;
    399     return 1 + logBase2/4;
    400 }
    401 
    402 /*! Returns YES if the given string encoding is a superset of ASCII. */
    403 BOOL HFStringEncodingIsSupersetOfASCII(NSStringEncoding encoding);
    404 
    405 /*! Returns the "granularity" of an encoding, in bytes.  ASCII is 1, UTF-16 is 2, etc.  Variable width encodings return the smallest (e.g. Shift-JIS returns 1). */
    406 uint8_t HFStringEncodingCharacterLength(NSStringEncoding encoding);
    407 
    408 /*! Converts an unsigned long long to NSUInteger.  The unsigned long long should be no more than ULONG_MAX. */
    409 static inline NSUInteger ll2l(unsigned long long val) { assert(val <= ULONG_MAX); return (unsigned long)val; }
    410 
    411 /*! Converts an unsigned long long to uintptr_t.  The unsigned long long should be no more than UINTPTR_MAX. */
    412 static inline uintptr_t ll2p(unsigned long long val) { assert(val <= UINTPTR_MAX); return (uintptr_t)val; }
    413 
    414 /*! Returns an unsigned long long, which must be no more than ULLONG_MAX, as an unsigned long. */
    415 static inline CGFloat ld2f(long double val) {
    416 #if ! NDEBUG
    417      if (isfinite(val)) {
    418         assert(val <= CGFLOAT_MAX);
    419         assert(val >= -CGFLOAT_MAX);
    420         if ((val > 0 && val < CGFLOAT_MIN) || (val < 0 && val > -CGFLOAT_MIN)) {
    421             NSLog(@"Warning - conversion of long double %Lf to CGFloat will result in the non-normal CGFloat %f", val, (CGFloat)val);
    422         }
    423      }
    424 #endif
    425     return (CGFloat)val;
    426 }
    427 
    428 /*! Returns the quotient of a divided by b, rounding up, for unsigned long longs.  Will not overflow. */
    429 static inline unsigned long long HFDivideULLRoundingUp(unsigned long long a, unsigned long long b) {
    430     if (a == 0) return 0;
    431     else return ((a - 1) / b) + 1;
    432 }
    433 
    434 /*! Returns the quotient of a divided by b, rounding up, for NSUIntegers.  Will not overflow. */
    435 static inline NSUInteger HFDivideULRoundingUp(NSUInteger a, NSUInteger b) {
    436     if (a == 0) return 0;
    437     else return ((a - 1) / b) + 1;
    438 }
    439 
    440 /*! Draws a shadow. */
    441 void HFDrawShadow(CGContextRef context, NSRect rect, CGFloat size, NSRectEdge rectEdge, BOOL active, NSRect clip);
    442 
    443 /*! Registers a view to have the given notificationSEL invoked (taking the NSNotification object) when the window becomes or loses key.  If appToo is YES, this also registers with NSApplication for Activate and Deactivate methods. */
    444 void HFRegisterViewForWindowAppearanceChanges(NSView *view, SEL notificationSEL, BOOL appToo);
    445 
    446 /*! Unregisters a view to have the given notificationSEL invoked when the window becomes or loses key.  If appToo is YES, this also unregisters with NSApplication. */
    447 void HFUnregisterViewForWindowAppearanceChanges(NSView *view, BOOL appToo);
    448 
    449 /*! Returns a description of the given byte count (e.g. "24 kilobytes") */
    450 NSString *HFDescribeByteCount(unsigned long long count);
    451 
    452 /*! @brief An object wrapper for the HFRange type.
    453 
    454   A simple class responsible for holding an immutable HFRange as an object.  Methods that logically work on multiple HFRanges usually take or return arrays of HFRangeWrappers. */
    455 @interface HFRangeWrapper : NSObject <NSCopying> {
    456     @public
    457     HFRange range;
    458 }
    459 
    460 /*! Returns the HFRange for this HFRangeWrapper. */
    461 - (HFRange)HFRange;
    462 
    463 /*! Creates an autoreleased HFRangeWrapper for this HFRange. */
    464 + (HFRangeWrapper *)withRange:(HFRange)range;
    465 
    466 /*! Creates an NSArray of HFRangeWrappers for this HFRange. */
    467 + (NSArray *)withRanges:(const HFRange *)ranges count:(NSUInteger)count;
    468 
    469 /*! Given an NSArray of HFRangeWrappers, get all of the HFRanges into a C array. */
    470 + (void)getRanges:(HFRange *)ranges fromArray:(NSArray *)array;
    471 
    472 /*! Given an array of HFRangeWrappers, returns a "cleaned up" array of equivalent ranges.  This new array represents the same indexes, but overlapping ranges will have been merged, and the ranges will be sorted in ascending order. */
    473 + (NSArray *)organizeAndMergeRanges:(NSArray *)inputRanges;
    474 
    475 @end
    476 
    477 /*! @brief A set of HFRanges. HFRangeSet takes the interpetation that all zero-length ranges are identical.
    478  
    479  Essentially, a mutable array of ranges that is maintained to be sorted and minimized (i.e. merged with overlapping neighbors).
    480  
    481  TODO: The HexFiend codebase currently uses arrays of HFRangeWrappers that have been run through organizeAndMergeRanges:, and not HFRangeSet. The advantage of HFRangeSet is that the sorting & merging is implied by the type, instead of just tacitly assumed. This should lead to less confusion and fewer extra applications of organizeAndMergeRanges.
    482  
    483  TODO: HFRangeSet needs to be tested! I guarantee it has bugs! (Which doesn't matter right now because it's all dead code...)
    484  */
    485 @interface HFRangeSet : NSObject <NSCopying, NSSecureCoding, NSFastEnumeration> {
    486     @private
    487     CFMutableArrayRef array;
    488 }
    489 
    490 /*! Create a range set with just one range. */
    491 + (HFRangeSet *)withRange:(HFRange)range;
    492 
    493 /*! Create a range set with a C array of ranges. No prior sorting is necessary. */
    494 + (HFRangeSet *)withRanges:(const HFRange *)ranges count:(NSUInteger)count;
    495 
    496 /*! Create a range set with an array of HFRangeWrappers. No prior sorting is necessary. */
    497 + (HFRangeSet *)withRangeWrappers:(NSArray *)ranges;
    498 
    499 /*! Create a range set as a copy of another. */
    500 + (HFRangeSet *)withRangeSet:(HFRangeSet *)rangeSet;
    501 
    502 /*! Equivalent to HFRangeSet *x = [HFRangeSet withRange:range]; [x removeRange:rangeSet]; */
    503 + (HFRangeSet *)complementOfRangeSet:(HFRangeSet *)rangeSet inRange:(HFRange)range;
    504 
    505 - (void)addRange:(HFRange)range;    /*!< Union with range */
    506 - (void)removeRange:(HFRange)range; /*!< Subtract range */
    507 - (void)clipToRange:(HFRange)range; /*!< Intersect with range */
    508 - (void)toggleRange:(HFRange)range; /*!< Symmetric difference with range */
    509 
    510 - (void)addRangeSet:(HFRangeSet *)rangeSet;    /*!< Union with range set */
    511 - (void)removeRangeSet:(HFRangeSet *)rangeSet; /*!< Subtract range set */
    512 - (void)clipToRangeSet:(HFRangeSet *)rangeSet; /*!< Intersect with range set */
    513 - (void)toggleRangeSet:(HFRangeSet *)rangeSet; /*!< Symmetric difference with range set */
    514 
    515 
    516 - (BOOL)isEqualToRangeSet:(HFRangeSet *)rangeSet; /*!< Test if two range sets are equivalent. */
    517 - (BOOL)isEmpty;                                  /*!< Test if range set is empty. */
    518 
    519 - (BOOL)containsAllRange:(HFRange)range;             /*!< Check if the range set covers all of a range. Always true if 'range' is zero length. */
    520 - (BOOL)overlapsAnyRange:(HFRange)range;             /*!< Check if the range set covers any of a range. Never true if 'range' is zero length. */
    521 - (BOOL)containsAllRangeSet:(HFRangeSet *)rangeSet;  /*!< Check if this range is a superset of another. */
    522 - (BOOL)overlapsAnyRangeSet:(HFRangeSet *)rangeSet;  /*!< Check if this range has a nonempty intersection with another. */
    523 
    524 - (HFRange)spanningRange;  /*!< Return a single range that covers the entire range set */
    525 
    526 - (void)assertIntegrity;
    527 
    528 @end
    529 
    530 #ifndef NDEBUG
    531 void HFStartTiming(const char *name);
    532 void HFStopTiming(void);
    533 #endif

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.