From fdd07cb571d28e095b1bca4c2a2571c4ca14d356 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Fri, 15 Jun 2018 08:54:48 -0700 Subject: [PATCH] Reduce block enumerations --- Source/ASCollectionView.mm | 4 +-- Source/Base/ASBaseDefines.h | 36 +++++++++++++++++++ Source/Details/ASDataController.mm | 28 +++++++-------- Source/Details/ASElementMap.m | 4 +-- Source/Details/ASObjectDescriptionHelpers.m | 4 +-- Source/Details/NSIndexSet+ASHelpers.m | 31 ++++++++-------- Source/Details/_ASDisplayViewAccessiblity.mm | 8 +++-- Source/Private/ASMutableElementMap.m | 17 +++++---- .../TextExperiment/Component/ASTextLayout.m | 4 +-- .../Utility/NSAttributedString+ASText.m | 4 +-- .../Utility/NSParagraphStyle+ASText.m | 4 +-- Source/Private/_ASHierarchyChangeSet.mm | 12 +++---- Source/TextKit/ASTextKitCoreTextAdditions.m | 10 +++--- 13 files changed, 97 insertions(+), 69 deletions(-) diff --git a/Source/ASCollectionView.mm b/Source/ASCollectionView.mm index 3b896468..8bb041ca 100644 --- a/Source/ASCollectionView.mm +++ b/Source/ASCollectionView.mm @@ -2007,10 +2007,10 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier"; if (_asyncDataSourceFlags.collectionNodeSupplementaryElementKindsInSection) { NSMutableSet *kinds = [NSMutableSet set]; GET_COLLECTIONNODE_OR_RETURN(collectionNode, @[]); - [sections enumerateIndexesUsingBlock:^(NSUInteger section, BOOL * _Nonnull stop) { + AS_FOR_INDEXSET(sections, section) { NSArray *kindsForSection = [_asyncDataSource collectionNode:collectionNode supplementaryElementKindsInSection:section]; [kinds addObjectsFromArray:kindsForSection]; - }]; + } return [kinds allObjects]; } else { // TODO: Lock this diff --git a/Source/Base/ASBaseDefines.h b/Source/Base/ASBaseDefines.h index 6706b6da..900443e8 100755 --- a/Source/Base/ASBaseDefines.h +++ b/Source/Base/ASBaseDefines.h @@ -296,3 +296,39 @@ } \ a; \ }) + +/** + * A fast enumeration for a dictionary. It evaluates to a declaration for a + * for loop that provides each key-value pair using the name and type you give. + * + * Usage: + * AS_FOR_DICT(myDict, NSString *, name, NSNumber *, age) { + * NSLog(@"Name: %@, age: %@", name, age); + * } + * + * In implementation terms: + * - We namespace all temporary variables by the key name + * so that multiple declarations don't interfere. + * - We are careful not to encompass the body inside the macro or + * we'll make debugging tough. + * - We make the stack arrays one extra long, so that we can advance the key & val + * pointers in the "increment" portion of the loop decl without going + * out-of-bounds. The loop will exit before the user uses the garbage values there. + */ +#define AS_FOR_DICT(dict, keyType, key, valType, val) \ + NSUInteger c_##key = dict.count; \ + __unsafe_unretained keyType karr_##key[c_##key+1]; \ + __unsafe_unretained valType varr_##key[c_##key+1]; \ + [dict getObjects:varr_##key andKeys:karr_##key count:c_##key]; \ + int i_##key = 0; \ + __unsafe_unretained keyType key = c_##key ? karr_##key[0] : nil; \ + __unsafe_unretained valType val = c_##key ? varr_##key[0] : nil; \ + for (; i_##key < c_##key; i_##key++, key = karr_##key[i_##key], val = varr_##key[i_##key]) + +#define AS_FOR_INDEXSET(indexSet, val) \ + NSUInteger c = indexSet.count; \ + NSUInteger buf[c + 1]; \ + [indexSet getIndexes:buf maxCount:c inIndexRange:NULL]; \ + NSUInteger i = 0; \ + NSUInteger val = c ? buf[0] : NSNotFound; \ + for (; i < c; val = buf[i++]) diff --git a/Source/Details/ASDataController.mm b/Source/Details/ASDataController.mm index e1b25c63..e6eeaf99 100644 --- a/Source/Details/ASDataController.mm +++ b/Source/Details/ASDataController.mm @@ -217,24 +217,20 @@ typedef void (^ASDataControllerSynchronizationBlock)(); NSMutableArray *indexPaths = [NSMutableArray array]; if ([kind isEqualToString:ASDataControllerRowNodeKind]) { std::vector counts = [self itemCountsFromDataSource]; - [sections enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) { - for (NSUInteger sectionIndex = range.location; sectionIndex < NSMaxRange(range); sectionIndex++) { - NSUInteger itemCount = counts[sectionIndex]; - for (NSUInteger i = 0; i < itemCount; i++) { - [indexPaths addObject:[NSIndexPath indexPathForItem:i inSection:sectionIndex]]; - } + AS_FOR_INDEXSET(sections, sectionIndex) { + NSUInteger itemCount = counts[sectionIndex]; + for (NSUInteger i = 0; i < itemCount; i++) { + [indexPaths addObject:[NSIndexPath indexPathForItem:i inSection:sectionIndex]]; } - }]; + } } else if (_dataSourceFlags.supplementaryNodesOfKindInSection) { id dataSource = _dataSource; - [sections enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) { - for (NSUInteger sectionIndex = range.location; sectionIndex < NSMaxRange(range); sectionIndex++) { - NSUInteger itemCount = [dataSource dataController:self supplementaryNodesOfKind:kind inSection:sectionIndex]; - for (NSUInteger i = 0; i < itemCount; i++) { - [indexPaths addObject:[NSIndexPath indexPathForItem:i inSection:sectionIndex]]; - } + AS_FOR_INDEXSET(sections, sectionIndex) { + NSUInteger itemCount = [dataSource dataController:self supplementaryNodesOfKind:kind inSection:sectionIndex]; + for (NSUInteger i = 0; i < itemCount; i++) { + [indexPaths addObject:[NSIndexPath indexPathForItem:i inSection:sectionIndex]]; } - }]; + } } return indexPaths; @@ -721,7 +717,7 @@ typedef void (^ASDataControllerSynchronizationBlock)(); { ASDisplayNodeAssertMainThread(); - [sectionIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) { + AS_FOR_INDEXSET(sectionIndexes, idx) { id context; if (_dataSourceFlags.contextForSection) { context = [_dataSource dataController:self contextForSection:idx]; @@ -729,7 +725,7 @@ typedef void (^ASDataControllerSynchronizationBlock)(); ASSection *section = [[ASSection alloc] initWithSectionID:_nextSectionID context:context]; [map insertSection:section atIndex:idx]; _nextSectionID++; - }]; + } } /** diff --git a/Source/Details/ASElementMap.m b/Source/Details/ASElementMap.m index dd451a87..9fed8624 100644 --- a/Source/Details/ASElementMap.m +++ b/Source/Details/ASElementMap.m @@ -67,9 +67,9 @@ s++; } for (NSDictionary *supplementariesForKind in [_supplementaryElements objectEnumerator]) { - [supplementariesForKind enumerateKeysAndObjectsUsingBlock:^(NSIndexPath *_Nonnull indexPath, ASCollectionElement * _Nonnull element, BOOL * _Nonnull stop) { + AS_FOR_DICT(supplementariesForKind, NSIndexPath *, indexPath, ASCollectionElement *, element) { [_elementToIndexPathMap setObject:indexPath forKey:element]; - }]; + } } } return self; diff --git a/Source/Details/ASObjectDescriptionHelpers.m b/Source/Details/ASObjectDescriptionHelpers.m index b3487286..9a02050e 100644 --- a/Source/Details/ASObjectDescriptionHelpers.m +++ b/Source/Details/ASObjectDescriptionHelpers.m @@ -58,7 +58,7 @@ NSString *_ASObjectDescriptionMakePropertyList(NSArray * _Nullab { NSMutableArray *components = [NSMutableArray array]; for (NSDictionary *properties in propertyGroups) { - [properties enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { + AS_FOR_DICT(properties, id, key, id, obj) { NSString *str; if (key == (id)kCFNull) { str = ASGetDescriptionValueString(obj); @@ -66,7 +66,7 @@ NSString *_ASObjectDescriptionMakePropertyList(NSArray * _Nullab str = [NSString stringWithFormat:@"%@ = %@", key, ASGetDescriptionValueString(obj)]; } [components addObject:str]; - }]; + } } return [components componentsJoinedByString:@"; "]; } diff --git a/Source/Details/NSIndexSet+ASHelpers.m b/Source/Details/NSIndexSet+ASHelpers.m index 06743e0a..8e34ec3e 100644 --- a/Source/Details/NSIndexSet+ASHelpers.m +++ b/Source/Details/NSIndexSet+ASHelpers.m @@ -18,21 +18,20 @@ // UIKit indexPath helpers #import +#import #import @implementation NSIndexSet (ASHelpers) - (NSIndexSet *)as_indexesByMapping:(NSUInteger (^)(NSUInteger))block { - NSMutableIndexSet *result = [NSMutableIndexSet indexSet]; - [self enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) { - for (NSUInteger i = range.location; i < NSMaxRange(range); i++) { - NSUInteger newIndex = block(i); - if (newIndex != NSNotFound) { - [result addIndex:newIndex]; - } + NSMutableIndexSet *result = [[NSMutableIndexSet alloc] init]; + AS_FOR_INDEXSET(self, i) { + NSUInteger newIndex = block(i); + if (newIndex != NSNotFound) { + [result addIndex:newIndex]; } - }]; + } return result; } @@ -60,16 +59,14 @@ - (NSUInteger)as_indexChangeByInsertingItemsBelowIndex:(NSUInteger)index { - __block NSUInteger newIndex = index; - [self enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) { - for (NSUInteger i = range.location; i < NSMaxRange(range); i++) { - if (i <= newIndex) { - newIndex += 1; - } else { - *stop = YES; - } + NSUInteger newIndex = index; + AS_FOR_INDEXSET(self, i) { + if (i <= newIndex) { + newIndex += 1; + } else { + break; } - }]; + } return newIndex - index; } diff --git a/Source/Details/_ASDisplayViewAccessiblity.mm b/Source/Details/_ASDisplayViewAccessiblity.mm index d311cdbc..eef6bbbd 100644 --- a/Source/Details/_ASDisplayViewAccessiblity.mm +++ b/Source/Details/_ASDisplayViewAccessiblity.mm @@ -182,12 +182,14 @@ static void CollectAccessibilityElementsForContainer(ASDisplayNode *container, _ if (AS_AVAILABLE_IOS_TVOS(11, 11)) { NSArray *attributedLabels = [labeledNodes valueForKey:@"accessibilityAttributedLabel"]; NSMutableAttributedString *attributedLabel = [NSMutableAttributedString new]; - [attributedLabels enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + NSUInteger idx = 0; + for (NSAttributedString *obj in attributedLabels) { if (idx != 0) { [attributedLabel appendAttributedString:[[NSAttributedString alloc] initWithString:@", "]]; } - [attributedLabel appendAttributedString:(NSAttributedString *)obj]; - }]; + [attributedLabel appendAttributedString:obj]; + idx++; + } accessiblityElement.accessibilityAttributedLabel = attributedLabel; } else #endif diff --git a/Source/Private/ASMutableElementMap.m b/Source/Private/ASMutableElementMap.m index 1ddbc127..1502435f 100644 --- a/Source/Private/ASMutableElementMap.m +++ b/Source/Private/ASMutableElementMap.m @@ -86,9 +86,9 @@ typedef NSMutableDictionary * _Nonnull supps, BOOL * _Nonnull stop) { - + AS_FOR_DICT(_supplementaryElements, NSString *, key, NSMutableDictionary *, supps) { // For each index path of that kind, move entries into a new dictionary. // Note: it's tempting to update the dictionary in-place but because of the likely collision between old and new index paths, // subtle bugs are possible. Note that this process is rare (only on section-level updates), // that this work is done off-main, and that the typical supplementary element use case is just 1-per-section (header). - NSMutableDictionary *newSupps = [NSMutableDictionary dictionary]; - [supps enumerateKeysAndObjectsUsingBlock:^(NSIndexPath * _Nonnull oldIndexPath, ASCollectionElement * _Nonnull obj, BOOL * _Nonnull stop) { + NSMutableDictionary *newSupps = [[NSMutableDictionary alloc] init]; + AS_FOR_DICT(supps, NSIndexPath *, oldIndexPath, ASCollectionElement *, obj) { NSInteger oldSection = oldIndexPath.section; NSInteger newSection = [mapping integerForKey:oldSection]; @@ -133,9 +132,9 @@ typedef NSMutableDictionary