Commits

Jason Harris committed dc39614

- Upgrade to RegexKitLite 4.0

  • Participants
  • Parent commits f27460a

Comments (0)

Files changed (2)

Classes/ExternalClasses/RegexKitLite/RegexKitLite.h

 //
 
 /*
- Copyright (c) 2008-2009, John Engelhart
+ Copyright (c) 2008-2010, John Engelhart
  
  All rights reserved.
  
 #define _RKL_JOIN_VERSION(a,b)   _RKL_STRINGIFY(a##.##b)
 #define _RKL_VERSION_STRING(a,b) _RKL_JOIN_VERSION(a,b)
 
-#define REGEXKITLITE_VERSION_MAJOR 3
-#define REGEXKITLITE_VERSION_MINOR 3
+#define REGEXKITLITE_VERSION_MAJOR 4
+#define REGEXKITLITE_VERSION_MINOR 0
 
 #define REGEXKITLITE_VERSION_CSTRING   _RKL_VERSION_STRING(REGEXKITLITE_VERSION_MAJOR, REGEXKITLITE_VERSION_MINOR)
 #define REGEXKITLITE_VERSION_NSSTRING  @REGEXKITLITE_VERSION_CSTRING
 
 #endif // REGEXKITLITE_VERSION_DEFINED
 
+#if !defined(RKL_BLOCKS) && defined(NS_BLOCKS_AVAILABLE) && (NS_BLOCKS_AVAILABLE == 1)
+#define RKL_BLOCKS 1
+#endif
+  
+#if       defined(RKL_BLOCKS) && (RKL_BLOCKS == 1)
+#define _RKL_BLOCKS_ENABLED 1
+#endif // defined(RKL_BLOCKS) && (RKL_BLOCKS == 1)
+
+#if       defined(_RKL_BLOCKS_ENABLED) && !defined(__BLOCKS__)
+#warning RegexKitLite support for Blocks is enabled, but __BLOCKS__ is not defined.  This compiler may not support Blocks, in which case the behavior is undefined.  This will probably cause numerous compiler errors.
+#endif // defined(_RKL_BLOCKS_ENABLED) && !defined(__BLOCKS__)
+
 // For Mac OS X < 10.5.
 #ifndef   NSINTEGER_DEFINED
 #define   NSINTEGER_DEFINED
 #ifndef   RKLREGEXOPTIONS_DEFINED
 #define   RKLREGEXOPTIONS_DEFINED
 
-// These must be idential to their ICU regex counterparts. See http://www.icu-project.org/userguide/regexp.html
+// These must be identical to their ICU regex counterparts. See http://www.icu-project.org/userguide/regexp.html
 enum {
   RKLNoOptions             = 0,
   RKLCaseless              = 2,
 
 #endif // RKLREGEXOPTIONS_DEFINED
 
+#ifndef   RKLREGEXENUMERATIONOPTIONS_DEFINED
+#define   RKLREGEXENUMERATIONOPTIONS_DEFINED
+
+enum {
+  RKLRegexEnumerationNoOptions                               = 0UL,
+  RKLRegexEnumerationCapturedStringsNotRequired              = 1UL << 9,
+  RKLRegexEnumerationReleaseStringReturnedByReplacementBlock = 1UL << 10,
+  RKLRegexEnumerationFastCapturedStringsXXX                  = 1UL << 11,
+};
+typedef NSUInteger RKLRegexEnumerationOptions;
+  
+#endif // RKLREGEXENUMERATIONOPTIONS_DEFINED
+
 #ifndef _REGEXKITLITE_H_
 #define _REGEXKITLITE_H_
 
 #else
 #define RKL_DEPRECATED_ATTRIBUTE
 #endif
+
+#if       defined(NS_REQUIRES_NIL_TERMINATION)
+#define RKL_REQUIRES_NIL_TERMINATION NS_REQUIRES_NIL_TERMINATION
+#else  // defined(NS_REQUIRES_NIL_TERMINATION)
+#define RKL_REQUIRES_NIL_TERMINATION
+#endif // defined(NS_REQUIRES_NIL_TERMINATION)
   
 // This requires a few levels of rewriting to get the desired results.
 #define _RKL_CONCAT_2(c,d) c ## d
 // NSError error domains and user info keys.
 extern NSString * const RKLICURegexErrorDomain;
 
+extern NSString * const RKLICURegexEnumerationOptionsErrorKey;
 extern NSString * const RKLICURegexErrorCodeErrorKey;
 extern NSString * const RKLICURegexErrorNameErrorKey;
 extern NSString * const RKLICURegexLineErrorKey;
 extern NSString * const RKLICURegexPostContextErrorKey;
 extern NSString * const RKLICURegexRegexErrorKey;
 extern NSString * const RKLICURegexRegexOptionsErrorKey;
-
+extern NSString * const RKLICURegexReplacedCountErrorKey;
+extern NSString * const RKLICURegexReplacedStringErrorKey;
+extern NSString * const RKLICURegexReplacementStringErrorKey;
+extern NSString * const RKLICURegexSubjectRangeErrorKey;
+extern NSString * const RKLICURegexSubjectStringErrorKey;
+  
 @interface NSString (RegexKitLiteAdditions)
 
 + (void)RKL_METHOD_PREPEND(clearStringCache);
 - (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement range:(NSRange)searchRange;
 - (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement options:(RKLRegexOptions)options range:(NSRange)searchRange error:(NSError **)error;
 
-  ////
+  //// >= 3.0
 
 - (NSInteger)RKL_METHOD_PREPEND(captureCount);
 - (NSInteger)RKL_METHOD_PREPEND(captureCountWithOptions):(RKLRegexOptions)options error:(NSError **)error;
 - (NSArray *)RKL_METHOD_PREPEND(arrayOfCaptureComponentsMatchedByRegex):(NSString *)regex range:(NSRange)range;
 - (NSArray *)RKL_METHOD_PREPEND(arrayOfCaptureComponentsMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error;
 
+  //// >= 4.0
+
+- (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION;
+- (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex range:(NSRange)range withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION;
+- (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION;
+- (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withFirstKey:(id)firstKey arguments:(va_list)varArgsList;
+
+- (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeys:(id *)keys forCaptures:(int *)captures count:(NSUInteger)count;
+
+- (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION;
+- (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex range:(NSRange)range withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION;
+- (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION;
+- (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withFirstKey:(id)firstKey arguments:(va_list)varArgsList;
+
+- (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeys:(id *)keys forCaptures:(int *)captures count:(NSUInteger)count;
+
+#ifdef    _RKL_BLOCKS_ENABLED
+
+- (BOOL)RKL_METHOD_PREPEND(enumerateStringsMatchedByRegex):(NSString *)regex usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
+- (BOOL)RKL_METHOD_PREPEND(enumerateStringsMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
+
+- (BOOL)RKL_METHOD_PREPEND(enumerateStringsSeparatedByRegex):(NSString *)regex usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
+- (BOOL)RKL_METHOD_PREPEND(enumerateStringsSeparatedByRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
+
+- (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
+- (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
+
+#endif // _RKL_BLOCKS_ENABLED
+
 @end
 
 @interface NSMutableString (RegexKitLiteAdditions)
 
-- (NSUInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement;
-- (NSUInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement range:(NSRange)searchRange;
-- (NSUInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement options:(RKLRegexOptions)options range:(NSRange)searchRange error:(NSError **)error;
+- (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement;
+- (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement range:(NSRange)searchRange;
+- (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement options:(RKLRegexOptions)options range:(NSRange)searchRange error:(NSError **)error;
+
+  //// >= 4.0
+
+#ifdef    _RKL_BLOCKS_ENABLED
+
+- (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
+- (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
+
+#endif // _RKL_BLOCKS_ENABLED
 
 @end
 

Classes/ExternalClasses/RegexKitLite/RegexKitLite.m

 //
 
 /*
- Copyright (c) 2008-2009, John Engelhart
+ Copyright (c) 2008-2010, John Engelhart
  
  All rights reserved.
  
 #ifdef    __OBJC_GC__
 #import <Foundation/NSGarbageCollector.h>
 #define RKL_STRONG_REF __strong
+#define RKL_GC_VOLATILE volatile
 #else  // __OBJC_GC__
 #define RKL_STRONG_REF
+#define RKL_GC_VOLATILE
 #endif // __OBJC_GC__
 
 #if (defined(TARGET_OS_EMBEDDED) && (TARGET_OS_EMBEDDED != 0)) || (defined(TARGET_OS_IPHONE) && (TARGET_OS_IPHONE != 0)) || (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050))
 #endif
 
 ////////////
-#pragma mark Compile time tuneables
+#pragma mark Compile time tunables
 
 #ifndef RKL_CACHE_SIZE
-#define RKL_CACHE_SIZE (23UL)
+#define RKL_CACHE_SIZE (13UL)
 #endif
 
+#if       RKL_CACHE_SIZE < 1
+#error RKL_CACHE_SIZE must be a non-negative number greater than 0.
+#endif // RKL_CACHE_SIZE < 1
+
 #ifndef RKL_FIXED_LENGTH
 #define RKL_FIXED_LENGTH (2048UL)
 #endif
 
+#if       RKL_FIXED_LENGTH < 1
+#error RKL_FIXED_LENGTH must be a non-negative number greater than 0.
+#endif // RKL_FIXED_LENGTH < 1
+
 #ifndef RKL_STACK_LIMIT
 #define RKL_STACK_LIMIT (128UL * 1024UL)
 #endif
 
+#if       RKL_STACK_LIMIT < 0
+#error RKL_STACK_LIMIT must be a non-negative number.
+#endif // RKL_STACK_LIMIT < 0
+
 #ifdef    RKL_APPEND_TO_ICU_FUNCTIONS
 #define RKL_ICU_FUNCTION_APPEND(x) _RKL_CONCAT(x, RKL_APPEND_TO_ICU_FUNCTIONS)
 #else  // RKL_APPEND_TO_ICU_FUNCTIONS
 #endif // RKL_APPEND_TO_ICU_FUNCTIONS
 
 #if       defined(RKL_DTRACE) && (RKL_DTRACE != 0)
-#define _RKL_DTRACE_ENABLED
+#define _RKL_DTRACE_ENABLED 1
 #endif // defined(RKL_DTRACE) && (RKL_DTRACE != 0)
 
-// These are internal, non-public tuneables.
-#define RKL_SCRATCH_BUFFERS (4UL)
-#define RKL_CACHE_LINE_SIZE (64UL)
-#define RKL_DTRACE_REGEXUTF8_SIZE (64UL)
+// These are internal, non-public tunables.
+#define _RKL_FIXED_LENGTH                ((NSUInteger)RKL_FIXED_LENGTH)
+#define _RKL_STACK_LIMIT                 ((NSUInteger)RKL_STACK_LIMIT)
+#define _RKL_SCRATCH_BUFFERS             (5UL)
+#if       _RKL_SCRATCH_BUFFERS != 5
+#error _RKL_SCRATCH_BUFFERS is not tunable, it must be set to 5.
+#endif // _RKL_SCRATCH_BUFFERS != 5
+#define _RKL_PREFETCH_SIZE               (64UL)
+#define _RKL_DTRACE_REGEXUTF8_SIZE       (64UL)
+
+// A LRU Cache Set holds 4 lines, and the LRU algorithm uses 4 bits per line.
+// A LRU Cache Set has a type of RKLLRUCacheSet_t and is 16 bits wide (4 lines * 4 bits per line).
+// RKLLRUCacheSet_t must be initialized to a value of 0x0137 in order to work correctly.
+typedef uint16_t RKLLRUCacheSet_t;
+#define _RKL_LRU_CACHE_SET_INIT          ((RKLLRUCacheSet_t)0x0137U)
+#define _RKL_LRU_CACHE_SET_WAYS          (4UL)
+#if       _RKL_LRU_CACHE_SET_WAYS != 4
+#error _RKL_LRU_CACHE_SET_WAYS is not tunable, it must be set to 4.
+#endif // _RKL_LRU_CACHE_SET_WAYS != 4
+
+#define _RKL_REGEX_LRU_CACHE_SETS        ((NSUInteger)(RKL_CACHE_SIZE))
+#define _RKL_REGEX_CACHE_LINES           ((NSUInteger)((NSUInteger)(_RKL_REGEX_LRU_CACHE_SETS) * (NSUInteger)(_RKL_LRU_CACHE_SET_WAYS)))
+
+// Regex String Lookaside Cache parameters.
+#define _RKL_REGEX_LOOKASIDE_CACHE_BITS   (6UL)
+#if       _RKL_REGEX_LOOKASIDE_CACHE_BITS < 0
+#error _RKL_REGEX_LOOKASIDE_CACHE_BITS must be a non-negative number and is not intended to be user tunable.
+#endif // _RKL_REGEX_LOOKASIDE_CACHE_BITS < 0
+#define _RKL_REGEX_LOOKASIDE_CACHE_SIZE   (1LU << _RKL_REGEX_LOOKASIDE_CACHE_BITS)
+#define _RKL_REGEX_LOOKASIDE_CACHE_MASK  ((1LU << _RKL_REGEX_LOOKASIDE_CACHE_BITS) - 1LU)
+// RKLLookasideCache_t should be large enough to to hold the maximum number of cached regexes, or (RKL_CACHE_SIZE * _RKL_LRU_CACHE_SET_WAYS).
+#if       (RKL_CACHE_SIZE * _RKL_LRU_CACHE_SET_WAYS) <= (1 << 8)
+typedef uint8_t RKLLookasideCache_t;
+#elif     (RKL_CACHE_SIZE * _RKL_LRU_CACHE_SET_WAYS) <= (1 << 16)
+typedef uint16_t RKLLookasideCache_t;
+#else  // (RKL_CACHE_SIZE * _RKL_LRU_CACHE_SET_WAYS)  > (1 << 16)
+typedef uint32_t RKLLookasideCache_t;
+#endif // (RKL_CACHE_SIZE * _RKL_LRU_CACHE_SET_WAYS)
 
 //////////////
 #pragma mark -
 #define RKL_ATTRIBUTES(attr, ...)        __attribute__((attr, ##__VA_ARGS__))
 #define RKL_EXPECTED(cond, expect)       __builtin_expect((long)(cond), (expect))
 #define RKL_PREFETCH(ptr)                __builtin_prefetch(ptr)
-#define RKL_PREFETCH_UNICHAR(ptr, off)   { const char *p = ((const char *)(ptr)) + ((off) * sizeof(UniChar)) + RKL_CACHE_LINE_SIZE; RKL_PREFETCH(p); RKL_PREFETCH(p + RKL_CACHE_LINE_SIZE); }
+#define RKL_PREFETCH_UNICHAR(ptr, off)   { const char *p = ((const char *)(ptr)) + ((off) * sizeof(UniChar)) + _RKL_PREFETCH_SIZE; RKL_PREFETCH(p); RKL_PREFETCH(p + _RKL_PREFETCH_SIZE); }
 #define RKL_HAVE_CLEANUP
 #define RKL_CLEANUP(func)                RKL_ATTRIBUTES(cleanup(func))
-#else  // defined (__GNUC__) && (__GNUC__ >= 4)
+#else  // defined (__GNUC__) && (__GNUC__ >= 4) 
 #define RKL_ATTRIBUTES(attr, ...)
 #define RKL_EXPECTED(cond, expect)       (cond)
 #define RKL_PREFETCH(ptr)
 #define RKL_PREFETCH_UNICHAR(ptr, off)
 #define RKL_CLEANUP(func)
-#endif // defined (__GNUC__) && (__GNUC__ >= 4)
+#endif // defined (__GNUC__) && (__GNUC__ >= 4) 
 
 #define RKL_STATIC_INLINE                         static __inline__ RKL_ATTRIBUTES(always_inline)
+#define RKL_ALIGNED(arg)                                            RKL_ATTRIBUTES(aligned(arg))
 #define RKL_UNUSED_ARG                                              RKL_ATTRIBUTES(unused)
+#define RKL_WARN_UNUSED                                             RKL_ATTRIBUTES(warn_unused_result)
+#define RKL_WARN_UNUSED_CONST                                       RKL_ATTRIBUTES(warn_unused_result, const)
+#define RKL_WARN_UNUSED_PURE                                        RKL_ATTRIBUTES(warn_unused_result, pure)
+#define RKL_WARN_UNUSED_SENTINEL                                    RKL_ATTRIBUTES(warn_unused_result, sentinel)
 #define RKL_NONNULL_ARGS(arg, ...)                                  RKL_ATTRIBUTES(nonnull(arg, ##__VA_ARGS__))
-#define RKL_NONNULL_ARGS_WARN_UNUSED(arg, ...)                      RKL_ATTRIBUTES(warn_unused_result, nonnull(arg, ##__VA_ARGS__))
+#define RKL_WARN_UNUSED_NONNULL_ARGS(arg, ...)                      RKL_ATTRIBUTES(warn_unused_result, nonnull(arg, ##__VA_ARGS__))
+#define RKL_WARN_UNUSED_CONST_NONNULL_ARGS(arg, ...)                RKL_ATTRIBUTES(warn_unused_result, const, nonnull(arg, ##__VA_ARGS__))
+#define RKL_WARN_UNUSED_PURE_NONNULL_ARGS(arg, ...)                 RKL_ATTRIBUTES(warn_unused_result, pure, nonnull(arg, ##__VA_ARGS__))
 
 #if       defined (__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3)
 #define RKL_ALLOC_SIZE_NON_NULL_ARGS_WARN_UNUSED(as, nn, ...) RKL_ATTRIBUTES(warn_unused_result, nonnull(nn, ##__VA_ARGS__), alloc_size(as))
 #define RKL_ALLOC_SIZE_NON_NULL_ARGS_WARN_UNUSED(as, nn, ...) RKL_ATTRIBUTES(warn_unused_result, nonnull(nn, ##__VA_ARGS__))
 #endif // defined (__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3)
 
+#ifdef    _RKL_DTRACE_ENABLED
+#define RKL_UNUSED_DTRACE_ARG
+#else  // _RKL_DTRACE_ENABLED
+#define RKL_UNUSED_DTRACE_ARG RKL_ATTRIBUTES(unused)
+#endif // _RKL_DTRACE_ENABLED
 
 ////////////
 #pragma mark -
 #pragma mark Assertion macros
 
 // These macros are nearly identical to their NSCParameterAssert siblings.
-// This is required because nearly everything is done while cacheSpinLock is locked.
+// This is required because nearly everything is done while rkl_cacheSpinLock is locked.
 // We need to safely unlock before throwing any of these exceptions.
 // @try {} @finally {} significantly slows things down so it's not used.
 
+#define RKLCHardAbortAssert(c) do { int _c=(c); if(RKL_EXPECTED(!_c, 0L)) { NSLog(@"%@:%ld: Invalid parameter not satisfying: %s\n", [NSString stringWithUTF8String:__FILE__], (long)__LINE__, #c); abort(); } } while(0)
 #define RKLCAssertDictionary(d, ...) rkl_makeAssertDictionary(__PRETTY_FUNCTION__, __FILE__, __LINE__, (d), ##__VA_ARGS__)
 #define RKLCDelayedHardAssert(c, e, g) do { id *_e=(e); int _c=(c); if(RKL_EXPECTED(_e == NULL, 0L) || RKL_EXPECTED(*_e != NULL, 0L)) { goto g; } if(RKL_EXPECTED(!_c, 0L)) { *_e = RKLCAssertDictionary(@"Invalid parameter not satisfying: %s", #c); goto g; } } while(0)
 
 #ifdef    NS_BLOCK_ASSERTIONS
+#define RKLCAbortAssert(c)
 #define RKLCDelayedAssert(c, e, g)
 #define RKL_UNUSED_ASSERTION_ARG RKL_ATTRIBUTES(unused)
 #else  // NS_BLOCK_ASSERTIONS
+#define RKLCAbortAssert(c) RKLCHardAbortAssert(c)
 #define RKLCDelayedAssert(c, e, g) RKLCDelayedHardAssert(c, e, g)
 #define RKL_UNUSED_ASSERTION_ARG
 #endif // NS_BLOCK_ASSERTIONS
 #pragma mark -
 #pragma mark Utility functions and macros
 
-RKL_STATIC_INLINE BOOL NSRangeInsideRange(NSRange cin, NSRange win) RKL_ATTRIBUTES(warn_unused_result);
+RKL_STATIC_INLINE BOOL NSRangeInsideRange(NSRange cin, NSRange win) RKL_WARN_UNUSED;
 RKL_STATIC_INLINE BOOL NSRangeInsideRange(NSRange cin, NSRange win) { return((((cin.location - win.location) <= win.length) && ((NSMaxRange(cin) - win.location) <= win.length)) ? YES : NO); }
 
 #define NSMakeRange(loc, len) ((NSRange){.location=(NSUInteger)(loc),      .length=(NSUInteger)(len)})
 #define CFMakeRange(loc, len) ((CFRange){.location=   (CFIndex)(loc),      .length=   (CFIndex)(len)})
 #define NSNotFoundRange       ((NSRange){.location=(NSUInteger)NSNotFound, .length=              0UL})
 #define NSMaxiumRange         ((NSRange){.location=                   0UL, .length=    NSUIntegerMax})
+// These values are used to help tickle improper usage.
+#define RKLIllegalRange       ((NSRange){.location=          NSIntegerMax, .length=     NSIntegerMax})
+#define RKLIllegalPointer     ((void * RKL_GC_VOLATILE)0xBAD0C0DE)
 
 ////////////
 #pragma mark -
 #pragma mark Exported NSString symbols for exception names, error domains, error keys, etc
 
-NSString * const RKLICURegexException            = @"RKLICURegexException";
+NSString * const RKLICURegexException                  = @"RKLICURegexException";
 
-NSString * const RKLICURegexErrorDomain          = @"RKLICURegexErrorDomain";
+NSString * const RKLICURegexErrorDomain                = @"RKLICURegexErrorDomain";
 
-NSString * const RKLICURegexErrorCodeErrorKey    = @"RKLICURegexErrorCode";
-NSString * const RKLICURegexErrorNameErrorKey    = @"RKLICURegexErrorName";
-NSString * const RKLICURegexLineErrorKey         = @"RKLICURegexLine";
-NSString * const RKLICURegexOffsetErrorKey       = @"RKLICURegexOffset";
-NSString * const RKLICURegexPreContextErrorKey   = @"RKLICURegexPreContext";
-NSString * const RKLICURegexPostContextErrorKey  = @"RKLICURegexPostContext";
-NSString * const RKLICURegexRegexErrorKey        = @"RKLICURegexRegex";
-NSString * const RKLICURegexRegexOptionsErrorKey = @"RKLICURegexRegexOptions";
+NSString * const RKLICURegexEnumerationOptionsErrorKey = @"RKLICURegexEnumerationOptions";
+NSString * const RKLICURegexErrorCodeErrorKey          = @"RKLICURegexErrorCode";
+NSString * const RKLICURegexErrorNameErrorKey          = @"RKLICURegexErrorName";
+NSString * const RKLICURegexLineErrorKey               = @"RKLICURegexLine";
+NSString * const RKLICURegexOffsetErrorKey             = @"RKLICURegexOffset";
+NSString * const RKLICURegexPreContextErrorKey         = @"RKLICURegexPreContext";
+NSString * const RKLICURegexPostContextErrorKey        = @"RKLICURegexPostContext";
+NSString * const RKLICURegexRegexErrorKey              = @"RKLICURegexRegex";
+NSString * const RKLICURegexRegexOptionsErrorKey       = @"RKLICURegexRegexOptions";
+NSString * const RKLICURegexReplacedCountErrorKey      = @"RKLICURegexReplacedCount";
+NSString * const RKLICURegexReplacedStringErrorKey     = @"RKLICURegexReplacedString";
+NSString * const RKLICURegexReplacementStringErrorKey  = @"RKLICURegexReplacementString";
+NSString * const RKLICURegexSubjectRangeErrorKey       = @"RKLICURegexSubjectRange";
+NSString * const RKLICURegexSubjectStringErrorKey      = @"RKLICURegexSubjectString";
+
+// Used internally by rkl_userInfoDictionary to specify which arguments should be set in the NSError userInfo dictionary.
+enum {
+  RKLUserInfoNone                    = 0UL,
+  RKLUserInfoSubjectRange            = 1UL << 0,
+  RKLUserInfoReplacedCount           = 1UL << 1,
+  RKLUserInfoRegexEnumerationOptions = 1UL << 2,
+};
+typedef NSUInteger RKLUserInfoOptions;
 
 ////////////
 #pragma mark -
 } UParseError;
 
 // For use with GCC's cleanup() __attribute__.
-#define  RKLLockedCacheSpinLock   ((NSUInteger)(1UL<<0))
-#define  RKLUnlockedCacheSpinLock ((NSUInteger)(1UL<<1))
+enum {
+  RKLLockedCacheSpinLock   = 1UL << 0,
+  RKLUnlockedCacheSpinLock = 1UL << 1,
+};
 
 enum {
-  RKLSplitOp           = 1,
-  RKLReplaceOp         = 2,
-  RKLRangeOp           = 3,
-  RKLArrayOfStringsOp  = 4,
-  RKLArrayOfCapturesOp = 5,
-  RKLCapturesArrayOp   = 6,
-  RKLMaskOp            = 0xf,
-  RKLReplaceMutable    = 1 << 4,
-  RKLSubcapturesArray  = 1 << 5,
+  RKLSplitOp                         = 1UL,
+  RKLReplaceOp                       = 2UL,
+  RKLRangeOp                         = 3UL,
+  RKLArrayOfStringsOp                = 4UL,
+  RKLArrayOfCapturesOp               = 5UL,
+  RKLCapturesArrayOp                 = 6UL,
+  RKLDictionaryOfCapturesOp          = 7UL,
+  RKLArrayOfDictionariesOfCapturesOp = 8UL,
+  RKLMaskOp                          = 0xFUL,
+  RKLReplaceMutable                  = 1UL << 4,
+  RKLSubcapturesArray                = 1UL << 5,
 };
 typedef NSUInteger RKLRegexOp;
 
+enum {
+  RKLBlockEnumerationMatchOp   = 1UL,
+  RKLBlockEnumerationReplaceOp = 2UL,
+};
+typedef NSUInteger RKLBlockEnumerationOp;
+
 typedef struct {
-                 NSRange    *ranges, findInRange;
-                 NSInteger   capacity, found, findUpTo, capture;
-                 size_t      size, stackUsed;
-                 void      **rangesScratchBuffer;
-  RKL_STRONG_REF void      **stringsScratchBuffer;
-  RKL_STRONG_REF void      **arraysScratchBuffer;
+  RKL_STRONG_REF NSRange    * RKL_GC_VOLATILE ranges;
+                 NSRange                      findInRange, remainingRange;
+                 NSInteger                    capacity, found, findUpTo, capture, addedSplitRanges;
+                 size_t                       size, stackUsed;
+  RKL_STRONG_REF void      ** RKL_GC_VOLATILE rangesScratchBuffer;
+  RKL_STRONG_REF void      ** RKL_GC_VOLATILE stringsScratchBuffer;
+  RKL_STRONG_REF void      ** RKL_GC_VOLATILE arraysScratchBuffer;
+  RKL_STRONG_REF void      ** RKL_GC_VOLATILE dictionariesScratchBuffer;
+  RKL_STRONG_REF void      ** RKL_GC_VOLATILE keysScratchBuffer;
 } RKLFindAll;
 
 typedef struct {
-                 CFStringRef  string;
-                 CFHashCode   hash;
-                 CFIndex      length;
-  RKL_STRONG_REF UniChar     *uniChar;
+                 CFStringRef               string;
+                 CFHashCode                hash;
+                 CFIndex                   length;
+  RKL_STRONG_REF UniChar * RKL_GC_VOLATILE uniChar;
 } RKLBuffer;
 
 typedef struct {
-  CFStringRef      regexString;
-  RKLRegexOptions  options;
-  uregex          *icu_regex;
-  NSInteger        captureCount;
+                 CFStringRef                     regexString;
+                 CFHashCode                      regexHash;
+                 RKLRegexOptions                 options;
+                 uregex                         *icu_regex;
+                 NSInteger                       captureCount;
   
-  CFStringRef      setToString;
-  CFHashCode       setToHash;
-  CFIndex          setToLength;
-  NSUInteger       setToIsImmutable:1;
-  NSUInteger       setToNeedsConversion:1;
-  const UniChar   *setToUniChar;
-  NSRange          setToRange, lastFindRange, lastMatchRange;
-#ifndef   __LP64__
-  NSUInteger       pad[1]; // For 32 bits, this makes the struct 64 bytes exactly, which is good for cache line alignment.
-#endif // __LP64__
-} RKLCacheSlot;
+                 CFStringRef                     setToString;
+                 CFHashCode                      setToHash;
+                 CFIndex                         setToLength;
+                 NSUInteger                      setToIsImmutable:1;
+                 NSUInteger                      setToNeedsConversion:1;
+  RKL_STRONG_REF const UniChar * RKL_GC_VOLATILE setToUniChar;
+                 NSRange                         setToRange, lastFindRange, lastMatchRange;
+
+                 RKLBuffer                      *buffer;
+} RKLCachedRegex;
 
 ////////////
 #pragma mark -
 #pragma mark Translation unit scope global variables
 
-static UniChar              fixedUniChar[(RKL_FIXED_LENGTH)];     // This is the fixed sized UTF-16 conversion buffer.
-static RKLCacheSlot         rkl_cacheSlots[(RKL_CACHE_SIZE)], *lastCacheSlot;
-static OSSpinLock           cacheSpinLock = OS_SPINLOCK_INIT;
-static RKLBuffer            dynamicBuffer, fixedBuffer = {NULL, 0UL, 0L, &fixedUniChar[0]};
-static const UniChar        emptyUniCharString[1];                // For safety, icu_regexes are 'set' to this when the string they were searched is cleared.
-static RKL_STRONG_REF void *scratchBuffer[(RKL_SCRATCH_BUFFERS)]; // Used to hold temporary allocations that are allocated via reallocf().
+static RKLLRUCacheSet_t     rkl_lruFixedBufferCacheSet = _RKL_LRU_CACHE_SET_INIT, rkl_lruDynamicBufferCacheSet = _RKL_LRU_CACHE_SET_INIT;
+static RKLBuffer            rkl_lruDynamicBuffer[_RKL_LRU_CACHE_SET_WAYS];
+static UniChar              rkl_lruFixedUniChar[_RKL_LRU_CACHE_SET_WAYS][_RKL_FIXED_LENGTH]; // This is the fixed sized UTF-16 conversion buffer.
+static RKLBuffer            rkl_lruFixedBuffer[_RKL_LRU_CACHE_SET_WAYS] = {{NULL, 0UL, 0L, &rkl_lruFixedUniChar[0][0]}, {NULL, 0UL, 0L, &rkl_lruFixedUniChar[1][0]}, {NULL, 0UL, 0L, &rkl_lruFixedUniChar[2][0]}, {NULL, 0UL, 0L, &rkl_lruFixedUniChar[3][0]}};
+static RKLCachedRegex       rkl_cachedRegexes[_RKL_REGEX_CACHE_LINES];
+#if       defined(__GNUC__) && (__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ == 2)
+static RKLCachedRegex * volatile rkl_lastCachedRegex; // XXX This is a work around for what appears to be a optimizer code generation bug in GCC 4.2.
+#else
+static RKLCachedRegex *rkl_lastCachedRegex;
+#endif // defined(__GNUC__) && (__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ == 2)
+static RKLLRUCacheSet_t     rkl_cachedRegexCacheSets[_RKL_REGEX_LRU_CACHE_SETS] = { [0 ... (_RKL_REGEX_LRU_CACHE_SETS - 1UL)] = _RKL_LRU_CACHE_SET_INIT };
+static RKLLookasideCache_t  rkl_regexLookasideCache[_RKL_REGEX_LOOKASIDE_CACHE_SIZE] RKL_ALIGNED(64);
+static OSSpinLock           rkl_cacheSpinLock = OS_SPINLOCK_INIT;
+static const UniChar        rkl_emptyUniCharString[1];                                // For safety, icu_regexes are 'set' to this when the string they were searched is cleared.
+static RKL_STRONG_REF void * RKL_GC_VOLATILE rkl_scratchBuffer[_RKL_SCRATCH_BUFFERS]; // Used to hold temporary allocations that are allocated via reallocf().
 
 ////////////
 #pragma mark -
-#pragma mark CFArray call backs
+#pragma mark CFArray and CFDictionary call backs
 
 // These are used when running under manual memory management for the array that rkl_splitArray creates.
 // The split strings are created, but not autoreleased.  The (immutable) array is created using these callbacks, which skips the CFRetain() call, effectively transferring ownership to the CFArray object.
 // For each split string this saves the overhead of an autorelease, then an array retain, then an NSAutoreleasePool release. This is good for a ~30% speed increase.
 
-static void                   RKLCFArrayRelease                     (CFAllocatorRef allocator RKL_UNUSED_ARG, const void *ptr) { CFRelease((CFTypeRef)ptr);                                       }
-static const CFArrayCallBacks rkl_transferOwnershipArrayCallBacks =                                                            { (CFIndex)0L, NULL, RKLCFArrayRelease, CFCopyDescription, CFEqual };
+static void  rkl_CFCallbackRelease(CFAllocatorRef allocator RKL_UNUSED_ARG, const void *ptr) { CFRelease((CFTypeRef)ptr);                                                   }
+static const CFArrayCallBacks           rkl_transferOwnershipArrayCallBacks           =      { (CFIndex)0L, NULL, rkl_CFCallbackRelease, CFCopyDescription, CFEqual         };
+static const CFDictionaryKeyCallBacks   rkl_transferOwnershipDictionaryKeyCallBacks   =      { (CFIndex)0L, NULL, rkl_CFCallbackRelease, CFCopyDescription, CFEqual, CFHash };
+static const CFDictionaryValueCallBacks rkl_transferOwnershipDictionaryValueCallBacks =      { (CFIndex)0L, NULL, rkl_CFCallbackRelease, CFCopyDescription, CFEqual         };
 
 #ifdef    __OBJC_GC__
 ////////////
     //    "You may pass addresses of strong globals or statics into routines expecting pointers to object pointers (such as id* or NSError**)
     //     only if they have first been assigned to directly, rather than through a pointer dereference."
     // This is a surprisingly non-trivial condition to actually meet in practice and is a recipe for impossible to debug race condition bugs.
-    // We just happen to be very, very, very lucky in the fact that we can initilize our root set before the first use.
-    int x;
-    for(x = 0; x < (int)(RKL_SCRATCH_BUFFERS); x++) { scratchBuffer[x] = NSAllocateCollectable(16UL, 0UL); scratchBuffer[x] = NULL; }
-    dynamicBuffer.uniChar = (RKL_STRONG_REF UniChar *)NSAllocateCollectable(16UL, 0UL); dynamicBuffer.uniChar = NULL;
+    // We just happen to be very, very, very lucky in the fact that we can initialize our root set before the first use.
+    NSUInteger x = 0UL;
+    for(x = 0UL; x < _RKL_SCRATCH_BUFFERS; x++)    { rkl_scratchBuffer[x]            = NSAllocateCollectable(16UL, 0UL); rkl_scratchBuffer[x]            = NULL; }
+    for(x = 0UL; x < _RKL_LRU_CACHE_SET_WAYS; x++) { rkl_lruDynamicBuffer[x].uniChar = NSAllocateCollectable(16UL, 0UL); rkl_lruDynamicBuffer[x].uniChar = NULL; }
   }
   return((rkl_collectingEnabled = (gcEnabled == YES) ? rkl_collectingEnabled_yes : rkl_collectingEnabled_no)());
 }
 
 // rkl_realloc()
-static void   *rkl_realloc_first (RKL_STRONG_REF void **ptr, size_t size, NSUInteger flags);
-static void   *rkl_realloc_std   (RKL_STRONG_REF void **ptr, size_t size, NSUInteger flags RKL_UNUSED_ARG) { return((*ptr = reallocf(*ptr, size))); }
-static void   *rkl_realloc_gc    (RKL_STRONG_REF void **ptr, size_t size, NSUInteger flags)                { return((*ptr = NSReallocateCollectable(*ptr, (NSUInteger)size, flags))); }
-static void *(*rkl_realloc)      (RKL_STRONG_REF void **ptr, size_t size, NSUInteger flags) RKL_ALLOC_SIZE_NON_NULL_ARGS_WARN_UNUSED(2,1) = rkl_realloc_first;
-static void   *rkl_realloc_first (RKL_STRONG_REF void **ptr, size_t size, NSUInteger flags)                { if(rkl_collectingEnabled()==YES) { rkl_realloc = rkl_realloc_gc; } else { rkl_realloc = rkl_realloc_std; } return(rkl_realloc(ptr, size, flags)); }
+static void   *rkl_realloc_first (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr, size_t size, NSUInteger flags);
+static void   *rkl_realloc_std   (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr, size_t size, NSUInteger flags RKL_UNUSED_ARG) { return((*ptr = reallocf(*ptr, size))); }
+static void   *rkl_realloc_gc    (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr, size_t size, NSUInteger flags)                { return((*ptr = NSReallocateCollectable(*ptr, (NSUInteger)size, flags))); }
+static void *(*rkl_realloc)      (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr, size_t size, NSUInteger flags) RKL_ALLOC_SIZE_NON_NULL_ARGS_WARN_UNUSED(2,1) = rkl_realloc_first;
+static void   *rkl_realloc_first (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr, size_t size, NSUInteger flags)                { if(rkl_collectingEnabled()==YES) { rkl_realloc = rkl_realloc_gc; } else { rkl_realloc = rkl_realloc_std; } return(rkl_realloc(ptr, size, flags)); }
 
 // rkl_free()
-static void *  rkl_free_first (RKL_STRONG_REF void **ptr);
-static void *  rkl_free_std   (RKL_STRONG_REF void **ptr) { if(*ptr != NULL) { free(*ptr); *ptr = NULL; } return(NULL); }
-static void *  rkl_free_gc    (RKL_STRONG_REF void **ptr) { if(*ptr != NULL) {             *ptr = NULL; } return(NULL); }
-static void *(*rkl_free)      (RKL_STRONG_REF void **ptr) RKL_NONNULL_ARGS(1) = rkl_free_first;
-static void   *rkl_free_first (RKL_STRONG_REF void **ptr) { if(rkl_collectingEnabled()==YES) { rkl_free = rkl_free_gc; } else { rkl_free = rkl_free_std; } return(rkl_free(ptr)); }
+static void *  rkl_free_first (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr);
+static void *  rkl_free_std   (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr) { if(*ptr != NULL) { free(*ptr); *ptr = NULL; } return(NULL); }
+static void *  rkl_free_gc    (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr) { if(*ptr != NULL) {             *ptr = NULL; } return(NULL); }
+static void *(*rkl_free)      (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr) RKL_NONNULL_ARGS(1) = rkl_free_first;
+static void   *rkl_free_first (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr) { if(rkl_collectingEnabled()==YES) { rkl_free = rkl_free_gc; } else { rkl_free = rkl_free_std; } return(rkl_free(ptr)); }
 
 // rkl_CFAutorelease()
 static id  rkl_CFAutorelease_first (CFTypeRef obj);
 static id  rkl_CreateStringWithSubstring_first (id string, NSRange range);
 static id  rkl_CreateStringWithSubstring_std   (id string, NSRange range) { return((id)CFStringCreateWithSubstring(NULL, (CFStringRef)string, CFMakeRange((CFIndex)range.location, (CFIndex)range.length))); }
 static id  rkl_CreateStringWithSubstring_gc    (id string, NSRange range) { return([string substringWithRange:range]); }
-static id(*rkl_CreateStringWithSubstring)      (id string, NSRange range) RKL_NONNULL_ARGS_WARN_UNUSED(1) = rkl_CreateStringWithSubstring_first;
+static id(*rkl_CreateStringWithSubstring)      (id string, NSRange range) RKL_WARN_UNUSED_NONNULL_ARGS(1) = rkl_CreateStringWithSubstring_first;
 static id  rkl_CreateStringWithSubstring_first (id string, NSRange range) { return((rkl_CreateStringWithSubstring = (rkl_collectingEnabled()==YES) ? rkl_CreateStringWithSubstring_gc : rkl_CreateStringWithSubstring_std)(string, range)); }
 
 // rkl_ReleaseObject()
 static id  rkl_CreateArrayWithObjects_first (void **objects, NSUInteger count);
 static id  rkl_CreateArrayWithObjects_std   (void **objects, NSUInteger count) { return((id)CFArrayCreate(NULL, (const void **)objects, (CFIndex)count, &rkl_transferOwnershipArrayCallBacks)); }
 static id  rkl_CreateArrayWithObjects_gc    (void **objects, NSUInteger count) { return([NSArray arrayWithObjects:(const id *)objects count:count]); }
-static id(*rkl_CreateArrayWithObjects)      (void **objects, NSUInteger count) RKL_NONNULL_ARGS_WARN_UNUSED(1) = rkl_CreateArrayWithObjects_first;
+static id(*rkl_CreateArrayWithObjects)      (void **objects, NSUInteger count) RKL_WARN_UNUSED_NONNULL_ARGS(1) = rkl_CreateArrayWithObjects_first;
 static id  rkl_CreateArrayWithObjects_first (void **objects, NSUInteger count) { return((rkl_CreateArrayWithObjects = (rkl_collectingEnabled()==YES) ? rkl_CreateArrayWithObjects_gc : rkl_CreateArrayWithObjects_std)(objects, count)); }
 
 // rkl_CreateAutoreleasedArray()
 static id  rkl_CreateAutoreleasedArray_first (void **objects, NSUInteger count);
 static id  rkl_CreateAutoreleasedArray_std   (void **objects, NSUInteger count) { return((id)rkl_CFAutorelease(rkl_CreateArrayWithObjects(objects, count))); }
 static id  rkl_CreateAutoreleasedArray_gc    (void **objects, NSUInteger count) { return(                      rkl_CreateArrayWithObjects(objects, count) ); }
-static id(*rkl_CreateAutoreleasedArray)      (void **objects, NSUInteger count) RKL_NONNULL_ARGS_WARN_UNUSED(1) = rkl_CreateAutoreleasedArray_first;
+static id(*rkl_CreateAutoreleasedArray)      (void **objects, NSUInteger count) RKL_WARN_UNUSED_NONNULL_ARGS(1) = rkl_CreateAutoreleasedArray_first;
 static id  rkl_CreateAutoreleasedArray_first (void **objects, NSUInteger count) { return((rkl_CreateAutoreleasedArray = (rkl_collectingEnabled()==YES) ? rkl_CreateAutoreleasedArray_gc : rkl_CreateAutoreleasedArray_std)(objects, count)); }
 
 #else  // __OBJC_GC__ not defined
 
 RKL_STATIC_INLINE void *rkl_realloc                   (void **ptr, size_t size, NSUInteger flags) RKL_ALLOC_SIZE_NON_NULL_ARGS_WARN_UNUSED(2,1);
 RKL_STATIC_INLINE void *rkl_free                      (void **ptr)                                RKL_NONNULL_ARGS(1);
-RKL_STATIC_INLINE id    rkl_CFAutorelease             (CFTypeRef obj);
-RKL_STATIC_INLINE id    rkl_CreateAutoreleasedArray   (void **objects, NSUInteger count)          RKL_NONNULL_ARGS_WARN_UNUSED(1);
-RKL_STATIC_INLINE id    rkl_CreateArrayWithObjects    (void **objects, NSUInteger count)          RKL_NONNULL_ARGS_WARN_UNUSED(1);
-RKL_STATIC_INLINE id    rkl_CreateStringWithSubstring (id string, NSRange range)                  RKL_NONNULL_ARGS_WARN_UNUSED(1);
+RKL_STATIC_INLINE id    rkl_CFAutorelease             (CFTypeRef obj)                             RKL_WARN_UNUSED_NONNULL_ARGS(1);
+RKL_STATIC_INLINE id    rkl_CreateAutoreleasedArray   (void **objects, NSUInteger count)          RKL_WARN_UNUSED_NONNULL_ARGS(1);
+RKL_STATIC_INLINE id    rkl_CreateArrayWithObjects    (void **objects, NSUInteger count)          RKL_WARN_UNUSED_NONNULL_ARGS(1);
+RKL_STATIC_INLINE id    rkl_CreateStringWithSubstring (id string, NSRange range)                  RKL_WARN_UNUSED_NONNULL_ARGS(1);
 RKL_STATIC_INLINE id    rkl_ReleaseObject             (id obj)                                    RKL_NONNULL_ARGS(1);
 
 RKL_STATIC_INLINE void *rkl_realloc                   (void **ptr, size_t size, NSUInteger flags RKL_UNUSED_ARG) { return((*ptr = reallocf(*ptr, size))); }
 #pragma mark ICU function prototypes
 
 // ICU functions.  See http://www.icu-project.org/apiref/icu4c/uregex_8h.html Tweaked slightly from the originals, but functionally identical.
-const char *RKL_ICU_FUNCTION_APPEND(u_errorName)              (int32_t status)   RKL_ATTRIBUTES(pure);
-int32_t     RKL_ICU_FUNCTION_APPEND(u_strlen)                 (const UniChar *s) RKL_ATTRIBUTES(nonnull(1), pure);
-int32_t     RKL_ICU_FUNCTION_APPEND(uregex_appendReplacement) (uregex *regexp, const UniChar *replacementText, int32_t replacementLength, UniChar **destBuf, int32_t *destCapacity, int32_t *status) RKL_NONNULL_ARGS(1,2,4,5,6);
-int32_t     RKL_ICU_FUNCTION_APPEND(uregex_appendTail)        (uregex *regexp, UniChar **destBuf, int32_t *destCapacity, int32_t *status) RKL_NONNULL_ARGS(1,2,3,4);
-void        RKL_ICU_FUNCTION_APPEND(uregex_close)             (uregex *regexp) RKL_NONNULL_ARGS(1);
-int32_t     RKL_ICU_FUNCTION_APPEND(uregex_end)               (uregex *regexp, int32_t groupNum, int32_t *status) RKL_NONNULL_ARGS(1,3);
-BOOL        RKL_ICU_FUNCTION_APPEND(uregex_find)              (uregex *regexp, int32_t location, int32_t *status) RKL_NONNULL_ARGS(1,3);
-BOOL        RKL_ICU_FUNCTION_APPEND(uregex_findNext)          (uregex *regexp, int32_t *status) RKL_NONNULL_ARGS(1,2);
-int32_t     RKL_ICU_FUNCTION_APPEND(uregex_groupCount)        (uregex *regexp, int32_t *status) RKL_NONNULL_ARGS(1,2);
-uregex     *RKL_ICU_FUNCTION_APPEND(uregex_open)              (const UniChar *pattern, int32_t patternLength, RKLRegexOptions flags, UParseError *parseError, int32_t *status) RKL_NONNULL_ARGS_WARN_UNUSED(1,4,5);
-void        RKL_ICU_FUNCTION_APPEND(uregex_reset)             (uregex *regexp, int32_t newIndex, int32_t *status) RKL_NONNULL_ARGS(1,3);
-void        RKL_ICU_FUNCTION_APPEND(uregex_setText)           (uregex *regexp, const UniChar *text, int32_t textLength, int32_t *status) RKL_NONNULL_ARGS(1,2,4);
-int32_t     RKL_ICU_FUNCTION_APPEND(uregex_start)             (uregex *regexp, int32_t groupNum, int32_t *status) RKL_NONNULL_ARGS(1,3);
+const char *RKL_ICU_FUNCTION_APPEND(u_errorName)              (                                                                                                                             int32_t  status) RKL_WARN_UNUSED_PURE;
+int32_t     RKL_ICU_FUNCTION_APPEND(u_strlen)                 (const UniChar *s)                                                                                                                             RKL_WARN_UNUSED_PURE_NONNULL_ARGS(1);
+int32_t     RKL_ICU_FUNCTION_APPEND(uregex_appendReplacement) (      uregex  *regexp,  const UniChar *replacementText, int32_t replacementLength, UniChar **destBuf, int32_t *destCapacity, int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,2,4,5,6);
+int32_t     RKL_ICU_FUNCTION_APPEND(uregex_appendTail)        (      uregex  *regexp,                                                             UniChar **destBuf, int32_t *destCapacity, int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,2,3,4);
+void        RKL_ICU_FUNCTION_APPEND(uregex_close)             (      uregex  *regexp)                                                                                                                        RKL_NONNULL_ARGS(1);
+int32_t     RKL_ICU_FUNCTION_APPEND(uregex_end)               (      uregex  *regexp,  int32_t groupNum,                                                                                    int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,3);
+BOOL        RKL_ICU_FUNCTION_APPEND(uregex_find)              (      uregex  *regexp,  int32_t location,                                                                                    int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,3);
+BOOL        RKL_ICU_FUNCTION_APPEND(uregex_findNext)          (      uregex  *regexp,                                                                                                       int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,2);
+int32_t     RKL_ICU_FUNCTION_APPEND(uregex_groupCount)        (      uregex  *regexp,                                                                                                       int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,2);
+uregex     *RKL_ICU_FUNCTION_APPEND(uregex_open)              (const UniChar *pattern, int32_t patternLength, RKLRegexOptions flags, UParseError *parseError,                               int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,4,5);
+void        RKL_ICU_FUNCTION_APPEND(uregex_reset)             (      uregex  *regexp,  int32_t newIndex,                                                                                    int32_t *status) RKL_NONNULL_ARGS(1,3);
+void        RKL_ICU_FUNCTION_APPEND(uregex_setText)           (      uregex  *regexp,  const UniChar *text, int32_t textLength,                                                             int32_t *status) RKL_NONNULL_ARGS(1,2,4);
+int32_t     RKL_ICU_FUNCTION_APPEND(uregex_start)             (      uregex  *regexp,  int32_t groupNum,                                                                                    int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,3);
+uregex     *RKL_ICU_FUNCTION_APPEND(uregex_clone)             (const uregex  *regexp,                                                                                                       int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,2);
 
 ////////////
 #pragma mark -
 #pragma mark RegexKitLite internal, private function prototypes
 
-static RKLCacheSlot *rkl_getCachedRegex            (NSString *regexString, RKLRegexOptions options, NSError **error, id *exception)                                                                                                                            RKL_NONNULL_ARGS_WARN_UNUSED(1,4);
-static NSUInteger    rkl_setCacheSlotToString      (RKLCacheSlot *cacheSlot, const NSRange *range, int32_t *status, id *exception RKL_UNUSED_ASSERTION_ARG)                                                                                                    RKL_NONNULL_ARGS_WARN_UNUSED(1,2,3,4);
-static RKLCacheSlot *rkl_getCachedRegexSetToString (NSString *regexString, RKLRegexOptions options, NSString *matchString, NSUInteger *matchLengthPtr, NSRange *matchRange, NSError **error, id *exception, int32_t *status)                                   RKL_NONNULL_ARGS_WARN_UNUSED(1,3,4,5,7,8);
-static id            rkl_performRegexOp            (id self, SEL _cmd, RKLRegexOp regexOp, NSString *regexString, RKLRegexOptions options, NSInteger capture, id matchString, NSRange *matchRange, NSString *replacementString, NSError **error, void *result) RKL_NONNULL_ARGS(1,2);
-static void          rkl_handleDelayedAssert       (id self, SEL _cmd, id exception)                                                                                                                                                                           RKL_NONNULL_ARGS(1,2,3);
+// Functions used for managing the 4-way set associative LRU cache and regex string hash lookaside cache.
+RKL_STATIC_INLINE NSUInteger      rkl_leastRecentlyUsedWayInSet                          (      NSUInteger      cacheSetsCount, const RKLLRUCacheSet_t cacheSetsArray[cacheSetsCount], NSUInteger set)                  RKL_WARN_UNUSED_NONNULL_ARGS(2);
+RKL_STATIC_INLINE void            rkl_accessCacheSetWay                                  (      NSUInteger      cacheSetsCount,       RKLLRUCacheSet_t cacheSetsArray[cacheSetsCount], NSUInteger set, NSUInteger way)  RKL_NONNULL_ARGS(2);
+RKL_STATIC_INLINE NSUInteger      rkl_regexLookasideCacheIndexForPointerAndOptions       (const void           *ptr,         RKLRegexOptions options)                                                                   RKL_WARN_UNUSED_NONNULL_ARGS(1);
+RKL_STATIC_INLINE void            rkl_setRegexLookasideCacheToCachedRegexForPointer      (const RKLCachedRegex *cachedRegex, const void *ptr)                                                                           RKL_NONNULL_ARGS(1,2);
+RKL_STATIC_INLINE RKLCachedRegex *rkl_cachedRegexFromRegexLookasideCacheForString        (const void           *ptr,         RKLRegexOptions options)                                                                   RKL_WARN_UNUSED_NONNULL_ARGS(1);
+RKL_STATIC_INLINE NSUInteger      rkl_makeCacheSetHash                                   (      CFHashCode      regexHash,   RKLRegexOptions options)                                                                   RKL_WARN_UNUSED;
+RKL_STATIC_INLINE NSUInteger      rkl_cacheSetForRegexHashAndOptions                     (      CFHashCode      regexHash,   RKLRegexOptions options)                                                                   RKL_WARN_UNUSED;
+RKL_STATIC_INLINE NSUInteger      rkl_cacheWayForCachedRegex                             (const RKLCachedRegex *cachedRegex)                                                                                            RKL_WARN_UNUSED_NONNULL_ARGS(1);
+RKL_STATIC_INLINE NSUInteger      rkl_cacheSetForCachedRegex                             (const RKLCachedRegex *cachedRegex)                                                                                            RKL_WARN_UNUSED_NONNULL_ARGS(1);
+RKL_STATIC_INLINE RKLCachedRegex *rkl_cachedRegexForCacheSetAndWay                       (      NSUInteger      cacheSet,    NSUInteger      cacheWay)                                                                  RKL_WARN_UNUSED;
+RKL_STATIC_INLINE RKLCachedRegex *rkl_cachedRegexForRegexHashAndOptionsAndWay            (      CFHashCode      regexHash,   RKLRegexOptions options, NSUInteger cacheWay)                                              RKL_WARN_UNUSED;
+RKL_STATIC_INLINE void            rkl_updateCachesWithCachedRegex                        (      RKLCachedRegex *cachedRegex, const void *ptr, int hitOrMiss RKL_UNUSED_DTRACE_ARG, int status RKL_UNUSED_DTRACE_ARG)    RKL_NONNULL_ARGS(1,2);
+RKL_STATIC_INLINE RKLCachedRegex *rkl_leastRecentlyUsedCachedRegexForRegexHashAndOptions (      CFHashCode      regexHash,   RKLRegexOptions options)                                                                   RKL_WARN_UNUSED;
 
-static NSUInteger    rkl_search                    (RKLCacheSlot *cacheSlot, NSRange *searchRange, NSUInteger updateSearchRange, id *exception RKL_UNUSED_ASSERTION_ARG, int32_t *status)                        RKL_NONNULL_ARGS_WARN_UNUSED(1,2,4,5);
+static RKLCachedRegex *rkl_getCachedRegex            (NSString *regexString, RKLRegexOptions options, NSError **error, id *exception)                                                                                                                            RKL_WARN_UNUSED_NONNULL_ARGS(1,4);
+static NSUInteger      rkl_setCachedRegexToString    (RKLCachedRegex *cachedRegex, const NSRange *range, int32_t *status, id *exception RKL_UNUSED_ASSERTION_ARG)                                                                                                    RKL_WARN_UNUSED_NONNULL_ARGS(1,2,3,4);
+static RKLCachedRegex *rkl_getCachedRegexSetToString (NSString *regexString, RKLRegexOptions options, NSString *matchString, NSUInteger *matchLengthPtr, NSRange *matchRange, NSError **error, id *exception, int32_t *status)                                   RKL_WARN_UNUSED_NONNULL_ARGS(1,3,4,5,7,8);
+static id              rkl_performDictionaryVarArgsOp(id self, SEL _cmd, RKLRegexOp regexOp, NSString *regexString, RKLRegexOptions options, NSInteger capture, id matchString, NSRange *matchRange, NSString *replacementString, NSError **error, void *result, id firstKey, va_list varArgsList) RKL_NONNULL_ARGS(1,2);
+static id              rkl_performRegexOp            (id self, SEL _cmd, RKLRegexOp regexOp, NSString *regexString, RKLRegexOptions options, NSInteger capture, id matchString, NSRange *matchRange, NSString *replacementString, NSError **error, void *result, NSUInteger captureKeysCount, id captureKeys[captureKeysCount], const int captureKeyIndexes[captureKeysCount]) RKL_NONNULL_ARGS(1,2);
+static void            rkl_handleDelayedAssert       (id self, SEL _cmd, id exception)                                                                                                                                                                           RKL_NONNULL_ARGS(3);
 
-static BOOL          rkl_findRanges                (RKLCacheSlot *cacheSlot, RKLRegexOp regexOp,      RKLFindAll *findAll, id *exception, int32_t *status)                                                       RKL_NONNULL_ARGS_WARN_UNUSED(1,3,4,5);
-static NSUInteger    rkl_growFindRanges            (RKLCacheSlot *cacheSlot, NSUInteger lastLocation, RKLFindAll *findAll, id *exception RKL_UNUSED_ASSERTION_ARG)                                               RKL_NONNULL_ARGS_WARN_UNUSED(1,3,4);
-static NSArray      *rkl_makeArray                 (RKLCacheSlot *cacheSlot, RKLRegexOp regexOp,      RKLFindAll *findAll, id *exception RKL_UNUSED_ASSERTION_ARG)                                               RKL_NONNULL_ARGS_WARN_UNUSED(1,3,4);
+static NSUInteger      rkl_search                    (RKLCachedRegex *cachedRegex, NSRange *searchRange, NSUInteger updateSearchRange, id *exception RKL_UNUSED_ASSERTION_ARG, int32_t *status)                        RKL_WARN_UNUSED_NONNULL_ARGS(1,2,4,5);
 
-static NSString     *rkl_replaceString             (RKLCacheSlot *cacheSlot, id searchString, NSUInteger searchU16Length, NSString *replacementString, NSUInteger replacementU16Length, NSUInteger *replacedCount, NSUInteger replaceMutable, id *exception, int32_t *status)            RKL_NONNULL_ARGS_WARN_UNUSED(1,2,4,8,9);
-static int32_t       rkl_replaceAll                (RKLCacheSlot *cacheSlot, const UniChar *replacementUniChar, int32_t replacementU16Length, UniChar *replacedUniChar, int32_t replacedU16Capacity, NSUInteger *replacedCount, int32_t *needU16Capacity, id *exception RKL_UNUSED_ASSERTION_ARG, int32_t *status) RKL_NONNULL_ARGS_WARN_UNUSED(1,2,4,6,7,8,9);
+static BOOL            rkl_findRanges                (RKLCachedRegex *cachedRegex, RKLRegexOp regexOp,      RKLFindAll *findAll, id *exception, int32_t *status)                                                       RKL_WARN_UNUSED_NONNULL_ARGS(1,3,4,5);
+static NSUInteger      rkl_growFindRanges            (RKLCachedRegex *cachedRegex, NSUInteger lastLocation, RKLFindAll *findAll, id *exception RKL_UNUSED_ASSERTION_ARG)                                               RKL_WARN_UNUSED_NONNULL_ARGS(1,3,4);
+static NSArray        *rkl_makeArray                 (RKLCachedRegex *cachedRegex, RKLRegexOp regexOp,      RKLFindAll *findAll, id *exception RKL_UNUSED_ASSERTION_ARG)                                               RKL_WARN_UNUSED_NONNULL_ARGS(1,3,4);
+static id              rkl_makeDictionary            (RKLCachedRegex *cachedRegex, RKLRegexOp regexOp,      RKLFindAll *findAll, NSUInteger captureKeysCount, id captureKeys[captureKeysCount], const int captureKeyIndexes[captureKeysCount], id *exception RKL_UNUSED_ASSERTION_ARG) RKL_WARN_UNUSED_NONNULL_ARGS(1,3,5,6);
 
-static NSUInteger    rkl_isRegexValid              (id self, SEL _cmd, NSString *regex, RKLRegexOptions options, NSInteger *captureCountPtr, NSError **error) RKL_NONNULL_ARGS(1,2);
+static NSString       *rkl_replaceString             (RKLCachedRegex *cachedRegex, id searchString, NSUInteger searchU16Length, NSString *replacementString, NSUInteger replacementU16Length, NSInteger *replacedCount, NSUInteger replaceMutable, id *exception, int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,2,4,8,9);
+static int32_t         rkl_replaceAll                (RKLCachedRegex *cachedRegex, RKL_STRONG_REF const UniChar * RKL_GC_VOLATILE replacementUniChar, int32_t replacementU16Length, UniChar *replacedUniChar, int32_t replacedU16Capacity, NSInteger *replacedCount, int32_t *needU16Capacity, id *exception RKL_UNUSED_ASSERTION_ARG, int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,2,4,6,7,8,9);
 
-static void          rkl_clearStringCache          (void);
-static void          rkl_clearBuffer               (RKLBuffer *buffer, NSUInteger freeDynamicBuffer) RKL_NONNULL_ARGS(1);
-static void          rkl_clearCacheSlotRegex       (RKLCacheSlot *cacheSlot)                         RKL_NONNULL_ARGS(1);
-static void          rkl_clearCacheSlotSetTo       (RKLCacheSlot *cacheSlot)                         RKL_NONNULL_ARGS(1);
+static NSUInteger      rkl_isRegexValid              (id self, SEL _cmd, NSString *regex, RKLRegexOptions options, NSInteger *captureCountPtr, NSError **error) RKL_NONNULL_ARGS(1,2);
 
-static NSDictionary *rkl_userInfoDictionary        (NSString *regexString, RKLRegexOptions options, const UParseError *parseError, int32_t status, ...) RKL_ATTRIBUTES(sentinel, nonnull(1), warn_unused_result);
-static NSError      *rkl_NSErrorForRegex           (NSString *regexString, RKLRegexOptions options, const UParseError *parseError, int32_t status)      RKL_NONNULL_ARGS_WARN_UNUSED(1);
-static NSException  *rkl_NSExceptionForRegex       (NSString *regexString, RKLRegexOptions options, const UParseError *parseError, int32_t status)      RKL_NONNULL_ARGS_WARN_UNUSED(1);
-static NSDictionary *rkl_makeAssertDictionary      (const char *function, const char *file, int line, NSString *format, ...)                            RKL_NONNULL_ARGS_WARN_UNUSED(1,2,4);
-static NSString     *rkl_stringFromClassAndMethod  (id object, SEL selector, NSString *format, ...)                                                     RKL_NONNULL_ARGS_WARN_UNUSED(1,2,3);
+static void            rkl_clearStringCache          (void);
+static void            rkl_clearBuffer               (RKLBuffer *buffer, NSUInteger freeDynamicBuffer) RKL_NONNULL_ARGS(1);
+static void            rkl_clearCachedRegex          (RKLCachedRegex *cachedRegex)                     RKL_NONNULL_ARGS(1);
+static void            rkl_clearCachedRegexSetTo     (RKLCachedRegex *cachedRegex)                     RKL_NONNULL_ARGS(1);
 
-RKL_STATIC_INLINE int32_t rkl_getRangeForCapture(RKLCacheSlot *cs, int32_t *s, int32_t c, NSRange *r) RKL_NONNULL_ARGS_WARN_UNUSED(1,2,4);
-RKL_STATIC_INLINE int32_t rkl_getRangeForCapture(RKLCacheSlot *cs, int32_t *s, int32_t c, NSRange *r) { uregex *re = cs->icu_regex; int32_t start = RKL_ICU_FUNCTION_APPEND(uregex_start)(re, c, s); if(RKL_EXPECTED((*s > U_ZERO_ERROR), 0L) || (start == -1)) { *r = NSNotFoundRange; } else { r->location = (NSUInteger)start; r->length = (NSUInteger)RKL_ICU_FUNCTION_APPEND(uregex_end)(re, c, s) - r->location; r->location += cs->setToRange.location; } return(*s); }
+static NSDictionary   *rkl_userInfoDictionary        (RKLUserInfoOptions userInfoOptions, NSString *regexString, RKLRegexOptions options, const UParseError *parseError, int32_t status, NSString *matchString, NSRange matchRange, NSString *replacementString, NSString *replacedString, NSInteger replacedCount, RKLRegexEnumerationOptions enumerationOptions, ...)                        RKL_WARN_UNUSED_SENTINEL;
+static NSError        *rkl_makeNSError               (RKLUserInfoOptions userInfoOptions, NSString *regexString, RKLRegexOptions options, const UParseError *parseError, int32_t status, NSString *matchString, NSRange matchRange, NSString *replacementString, NSString *replacedString, NSInteger replacedCount, RKLRegexEnumerationOptions enumerationOptions, NSString *errorDescription) RKL_WARN_UNUSED;
 
-RKL_STATIC_INLINE RKLFindAll rkl_makeFindAll(NSRange *r, NSRange fir, NSInteger c, size_t s, size_t su, void **rsb, RKL_STRONG_REF void **ssb, RKL_STRONG_REF void **asb, NSInteger f, NSInteger cap, NSInteger fut) RKL_ATTRIBUTES(warn_unused_result);
-RKL_STATIC_INLINE RKLFindAll rkl_makeFindAll(NSRange *r, NSRange fir, NSInteger c, size_t s, size_t su, void **rsb, RKL_STRONG_REF void **ssb, RKL_STRONG_REF void **asb, NSInteger f, NSInteger cap, NSInteger fut) { return(((RKLFindAll){ .ranges=r, .findInRange=fir, .capacity=c, .found=f, .findUpTo=fut, .capture=cap, .size=s, .stackUsed=su, .rangesScratchBuffer=rsb, .stringsScratchBuffer=ssb, .arraysScratchBuffer=asb})); }
+static NSException    *rkl_NSExceptionForRegex       (NSString *regexString, RKLRegexOptions options, const UParseError *parseError, int32_t status) RKL_WARN_UNUSED_NONNULL_ARGS(1);
+static NSDictionary   *rkl_makeAssertDictionary      (const char *function, const char *file, int line, NSString *format, ...)                       RKL_WARN_UNUSED_NONNULL_ARGS(1,2,4);
+static NSString       *rkl_stringFromClassAndMethod  (id object, SEL selector, NSString *format, ...)                                                RKL_WARN_UNUSED_NONNULL_ARGS(3);
+
+RKL_STATIC_INLINE int32_t rkl_getRangeForCapture(RKLCachedRegex *cr, int32_t *s, int32_t c, NSRange *r) RKL_WARN_UNUSED_NONNULL_ARGS(1,2,4);
+RKL_STATIC_INLINE int32_t rkl_getRangeForCapture(RKLCachedRegex *cr, int32_t *s, int32_t c, NSRange *r) { uregex *re = cr->icu_regex; int32_t start = RKL_ICU_FUNCTION_APPEND(uregex_start)(re, c, s); if(RKL_EXPECTED((*s > U_ZERO_ERROR), 0L) || (start == -1)) { *r = NSNotFoundRange; } else { r->location = (NSUInteger)start; r->length = (NSUInteger)RKL_ICU_FUNCTION_APPEND(uregex_end)(re, c, s) - r->location; r->location += cr->setToRange.location; } return(*s); }
+
+RKL_STATIC_INLINE RKLFindAll rkl_makeFindAll(RKL_STRONG_REF NSRange * RKL_GC_VOLATILE r, NSRange fir, NSInteger c, size_t s, size_t su, RKL_STRONG_REF void ** RKL_GC_VOLATILE rsb, RKL_STRONG_REF void ** RKL_GC_VOLATILE ssb, RKL_STRONG_REF void ** RKL_GC_VOLATILE asb, RKL_STRONG_REF void ** RKL_GC_VOLATILE dsb, RKL_STRONG_REF void ** RKL_GC_VOLATILE ksb, NSInteger f, NSInteger cap, NSInteger fut) RKL_WARN_UNUSED_CONST;
+RKL_STATIC_INLINE RKLFindAll rkl_makeFindAll(RKL_STRONG_REF NSRange * RKL_GC_VOLATILE r, NSRange fir, NSInteger c, size_t s, size_t su, RKL_STRONG_REF void ** RKL_GC_VOLATILE rsb, RKL_STRONG_REF void ** RKL_GC_VOLATILE ssb, RKL_STRONG_REF void ** RKL_GC_VOLATILE asb, RKL_STRONG_REF void ** RKL_GC_VOLATILE dsb, RKL_STRONG_REF void ** RKL_GC_VOLATILE ksb, NSInteger f, NSInteger cap, NSInteger fut) { return(((RKLFindAll){ .ranges=r, .findInRange=fir, .remainingRange=fir, .capacity=c, .found=f, .findUpTo=fut, .capture=cap, .addedSplitRanges=0L, .size=s, .stackUsed=su, .rangesScratchBuffer=rsb, .stringsScratchBuffer=ssb, .arraysScratchBuffer=asb, .dictionariesScratchBuffer=dsb, .keysScratchBuffer=ksb})); }
 
 ////////////
 #pragma mark -
 #define rkl_CFStringIsMutable(s) (YES)
 #endif // RKL_FAST_MUTABLE_CHECK
 
-
 ////////////
 #pragma mark -
 #pragma mark iPhone / iPod touch low memory notification handler
 // The basic idea is that rkl_RegisterForLowMemoryNotifications() is set to be run once by the linker at load time via __attribute((constructor)).
 // rkl_RegisterForLowMemoryNotifications() tries to find the iPhone low memory notification symbol.  If it can find it,
 // it registers with the default NSNotificationCenter to call the RKLLowMemoryWarningObserver class method +lowMemoryWarning:.
-// rkl_RegisterForLowMemoryNotifications() uses an atomic compare and swap to guarantee that it initalizes exactly once.
+// rkl_RegisterForLowMemoryNotifications() uses an atomic compare and swap to guarantee that it initializes exactly once.
 // +lowMemoryWarning tries to acquire the cache lock.  If it gets the lock, it clears the cache.  If it can't, it calls performSelector:
 // with a delay of half a second to try again.  This will hopefully prevent any deadlocks, such as a RegexKitLite request for
-// memory triggering a notifcation while the lock is held.
+// memory triggering a notification while the lock is held.
 
 static void rkl_RegisterForLowMemoryNotifications(void) RKL_ATTRIBUTES(used);
 
 @interface      RKLLowMemoryWarningObserver : NSObject +(void)lowMemoryWarning:(id)notification; @end
 @implementation RKLLowMemoryWarningObserver
 +(void)lowMemoryWarning:(id)notification {
-  if(OSSpinLockTry(&cacheSpinLock)) { rkl_clearStringCache(); OSSpinLockUnlock(&cacheSpinLock); }
+  if(OSSpinLockTry(&rkl_cacheSpinLock)) { rkl_clearStringCache(); OSSpinLockUnlock(&rkl_cacheSpinLock); }
   else { [[RKLLowMemoryWarningObserver class] performSelector:@selector(lowMemoryWarning:) withObject:notification afterDelay:(NSTimeInterval)0.1]; }
 }
 @end
 
 #endif // defined(RKL_REGISTER_FOR_IPHONE_LOWMEM_NOTIFICATIONS) && (RKL_REGISTER_FOR_IPHONE_LOWMEM_NOTIFICATIONS == 1)
 
+////////////
+#pragma mark -
+#pragma mark DTrace functionality
+
 #ifdef    _RKL_DTRACE_ENABLED
 
 // compiledRegexCache(unsigned long eventID, const char *regexUTF8, int options, int captures, int hitMiss, int icuStatusCode, const char *icuErrorMessage, double *hitRate);
   RKLSetTextLookupFlag            = 1 << 2,
   RKLDynamicBufferLookupFlag      = 1 << 3,
   RKLErrorLookupFlag              = 1 << 4,
+  RKLEnumerationBufferLookupFlag  = 1 << 5,
 };
 
 #define rkl_dtrace_addLookupFlag(a,b) do { a |= (unsigned int)(b); } while(0)
 
-static char rkl_dtrace_regexUTF8[(RKL_CACHE_SIZE) + 1][(RKL_DTRACE_REGEXUTF8_SIZE)];
+static char rkl_dtrace_regexUTF8[_RKL_REGEX_CACHE_LINES + 1UL][_RKL_DTRACE_REGEXUTF8_SIZE];
 static NSUInteger rkl_dtrace_eventID, rkl_dtrace_compiledCacheLookups, rkl_dtrace_compiledCacheHits, rkl_dtrace_conversionBufferLookups, rkl_dtrace_conversionBufferHits;
 
 #define rkl_dtrace_incrementEventID() do { rkl_dtrace_eventID++; } while(0)
+#define rkl_dtrace_incrementAndGetEventID(v) do { rkl_dtrace_eventID++; v = rkl_dtrace_eventID; } while(0)
 #define rkl_dtrace_compiledRegexCache(a0, a1, a2, a3, a4, a5) do { int _a3 = (a3); rkl_dtrace_compiledCacheLookups++; if(_a3 == 1) { rkl_dtrace_compiledCacheHits++; } if(RKL_EXPECTED(REGEXKITLITE_COMPILEDREGEXCACHE_ENABLED(), 0L)) { double hitRate = 0.0; if(rkl_dtrace_compiledCacheLookups > 0UL) { hitRate = ((double)rkl_dtrace_compiledCacheHits / (double)rkl_dtrace_compiledCacheLookups) * 100.0; } REGEXKITLITE_COMPILEDREGEXCACHE(rkl_dtrace_eventID, a0, a1, a2, _a3, a4, a5, &hitRate); } } while(0)
 #define rkl_dtrace_utf16ConversionCache(a0, a1, a2, a3, a4) do { unsigned int _a0 = (a0); if((_a0 & RKLConversionRequiredLookupFlag) != 0U) { rkl_dtrace_conversionBufferLookups++; if((_a0 & RKLCacheHitLookupFlag) != 0U) { rkl_dtrace_conversionBufferHits++; } } if(RKL_EXPECTED(REGEXKITLITE_CONVERTEDSTRINGU16CACHE_ENABLED(), 0L)) { double hitRate = 0.0; if(rkl_dtrace_conversionBufferLookups > 0UL) { hitRate = ((double)rkl_dtrace_conversionBufferHits / (double)rkl_dtrace_conversionBufferLookups) * 100.0; } REGEXKITLITE_CONVERTEDSTRINGU16CACHE(rkl_dtrace_eventID, _a0, &hitRate, a1, a2, a3, a4); } } while(0)
+#define rkl_dtrace_utf16ConversionCacheWithEventID(c0, a0, a1, a2, a3, a4) do { unsigned int _a0 = (a0); if((_a0 & RKLConversionRequiredLookupFlag) != 0U) { rkl_dtrace_conversionBufferLookups++; if((_a0 & RKLCacheHitLookupFlag) != 0U) { rkl_dtrace_conversionBufferHits++; } } if(RKL_EXPECTED(REGEXKITLITE_CONVERTEDSTRINGU16CACHE_ENABLED(), 0L)) { double hitRate = 0.0; if(rkl_dtrace_conversionBufferLookups > 0UL) { hitRate = ((double)rkl_dtrace_conversionBufferHits / (double)rkl_dtrace_conversionBufferLookups) * 100.0; } REGEXKITLITE_CONVERTEDSTRINGU16CACHE(c0, _a0, &hitRate, a1, a2, a3, a4); } } while(0)
 
 
 // \342\200\246 == UTF8 for HORIZONTAL ELLIPSIS, aka triple dots '...'
 #define RKL_UTF8_ELLIPSE "\342\200\246"
 
 // rkl_dtrace_getRegexUTF8 will copy the str argument to utf8Buffer using UTF8 as the string encoding.
-// If the utf8 encoding would take up more bytes than the utf8Buffers length, then the unicode character 'HORIZONTAL ELLIPSIS' ('...') is appened to indicate truncation occured.
+// If the utf8 encoding would take up more bytes than the utf8Buffers length, then the unicode character 'HORIZONTAL ELLIPSIS' ('...') is appended to indicate truncation occurred.
 static void rkl_dtrace_getRegexUTF8(CFStringRef str, char *utf8Buffer) RKL_NONNULL_ARGS(2);
 static void rkl_dtrace_getRegexUTF8(CFStringRef str, char *utf8Buffer) {
   if((str == NULL) || (utf8Buffer == NULL)) { return; }
-  CFIndex maxLength = ((CFIndex)(RKL_DTRACE_REGEXUTF8_SIZE) - 2L), maxBytes = (maxLength - (CFIndex)sizeof(RKL_UTF8_ELLIPSE) - 1L), stringU16Length = CFStringGetLength(str), usedBytes = 0L;
+  CFIndex maxLength = ((CFIndex)_RKL_DTRACE_REGEXUTF8_SIZE - 2L), maxBytes = (maxLength - (CFIndex)sizeof(RKL_UTF8_ELLIPSE) - 1L), stringU16Length = CFStringGetLength(str), usedBytes = 0L;
   CFStringGetBytes(str, CFMakeRange(0L, ((stringU16Length < maxLength) ? stringU16Length : maxLength)), kCFStringEncodingUTF8, (UInt8)'?', (Boolean)0, (UInt8 *)utf8Buffer, maxBytes, &usedBytes);
-  if(usedBytes == maxBytes) { strncpy(utf8Buffer + usedBytes, RKL_UTF8_ELLIPSE, ((size_t)(RKL_DTRACE_REGEXUTF8_SIZE) - (size_t)usedBytes) - 2UL); } else { utf8Buffer[usedBytes] = (char)0; }
+  if(usedBytes == maxBytes) { strncpy(utf8Buffer + usedBytes, RKL_UTF8_ELLIPSE, ((size_t)_RKL_DTRACE_REGEXUTF8_SIZE - (size_t)usedBytes) - 2UL); } else { utf8Buffer[usedBytes] = (char)0; }
 }
 
 #else  // _RKL_DTRACE_ENABLED
 
 #define rkl_dtrace_incrementEventID()
+#define rkl_dtrace_incrementAndGetEventID(v)
 #define rkl_dtrace_compiledRegexCache(a0, a1, a2, a3, a4, a5)
 #define rkl_dtrace_utf16ConversionCache(a0, a1, a2, a3, a4)
+#define rkl_dtrace_utf16ConversionCacheWithEventID(c0, a0, a1, a2, a3, a4)
 #define rkl_dtrace_getRegexUTF8(str, buf)
 #define rkl_dtrace_addLookupFlag(a,b)
 
 ////////////
 #pragma mark -
 #pragma mark RegexKitLite low-level internal functions
+#pragma mark -
+
+// The 4-way set associative LRU logic comes from Henry S. Warren Jr.'s Hacker's Delight, "revisions", 7-7 An LRU Algorithm:
+// http://www.hackersdelight.org/revisions.pdf
+// The functions rkl_leastRecentlyUsedWayInSet() and rkl_accessCacheSetWay() implement the cache functionality and are used
+// from a number of different places that need to perform caching (i.e., cached regex, cached UTF16 conversions, etc)
+
+#pragma mark 4-way set associative LRU functions
+
+RKL_STATIC_INLINE NSUInteger rkl_leastRecentlyUsedWayInSet(NSUInteger cacheSetsCount, const RKLLRUCacheSet_t cacheSetsArray[cacheSetsCount], NSUInteger set) {
+  RKLCAbortAssert((cacheSetsArray != NULL) && ((NSInteger)cacheSetsCount > 0L) && (set < cacheSetsCount) && ((cacheSetsArray == rkl_cachedRegexCacheSets) ? set < _RKL_REGEX_LRU_CACHE_SETS : 1) && (((sizeof(unsigned int) - sizeof(RKLLRUCacheSet_t)) * 8) < (sizeof(unsigned int) * 8)));
+  unsigned int cacheSet = (((unsigned int)cacheSetsArray[set]) << ((sizeof(unsigned int) - sizeof(RKLLRUCacheSet_t)) * 8)); // __builtin_clz takes an 'unsigned int' argument.  The rest is to ensure bit alignment regardless of 32/64/whatever.
+  NSUInteger leastRecentlyUsed = ((NSUInteger)(3LU - (NSUInteger)((__builtin_clz((~(((cacheSet & 0x77777777U) + 0x77777777U) | cacheSet | 0x77777777U))) ) >> 2)));
+  RKLCAbortAssert(leastRecentlyUsed < _RKL_LRU_CACHE_SET_WAYS);
+  return(leastRecentlyUsed);
+}
+
+RKL_STATIC_INLINE void rkl_accessCacheSetWay(NSUInteger cacheSetsCount, RKLLRUCacheSet_t cacheSetsArray[cacheSetsCount], NSUInteger cacheSet, NSUInteger cacheWay) {
+  RKLCAbortAssert((cacheSetsArray != NULL) && ((NSInteger)cacheSetsCount > 0L) && (cacheSet < cacheSetsCount) && (cacheWay < _RKL_LRU_CACHE_SET_WAYS) && ((cacheSetsArray == rkl_cachedRegexCacheSets) ? cacheSet < _RKL_REGEX_LRU_CACHE_SETS : 1));
+  cacheSetsArray[cacheSet] = (RKLLRUCacheSet_t)(((cacheSetsArray[cacheSet] & (RKLLRUCacheSet_t)0xFFFFU) | (((RKLLRUCacheSet_t)0xFU) << (cacheWay * 4U))) & (~(((RKLLRUCacheSet_t)0x1111U) << (3U - cacheWay))));
+}
+
+#pragma mark Common, macro'ish compiled regular expression cache logic
+
+// These functions consolidate bits and pieces of code used to maintain, update, and access the 4-way set associative LRU cache and Regex Lookaside Cache.
+RKL_STATIC_INLINE NSUInteger      rkl_regexLookasideCacheIndexForPointerAndOptions  (const void           *ptr,       RKLRegexOptions options)                       { return(((((NSUInteger)(ptr)) >> 4) + options + (options >> 4)) & _RKL_REGEX_LOOKASIDE_CACHE_MASK); }
+RKL_STATIC_INLINE void            rkl_setRegexLookasideCacheToCachedRegexForPointer (const RKLCachedRegex *cachedRegex, const void *ptr)                             { rkl_regexLookasideCache[rkl_regexLookasideCacheIndexForPointerAndOptions(ptr, cachedRegex->options)] = (cachedRegex - rkl_cachedRegexes); }
+RKL_STATIC_INLINE RKLCachedRegex *rkl_cachedRegexFromRegexLookasideCacheForString   (const void           *ptr,       RKLRegexOptions options)                       { return(&rkl_cachedRegexes[rkl_regexLookasideCache[rkl_regexLookasideCacheIndexForPointerAndOptions(ptr, options)]]); }
+RKL_STATIC_INLINE NSUInteger      rkl_makeCacheSetHash                              (      CFHashCode      regexHash, RKLRegexOptions options)                       { return((NSUInteger)regexHash ^ (NSUInteger)options); }
+RKL_STATIC_INLINE NSUInteger      rkl_cacheSetForRegexHashAndOptions                (      CFHashCode      regexHash, RKLRegexOptions options)                       { return((rkl_makeCacheSetHash(regexHash, options) % _RKL_REGEX_LRU_CACHE_SETS)); }
+RKL_STATIC_INLINE NSUInteger      rkl_cacheWayForCachedRegex                        (const RKLCachedRegex *cachedRegex)                                              { return((cachedRegex - rkl_cachedRegexes) % _RKL_LRU_CACHE_SET_WAYS); }
+RKL_STATIC_INLINE NSUInteger      rkl_cacheSetForCachedRegex                        (const RKLCachedRegex *cachedRegex)                                              { return(rkl_cacheSetForRegexHashAndOptions(cachedRegex->regexHash, cachedRegex->options)); }
+RKL_STATIC_INLINE RKLCachedRegex *rkl_cachedRegexForCacheSetAndWay                  (      NSUInteger      cacheSet,  NSUInteger cacheWay)                           { return(&rkl_cachedRegexes[((cacheSet * _RKL_LRU_CACHE_SET_WAYS) + cacheWay)]); }
+RKL_STATIC_INLINE RKLCachedRegex *rkl_cachedRegexForRegexHashAndOptionsAndWay       (      CFHashCode      regexHash, RKLRegexOptions options, NSUInteger cacheWay)  { return(rkl_cachedRegexForCacheSetAndWay(rkl_cacheSetForRegexHashAndOptions(regexHash, options), cacheWay)); }
+
+RKL_STATIC_INLINE void rkl_updateCachesWithCachedRegex(RKLCachedRegex *cachedRegex, const void *ptr, int hitOrMiss RKL_UNUSED_DTRACE_ARG, int status RKL_UNUSED_DTRACE_ARG) {
+  rkl_lastCachedRegex = cachedRegex;
+  rkl_setRegexLookasideCacheToCachedRegexForPointer(cachedRegex, ptr);
+  rkl_accessCacheSetWay(_RKL_REGEX_LRU_CACHE_SETS, rkl_cachedRegexCacheSets, rkl_cacheSetForCachedRegex(cachedRegex), rkl_cacheWayForCachedRegex(cachedRegex)); // Set the matching line as the most recently used.
+  rkl_dtrace_compiledRegexCache(&rkl_dtrace_regexUTF8[(cachedRegex - rkl_cachedRegexes)][0], cachedRegex->options, (int)cachedRegex->captureCount, hitOrMiss, status, NULL);
+}
+
+RKL_STATIC_INLINE RKLCachedRegex *rkl_leastRecentlyUsedCachedRegexForRegexHashAndOptions(CFHashCode regexHash, RKLRegexOptions options) {
+  NSUInteger cacheSet = rkl_cacheSetForRegexHashAndOptions(regexHash, options);
+  return(rkl_cachedRegexForCacheSetAndWay(cacheSet, rkl_leastRecentlyUsedWayInSet(_RKL_REGEX_LRU_CACHE_SETS, rkl_cachedRegexCacheSets, cacheSet)));
+}
+
+#pragma mark Regular expression lookup function
 
 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
-//  IMPORTANT!   Should only be called with cacheSpinLock already locked!
+//  IMPORTANT!   Should only be called with rkl_cacheSpinLock already locked!
 //  ----------
 
-static RKLCacheSlot *rkl_getCachedRegex(NSString *regexString, RKLRegexOptions options, NSError **error, id *exception) {
-  RKLCacheSlot *cacheSlot = NULL;
-  CFHashCode    regexHash = 0UL;
-  int32_t       status    = 0;
+static RKLCachedRegex *rkl_getCachedRegex(NSString *regexString, RKLRegexOptions options, NSError **error, id *exception) {
+  //  ----------   vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+  //  IMPORTANT!   This section of code is called almost every single time that any RegexKitLite functionality is used! It /MUST/ be very fast!
+  //  ----------   vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
   
-  RKLCDelayedAssert((cacheSpinLock != (OSSpinLock)0) && (regexString != NULL), exception, exitNow);
+  RKLCachedRegex *cachedRegex = NULL;
+  CFHashCode      regexHash   = 0UL;
+  int32_t         status      = 0;
+
+  RKLCDelayedAssert((rkl_cacheSpinLock != (OSSpinLock)0) && (regexString != NULL), exception, exitNow);
   
   // Fast path the common case where this regex is exactly the same one used last time.
-  // The pointer equality test is valid under these circumstances since the cacheSlot->regexString is an immutable copy.
+  // The pointer equality test is valid under these circumstances since the cachedRegex->regexString is an immutable copy.
   // If the regexString argument is mutable, this test will fail, and we'll use the the slow path cache check below.
-  if(RKL_EXPECTED(lastCacheSlot != NULL, 1L) && RKL_EXPECTED(lastCacheSlot->options == options, 1L) && RKL_EXPECTED(lastCacheSlot->icu_regex != NULL, 1L) && RKL_EXPECTED(lastCacheSlot->regexString != NULL, 1L) && RKL_EXPECTED(lastCacheSlot->regexString == (CFStringRef)regexString, 1L)) {
-    rkl_dtrace_compiledRegexCache(&rkl_dtrace_regexUTF8[(lastCacheSlot - &rkl_cacheSlots[0])][0], lastCacheSlot->options, (int)lastCacheSlot->captureCount, 1, 0, NULL);
-    return(lastCacheSlot);
+  if(RKL_EXPECTED(rkl_lastCachedRegex != NULL, 1L) && RKL_EXPECTED(rkl_lastCachedRegex->regexString == (CFStringRef)regexString, 1L) && RKL_EXPECTED(rkl_lastCachedRegex->options == options, 1L) && RKL_EXPECTED(rkl_lastCachedRegex->icu_regex != NULL, 1L)) {
+    rkl_dtrace_compiledRegexCache(&rkl_dtrace_regexUTF8[(rkl_lastCachedRegex - rkl_cachedRegexes)][0], rkl_lastCachedRegex->options, (int)rkl_lastCachedRegex->captureCount, 1, 0, NULL);
+    return(rkl_lastCachedRegex);
   }
 
-  lastCacheSlot = NULL;
-  regexHash     = CFHash((CFTypeRef)regexString);
-  cacheSlot     = &rkl_cacheSlots[(regexHash % (CFHashCode)(RKL_CACHE_SIZE))]; // Retrieve the cache slot for this regex.
-  
-  // Return the cached entry if it's a match, otherwise clear the slot and create a new ICU regex in its place.
-  // If regexString is mutable, the pointer equality test will fail, and CFEqual() is used to determine true
-  // equality with the immutable cacheSlot copy.  CFEqual() performs a slow character by character check.
-  if(RKL_EXPECTED(cacheSlot->options == options, 1L) && RKL_EXPECTED(cacheSlot->icu_regex != NULL, 1L) && RKL_EXPECTED(cacheSlot->regexString != NULL, 1L) && (RKL_EXPECTED(cacheSlot->regexString == (CFStringRef)regexString, 1L) || RKL_EXPECTED(CFEqual((CFTypeRef)regexString, (CFTypeRef)cacheSlot->regexString) == YES, 1L))) {
-    lastCacheSlot = cacheSlot;
-    rkl_dtrace_compiledRegexCache(&rkl_dtrace_regexUTF8[(lastCacheSlot - &rkl_cacheSlots[0])][0], lastCacheSlot->options, (int)lastCacheSlot->captureCount, 1, 0, NULL);
-    return(cacheSlot);
+  rkl_lastCachedRegex = NULL; // Make sure that rkl_lastCachedRegex is NULL in case there is some kind of error.
+  cachedRegex         = rkl_cachedRegexFromRegexLookasideCacheForString(regexString, options); // Check the Regex Lookaside Cache to see if we can quickly find the correct Cached Regex for this regexString pointer + options.
+  if((RKL_EXPECTED(cachedRegex->regexString == (CFStringRef)regexString, 1L) || (RKL_EXPECTED(cachedRegex->regexString != NULL, 1L) && RKL_EXPECTED(CFEqual((CFTypeRef)regexString, (CFTypeRef)cachedRegex->regexString) == YES, 1L))) && RKL_EXPECTED(cachedRegex->options == options, 1L) && RKL_EXPECTED(cachedRegex->icu_regex != NULL, 1L)) { goto foundMatch; } // There was a Regex Lookaside Cache hit, jump to foundMatch: to quickly return the result. A Regex Lookaside Cache hit allows us to bypass calling CFHash(), which is a decent performance win.
+  else { cachedRegex = NULL; regexHash = CFHash((CFTypeRef)regexString); } // Regex Lookaside Cache miss.  We need to call CFHash() to determine the cache set for this regex.
+
+  NSInteger cacheWay = 0L;                                                               // Check each way of the set that this regex belongs to.
+  for(cacheWay = ((NSInteger)_RKL_LRU_CACHE_SET_WAYS - 1L); cacheWay > 0L; cacheWay--) { // Checking the ways in reverse (3, 2, 1, 0) finds a match "sooner" on average.
+    cachedRegex = rkl_cachedRegexForRegexHashAndOptionsAndWay(regexHash, options, (NSUInteger)cacheWay);
+    // Return the cached entry if it's a match. If regexString is mutable, the pointer equality test will fail, and CFEqual() is used to determine true equality with the immutable cachedRegex copy.  CFEqual() performs a slow character by character check.
+    if(RKL_EXPECTED(cachedRegex->regexHash == regexHash, 0UL) && ((cachedRegex->regexString == (CFStringRef)regexString) || (RKL_EXPECTED(cachedRegex->regexString != NULL, 1L) && RKL_EXPECTED(CFEqual((CFTypeRef)regexString, (CFTypeRef)cachedRegex->regexString) == YES, 1L))) && RKL_EXPECTED(cachedRegex->options == options, 1L) && RKL_EXPECTED(cachedRegex->icu_regex != NULL, 1L)) {
+    foundMatch: // Control can transfer here (from above) via a Regex Lookaside Cache hit.
+      rkl_updateCachesWithCachedRegex(cachedRegex, regexString, 1, 0);
+      return(cachedRegex);
+    }
   }
 
-  rkl_clearCacheSlotRegex(cacheSlot);
+  //  ----------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  //  IMPORTANT!   This section of code is called almost every single time that any RegexKitLite functionality is used! It /MUST/ be very fast!
+  //  ----------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+  // Code below this point is not as sensitive to speed since compiling a regular expression is an extremely expensive operation.
+  // The regex was not found in the cache.  Get the cached regex for the least recently used line in the set, then clear the cached regex and create a new ICU regex in its place.
+  cachedRegex = rkl_leastRecentlyUsedCachedRegexForRegexHashAndOptions(regexHash, options);
+  rkl_clearCachedRegex(cachedRegex);
   
-  if(RKL_EXPECTED((cacheSlot->regexString = CFStringCreateCopy(NULL, (CFStringRef)regexString)) == NULL, 0L)) { goto exitNow; } ; // Get a cheap immutable copy.
-  rkl_dtrace_getRegexUTF8(cacheSlot->regexString, &rkl_dtrace_regexUTF8[(cacheSlot - &rkl_cacheSlots[0])][0]);
-  cacheSlot->options = options;
+  if(RKL_EXPECTED((cachedRegex->regexString = CFStringCreateCopy(NULL, (CFStringRef)regexString)) == NULL, 0L)) { goto exitNow; } ; // Get a cheap immutable copy.
+  rkl_dtrace_getRegexUTF8(cachedRegex->regexString, &rkl_dtrace_regexUTF8[(cachedRegex - rkl_cachedRegexes)][0]);
+  cachedRegex->regexHash = regexHash;
+  cachedRegex->options   = options;
   
-  CFIndex        regexStringU16Length = CFStringGetLength(cacheSlot->regexString); // In UTF16 code units.
-  UParseError    parseError           = (UParseError){-1, -1, {0}, {0}};
-  const UniChar *regexUniChar         = NULL;
+  CFIndex                                        regexStringU16Length = CFStringGetLength(cachedRegex->regexString); // In UTF16 code units.
+  UParseError                                    parseError           = (UParseError){-1, -1, {0}, {0}};
+  RKL_STRONG_REF const UniChar * RKL_GC_VOLATILE regexUniChar         = NULL;
   
   if(RKL_EXPECTED(regexStringU16Length >= (CFIndex)INT_MAX, 0L)) { *exception = [NSException exceptionWithName:NSRangeException reason:@"Regex string length exceeds INT_MAX" userInfo:NULL]; goto exitNow; }
 
   // Try to quickly obtain regexString in UTF16 format.
-  if((regexUniChar = CFStringGetCharactersPtr(cacheSlot->regexString)) == NULL) { // We didn't get the UTF16 pointer quickly and need to perform a full conversion in a temp buffer.
-    UniChar *uniCharBuffer = NULL;
-    if(((size_t)regexStringU16Length * sizeof(UniChar)) < (size_t)(RKL_STACK_LIMIT)) { if(RKL_EXPECTED((uniCharBuffer = (UniChar *)alloca(                        (size_t)regexStringU16Length * sizeof(UniChar)     )) == NULL, 0L)) { goto exitNow; } } // Try to use the stack.
-    else {                                                                             if(RKL_EXPECTED((uniCharBuffer = (UniChar *)rkl_realloc(&scratchBuffer[0], (size_t)regexStringU16Length * sizeof(UniChar), 0UL)) == NULL, 0L)) { goto exitNow; } } // Otherwise use the heap.
-    CFStringGetCharacters(cacheSlot->regexString, CFMakeRange(0L, regexStringU16Length), uniCharBuffer); // Convert regexString to UTF16.
+  if((regexUniChar = CFStringGetCharactersPtr(cachedRegex->regexString)) == NULL) { // We didn't get the UTF16 pointer quickly and need to perform a full conversion in a temp buffer.
+    RKL_STRONG_REF UniChar * RKL_GC_VOLATILE uniCharBuffer = NULL;
+    if(((size_t)regexStringU16Length * sizeof(UniChar)) < (size_t)_RKL_STACK_LIMIT) { if(RKL_EXPECTED((uniCharBuffer = (RKL_STRONG_REF UniChar * RKL_GC_VOLATILE)alloca(                            (size_t)regexStringU16Length * sizeof(UniChar)     )) == NULL, 0L)) { goto exitNow; } } // Try to use the stack.
+    else {                                                                            if(RKL_EXPECTED((uniCharBuffer = (RKL_STRONG_REF UniChar * RKL_GC_VOLATILE)rkl_realloc(&rkl_scratchBuffer[0], (size_t)regexStringU16Length * sizeof(UniChar), 0UL)) == NULL, 0L)) { goto exitNow; } } // Otherwise use the heap.
+    CFStringGetCharacters(cachedRegex->regexString, CFMakeRange(0L, regexStringU16Length), uniCharBuffer); // Convert regexString to UTF16.
     regexUniChar = uniCharBuffer;
   }
   
   // Create the ICU regex.
-  if(RKL_EXPECTED((cacheSlot->icu_regex = RKL_ICU_FUNCTION_APPEND(uregex_open)(regexUniChar, (int32_t)regexStringU16Length, options, &parseError, &status)) == NULL, 0L)) { goto exitNow; }
-  if(RKL_EXPECTED(status <= U_ZERO_ERROR, 1L)) { cacheSlot->captureCount = (NSInteger)RKL_ICU_FUNCTION_APPEND(uregex_groupCount)(cacheSlot->icu_regex, &status); }
-  if(RKL_EXPECTED(status <= U_ZERO_ERROR, 1L)) { lastCacheSlot           = cacheSlot; }
+  if(RKL_EXPECTED((cachedRegex->icu_regex = RKL_ICU_FUNCTION_APPEND(uregex_open)(regexUniChar, (int32_t)regexStringU16Length, options, &parseError, &status)) == NULL, 0L)) { goto exitNow; }
+  if(RKL_EXPECTED(status <= U_ZERO_ERROR, 1L)) { cachedRegex->captureCount = (NSInteger)RKL_ICU_FUNCTION_APPEND(uregex_groupCount)(cachedRegex->icu_regex, &status); }
+  if(RKL_EXPECTED(status <= U_ZERO_ERROR, 1L)) { rkl_updateCachesWithCachedRegex(cachedRegex, regexString, 0, status); }
   
 exitNow:
-  if(RKL_EXPECTED(scratchBuffer[0] != NULL,         0L)) { scratchBuffer[0] = rkl_free(&scratchBuffer[0]); }
-  if(RKL_EXPECTED(status            > U_ZERO_ERROR, 0L)) { rkl_clearCacheSlotRegex(cacheSlot); cacheSlot = NULL; if(error != NULL) { *error = rkl_NSErrorForRegex(regexString, options, &parseError, status); } }
+  if(RKL_EXPECTED(rkl_scratchBuffer[0] != NULL,         0L)) { rkl_scratchBuffer[0] = rkl_free(&rkl_scratchBuffer[0]); }
+  if(RKL_EXPECTED(status                > U_ZERO_ERROR, 0L)) { rkl_clearCachedRegex(cachedRegex); cachedRegex = rkl_lastCachedRegex = NULL; if(error != NULL) { *error = rkl_makeNSError((RKLUserInfoOptions)RKLUserInfoNone, regexString, options, &parseError, status, NULL, NSNotFoundRange, NULL, NULL, 0L, (RKLRegexEnumerationOptions)RKLRegexEnumerationNoOptions, @"There was an error compiling the regular expression."); } }
   
 #ifdef    _RKL_DTRACE_ENABLED
-  if(RKL_EXPECTED(cacheSlot != NULL, 1L)) { rkl_dtrace_compiledRegexCache(&rkl_dtrace_regexUTF8[(cacheSlot - &rkl_cacheSlots[0])][0], cacheSlot->options, (int)cacheSlot->captureCount, 0, status, NULL); }
-  else { char regexUTF8[(RKL_DTRACE_REGEXUTF8_SIZE)]; const char *err = NULL; if(status != U_ZERO_ERROR) { err = RKL_ICU_FUNCTION_APPEND(u_errorName)(status); } rkl_dtrace_getRegexUTF8((CFStringRef)regexString, regexUTF8); rkl_dtrace_compiledRegexCache(regexUTF8, options, -1, -1, status, err); }
+  if(RKL_EXPECTED(cachedRegex == NULL, 1L)) { char regexUTF8[_RKL_DTRACE_REGEXUTF8_SIZE]; const char *err = NULL; if(status != U_ZERO_ERROR) { err = RKL_ICU_FUNCTION_APPEND(u_errorName)(status); } rkl_dtrace_getRegexUTF8((CFStringRef)regexString, regexUTF8); rkl_dtrace_compiledRegexCache(regexUTF8, options, -1, -1, status, err); }
 #endif // _RKL_DTRACE_ENABLED
   
-  return(cacheSlot);
+  return(cachedRegex);
 }
 
 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
-//  IMPORTANT!   Should only be called with cacheSpinLock already locked!
+//  IMPORTANT!   Should only be called with rkl_cacheSpinLock already locked!
 //  ----------
 
-static NSUInteger rkl_setCacheSlotToString(RKLCacheSlot *cacheSlot, const NSRange *range, int32_t *status, id *exception RKL_UNUSED_ASSERTION_ARG) {
-  RKLCDelayedAssert((cacheSlot != NULL) && (cacheSlot->setToString != NULL) && ((range != NULL) && (NSEqualRanges(*range, NSNotFoundRange) == NO)) && (status != NULL), exception, exitNow);
-  const UniChar *stringUniChar = NULL;
+#pragma mark Set a cached regular expression to a NSStrings UTF-16 text
+
+static NSUInteger rkl_setCachedRegexToString(RKLCachedRegex *cachedRegex, const NSRange *range, int32_t *status, id *exception RKL_UNUSED_ASSERTION_ARG) {
+  //  ----------   vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+  //  IMPORTANT!   This section of code is called almost every single time that any RegexKitLite functionality is used! It /MUST/ be very fast!
+  //  ----------   vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+  
+  RKLCDelayedAssert((cachedRegex != NULL) && (cachedRegex->setToString != NULL) && ((range != NULL) && (NSEqualRanges(*range, NSNotFoundRange) == NO)) && (status != NULL), exception, exitNow);
+  RKL_STRONG_REF const UniChar * RKL_GC_VOLATILE stringUniChar = NULL;
 #ifdef _RKL_DTRACE_ENABLED
   unsigned int lookupResultFlags = 0U;
 #endif
   
-  if(cacheSlot->setToNeedsConversion == 0U) {
-    if(RKL_EXPECTED((stringUniChar = CFStringGetCharactersPtr(cacheSlot->setToString)) == NULL, 0L)) { cacheSlot->setToNeedsConversion = 1U; }
-    else { if(RKL_EXPECTED(cacheSlot->setToUniChar != stringUniChar, 0L)) { cacheSlot->setToRange = NSNotFoundRange; cacheSlot->setToUniChar = stringUniChar; } goto setRegexText; }
+  NSUInteger  useFixedBuffer = (cachedRegex->setToLength < (CFIndex)_RKL_FIXED_LENGTH) ? 1UL : 0UL;
+  RKLBuffer  *buffer         = NULL;
+  
+  if(cachedRegex->setToNeedsConversion == 0U) {
+    RKLCDelayedAssert((cachedRegex->setToUniChar != NULL) && (cachedRegex->buffer == NULL), exception, exitNow);
+    if(RKL_EXPECTED((stringUniChar = (RKL_STRONG_REF const UniChar * RKL_GC_VOLATILE)CFStringGetCharactersPtr(cachedRegex->setToString)) == NULL, 0L)) { cachedRegex->setToUniChar = NULL; cachedRegex->setToRange = NSNotFoundRange; cachedRegex->setToNeedsConversion = 1U; }
+    else { if(RKL_EXPECTED(cachedRegex->setToUniChar != stringUniChar, 0L)) { cachedRegex->setToRange = NSNotFoundRange; cachedRegex->setToUniChar = stringUniChar; } goto setRegexText; }
   }
-  rkl_dtrace_addLookupFlag(lookupResultFlags, RKLConversionRequiredLookupFlag);
+
+  buffer = cachedRegex->buffer;
+
+  RKLCDelayedAssert((buffer == NULL) ? 1 : (((buffer == &rkl_lruFixedBuffer[0])   || (buffer == &rkl_lruFixedBuffer[1])   || (buffer == &rkl_lruFixedBuffer[2])   || (buffer == &rkl_lruFixedBuffer[3])) ||
+                                            ((buffer == &rkl_lruDynamicBuffer[0]) || (buffer == &rkl_lruDynamicBuffer[1]) || (buffer == &rkl_lruDynamicBuffer[2]) || (buffer == &rkl_lruDynamicBuffer[3]))), exception, exitNow);
   
-  NSUInteger  useFixedBuffer = (cacheSlot->setToLength < (CFIndex)(RKL_FIXED_LENGTH)) ? 1UL : 0UL;
-  RKLBuffer  *buffer         = useFixedBuffer ? &fixedBuffer : &dynamicBuffer;
-  rkl_dtrace_addLookupFlag(lookupResultFlags, (useFixedBuffer ? 0U : RKLDynamicBufferLookupFlag));
+  if((buffer != NULL) && RKL_EXPECTED(cachedRegex->setToString == buffer->string, 1L) && RKL_EXPECTED(cachedRegex->setToHash == buffer->hash, 1L) && RKL_EXPECTED(cachedRegex->setToLength == buffer->length, 1L)) {
+    RKLCDelayedAssert((buffer->uniChar != NULL), exception, exitNow);
+    rkl_dtrace_addLookupFlag(lookupResultFlags, RKLCacheHitLookupFlag | RKLConversionRequiredLookupFlag | (useFixedBuffer ? 0U : RKLDynamicBufferLookupFlag));
+    if(cachedRegex->setToUniChar != buffer->uniChar) { cachedRegex->setToRange = NSNotFoundRange; cachedRegex->setToUniChar = buffer->uniChar; }
+    goto setRegexText;
+  }
 
-  if((buffer->uniChar != NULL) && (cacheSlot->setToString == buffer->string) && (cacheSlot->setToLength == buffer->length) && (cacheSlot->setToHash == buffer->hash)) { rkl_dtrace_addLookupFlag(lookupResultFlags, RKLCacheHitLookupFlag); cacheSlot->setToUniChar = buffer->uniChar; goto setRegexText; }
+  buffer              = NULL;
+  cachedRegex->buffer = NULL;
+
+  NSInteger cacheWay = 0L;
+  for(cacheWay = ((NSInteger)_RKL_LRU_CACHE_SET_WAYS - 1L); cacheWay > 0L; cacheWay--) {
+    if(useFixedBuffer) { buffer = &rkl_lruFixedBuffer[cacheWay]; } else { buffer = &rkl_lruDynamicBuffer[cacheWay]; }
+    if(RKL_EXPECTED(cachedRegex->setToString == buffer->string, 1L) && RKL_EXPECTED(cachedRegex->setToHash == buffer->hash, 1L) && RKL_EXPECTED(cachedRegex->setToLength == buffer->length, 1L)) {
+      RKLCDelayedAssert((buffer->uniChar != NULL), exception, exitNow);
+      rkl_dtrace_addLookupFlag(lookupResultFlags, RKLCacheHitLookupFlag | RKLConversionRequiredLookupFlag | (useFixedBuffer ? 0U : RKLDynamicBufferLookupFlag));
+      if(cachedRegex->setToUniChar != buffer->uniChar) { cachedRegex->setToRange = NSNotFoundRange; cachedRegex->setToUniChar = buffer->uniChar; }
+      cachedRegex->buffer = buffer;
+      goto setRegexText;
+    }
+  }
+
+  buffer                    = NULL;
+  cachedRegex->setToUniChar = NULL;
+  cachedRegex->setToRange   = NSNotFoundRange;
+  cachedRegex->buffer       = NULL;
   
-  if((cacheSlot->setToNeedsConversion == 1U) && RKL_EXPECTED((stringUniChar = CFStringGetCharactersPtr(cacheSlot->setToString)) != NULL, 0L)) { cacheSlot->setToNeedsConversion = 0U; cacheSlot->setToRange = NSNotFoundRange; cacheSlot->setToUniChar = stringUniChar; goto setRegexText; }
+  RKLCDelayedAssert((cachedRegex->setToNeedsConversion == 1U) && (cachedRegex->buffer == NULL), exception, exitNow);
+  if(RKL_EXPECTED(cachedRegex->setToNeedsConversion == 1U, 1L) && RKL_EXPECTED((cachedRegex->setToUniChar = (RKL_STRONG_REF const UniChar * RKL_GC_VOLATILE)CFStringGetCharactersPtr(cachedRegex->setToString)) != NULL, 0L)) { cachedRegex->setToNeedsConversion = 0U; cachedRegex->setToRange = NSNotFoundRange; goto setRegexText; }
+  
+  rkl_dtrace_addLookupFlag(lookupResultFlags, RKLConversionRequiredLookupFlag | (useFixedBuffer ? 0U : RKLDynamicBufferLookupFlag));
 
+  if(useFixedBuffer) { buffer = &rkl_lruFixedBuffer  [rkl_leastRecentlyUsedWayInSet(1UL, &rkl_lruFixedBufferCacheSet,   0UL)]; }
+  else               { buffer = &rkl_lruDynamicBuffer[rkl_leastRecentlyUsedWayInSet(1UL, &rkl_lruDynamicBufferCacheSet, 0UL)]; }
+
+  RKLCDelayedAssert((useFixedBuffer) ? ((buffer == &rkl_lruFixedBuffer[0])   || (buffer == &rkl_lruFixedBuffer[1])   || (buffer == &rkl_lruFixedBuffer[2])   || (buffer == &rkl_lruFixedBuffer[3])) :
+                                       ((buffer == &rkl_lruDynamicBuffer[0]) || (buffer == &rkl_lruDynamicBuffer[1]) || (buffer == &rkl_lruDynamicBuffer[2]) || (buffer == &rkl_lruDynamicBuffer[3])), exception, exitNow);
+  
   rkl_clearBuffer(buffer, 0UL);
+
+  RKLCDelayedAssert((buffer->string == NULL) && (cachedRegex->setToString != NULL), exception, exitNow);
+  if(RKL_EXPECTED((buffer->string = (CFStringRef)CFRetain((CFTypeRef)cachedRegex->setToString)) == NULL, 0L)) { goto exitNow; }
+  buffer->hash   = cachedRegex->setToHash;
+  buffer->length = cachedRegex->setToLength;
   
-  if(useFixedBuffer == 0U) {
-    RKLCDelayedAssert(buffer == &dynamicBuffer, exception, exitNow);
-    RKL_STRONG_REF void *p = (RKL_STRONG_REF void *)dynamicBuffer.uniChar;
-    if(RKL_EXPECTED((dynamicBuffer.uniChar = (RKL_STRONG_REF UniChar *)rkl_realloc(&p, ((size_t)cacheSlot->setToLength * sizeof(UniChar)), 0UL)) == NULL, 0L)) { goto exitNow; } // Resize the buffer.
+  if(useFixedBuffer == 0UL) {
+    RKL_STRONG_REF void * RKL_GC_VOLATILE p = (RKL_STRONG_REF void * RKL_GC_VOLATILE)buffer->uniChar;
+    if(RKL_EXPECTED((buffer->uniChar = (RKL_STRONG_REF UniChar * RKL_GC_VOLATILE)rkl_realloc(&p, ((size_t)buffer->length * sizeof(UniChar)), 0UL)) == NULL, 0L)) { goto exitNow; } // Resize the buffer.
   }
   
-  RKLCDelayedAssert(buffer->uniChar != NULL, exception, exitNow);
-  CFStringGetCharacters(cacheSlot->setToString, CFMakeRange(0L, cacheSlot->setToLength), (UniChar *)buffer->uniChar); // Convert to a UTF16 string.
+  RKLCDelayedAssert((buffer->string != NULL) && (buffer->uniChar != NULL), exception, exitNow);
+  CFStringGetCharacters(buffer->string, CFMakeRange(0L, buffer->length), (UniChar *)buffer->uniChar); // Convert to a UTF16 string.
   
-  RKLCDelayedAssert(buffer->string == NULL, exception, exitNow);
-  if(RKL_EXPECTED((buffer->string = (CFStringRef)CFRetain((CFTypeRef)cacheSlot->setToString)) == NULL, 0L)) { goto exitNow; }
-  buffer->hash            = cacheSlot->setToHash;
-  buffer->length          = cacheSlot->setToLength;
-  
-  cacheSlot->setToUniChar = buffer->uniChar;
-  cacheSlot->setToRange   = NSNotFoundRange;
-  
+  cachedRegex->setToUniChar = buffer->uniChar;
+  cachedRegex->setToRange   = NSNotFoundRange;
+  cachedRegex->buffer       = buffer;
+
 setRegexText:
-  if(NSEqualRanges(cacheSlot->setToRange, *range) == NO) {
-    RKLCDelayedAssert((cacheSlot->icu_regex != NULL) && (cacheSlot->setToUniChar != NULL) && (NSMaxRange(*range) <= (NSUInteger)cacheSlot->setToLength) && (cacheSlot->setToRange.length <= INT_MAX), exception, exitNow);
-    cacheSlot->lastFindRange = cacheSlot->lastMatchRange = NSNotFoundRange;
-    cacheSlot->setToRange    = *range;
-    RKL_ICU_FUNCTION_APPEND(uregex_setText)(cacheSlot->icu_regex, cacheSlot->setToUniChar + cacheSlot->setToRange.location, (int32_t)cacheSlot->setToRange.length, status);
+  if(buffer != NULL) { if(useFixedBuffer == 1UL) { rkl_accessCacheSetWay(1UL, &rkl_lruFixedBufferCacheSet, 0UL, (NSUInteger)(buffer - rkl_lruFixedBuffer)); } else { rkl_accessCacheSetWay(1UL, &rkl_lruDynamicBufferCacheSet, 0UL, (NSUInteger)(buffer - rkl_lruDynamicBuffer)); } }
+
+  if(NSEqualRanges(cachedRegex->setToRange, *range) == NO) {
+    RKLCDelayedAssert((cachedRegex->icu_regex != NULL) && (cachedRegex->setToUniChar != NULL) && (NSMaxRange(*range) <= (NSUInteger)cachedRegex->setToLength) && (cachedRegex->setToRange.length <= INT_MAX), exception, exitNow);
+    cachedRegex->lastFindRange =  cachedRegex->lastMatchRange = NSNotFoundRange;
+    cachedRegex->setToRange    = *range;
+    RKL_ICU_FUNCTION_APPEND(uregex_setText)(cachedRegex->icu_regex, cachedRegex->setToUniChar + cachedRegex->setToRange.location, (int32_t)cachedRegex->setToRange.length, status);
     rkl_dtrace_addLookupFlag(lookupResultFlags, RKLSetTextLookupFlag);
-    if(RKL_EXPECTED(*status > U_ZERO_ERROR, 0L)) { goto exitNow; }
+    if(RKL_EXPECTED(*status > U_ZERO_ERROR, 0L)) { rkl_dtrace_addLookupFlag(lookupResultFlags, RKLErrorLookupFlag); goto exitNow; }
   }
   
-  rkl_dtrace_utf16ConversionCache(lookupResultFlags, cacheSlot->setToString, cacheSlot->setToRange.location, cacheSlot->setToRange.length, cacheSlot->setToLength);
+  rkl_dtrace_utf16ConversionCache(lookupResultFlags, cachedRegex->setToString, cachedRegex->setToRange.location, cachedRegex->setToRange.length, cachedRegex->setToLength);
+
   return(1UL);
+
+  //  ----------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  //  IMPORTANT!   This section of code is called almost every single time that any RegexKitLite functionality is used! It /MUST/ be very fast!
+  //  ----------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   
 exitNow:
+#ifdef    _RKL_DTRACE_ENABLED
+  rkl_dtrace_addLookupFlag(lookupResultFlags, RKLErrorLookupFlag); 
+  if(cachedRegex != NULL) { rkl_dtrace_utf16ConversionCache(lookupResultFlags, cachedRegex->setToString, cachedRegex->setToRange.location, cachedRegex->setToRange.length, cachedRegex->setToLength); }
+#endif // _RKL_DTRACE_ENABLED
+  if(cachedRegex != NULL) { cachedRegex->buffer = NULL; cachedRegex->setToRange = NSNotFoundRange; cachedRegex->lastFindRange = NSNotFoundRange; cachedRegex->lastMatchRange = NSNotFoundRange; }
   return(0UL);
 }
 
 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
-//  IMPORTANT!   Should only be called with cacheSpinLock already locked!
+//  IMPORTANT!   Should only be called with rkl_cacheSpinLock already locked!
 //  ----------
 
-static RKLCacheSlot *rkl_getCachedRegexSetToString(NSString *regexString, RKLRegexOptions options, NSString *matchString, NSUInteger *matchLengthPtr, NSRange *matchRange, NSError **error, id *exception, int32_t *status) {
-  RKLCacheSlot *cacheSlot = NULL;
-  RKLCDelayedAssert((regexString != NULL) && (exception != NULL) && (status != NULL) && (matchLengthPtr != NULL), exception, exitNow);
+#pragma mark Get a regular expression and set it to a NSStrings UTF-16 text
 
-  // Fast path the common case where this regex is exactly the same one used last time.
-  if(RKL_EXPECTED(lastCacheSlot != NULL, 1L) && RKL_EXPECTED(lastCacheSlot->icu_regex != NULL, 1L) && RKL_EXPECTED(lastCacheSlot->regexString == (CFStringRef)regexString, 1L) && RKL_EXPECTED(lastCacheSlot->options == options, 1L)) { cacheSlot = lastCacheSlot; rkl_dtrace_compiledRegexCache(&rkl_dtrace_regexUTF8[(cacheSlot - &rkl_cacheSlots[0])][0], cacheSlot->options, (int)cacheSlot->captureCount, 1, 0, NULL); }
-  else { lastCacheSlot = NULL; if(RKL_EXPECTED((cacheSlot = rkl_getCachedRegex(regexString, options, error, exception)) == NULL, 0L)) { goto exitNow; } }
-  RKLCDelayedAssert((cacheSlot != NULL) && (cacheSlot->icu_regex != NULL) && (cacheSlot->regexString != NULL) && (cacheSlot->captureCount >= 0L) && (cacheSlot == lastCacheSlot), exception, exitNow);
+static RKLCachedRegex *rkl_getCachedRegexSetToString(NSString *regexString, RKLRegexOptions options, NSString *matchString, NSUInteger *matchLengthPtr, NSRange *matchRange, NSError **error, id *exception, int32_t *status) {
+  //  ----------   vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+  //  IMPORTANT!   This section of code is called almost every single time that any RegexKitLite functionality is used! It /MUST/ be very fast!
+  //  ----------   vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+  
+  RKLCachedRegex *cachedRegex = NULL;
+  RKLCDelayedAssert((regexString != NULL) && (matchString != NULL) && (exception != NULL) && (status != NULL) && (matchLengthPtr != NULL), exception, exitNow);
+
+  if(RKL_EXPECTED((cachedRegex = rkl_getCachedRegex(regexString, options, error, exception)) == NULL, 0L)) { goto exitNow; }
+  RKLCDelayedAssert(((cachedRegex >= rkl_cachedRegexes) && ((cachedRegex - rkl_cachedRegexes) < (ssize_t)_RKL_REGEX_CACHE_LINES)) && (cachedRegex != NULL) && (cachedRegex->icu_regex != NULL) && (cachedRegex->regexString != NULL) && (cachedRegex->captureCount >= 0L) && (cachedRegex == rkl_lastCachedRegex), exception, exitNow);
 
   // Optimize the case where the string to search (matchString) is immutable and the setToString immutable copy is the same string with its reference count incremented.
-  NSUInteger isSetTo     = ((cacheSlot->setToString != NULL) && (cacheSlot->setToString      == (CFStringRef)matchString)) ? 1UL : 0UL;
-  CFIndex    matchLength = ((isSetTo                == 1UL)  && (cacheSlot->setToIsImmutable == 1U))                       ? cacheSlot->setToLength : CFStringGetLength((CFStringRef)matchString);
+  NSUInteger isSetTo     = ((cachedRegex->setToString      == (CFStringRef)matchString)) ? 1UL : 0UL;
+  CFIndex    matchLength = ((cachedRegex->setToIsImmutable == 1U) && (isSetTo == 1UL))   ? cachedRegex->setToLength : CFStringGetLength((CFStringRef)matchString);
 
   *matchLengthPtr = (NSUInteger)matchLength;
   if(matchRange->length == NSUIntegerMax) { matchRange->length = (NSUInteger)matchLength; } // For convenience, allow NSUIntegerMax == string length.
   
   if(RKL_EXPECTED((NSUInteger)matchLength < NSMaxRange(*matchRange), 0L)) { goto exitNow; } // The match range is out of bounds for the string.  performRegexOp will catch and report the problem.
-  
-  if((isSetTo == 1UL) && (cacheSlot->setToIsImmutable == 0U) && (cacheSlot->setToString != NULL) && ((cacheSlot->setToLength != CFStringGetLength(cacheSlot->setToString)) || (cacheSlot->setToHash != CFHash((CFTypeRef)cacheSlot->setToString)))) { isSetTo = 0UL; }
-  else { // If the first pointer equality check failed, check the hash and length.
-    if(((isSetTo == 0UL) || (cacheSlot->setToIsImmutable == 0U)) && (cacheSlot->setToString != NULL)) { isSetTo = ((cacheSlot->setToString == (CFStringRef)matchString) && (cacheSlot->setToLength == matchLength) && (cacheSlot->setToHash == CFHash((CFTypeRef)matchString))) ? 1UL : 0UL; }
+
+  RKLCDelayedAssert((isSetTo == 1UL) ? (cachedRegex->setToString != NULL) : 1, exception, exitNow);
+
+  if(((cachedRegex->setToIsImmutable == 1U) ? isSetTo : (NSUInteger)((isSetTo == 1UL) && (cachedRegex->setToLength == matchLength) && (cachedRegex->setToHash == CFHash((CFTypeRef)matchString)))) == 0UL) {
+    if(cachedRegex->setToString != NULL) { rkl_clearCachedRegexSetTo(cachedRegex); }
     
-    if(isSetTo == 1UL) { if(RKL_EXPECTED(rkl_setCacheSlotToString(cacheSlot, matchRange, status, exception) == 0UL, 0L)) { cacheSlot = NULL; if(*exception == NULL) { *exception = (id)RKLCAssertDictionary(@"Failed to set up UTF16 buffer."); } } goto exitNow; }
+    cachedRegex->setToString          = (CFStringRef)CFRetain((CFTypeRef)matchString);
+    RKLCDelayedAssert(cachedRegex->setToString != NULL, exception, exitNow);
+    cachedRegex->setToUniChar         = CFStringGetCharactersPtr(cachedRegex->setToString);
+    cachedRegex->setToNeedsConversion = (cachedRegex->setToUniChar == NULL) ? 1U : 0U;
+    cachedRegex->setToIsImmutable     = (rkl_CFStringIsMutable(cachedRegex->setToString) == YES) ? 0U : 1U; // If RKL_FAST_MUTABLE_CHECK is not defined then setToIsImmutable will always be set to '0', or in other words mutable..
+    cachedRegex->setToHash            = CFHash((CFTypeRef)cachedRegex->setToString);
+    cachedRegex->setToRange           = NSNotFoundRange;
+    cachedRegex->setToLength          = matchLength;
+    
   }
   
-  // Sometimes the range that the regex is set to isn't right, in which case we don't want to clear the cache slot.  Otherwise, flush it out.
-  if((cacheSlot->setToString != NULL) && (isSetTo == 0UL)) { rkl_clearCacheSlotSetTo(cacheSlot); }
-  
-  if(cacheSlot->setToString == NULL) {
-    cacheSlot->setToString          = (CFStringRef)CFRetain((CFTypeRef)matchString);
-    RKLCDelayedAssert(cacheSlot->setToString != NULL, exception, exitNow);
-    cacheSlot->setToUniChar         = CFStringGetCharactersPtr(cacheSlot->setToString);
-    cacheSlot->setToNeedsConversion = (cacheSlot->setToUniChar == NULL) ? 1U : 0U;
-    cacheSlot->setToIsImmutable     = (rkl_CFStringIsMutable(cacheSlot->setToString) == YES) ? 0U : 1U; // If RKL_FAST_MUTABLE_CHECK is not defined then setToIsImmutable will always be set to '0', or in other words mutable..
-    cacheSlot->setToHash            = CFHash((CFTypeRef)cacheSlot->setToString);
-    cacheSlot->setToRange           = NSNotFoundRange;
-    cacheSlot->setToLength          = matchLength;
-  }
-  
-  if(RKL_EXPECTED(rkl_setCacheSlotToString(cacheSlot, matchRange, status, exception) == 0UL, 0L)) { cacheSlot = NULL; if(*exception == NULL) { *exception = (id)RKLCAssertDictionary(@"Failed to set up UTF16 buffer."); } goto exitNow; }
+  if(RKL_EXPECTED(rkl_setCachedRegexToString(cachedRegex, matchRange, status, exception) == 0UL, 0L)) { cachedRegex = NULL; if(*exception == NULL) { *exception = (id)RKLCAssertDictionary(@"Failed to set up UTF16 buffer."); } goto exitNow; }
   
 exitNow:
-  return(cacheSlot);
+  return(cachedRegex);
+  //  ----------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  //  IMPORTANT!   This section of code is called almost every single time that any RegexKitLite functionality is used! It /MUST/ be very fast!
+  //  ----------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 }
 
+#pragma mark GCC cleanup __attribute__ functions that ensure the global rkl_cacheSpinLock is properly unlocked
 #ifdef    RKL_HAVE_CLEANUP
 
 // rkl_cleanup_cacheSpinLockStatus takes advantage of GCC's 'cleanup' variable attribute.  When an 'auto' variable with the 'cleanup' attribute goes out of scope,
 // GCC arranges to have the designated function called.  In this case, we make sure that if rkl_cacheSpinLock was locked that it was also unlocked.
-// If rkl_cacheSpinLock was locked, but the cacheSpinLockStatus unlocked flag was not set, we force cacheSpinLock unlocked with a call to OSSpinLockUnlock.
+// If rkl_cacheSpinLock was locked, but the rkl_cacheSpinLockStatus unlocked flag was not set, we force rkl_cacheSpinLock unlocked with a call to OSSpinLockUnlock.
 // This is not a panacea for preventing mutex usage errors.  Old style ObjC exceptions will bypass the cleanup call, but newer C++ style ObjC exceptions should cause the cleanup function to be called during the stack unwind.
 
 // We do not depend on this cleanup function being called.  It is used only as an extra safety net.  It is probably a bug in RegexKitLite if it is ever invoked and forced to take some kind of protective action.
 
 volatile NSUInteger rkl_debugCacheSpinLockCount = 0UL;
 
-void        rkl_debugCacheSpinLock          (void)                                        RKL_ATTRIBUTES(used, noinline, visibility("default"));
-static void rkl_cleanup_cacheSpinLockStatus (volatile NSUInteger *cacheSpinLockStatusPtr) RKL_ATTRIBUTES(used);
+void        rkl_debugCacheSpinLock          (void)                                            RKL_ATTRIBUTES(used, noinline, visibility("default"));
+static void rkl_cleanup_cacheSpinLockStatus (volatile NSUInteger *rkl_cacheSpinLockStatusPtr) RKL_ATTRIBUTES(used);
 
 void rkl_debugCacheSpinLock(void) {
   rkl_debugCacheSpinLockCount++; // This is here primarily to prevent the optimizer from optimizing away the function.
 }
 
-static void rkl_cleanup_cacheSpinLockStatus(volatile NSUInteger *cacheSpinLockStatusPtr) {
+static void rkl_cleanup_cacheSpinLockStatus(volatile NSUInteger *rkl_cacheSpinLockStatusPtr) {
   static NSUInteger didPrintForcedUnlockWarning = 0UL, didPrintNotLockedWarning = 0UL;
-  NSUInteger        cacheSpinLockStatus         = *cacheSpinLockStatusPtr;
+  NSUInteger        rkl_cacheSpinLockStatus     = *rkl_cacheSpinLockStatusPtr;
   
-  if(RKL_EXPECTED((cacheSpinLockStatus & RKLUnlockedCacheSpinLock) == 0UL, 0L) && RKL_EXPECTED((cacheSpinLockStatus & RKLLockedCacheSpinLock) != 0UL, 1L)) {
-    if(cacheSpinLock != (OSSpinLock)0) {
-      if(didPrintForcedUnlockWarning == 0UL) { didPrintForcedUnlockWarning = 1UL; NSLog(@"[RegexKitLite] Unusual condition detected: Recorded that cacheSpinLock was locked, but for some reason it was not unlocked.  Forcibly unlocking cacheSpinLock. Set a breakpoint at rkl_debugCacheSpinLock to debug. This warning is only printed once."); }
+  if(RKL_EXPECTED((rkl_cacheSpinLockStatus & RKLUnlockedCacheSpinLock) == 0UL, 0L) && RKL_EXPECTED((rkl_cacheSpinLockStatus & RKLLockedCacheSpinLock) != 0UL, 1L)) {
+    if(rkl_cacheSpinLock != (OSSpinLock)0) {
+      if(didPrintForcedUnlockWarning == 0UL) { didPrintForcedUnlockWarning = 1UL; NSLog(@"[RegexKitLite] Unusual condition detected: Recorded that rkl_cacheSpinLock was locked, but for some reason it was not unlocked.  Forcibly unlocking rkl_cacheSpinLock. Set a breakpoint at rkl_debugCacheSpinLock to debug. This warning is only printed once."); }
       rkl_debugCacheSpinLock(); // Since this is an unusual condition, offer an attempt to catch it before we unlock.
-      OSSpinLockUnlock(&cacheSpinLock);
+      OSSpinLockUnlock(&rkl_cacheSpinLock);
     } else {
-      if(didPrintNotLockedWarning    == 0UL) { didPrintNotLockedWarning    = 1UL; NSLog(@"[RegexKitLite] Unusual condition detected: Recorded that cacheSpinLock was locked, but for some reason it was not unlocked, yet cacheSpinLock is currently not locked? Set a breakpoint at rkl_debugCacheSpinLock to debug. This warning is only printed once."); }
+      if(didPrintNotLockedWarning    == 0UL) { didPrintNotLockedWarning    = 1UL; NSLog(@"[RegexKitLite] Unusual condition detected: Recorded that rkl_cacheSpinLock was locked, but for some reason it was not unlocked, yet rkl_cacheSpinLock is currently not locked? Set a breakpoint at rkl_debugCacheSpinLock to debug. This warning is only printed once."); }
       rkl_debugCacheSpinLock();
     }
   }
 
 #endif // RKL_HAVE_CLEANUP
 
+// rkl_performDictionaryVarArgsOp is a front end to rkl_performRegexOp which converts a ', ...' varargs key/captures list and converts it in to a form that rkl_performRegexOp can use.
+// All error checking of arguments is handled by rkl_performRegexOp.
+
+#pragma mark Front end function that handles varargs and calls rkl_performRegexOp with the marshaled results
+
+static id rkl_performDictionaryVarArgsOp(id self, SEL _cmd, RKLRegexOp regexOp, NSString *regexString, RKLRegexOptions options, NSInteger capture, id matchString, NSRange *matchRange, NSString *replacementString, NSError **error, void *result, id firstKey, va_list varArgsList) {
+  id         captureKeys[64];
+  int        captureKeyIndexes[64];
+  NSUInteger captureKeysCount = 0UL;
+  
+  if(varArgsList != NULL) {
+    while(captureKeysCount < 62UL) {
+      id  thisCaptureKey      = (captureKeysCount == 0) ? firstKey : va_arg(varArgsList, id);
+      if(RKL_EXPECTED(thisCaptureKey == NULL, 0L)) { break; }
+      int thisCaptureKeyIndex = va_arg(varArgsList, int);
+      captureKeys[captureKeysCount]       = thisCaptureKey;
+      captureKeyIndexes[captureKeysCount] = thisCaptureKeyIndex;
+      captureKeysCount++;
+    }
+  }
+  
+  return(rkl_performRegexOp(self, _cmd, regexOp, regexString, options, capture, matchString, matchRange, replacementString, error, result, captureKeysCount, captureKeys, captureKeyIndexes));
+}
+
 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
 //  ----------
 
-static id rkl_performRegexOp(id self, SEL _cmd, RKLRegexOp regexOp, NSString *regexString, RKLRegexOptions options, NSInteger capture, id matchString, NSRange *matchRange, NSString *replacementString, NSError **error, void *result) {
-  volatile NSUInteger RKL_CLEANUP(rkl_cleanup_cacheSpinLockStatus) cacheSpinLockStatus = 0UL;
+#pragma mark Primary internal function that Objective-C methods call to perform regular expression operations
+
+static id rkl_performRegexOp(id self, SEL _cmd, RKLRegexOp regexOp, NSString *regexString, RKLRegexOptions options, NSInteger capture, id matchString, NSRange *matchRange, NSString *replacementString, NSError **error, void *result, NSUInteger captureKeysCount, id captureKeys[captureKeysCount], const int captureKeyIndexes[captureKeysCount]) {
+  volatile NSUInteger RKL_CLEANUP(rkl_cleanup_cacheSpinLockStatus) rkl_cacheSpinLockStatus = 0UL;
   
   NSUInteger replaceMutable = 0UL;
   RKLRegexOp maskedRegexOp  = (regexOp & RKLMaskOp);
+  BOOL       dictionaryOp   = ((maskedRegexOp == RKLDictionaryOfCapturesOp) || (maskedRegexOp == RKLArrayOfDictionariesOfCapturesOp)) ? YES : NO;
   
-  if((error != NULL) && (*error != NULL))                            { *error = NULL; }
+  if((error != NULL) && (*error != NULL))                                            { *error = NULL; }
   
-  if(RKL_EXPECTED(regexString == NULL, 0L))                          { RKL_RAISE_EXCEPTION(NSInvalidArgumentException, @"The regular expression argument is NULL."); }
-  if(RKL_EXPECTED(matchString == NULL, 0L))                          { RKL_RAISE_EXCEPTION(NSInternalInconsistencyException, @"The match string argument is NULL."); }
-  if((maskedRegexOp == RKLReplaceOp) && (replacementString == NULL)) { RKL_RAISE_EXCEPTION(NSInvalidArgumentException, @"The replacement string argument is NULL."); }
+  if(RKL_EXPECTED(regexString == NULL, 0L))                                          { RKL_RAISE_EXCEPTION(NSInvalidArgumentException, @"The regular expression argument is NULL."); }
+  if(RKL_EXPECTED(matchString == NULL, 0L))                                          { RKL_RAISE_EXCEPTION(NSInternalInconsistencyException, @"The match string argument is NULL."); }
+  if(RKL_EXPECTED(matchRange  == NULL, 0L))                                          { RKL_RAISE_EXCEPTION(NSInternalInconsistencyException, @"The match range argument is NULL.");  }
+  if((maskedRegexOp == RKLReplaceOp) && RKL_EXPECTED(replacementString == NULL, 0L)) { RKL_RAISE_EXCEPTION(NSInvalidArgumentException, @"The replacement string argument is NULL."); }
+  if((dictionaryOp  == YES)          && RKL_EXPECTED(captureKeys       == NULL, 0L)) { RKL_RAISE_EXCEPTION(NSInvalidArgumentException, @"The keys argument is NULL.");               }
+  if((dictionaryOp  == YES)          && RKL_EXPECTED(captureKeyIndexes == NULL, 0L)) { RKL_RAISE_EXCEPTION(NSInvalidArgumentException, @"The captures argument is NULL.");           }
   
-  id            resultObject    = NULL, exception = NULL;
-  int32_t       status          = U_ZERO_ERROR;
-  RKLCacheSlot *cacheSlot       = NULL;
-  NSUInteger    stringU16Length = 0UL;
-  NSRange       stackRanges[2048];
-  RKLFindAll    findAll;
-  
+  id              resultObject    = NULL, exception = NULL;
+  int32_t         status          = U_ZERO_ERROR;
+  RKLCachedRegex *cachedRegex     = NULL;
+  NSUInteger      stringU16Length = 0UL, tmpIdx = 0UL;
+  NSRange         stackRanges[2048];
+  RKLFindAll      findAll;
   
   // IMPORTANT!   Once we have obtained the lock, code MUST exit via 'goto exitNow;' to unlock the lock!  NO EXCEPTIONS!
   // ----------
-  OSSpinLockLock(&cacheSpinLock); // Grab the lock and get cache entry.
-  cacheSpinLockStatus |= RKLLockedCacheSpinLock;
+  OSSpinLockLock(&rkl_cacheSpinLock); // Grab the lock and get cache entry.
+  rkl_cacheSpinLockStatus |= RKLLockedCacheSpinLock;
   rkl_dtrace_incrementEventID();
   
-  if(RKL_EXPECTED((cacheSlot = rkl_getCachedRegexSetToString(regexString, options, matchString, &stringU16Length, matchRange, error, &exception, &status)) == NULL, 0L)) { stringU16Length = (NSUInteger)CFStringGetLength((CFStringRef)matchString); }
-  if(RKL_EXPECTED(matchRange->length == NSUIntegerMax, 1L)) { matchRange->length = stringU16Length; } // For convenience.
-  if(RKL_EXPECTED(stringU16Length  < NSMaxRange(*matchRange), 0L) && RKL_EXPECTED(exception == NULL, 1L)) { exception = (id)RKL_EXCEPTION(NSRangeException, @"Range or index out of bounds.");  goto exitNow; }
-  if(RKL_EXPECTED(stringU16Length >= (NSUInteger)INT_MAX,     0L) && RKL_EXPECTED(exception == NULL, 1L)) { exception = (id)RKL_EXCEPTION(NSRangeException, @"String length exceeds INT_MAX."); goto exitNow; }
-  if(((maskedRegexOp == RKLRangeOp) || (maskedRegexOp == RKLArrayOfStringsOp)) && RKL_EXPECTED(cacheSlot != NULL, 1L) && (RKL_EXPECTED(capture < 0L, 0L) || RKL_EXPECTED(capture > cacheSlot->captureCount, 0L)) && RKL_EXPECTED(exception == NULL, 1L)) { exception = (id)RKL_EXCEPTION(NSInvalidArgumentException, @"The capture argument is not valid."); goto exitNow; }
-  if(RKL_EXPECTED(cacheSlot == NULL, 0L) || RKL_EXPECTED(status > U_ZERO_ERROR, 0L) || RKL_EXPECTED(exception != NULL, 0L)) { goto exitNow; }
+  if(RKL_EXPECTED((cachedRegex = rkl_getCachedRegexSetToString(regexString, options, matchString, &stringU16Length, matchRange, error, &exception, &status)) == NULL, 0L)) { stringU16Length = (NSUInteger)CFStringGetLength((CFStringRef)matchString); }
+  if(RKL_EXPECTED(matchRange->length == NSUIntegerMax,           0L))                                        { matchRange->length = stringU16Length; } // For convenience.
+  if(RKL_EXPECTED(stringU16Length     < NSMaxRange(*matchRange), 0L) && RKL_EXPECTED(exception == NULL, 1L)) { exception = (id)RKL_EXCEPTION(NSRangeException, @"Range or index out of bounds.");  goto exitNow; }
+  if(RKL_EXPECTED(stringU16Length    >= (NSUInteger)INT_MAX,     0L) && RKL_EXPECTED(exception == NULL, 1L)) { exception = (id)RKL_EXCEPTION(NSRangeException, @"String length exceeds INT_MAX."); goto exitNow; }
+  if(((maskedRegexOp == RKLRangeOp) || (maskedRegexOp == RKLArrayOfStringsOp)) && RKL_EXPECTED(cachedRegex != NULL, 1L) && (RKL_EXPECTED(capture < 0L, 0L) || RKL_EXPECTED(capture > cachedRegex->captureCount, 0L)) && RKL_EXPECTED(exception == NULL, 1L)) { exception = (id)RKL_EXCEPTION(NSInvalidArgumentException, @"The capture argument is not valid."); goto exitNow; }
+
+  if((dictionaryOp == YES) && RKL_EXPECTED(cachedRegex != NULL, 1L) && RKL_EXPECTED(exception == NULL, 1L)) {
+    for(tmpIdx = 0UL; tmpIdx < captureKeysCount; tmpIdx++) {
+      if(RKL_EXPECTED(captureKeys[tmpIdx] == NULL, 0L)) { exception = (id)RKL_EXCEPTION(NSInvalidArgumentException, @"The capture key (key %lu of %lu) is NULL.", (unsigned long)(tmpIdx + 1UL), (unsigned long)captureKeysCount); break; }
+      if((RKL_EXPECTED(captureKeyIndexes[tmpIdx] < 0, 0L) || RKL_EXPECTED(captureKeyIndexes[tmpIdx] > cachedRegex->captureCount, 0L))) { exception = (id)RKL_EXCEPTION(NSInvalidArgumentException, @"The capture argument %d (capture %lu of %lu) for key '%@' is not valid.", captureKeyIndexes[tmpIdx], (unsigned long)(tmpIdx + 1UL), (unsigned long)captureKeysCount, captureKeys[tmpIdx]); break; }
+    }
+  }
+
+  if(RKL_EXPECTED(cachedRegex == NULL, 0L) || RKL_EXPECTED(status > U_ZERO_ERROR, 0L) || RKL_EXPECTED(exception != NULL, 0L)) { goto exitNow; }
   
-  RKLCDelayedAssert((cacheSlot != NULL) && (cacheSlot->icu_regex != NULL) && (cacheSlot->regexString != NULL) && (cacheSlot->captureCount >= 0L) && (cacheSlot->setToString != NULL) && (cacheSlot->setToLength >= 0L) && (cacheSlot->setToUniChar != NULL) && ((CFIndex)NSMaxRange(cacheSlot->setToRange) <= cacheSlot->setToLength), &exception, exitNow);
-  
-#ifndef NS_BLOCK_ASSERTIONS
-  if(cacheSlot->setToNeedsConversion == 0U) { RKLCDelayedAssert((cacheSlot->setToUniChar == CFStringGetCharactersPtr(cacheSlot->setToString)), &exception, exitNow); }
-  else {
-    RKLBuffer *buffer = (cacheSlot->setToLength < (CFIndex)(RKL_FIXED_LENGTH)) ? &fixedBuffer : &dynamicBuffer;
-    RKLCDelayedAssert((cacheSlot->setToHash == buffer->hash) && (cacheSlot->setToLength == buffer->length) && (cacheSlot->setToUniChar == buffer->uniChar), &exception, exitNow);
-  }
-#endif
+  RKLCDelayedAssert(((cachedRegex >= rkl_cachedRegexes) && ((cachedRegex - rkl_cachedRegexes) < (ssize_t)_RKL_REGEX_CACHE_LINES)) && (cachedRegex != NULL) && (cachedRegex->icu_regex != NULL) && (cachedRegex->regexString != NULL) && (cachedRegex->captureCount >= 0L) && (cachedRegex->setToString != NULL) && (cachedRegex->setToLength >= 0L) && (cachedRegex->setToUniChar != NULL) && ((CFIndex)NSMaxRange(cachedRegex->setToRange) <= cachedRegex->setToLength), &exception, exitNow);
+  RKLCDelayedAssert((cachedRegex->setToNeedsConversion == 0U) ? ((cachedRegex->setToNeedsConversion == 0U) && (cachedRegex->setToUniChar == CFStringGetCharactersPtr(cachedRegex->setToString))) : ((cachedRegex->buffer != NULL) && (cachedRegex->setToHash == cachedRegex->buffer->hash) && (cachedRegex->setToLength == cachedRegex->buffer->length) && (cachedRegex->setToUniChar == cachedRegex->buffer->uniChar)), &exception, exitNow);
   
   switch(maskedRegexOp) {
     case RKLRangeOp:
-      if((rkl_search(cacheSlot, matchRange, 0UL, &exception, &status) == NO) || (RKL_EXPECTED(status > U_ZERO_ERROR, 0L))) { *(NSRange *)result = NSNotFoundRange; goto exitNow; }
-      if(RKL_EXPECTED(capture == 0L, 1L)) { *(NSRange *)result = cacheSlot->lastMatchRange; } else { if(RKL_EXPECTED(rkl_getRangeForCapture(cacheSlot, &status, (int32_t)capture, (NSRange *)result) > U_ZERO_ERROR, 0L)) { goto exitNow; } }
+      if((RKL_EXPECTED(rkl_search(cachedRegex, matchRange, 0UL, &exception, &status) == NO, 0L)) || (RKL_EXPECTED(status > U_ZERO_ERROR, 0L))) { *(NSRange *)result = NSNotFoundRange; goto exitNow; }
+      if(RKL_EXPECTED(capture == 0L, 1L)) { *(NSRange *)result = cachedRegex->lastMatchRange; } else { if(RKL_EXPECTED(rkl_getRangeForCapture(cachedRegex, &status, (int32_t)capture, (NSRange *)result) > U_ZERO_ERROR, 0L)) { goto exitNow; } }
       break;
       
-    case RKLSplitOp:          // Fall-thru...
-    case RKLArrayOfStringsOp: // Fall-thru...
-    case RKLCapturesArrayOp:  // Fall-thru...
-    case RKLArrayOfCapturesOp:
-      findAll = rkl_makeFindAll(stackRanges, *matchRange, 2048L, (2048UL * sizeof(NSRange)), 0UL, (void **)&scratchBuffer[0], &scratchBuffer[1], &scratchBuffer[2], 0L, capture, ((maskedRegexOp == RKLCapturesArrayOp) ? 1L : NSIntegerMax));
+    case RKLSplitOp:                         // Fall-thru...
+    case RKLArrayOfStringsOp:                // Fall-thru...
+    case RKLCapturesArrayOp:                 // Fall-thru...
+    case RKLArrayOfCapturesOp:               // Fall-thru...
+    case RKLDictionaryOfCapturesOp:          // Fall-thru...
+    case RKLArrayOfDictionariesOfCapturesOp:
+      findAll = rkl_makeFindAll(stackRanges, *matchRange, 2048L, (2048UL * sizeof(NSRange)), 0UL, &rkl_scratchBuffer[0], &rkl_scratchBuffer[1], &rkl_scratchBuffer[2], &rkl_scratchBuffer[3], &rkl_scratchBuffer[4], 0L, capture, (((maskedRegexOp == RKLCapturesArrayOp) || (maskedRegexOp == RKLDictionaryOfCapturesOp)) ? 1L : NSIntegerMax));
       
-      if(RKL_EXPECTED(rkl_findRanges(cacheSlot, regexOp, &findAll, &exception, &status) == NO, 1L)) {
-        if(RKL_EXPECTED(findAll.found == 0L, 0L)) { resultObject = [NSArray array]; } else { resultObject = rkl_makeArray(cacheSlot, regexOp, &findAll, &exception); }
+      if(RKL_EXPECTED(rkl_findRanges(cachedRegex, regexOp, &findAll, &exception, &status) == NO, 1L)) {
+        if(RKL_EXPECTED(findAll.found == 0L, 0L)) { resultObject = (maskedRegexOp == RKLDictionaryOfCapturesOp) ? [NSDictionary dictionary] : [NSArray array]; }
+        else {
+          if(dictionaryOp == YES) { resultObject = rkl_makeDictionary (cachedRegex, regexOp, &findAll, captureKeysCount, captureKeys, captureKeyIndexes, &exception); }
+          else                    { resultObject = rkl_makeArray      (cachedRegex, regexOp, &findAll, &exception); }
+        }
       }
       
-      if(RKL_EXPECTED(scratchBuffer[0] != NULL, 0L)) { scratchBuffer[0] = rkl_free(&scratchBuffer[0]); }
-      if(RKL_EXPECTED(scratchBuffer[1] != NULL, 0L)) { scratchBuffer[1] = rkl_free(&scratchBuffer[1]); }
-      if(RKL_EXPECTED(scratchBuffer[2] != NULL, 0L)) { scratchBuffer[2] = rkl_free(&scratchBuffer[2]); }
+      for(tmpIdx = 0UL; tmpIdx < _RKL_SCRATCH_BUFFERS; tmpIdx++) { if(RKL_EXPECTED(rkl_scratchBuffer[tmpIdx] != NULL, 0L)) { rkl_scratchBuffer[tmpIdx] = rkl_free(&rkl_scratchBuffer[tmpIdx]); } }
 
       break;
-      
-    case RKLReplaceOp: resultObject = rkl_replaceString(cacheSlot, matchString, stringU16Length, replacementString, (NSUInteger)CFStringGetLength((CFStringRef)replacementString), (NSUInteger *)result, (replaceMutable = (((regexOp & RKLReplaceMutable) != 0) ? 1UL : 0UL)), &exception, &status); break;
+
+    case RKLReplaceOp: resultObject = rkl_replaceString(cachedRegex, matchString, stringU16Length, replacementString, (NSUInteger)CFStringGetLength((CFStringRef)replacementString), (NSInteger *)result, (replaceMutable = (((regexOp & RKLReplaceMutable) != 0) ? 1UL : 0UL)), &exception, &status); break;
+
     default:           exception    = RKLCAssertDictionary(@"Unknown regexOp code."); break;
   }
   
 exitNow:
-  OSSpinLockUnlock(&cacheSpinLock);
-  cacheSpinLockStatus |= RKLUnlockedCacheSpinLock; // Warning about cacheSpinLockStatus never being read can be safely ignored.
+  OSSpinLockUnlock(&rkl_cacheSpinLock);
+  rkl_cacheSpinLockStatus |= RKLUnlockedCacheSpinLock; // Warning about rkl_cacheSpinLockStatus never being read can be safely ignored.
   
   if(RKL_EXPECTED(status     > U_ZERO_ERROR, 0L) && RKL_EXPECTED(exception == NULL, 0L)) { exception = rkl_NSExceptionForRegex(regexString, options, NULL, status); } // If we had a problem, prepare an exception to be thrown.
   if(RKL_EXPECTED(exception != NULL,         0L))                                        { rkl_handleDelayedAssert(self, _cmd, exception);                          } // If there is an exception, throw it at this point.
   // This is done outside the cache lock and with the objc replaceCharactersInRange:withString: method because Core Foundation
   // does not assert that the string we are attempting to update is actually a mutable string, whereas Foundation ensures
   // the object receiving the message is a mutable string and throws an exception if we're attempting to modify an immutable string.
-  if(RKL_EXPECTED(status == U_ZERO_ERROR, 1L) && RKL_EXPECTED(resultObject != NULL, 1L) && RKL_EXPECTED(replaceMutable == 1UL, 0L) && RKL_EXPECTED(*((NSUInteger *)result) > 0UL, 1L)) { [matchString replaceCharactersInRange:*matchRange withString:resultObject]; }
+  if(RKL_EXPECTED(replaceMutable == 1UL, 0L) && RKL_EXPECTED(*((NSInteger *)result) > 0L, 1L) && RKL_EXPECTED(status == U_ZERO_ERROR, 1L) && RKL_EXPECTED(resultObject != NULL, 1L)) { [matchString replaceCharactersInRange:*matchRange withString:resultObject]; }
   // If status < U_ZERO_ERROR, consider it an error, even though status < U_ZERO_ERROR is a 'warning' in ICU nomenclature.
   // status > U_ZERO_ERROR are an exception and handled above.
   // http://sourceforge.net/tracker/?func=detail&atid=990188&aid=2890810&group_id=204582
-  if(RKL_EXPECTED(status  < U_ZERO_ERROR, 0L) && RKL_EXPECTED(resultObject == NULL, 0L) && (error != NULL)) { *error = [NSError errorWithDomain:RKLICURegexErrorDomain code:(NSInteger)status userInfo:rkl_userInfoDictionary(regexString, options, NULL, status, @"The ICU library returned an unexpected error code.", @"NSLocalizedDescription", NULL)]; }
+  if(RKL_EXPECTED(status  < U_ZERO_ERROR, 0L) && RKL_EXPECTED(resultObject == NULL, 0L) && (error != NULL)) {
+    NSString *replacedString = NULL;
+    NSInteger replacedCount = 0L;
+    RKLUserInfoOptions userInfoOptions = RKLUserInfoNone;
+    if((maskedRegexOp == RKLReplaceOp) && (result != NULL)) { userInfoOptions |= RKLUserInfoReplacedCount; replacedString = resultObject; replacedCount = *((NSInteger *)result); }
+    if(matchRange != NULL) { userInfoOptions |= RKLUserInfoSubjectRange; }
+    *error = rkl_makeNSError(userInfoOptions, regexString, options, NULL, status, matchString, (matchRange != NULL) ? *matchRange : NSNotFoundRange, replacementString, replacedString, replacedCount, (RKLRegexEnumerationOptions)RKLRegexEnumerationNoOptions, @"The ICU library returned an unexpected error.");
+  }
   return(resultObject);
 }
 
 static void rkl_handleDelayedAssert(id self, SEL _cmd, id exception) {
-  if(RKL_EXPECTED(exception != NULL, 0L)) {
+  if(RKL_EXPECTED(exception != NULL, 1L)) {
     if([exception isKindOfClass:[NSException class]]) { [[NSException exceptionWithName:[exception name] reason:rkl_stringFromClassAndMethod(self, _cmd, [exception reason]) userInfo:[exception userInfo]] raise]; }
     else {
       id functionString = [exception objectForKey:@"function"], fileString = [exception objectForKey:@"file"], descriptionString = [exception objectForKey:@"description"], lineNumber = [exception objectForKey:@"line"];
-      NSCParameterAssert((functionString != NULL) && (fileString != NULL) && (descriptionString != NULL) && (lineNumber != NULL));
+      RKLCHardAbortAssert((functionString != NULL) && (fileString != NULL) && (descriptionString != NULL) && (lineNumber != NULL));
       [[NSAssertionHandler currentHandler] handleFailureInFunction:functionString file:fileString lineNumber:(NSInteger)[lineNumber longValue] description:descriptionString];
     }
   }
 //  IMPORTANT!   Should only be called from rkl_performRegexOp() or rkl_findRanges().
 //  ----------
 
-static NSUInteger rkl_search(RKLCacheSlot *cacheSlot, NSRange *searchRange, NSUInteger updateSearchRange, id *exception RKL_UNUSED_ASSERTION_ARG, int32_t *status) {
-  NSUInteger foundMatch = 0UL, searchEqualsEndOfRange = (RKL_EXPECTED(NSEqualRanges(*searchRange, NSMakeRange(NSMaxRange(cacheSlot->setToRange), 0UL)) == YES, 0L) ? 1UL : 0UL);
+#pragma mark Primary means of performing a search with a regular expression
 
-  if((NSEqualRanges(*searchRange, cacheSlot->lastFindRange) == YES) || (searchEqualsEndOfRange == 1UL)) { foundMatch = (((cacheSlot->lastMatchRange.location == (NSUInteger)NSNotFound) || (searchEqualsEndOfRange == 1UL)) ? 0UL : 1UL);}
+static NSUInteger rkl_search(RKLCachedRegex *cachedRegex, NSRange *searchRange, NSUInteger updateSearchRange, id *exception RKL_UNUSED_ASSERTION_ARG, int32_t *status) {
+  NSUInteger foundMatch = 0UL;
+
+  if((NSEqualRanges(*searchRange, cachedRegex->lastFindRange) == YES) && ((cachedRegex->lastMatchRange.length > 0UL) || (cachedRegex->lastMatchRange.location == (NSUInteger)NSNotFound))) { foundMatch = ((cachedRegex->lastMatchRange.location == (NSUInteger)NSNotFound) ? 0UL : 1UL);}
   else { // Only perform an expensive 'find' operation iff the current find range is different than the last find range.
-    NSUInteger findLocation = (searchRange->location - cacheSlot->setToRange.location);
-    RKLCDelayedAssert(((searchRange->location >= cacheSlot->setToRange.location)) && (NSRangeInsideRange(*searchRange, cacheSlot->setToRange) == YES) && (findLocation < INT_MAX) && (findLocation <= cacheSlot->setToRange.length), exception, exitNow);
+    NSUInteger findLocation = (searchRange->location - cachedRegex->setToRange.location);
+    RKLCDelayedAssert(((searchRange->location >= cachedRegex->setToRange.location)) && (NSRangeInsideRange(*searchRange, cachedRegex->setToRange) == YES) && (findLocation < INT_MAX) && (findLocation <= cachedRegex->setToRange.length), exception, exitNow);
     
-    RKL_PREFETCH_UNICHAR(cacheSlot->setToUniChar, searchRange->location); // Spool up the CPU caches.
+    RKL_PREFETCH_UNICHAR(cachedRegex->setToUniChar, searchRange->location); // Spool up the CPU caches.
     
     // Using uregex_findNext can be a slight performance win.
-    NSUInteger useFindNext = ((searchRange->location == (NSMaxRange(cacheSlot->lastMatchRange) + (((cacheSlot->lastMatchRange.length == 0UL) && (cacheSlot->lastMatchRange.location < NSMaxRange(cacheSlot->setToRange))) ? 1UL : 0UL))) ? 1UL : 0UL);
+    NSUInteger useFindNext = (RKL_EXPECTED(searchRange->location == (NSMaxRange(cachedRegex->lastMatchRange) + ((RKL_EXPECTED(cachedRegex->lastMatchRange.length == 0UL, 0L) && RKL_EXPECTED(cachedRegex->lastMatchRange.location < NSMaxRange(cachedRegex->setToRange), 0L)) ? 1UL : 0UL)), 1L) ? 1UL : 0UL);
 
-    cacheSlot->lastFindRange = *searchRange;
-    if(RKL_EXPECTED(useFindNext == 0UL, 0L)) { if(RKL_EXPECTED((RKL_ICU_FUNCTION_APPEND(uregex_find)    (cacheSlot->icu_regex, (int32_t)findLocation, status) == NO), 0L) || RKL_EXPECTED(*status > U_ZERO_ERROR, 0L)) { goto finishedFind; } }
-    else {                                     if(RKL_EXPECTED((RKL_ICU_FUNCTION_APPEND(uregex_findNext)(cacheSlot->icu_regex,                        status) == NO), 0L) || RKL_EXPECTED(*status > U_ZERO_ERROR, 0L)) { goto finishedFind; } }
-    foundMatch = 1UL;
+    cachedRegex->lastFindRange = *searchRange;
+    if(RKL_EXPECTED(useFindNext == 0UL, 0L)) { if(RKL_EXPECTED((RKL_ICU_FUNCTION_APPEND(uregex_find)    (cachedRegex->icu_regex, (int32_t)findLocation, status) == NO), 0L) || RKL_EXPECTED(*status > U_ZERO_ERROR, 0L)) { goto finishedFind; } }
+    else {                                     if(RKL_EXPECTED((RKL_ICU_FUNCTION_APPEND(uregex_findNext)(cachedRegex->icu_regex,                        status) == NO), 0L) || RKL_EXPECTED(*status > U_ZERO_ERROR, 0L)) { goto finishedFind; } }
+    foundMatch = 1UL; 
     
-    if(RKL_EXPECTED(rkl_getRangeForCapture(cacheSlot, status, 0, &cacheSlot->lastMatchRange) > U_ZERO_ERROR, 0L)) { goto finishedFind; }
-    RKLCDelayedAssert(NSRangeInsideRange(cacheSlot->lastMatchRange, *searchRange) == YES, exception, exitNow);
+    if(RKL_EXPECTED(rkl_getRangeForCapture(cachedRegex, status, 0, &cachedRegex->lastMatchRange) > U_ZERO_ERROR, 0L)) { goto finishedFind; }
+    RKLCDelayedAssert(NSRangeInsideRange(cachedRegex->lastMatchRange, *searchRange) == YES, exception, exitNow);
   }
   
 finishedFind:
-  if(RKL_EXPECTED(*status > U_ZERO_ERROR, 0L)) { foundMatch = 0UL; cacheSlot->lastFindRange = NSNotFoundRange; }
+  if(RKL_EXPECTED(*status > U_ZERO_ERROR, 0L)) { foundMatch = 0UL; cachedRegex->lastFindRange = NSNotFoundRange; }
   
-  if(foundMatch == 0UL) { cacheSlot->lastFindRange = NSNotFoundRange; cacheSlot->lastMatchRange = NSNotFoundRange; if(updateSearchRange == 1UL) { *searchRange = NSMakeRange(NSMaxRange(*searchRange), 0UL); } }
+  if(RKL_EXPECTED(foundMatch == 0UL, 0L)) { cachedRegex->lastFindRange = NSNotFoundRange; cachedRegex->lastMatchRange = NSNotFoundRange; if(RKL_EXPECTED(updateSearchRange == 1UL, 1L)) { *searchRange = NSMakeRange(NSMaxRange(*searchRange), 0UL); } }
   else {
-    RKLCDelayedAssert(NSRangeInsideRange(cacheSlot->lastMatchRange, *searchRange) == YES, exception, exitNow);
-    if(updateSearchRange == 1UL) {
-      NSUInteger nextLocation = (NSMaxRange(cacheSlot->lastMatchRange) + (((cacheSlot->lastMatchRange.length == 0UL) && (cacheSlot->lastMatchRange.location < NSMaxRange(cacheSlot->setToRange))) ? 1UL : 0UL)), locationDiff = nextLocation - searchRange->location;
-      RKLCDelayedAssert((((locationDiff > 0UL) || ((locationDiff == 0UL) && (cacheSlot->lastMatchRange.location == NSMaxRange(cacheSlot->setToRange)))) && (locationDiff <= searchRange->length)), exception, exitNow);
+    RKLCDelayedAssert(NSRangeInsideRange(cachedRegex->lastMatchRange, *searchRange) == YES, exception, exitNow);
+    if(RKL_EXPECTED(updateSearchRange == 1UL, 1L)) {
+      NSUInteger nextLocation = (NSMaxRange(cachedRegex->lastMatchRange) + ((RKL_EXPECTED(cachedRegex->lastMatchRange.length == 0UL, 0L) && RKL_EXPECTED(cachedRegex->lastMatchRange.location < NSMaxRange(cachedRegex->setToRange), 1L)) ? 1UL : 0UL)), locationDiff = nextLocation - searchRange->location;
+      RKLCDelayedAssert((((locationDiff > 0UL) || ((locationDiff == 0UL) && (cachedRegex->lastMatchRange.location == NSMaxRange(cachedRegex->setToRange)))) && (locationDiff <= searchRange->length)), exception, exitNow);
       searchRange->location  = nextLocation;
       searchRange->length   -= locationDiff;
     }
 }
 
 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
-//  IMPORTANT!   Should only be called from rkl_doFindOp().
+//  IMPORTANT!   Should only be called from rkl_performRegexOp() or rkl_performEnumerationUsingBlock().
 //  ----------
 
-static BOOL rkl_findRanges(RKLCacheSlot *cacheSlot, RKLRegexOp regexOp, RKLFindAll *findAll, id *exception, int32_t *status) {
+#pragma mark Used to perform multiple searches at once and return the NSRange results in bulk
+
+static BOOL rkl_findRanges(RKLCachedRegex *cachedRegex, RKLRegexOp regexOp, RKLFindAll *findAll, id *exception, int32_t *status) {
   BOOL returnWithError = YES;
-  RKLCDelayedAssert((((cacheSlot != NULL) && (cacheSlot->icu_regex != NULL) && (cacheSlot->setToUniChar != NULL) && (cacheSlot->captureCount >= 0L) && (cacheSlot->setToRange.location != (NSUInteger)NSNotFound)) && (status != NULL) && ((findAll != NULL) && (findAll->found == 0L) && ((findAll->capacity >= 0L) && (((findAll->capacity > 0L) || (findAll->size > 0UL)) ? ((findAll->ranges != NULL) && (findAll->capacity > 0L) && (findAll->size > 0UL)) : 1)) && (findAll->rangesScratchBuffer != NULL) && ((findAll->capture >= 0L) && (findAll->capture <= cacheSlot->captureCount)))), exception, exitNow);
+  RKLCDelayedAssert((((cachedRegex != NULL) && (cachedRegex->icu_regex != NULL) && (cachedRegex->setToUniChar != NULL) && (cachedRegex->captureCount >= 0L) && (cachedRegex->setToRange.location != (NSUInteger)NSNotFound)) && (status != NULL) && ((findAll != NULL) && (findAll->found == 0L) && (findAll->addedSplitRanges == 0L) && ((findAll->capacity >= 0L) && (((findAll->capacity > 0L) || (findAll->size > 0UL)) ? ((findAll->ranges != NULL) && (findAll->capacity > 0L) && (findAll->size > 0UL)) : 1)) && ((findAll->capture >= 0L) && (findAll->capture <= cachedRegex->captureCount)))), exception, exitNow);
   
-  if(RKL_EXPECTED(cacheSlot->setToLength == 0L, 0L) || RKL_EXPECTED(cacheSlot->setToRange.length == 0UL, 0L)) { returnWithError = NO; goto exitNow; }
-  
-  NSInteger  captureCount  = cacheSlot->captureCount;
+  NSInteger  captureCount  = cachedRegex->captureCount, findAllRangeIndexOfLastNonZeroLength = 0L;
+  NSUInteger lastLocation  = findAll->findInRange.location;
   RKLRegexOp maskedRegexOp = (regexOp & RKLMaskOp);
-  NSUInteger lastLocation  = findAll->findInRange.location;
   NSRange    searchRange   = findAll->findInRange;
-  
+
   for(findAll->found = 0L; (findAll->found < findAll->findUpTo) && ((findAll->found < findAll->capacity) || (findAll->found == 0L)); findAll->found++) {
     NSInteger loopCapture, shouldBreak = 0L;
+
+    if(RKL_EXPECTED(findAll->found >= ((findAll->capacity - ((captureCount + 2L) * 4L)) - 4L), 0L)) { if(RKL_EXPECTED(rkl_growFindRanges(cachedRegex, lastLocation, findAll, exception) == 0UL, 0L)) { goto exitNow; } }
     
-    if(RKL_EXPECTED(findAll->found >= ((findAll->capacity - ((captureCount + 2L) * 4L)) - 4L), 0L)) { if(RKL_EXPECTED(rkl_growFindRanges(cacheSlot, lastLocation, findAll, exception) == 0UL, 0L)) { goto exitNow; } }
-    
-    RKLCDelayedAssert((searchRange.location != (NSUInteger)NSNotFound) && (NSRangeInsideRange(searchRange, cacheSlot->setToRange) == YES) && (NSRangeInsideRange(findAll->findInRange, cacheSlot->setToRange) == YES), exception, exitNow);
+    RKLCDelayedAssert((searchRange.location != (NSUInteger)NSNotFound) && (NSRangeInsideRange(searchRange, cachedRegex->setToRange) == YES) && (NSRangeInsideRange(findAll->findInRange, cachedRegex->setToRange) == YES), exception, exitNow);
     
     // This fixes a 'bug' that is also present in ICU's uregex_split().  'Bug', in this case, means that the results of a split operation can differ from those that perl's split() creates for the same input.
     // "I|at|ice I eat rice" split using the regex "\b\s*" demonstrates the problem. ICU bug http://bugs.icu-project.org/trac/ticket/6826
     // ICU : "", "I", "|", "at", "|", "ice", "", "I", "", "eat", "", "rice" <- Results that RegexKitLite used to produce.
     // PERL:     "I", "|", "at", "|", "ice",     "I",     "eat",     "rice" <- Results that RegexKitLite now produces.
-    do { if((rkl_search(cacheSlot, &searchRange, 1UL, exception, status) == NO) || (RKL_EXPECTED(*status > U_ZERO_ERROR, 0L))) { shouldBreak = 1L; } }
-    while((maskedRegexOp == RKLSplitOp) && RKL_EXPECTED(shouldBreak == 0L, 1L) && RKL_EXPECTED(cacheSlot->lastMatchRange.length == 0UL, 0L) && RKL_EXPECTED((cacheSlot->lastMatchRange.location - lastLocation) == 0UL, 0L));
+    do { if((rkl_search(cachedRegex, &searchRange, 1UL, exception, status) == NO) || (RKL_EXPECTED(*status > U_ZERO_ERROR, 0L))) { shouldBreak = 1L; } findAll->remainingRange = searchRange; }
+    while(RKL_EXPECTED((cachedRegex->lastMatchRange.location - lastLocation) == 0UL, 0L) && RKL_EXPECTED(cachedRegex->lastMatchRange.length == 0UL, 0L) && (maskedRegexOp == RKLSplitOp) && RKL_EXPECTED(shouldBreak == 0L, 1L));
     if(RKL_EXPECTED(shouldBreak == 1L, 0L)) { break; }
 
-    RKLCDelayedAssert((searchRange.location != (NSUInteger)NSNotFound) && (NSRangeInsideRange(searchRange, cacheSlot->setToRange) == YES) && (NSRangeInsideRange(findAll->findInRange, cacheSlot->setToRange) == YES) && (NSRangeInsideRange(searchRange, findAll->findInRange) == YES), exception, exitNow);
-    RKLCDelayedAssert((NSRangeInsideRange(cacheSlot->lastFindRange, cacheSlot->setToRange) == YES) && (NSRangeInsideRange(cacheSlot->lastMatchRange, cacheSlot->setToRange) == YES) && (NSRangeInsideRange(cacheSlot->lastMatchRange, findAll->findInRange) == YES), exception, exitNow);
+    RKLCDelayedAssert((searchRange.location != (NSUInteger)NSNotFound) && (NSRangeInsideRange(searchRange, cachedRegex->setToRange) == YES) && (NSRangeInsideRange(findAll->findInRange, cachedRegex->setToRange) == YES) && (NSRangeInsideRange(searchRange, findAll->findInRange) == YES), exception, exitNow);
+    RKLCDelayedAssert((NSRangeInsideRange(cachedRegex->lastFindRange, cachedRegex->setToRange) == YES) && (NSRangeInsideRange(cachedRegex->lastMatchRange, cachedRegex->setToRange) == YES) && (NSRangeInsideRange(cachedRegex->lastMatchRange, findAll->findInRange) == YES), exception, exitNow);
     RKLCDelayedAssert((findAll->ranges != NULL) && (findAll->found >= 0L) && (findAll->capacity >= 0L) && ((findAll->found + (captureCount + 3L) + 1L) < (findAll->capacity - 2L)), exception, exitNow);
     
+    NSInteger findAllRangesIndexForCapture0 = findAll->found;
     switch(maskedRegexOp) {
       case RKLArrayOfStringsOp:
-        if(findAll->capture == 0L) { findAll->ranges[findAll->found] = cacheSlot->lastMatchRange; } else { if(RKL_EXPECTED(rkl_getRangeForCapture(cacheSlot, status, (int32_t)findAll->capture, &findAll->ranges[findAll->found]) > U_ZERO_ERROR, 0L)) { goto exitNow; } }
+        if(findAll->capture == 0L) { findAll->ranges[findAll->found] = cachedRegex->lastMatchRange; } else { if(RKL_EXPECTED(rkl_getRangeForCapture(cachedRegex, status, (int32_t)findAll->capture, &findAll->ranges[findAll->found]) > U_ZERO_ERROR, 0L)) { goto exitNow; } }
         break;
         
-      case RKLSplitOp:         // Fall-thru...
-      case RKLCapturesArrayOp: // Fall-thru...
+      case RKLSplitOp:                         // Fall-thru...
+      case RKLCapturesArrayOp:                 // Fall-thru...
+      case RKLDictionaryOfCapturesOp:          // Fall-thru...
+      case RKLArrayOfDictionariesOfCapturesOp: // Fall-thru...
       case RKLArrayOfCapturesOp:
-        findAll->ranges[findAll->found] = ((maskedRegexOp == RKLSplitOp) ? NSMakeRange(lastLocation, cacheSlot->lastMatchRange.location - lastLocation) : cacheSlot->lastMatchRange);
-        
+        findAll->ranges[findAll->found] = ((maskedRegexOp == RKLSplitOp) ? NSMakeRange(lastLocation, cachedRegex->lastMatchRange.location - lastLocation) : cachedRegex->lastMatchRange);
+
         for(loopCapture = 1L; loopCapture <= captureCount; loopCapture++) {
           RKLCDelayedAssert((findAll->found >= 0L) && (findAll->found < (findAll->capacity - 2L)) && (loopCapture < INT_MAX), exception, exitNow);
-          if(RKL_EXPECTED(rkl_getRangeForCapture(cacheSlot, status, (int32_t)loopCapture, &findAll->ranges[++findAll->found]) > U_ZERO_ERROR, 0L)) { goto exitNow; }
+          if(RKL_EXPECTED(rkl_getRangeForCapture(cachedRegex, status, (int32_t)loopCapture, &findAll->ranges[++findAll->found]) > U_ZERO_ERROR, 0L)) { goto exitNow; }
         }
         break;
         
-      default: if(*exception != NULL) { *exception = RKLCAssertDictionary(@"Unknown regexOp."); } goto exitNow; break;
+      default: if(*exception == NULL) { *exception = RKLCAssertDictionary(@"Unknown regexOp."); } goto exitNow; break;
     }
     
-    lastLocation = NSMaxRange(cacheSlot->lastMatchRange);
+    if(findAll->ranges[findAllRangesIndexForCapture0].length > 0UL) { findAllRangeIndexOfLastNonZeroLength = findAll->found + 1UL; }
+    lastLocation = NSMaxRange(cachedRegex->lastMatchRange);
   }
   
   if(RKL_EXPECTED(*status > U_ZERO_ERROR, 0L)) { goto exitNow; }
   
   RKLCDelayedAssert((findAll->ranges != NULL) && (findAll->found >= 0L) && (findAll->found < (findAll->capacity - 2L)), exception, exitNow);
-  if((maskedRegexOp == RKLSplitOp) && (lastLocation != NSMaxRange(findAll->findInRange))) { findAll->ranges[findAll->found++] = NSMakeRange(lastLocation, NSMaxRange(findAll->findInRange) - lastLocation); }
-    
+  if(maskedRegexOp == RKLSplitOp) {
+    if(lastLocation != NSMaxRange(findAll->findInRange)) { findAll->addedSplitRanges++; findAll->ranges[findAll->found++] = NSMakeRange(lastLocation, NSMaxRange(findAll->findInRange) - lastLocation); findAllRangeIndexOfLastNonZeroLength = findAll->found; }
+    findAll->found = findAllRangeIndexOfLastNonZeroLength;
+  }
+  
   RKLCDelayedAssert((findAll->ranges != NULL) && (findAll->found >= 0L) && (findAll->found < (findAll->capacity - 2L)), exception, exitNow);
   returnWithError = NO;
   
 //  IMPORTANT!   Should only be called from rkl_findRanges().
 //  ----------
 
-static NSUInteger rkl_growFindRanges(RKLCacheSlot *cacheSlot, NSUInteger lastLocation, RKLFindAll *findAll, id *exception RKL_UNUSED_ASSERTION_ARG) {
+static NSUInteger rkl_growFindRanges(RKLCachedRegex *cachedRegex, NSUInteger lastLocation, RKLFindAll *findAll, id *exception RKL_UNUSED_ASSERTION_ARG) {
   NSUInteger didGrowRanges = 0UL;
-  RKLCDelayedAssert((((cacheSlot != NULL) && (cacheSlot->captureCount >= 0L)) && ((findAll != NULL) && (findAll->capacity >= 0L) && (findAll->rangesScratchBuffer != NULL) && (findAll->found >= 0L) && (((findAll->capacity > 0L) || (findAll->size > 0UL) || (findAll->ranges != NULL)) ? ((findAll->capacity > 0L) && (findAll->size > 0UL) && (findAll->ranges != NULL) && (((size_t)findAll->capacity * sizeof(NSRange)) == findAll->size)) : 1))), exception, exitNow);
+  RKLCDelayedAssert((((cachedRegex != NULL) && (cachedRegex->captureCount >= 0L)) && ((findAll != NULL) && (findAll->capacity >= 0L) && (findAll->rangesScratchBuffer != NULL) && (findAll->found >= 0L) && (((findAll->capacity > 0L) || (findAll->size > 0UL) || (findAll->ranges != NULL)) ? ((findAll->capacity > 0L) && (findAll->size > 0UL) && (findAll->ranges != NULL) && (((size_t)findAll->capacity * sizeof(NSRange)) == findAll->size)) : 1))), exception, exitNow);
   
   // Attempt to guesstimate the required capacity based on: the total length needed to search / (length we've searched so far / ranges found so far).
-  NSInteger newCapacity = (findAll->capacity + (findAll->capacity / 2L)), estimate = (NSInteger)((float)cacheSlot->setToLength / (((float)lastLocation + 1.0f) / ((float)findAll->found + 1.0f)));
-  newCapacity = (((newCapacity + ((estimate > newCapacity) ? estimate : newCapacity)) / 2L) + ((cacheSlot->captureCount + 2L) * 4L) + 4L);
+  NSInteger newCapacity = (findAll->capacity + (findAll->capacity / 2L)), estimate = (NSInteger)((float)cachedRegex->setToLength / (((float)lastLocation + 1.0f) / ((float)findAll->found + 1.0f)));
+  newCapacity = (((newCapacity + ((estimate > newCapacity) ? estimate : newCapacity)) / 2L) + ((cachedRegex->captureCount + 2L) * 4L) + 4L);
   
-  NSUInteger  needToCopy = ((findAll->ranges != NULL) && (*findAll->rangesScratchBuffer != findAll->ranges)) ? 1UL : 0UL; // If findAll->ranges is set to a stack allocation then we need to manually copy the data from the stack to the new heap allocation.
-  size_t      newSize    = ((size_t)newCapacity * sizeof(NSRange));
-  NSRange    *newRanges  = NULL;
+  NSUInteger                               needToCopy = ((*findAll->rangesScratchBuffer != findAll->ranges) && (findAll->ranges != NULL)) ? 1UL : 0UL; // If findAll->ranges is set to a stack allocation then we need to manually copy the data from the stack to the new heap allocation.
+  size_t                                   newSize    = ((size_t)newCapacity * sizeof(NSRange));
+  RKL_STRONG_REF NSRange * RKL_GC_VOLATILE newRanges  = NULL;
   
-  if(RKL_EXPECTED((newRanges = (NSRange *)rkl_realloc((RKL_STRONG_REF void **)findAll->rangesScratchBuffer, newSize, 0UL)) == NULL, 0L)) { findAll->capacity = 0L; findAll->size = 0UL; findAll->ranges = NULL; *findAll->rangesScratchBuffer = rkl_free((RKL_STRONG_REF void **)findAll->rangesScratchBuffer); goto exitNow; } else { didGrowRanges = 1UL; }
+  if(RKL_EXPECTED((newRanges = (RKL_STRONG_REF NSRange * RKL_GC_VOLATILE)rkl_realloc((RKL_STRONG_REF void ** RKL_GC_VOLATILE)findAll->rangesScratchBuffer, newSize, 0UL)) == NULL, 0L)) { findAll->capacity = 0L; findAll->size = 0UL; findAll->ranges = NULL; *findAll->rangesScratchBuffer = rkl_free((RKL_STRONG_REF void ** RKL_GC_VOLATILE)findAll->rangesScratchBuffer); goto exitNow; } else { didGrowRanges = 1UL; }
   if(needToCopy == 1UL) { memcpy(newRanges, findAll->ranges, findAll->size); } // If necessary, copy the existing data to the new heap allocation.
   
   findAll->capacity = newCapacity;
 }
 
 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
-//  IMPORTANT!   Should only be called from rkl_doFindOp().
+//  IMPORTANT!   Should only be called from rkl_performRegexOp().
 //  ----------
 
-static NSArray *rkl_makeArray(RKLCacheSlot *cacheSlot, RKLRegexOp regexOp, RKLFindAll *findAll, id *exception RKL_UNUSED_ASSERTION_ARG) {
-  NSUInteger  createdStringsCount = 0UL,   createdArraysCount = 0UL,  transferedStringsCount = 0UL;
-  id         *matchedStrings      = NULL, *subcaptureArrays   = NULL, emptyString            = @"";
-  NSArray    *resultArray         = NULL;
+#pragma mark Convert bulk results from rkl_findRanges in to various NSArray types
+
+static NSArray *rkl_makeArray(RKLCachedRegex *cachedRegex, RKLRegexOp regexOp, RKLFindAll *findAll, id *exception RKL_UNUSED_ASSERTION_ARG) {
+  NSUInteger  createdStringsCount = 0UL,   createdArraysCount = 0UL,  transferredStringsCount = 0UL;
+  id         * RKL_GC_VOLATILE matchedStrings = NULL, * RKL_GC_VOLATILE subcaptureArrays = NULL, emptyString = @"";
+  NSArray    * RKL_GC_VOLATILE resultArray    = NULL;
   
-  RKLCDelayedAssert((cacheSlot != NULL) && ((findAll != NULL) && (findAll->found >= 0L) && (findAll->stringsScratchBuffer != NULL) && (findAll->arraysScratchBuffer != NULL)), exception, exitNow);
+  RKLCDelayedAssert((cachedRegex != NULL) && ((findAll != NULL) && (findAll->found >= 0L) && (findAll->stringsScratchBuffer != NULL) && (findAll->arraysScratchBuffer != NULL)), exception, exitNow);
   
   size_t      matchedStringsSize = ((size_t)findAll->found * sizeof(id));
-  CFStringRef setToString        = cacheSlot->setToString;
+  CFStringRef setToString        = cachedRegex->setToString;
   
-  if((findAll->stackUsed + matchedStringsSize) < (size_t)(RKL_STACK_LIMIT)) { if(RKL_EXPECTED((matchedStrings = (id *)alloca(matchedStringsSize))                                                                   == NULL, 0L)) { goto exitNow; } findAll->stackUsed += matchedStringsSize; }
-  else {                                                                      if(RKL_EXPECTED((matchedStrings = (id *)rkl_realloc(findAll->stringsScratchBuffer, matchedStringsSize, (NSUInteger)RKLScannedOption)) == NULL, 0L)) { goto exitNow; } }
+  if((findAll->stackUsed + matchedStringsSize) < (size_t)_RKL_STACK_LIMIT) { if(RKL_EXPECTED((matchedStrings = (id * RKL_GC_VOLATILE)alloca(matchedStringsSize))                                                                   == NULL, 0L)) { goto exitNow; } findAll->stackUsed += matchedStringsSize; }
+  else {                                                                     if(RKL_EXPECTED((matchedStrings = (id * RKL_GC_VOLATILE)rkl_realloc(findAll->stringsScratchBuffer, matchedStringsSize, (NSUInteger)RKLScannedOption)) == NULL, 0L)) { goto exitNow; } }
   
   { // This sub-block (and its local variables) is here for the benefit of the optimizer.
     NSUInteger     found             = (NSUInteger)findAll->found;
     }
   }
   
-  NSUInteger  arrayCount   = createdStringsCount;