Skip to content

Commit

Permalink
Create transfer-array method and use it (TextureGroup#987)
Browse files Browse the repository at this point in the history
* Create transfer-array method and use it

* License headers

* Update ASArrayByFlatMapping
  • Loading branch information
Adlai-Holler authored and mikezucc committed Oct 2, 2018
1 parent ccd1bca commit c9050c1
Show file tree
Hide file tree
Showing 15 changed files with 213 additions and 34 deletions.
12 changes: 12 additions & 0 deletions AsyncDisplayKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,9 @@
CC224E962066CA6D00BBA57F /* configuration.json in Resources */ = {isa = PBXBuildFile; fileRef = CC224E952066CA6D00BBA57F /* configuration.json */; };
CC2F65EE1E5FFB1600DA57C9 /* ASMutableElementMap.h in Headers */ = {isa = PBXBuildFile; fileRef = CC2F65EC1E5FFB1600DA57C9 /* ASMutableElementMap.h */; };
CC2F65EF1E5FFB1600DA57C9 /* ASMutableElementMap.m in Sources */ = {isa = PBXBuildFile; fileRef = CC2F65ED1E5FFB1600DA57C9 /* ASMutableElementMap.m */; };
CC35CEC320DD7F600006448D /* ASCollections.h in Headers */ = {isa = PBXBuildFile; fileRef = CC35CEC120DD7F600006448D /* ASCollections.h */; settings = {ATTRIBUTES = (Public, ); }; };
CC35CEC420DD7F600006448D /* ASCollections.m in Sources */ = {isa = PBXBuildFile; fileRef = CC35CEC220DD7F600006448D /* ASCollections.m */; };
CC35CEC620DD87280006448D /* ASCollectionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC35CEC520DD87280006448D /* ASCollectionsTests.m */; };
CC3B20841C3F76D600798563 /* ASPendingStateController.h in Headers */ = {isa = PBXBuildFile; fileRef = CC3B20811C3F76D600798563 /* ASPendingStateController.h */; settings = {ATTRIBUTES = (Private, ); }; };
CC3B20861C3F76D600798563 /* ASPendingStateController.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC3B20821C3F76D600798563 /* ASPendingStateController.mm */; };
CC3B208A1C3F7A5400798563 /* ASWeakSet.h in Headers */ = {isa = PBXBuildFile; fileRef = CC3B20871C3F7A5400798563 /* ASWeakSet.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -841,6 +844,9 @@
CC2E317F1DAC353700EEE891 /* ASCollectionView+Undeprecated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASCollectionView+Undeprecated.h"; sourceTree = "<group>"; };
CC2F65EC1E5FFB1600DA57C9 /* ASMutableElementMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMutableElementMap.h; sourceTree = "<group>"; };
CC2F65ED1E5FFB1600DA57C9 /* ASMutableElementMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASMutableElementMap.m; sourceTree = "<group>"; };
CC35CEC120DD7F600006448D /* ASCollections.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASCollections.h; sourceTree = "<group>"; };
CC35CEC220DD7F600006448D /* ASCollections.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASCollections.m; sourceTree = "<group>"; };
CC35CEC520DD87280006448D /* ASCollectionsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASCollectionsTests.m; sourceTree = "<group>"; };
CC3B20811C3F76D600798563 /* ASPendingStateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPendingStateController.h; sourceTree = "<group>"; };
CC3B20821C3F76D600798563 /* ASPendingStateController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASPendingStateController.mm; sourceTree = "<group>"; };
CC3B20871C3F7A5400798563 /* ASWeakSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASWeakSet.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1117,6 +1123,8 @@
058D09B1195D04C000B7D73C /* Source */ = {
isa = PBXGroup;
children = (
CC35CEC120DD7F600006448D /* ASCollections.h */,
CC35CEC220DD7F600006448D /* ASCollections.m */,
058D0A42195D058D00B7D73C /* Base */,
CCE04B1D1E313E99006AEBBB /* Collection Data Adapter */,
DE89C1691DCEB9CC00D49D74 /* Debug */,
Expand Down Expand Up @@ -1241,6 +1249,7 @@
058D09C5195D04C000B7D73C /* Tests */ = {
isa = PBXGroup;
children = (
CC35CEC520DD87280006448D /* ASCollectionsTests.m */,
DBC452DD1C5C6A6A00B16017 /* ArrayDiffingTests.m */,
AC026B571BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.m */,
696FCB301D6E46050093471E /* ASBackgroundLayoutSpecSnapshotTests.mm */,
Expand Down Expand Up @@ -2023,6 +2032,7 @@
CCCCCCDB1EC3EF060087FE10 /* ASTextLine.h in Headers */,
9C70F20E1CDBE9E5007D6C76 /* NSArray+Diffing.h in Headers */,
CCCCCCE71EC3F0FC0087FE10 /* NSAttributedString+ASText.h in Headers */,
CC35CEC320DD7F600006448D /* ASCollections.h in Headers */,
CC7AF196200D9BD500A21BDE /* ASExperimentalFeatures.h in Headers */,
CCCCCCDF1EC3EF060087FE10 /* ASTextRunDelegate.h in Headers */,
9C49C3701B853961000B0DD5 /* ASStackLayoutElement.h in Headers */,
Expand Down Expand Up @@ -2304,6 +2314,7 @@
1A6C00111FAB4EDD00D05926 /* ASCornerLayoutSpecSnapshotTests.mm in Sources */,
254C6B541BF8FF2A003EC431 /* ASTextKitTests.mm in Sources */,
05EA6FE71AC0966E00E35788 /* ASSnapshotTestCase.m in Sources */,
CC35CEC620DD87280006448D /* ASCollectionsTests.m in Sources */,
ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */,
E52AC9C01FEA916C00AA4040 /* ASRectMapTests.m in Sources */,
CCE4F9BA1F0DBB5000062E4E /* ASLayoutTestNode.mm in Sources */,
Expand Down Expand Up @@ -2448,6 +2459,7 @@
CCA282B51E9EA7310037E8B7 /* ASTipsController.m in Sources */,
B35062271B010EFD0018CF92 /* ASRangeController.mm in Sources */,
0442850A1BAA63FE00D16268 /* ASBatchFetching.m in Sources */,
CC35CEC420DD7F600006448D /* ASCollections.m in Sources */,
68FC85E61CE29B9400EDD713 /* ASNavigationController.m in Sources */,
CC4C2A791D88E3BF0039ACAB /* ASTraceEvent.m in Sources */,
34EFC76F1B701CF700AD841F /* ASRatioLayoutSpec.mm in Sources */,
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Clean up C-function `extern` decorators. [Adlai Holler](https://github.com/Adlai-Holler)
- Add an experiment to reduce work involved in collection teardown. [Adlai Holler](https://github.com/Adlai-Holler)
- Optimize layout flattening, particularly reducing retain/release operations. [Adlai Holler](https://github.com/Adlai-Holler)
- Create a method to transfer strong C-arrays into immutable NSArrays, reducing retain/release traffic. [Adlai Holler](https://github.com/Adlai-Holler)

## 2.7
- Fix pager node for interface coalescing. [Max Wang](https://github.com/wsdwsd0829) [#877](https://github.com/TextureGroup/Texture/pull/877)
Expand Down
23 changes: 3 additions & 20 deletions Source/ASCollectionView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#import <AsyncDisplayKit/ASCollectionInternal.h>
#import <AsyncDisplayKit/ASCollectionLayout.h>
#import <AsyncDisplayKit/ASCollectionNode+Beta.h>
#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/ASCollectionViewLayoutController.h>
#import <AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h>
#import <AsyncDisplayKit/ASCollectionViewFlowLayoutInspector.h>
Expand Down Expand Up @@ -751,19 +752,7 @@ - (NSIndexPath *)convertIndexPathToCollectionNode:(NSIndexPath *)indexPath

- (NSArray<NSIndexPath *> *)convertIndexPathsToCollectionNode:(NSArray<NSIndexPath *> *)indexPaths
{
if (indexPaths == nil) {
return nil;
}

NSMutableArray<NSIndexPath *> *indexPathsArray = [NSMutableArray arrayWithCapacity:indexPaths.count];

for (NSIndexPath *indexPathInView in indexPaths) {
NSIndexPath *indexPath = [self convertIndexPathToCollectionNode:indexPathInView];
if (indexPath != nil) {
[indexPathsArray addObject:indexPath];
}
}
return indexPathsArray;
return ASArrayByFlatMapping(indexPaths, NSIndexPath *viewIndexPath, [self convertIndexPathToCollectionNode:viewIndexPath]);
}

- (ASCellNode *)supplementaryNodeForElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
Expand Down Expand Up @@ -2225,13 +2214,7 @@ - (void)nodesDidRelayout:(NSArray<ASCellNode *> *)nodes
return;
}

NSMutableArray<NSIndexPath *> *uikitIndexPaths = [NSMutableArray arrayWithCapacity:nodes.count];
for (ASCellNode *node in nodes) {
NSIndexPath *uikitIndexPath = [self indexPathForNode:node];
if (uikitIndexPath != nil) {
[uikitIndexPaths addObject:uikitIndexPath];
}
}
auto uikitIndexPaths = ASArrayByFlatMapping(nodes, ASCellNode *node, [self indexPathForNode:node]);

[_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:uikitIndexPaths batched:NO];

Expand Down
42 changes: 42 additions & 0 deletions Source/ASCollections.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// ASCollections.h
// Texture
//
// Copyright (c) 2018-present, Pinterest, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSArray<__covariant ObjectType> (ASCollections)

/**
* Create an immutable NSArray from a C-array of strong pointers.
*
* Note: The memory for the array you pass in will be zero'd (to prevent ARC from releasing
* the references when the array goes out of scope.)
*
* Can be combined with vector like:
* vector<NSString *> vec;
* vec.push_back(@"foo");
* vec.push_back(@"bar");
* NSArray *arr = [NSArray arrayTransferring:vec.data() count:vec.size()]
* ** vec is now { nil, nil } **
*
* Unfortunately making a convenience method to do this is currently impossible because
* vector<NSString *> can't be converted to vector<id> by the compiler (silly).
*
* See the private __CFArrayCreateTransfer function.
*/
+ (NSArray<ObjectType> *)arrayByTransferring:(ObjectType _Nonnull __strong * _Nonnull)pointers
count:(NSUInteger)count NS_RETURNS_RETAINED;

@end

NS_ASSUME_NONNULL_END
65 changes: 65 additions & 0 deletions Source/ASCollections.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//
// ASCollections.m
// Texture
//
// Copyright (c) 2018-present, Pinterest, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//

#import "ASCollections.h"

/**
* A private allocator that signals to our retain callback to skip the retain.
* It behaves the same as the default allocator, but acts as a signal that we
* are creating a transfer array so we should skip the retain.
*/
static CFAllocatorRef gTransferAllocator;

static const void *ASTransferRetain(CFAllocatorRef allocator, const void *val) {
if (allocator == gTransferAllocator) {
// Transfer allocator. Ignore retain and pass through.
return val;
} else {
// Other allocator. Retain like normal.
// This happens when they make a mutable copy.
return (&kCFTypeArrayCallBacks)->retain(allocator, val);
}
}

@implementation NSArray (ASCollections)

+ (NSArray *)arrayByTransferring:(__strong id *)pointers count:(NSUInteger)count NS_RETURNS_RETAINED
{
// Custom callbacks that point to our ASTransferRetain callback.
static CFArrayCallBacks callbacks;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
callbacks = kCFTypeArrayCallBacks;
callbacks.retain = ASTransferRetain;
CFAllocatorContext ctx;
CFAllocatorGetContext(NULL, &ctx);
gTransferAllocator = CFAllocatorCreate(NULL, &ctx);
});

// NSZeroArray fast path.
if (count == 0) {
return @[]; // Does not actually call +array when optimized.
}

// NSSingleObjectArray fast path. Retain/release here is worth it.
if (count == 1) {
NSArray *result = [[NSArray alloc] initWithObjects:pointers count:1];
pointers[0] = nil;
return result;
}

NSArray *result = (__bridge_transfer NSArray *)CFArrayCreate(gTransferAllocator, (void *)pointers, count, &callbacks);
memset(pointers, 0, count * sizeof(id));
return result;
}

@end
2 changes: 2 additions & 0 deletions Source/ASExperimentalFeatures.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

#import <AsyncDisplayKit/ASExperimentalFeatures.h>

#import <AsyncDisplayKit/ASCollections.h>

NSArray<NSString *> *ASExperimentalFeaturesGetNames(ASExperimentalFeatures flags)
{
NSArray *allNames = ASCreateOnce((@[@"exp_graphics_contexts",
Expand Down
1 change: 1 addition & 0 deletions Source/ASTableView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#import <AsyncDisplayKit/ASBatchFetching.h>
#import <AsyncDisplayKit/ASCellNode+Internal.h>
#import <AsyncDisplayKit/ASCollectionElement.h>
#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/ASConfigurationInternal.h>
#import <AsyncDisplayKit/ASDelegateProxy.h>
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
Expand Down
1 change: 1 addition & 0 deletions Source/AsyncDisplayKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
#import <AsyncDisplayKit/_ASAsyncTransaction.h>
#import <AsyncDisplayKit/_ASAsyncTransactionGroup.h>
#import <AsyncDisplayKit/_ASAsyncTransactionContainer.h>
#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/_ASDisplayLayer.h>
#import <AsyncDisplayKit/_ASDisplayView.h>
#import <AsyncDisplayKit/ASDisplayNode+Beta.h>
Expand Down
19 changes: 12 additions & 7 deletions Source/Base/ASBaseDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,13 +214,18 @@
/**
* Create a new array by mapping `collection` over `work`, ignoring nil.
*/
#define ASArrayByFlatMapping(collection, decl, work) ({ \
NSMutableArray *a = [[NSMutableArray alloc] init]; \
for (decl in collection) {\
id result = work; \
if (result != nil) { \
[a addObject:result]; \
#define ASArrayByFlatMapping(collectionArg, decl, work) ({ \
id __collection = collectionArg; \
NSArray *__result; \
if (__collection) { \
id __buf[[__collection count]]; \
NSUInteger __i = 0; \
for (decl in __collection) {\
if ((__buf[__i] = work)) { \
__i++; \
} \
} \
__result = [NSArray arrayByTransferring:__buf count:__i]; \
} \
a; \
__result; \
})
1 change: 1 addition & 0 deletions Source/Details/ASCollectionFlowLayoutDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#import <AsyncDisplayKit/ASCollectionElement.h>
#import <AsyncDisplayKit/ASCollectionLayoutContext.h>
#import <AsyncDisplayKit/ASCollectionLayoutDefines.h>
#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/ASElementMap.h>
#import <AsyncDisplayKit/ASLayout.h>
#import <AsyncDisplayKit/ASStackLayoutSpec.h>
Expand Down
7 changes: 4 additions & 3 deletions Source/Details/ASCollectionGalleryLayoutDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#import <AsyncDisplayKit/ASAssert.h>
#import <AsyncDisplayKit/ASCellNode.h>
#import <AsyncDisplayKit/ASCollectionElement.h>
#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/ASCollectionLayoutContext.h>
#import <AsyncDisplayKit/ASCollectionLayoutDefines.h>
#import <AsyncDisplayKit/ASCollectionLayoutState.h>
Expand Down Expand Up @@ -102,9 +103,9 @@ + (ASCollectionLayoutState *)calculateLayoutWithContext:(ASCollectionLayoutConte
return [[ASCollectionLayoutState alloc] initWithContext:context];
}

NSMutableArray<_ASGalleryLayoutItem *> *children = ASArrayByFlatMapping(elements.itemElements,
ASCollectionElement *element,
[[_ASGalleryLayoutItem alloc] initWithItemSize:itemSize collectionElement:element]);
NSArray<_ASGalleryLayoutItem *> *children = ASArrayByFlatMapping(elements.itemElements,
ASCollectionElement *element,
[[_ASGalleryLayoutItem alloc] initWithItemSize:itemSize collectionElement:element]);
if (children.count == 0) {
return [[ASCollectionLayoutState alloc] initWithContext:context];
}
Expand Down
12 changes: 8 additions & 4 deletions Source/Layout/ASLayout.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#import <queue>

#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/ASDimension.h>
#import <AsyncDisplayKit/ASLayoutSpecUtilities.h>
#import <AsyncDisplayKit/ASLayoutSpec+Subclasses.h>
Expand Down Expand Up @@ -236,7 +237,7 @@ - (ASLayout *)filteredNodeLayoutTree NS_RETURNS_RETAINED
queue.push_back({sublayout, sublayout.position});
}

auto flattenedSublayouts = [[NSMutableArray<ASLayout *> alloc] init];
std::vector<ASLayout *> flattenedSublayouts;

while (!queue.empty()) {
const Context context = std::move(queue.front());
Expand All @@ -254,9 +255,9 @@ - (ASLayout *)filteredNodeLayoutTree NS_RETURNS_RETAINED
size:layout.size
position:absolutePosition
sublayouts:@[]];
[flattenedSublayouts addObject:newLayout];
flattenedSublayouts.push_back(newLayout);
} else {
[flattenedSublayouts addObject:layout];
flattenedSublayouts.push_back(layout);
}
} else if (sublayoutsCount > 0) {
// Fast-reverse-enumerate the sublayouts array by copying it into a C-array and push_front'ing each into the queue.
Expand All @@ -268,7 +269,10 @@ - (ASLayout *)filteredNodeLayoutTree NS_RETURNS_RETAINED
}
}

ASLayout *layout = [ASLayout layoutWithLayoutElement:_layoutElement size:_size sublayouts:flattenedSublayouts];
NSArray *array = [NSArray arrayByTransferring:flattenedSublayouts.data() count:flattenedSublayouts.size()];
// flattenedSublayouts is now all nils.

ASLayout *layout = [ASLayout layoutWithLayoutElement:_layoutElement size:_size sublayouts:array];
// All flattened layouts must have this flag enabled
// to ensure sublayout elements are retained until the layouts are applied.
layout.retainSublayoutLayoutElements = YES;
Expand Down
1 change: 1 addition & 0 deletions Source/Layout/ASLayoutSpec.mm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#import <AsyncDisplayKit/ASLayoutSpec+Subclasses.h>

#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/ASLayoutElementStylePrivate.h>
#import <AsyncDisplayKit/ASTraitCollection.h>
#import <AsyncDisplayKit/ASEqualityHelpers.h>
Expand Down
1 change: 1 addition & 0 deletions Source/Private/_ASHierarchyChangeSet.mm
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#import <AsyncDisplayKit/_ASHierarchyChangeSet.h>
#import <AsyncDisplayKit/ASInternalHelpers.h>
#import <AsyncDisplayKit/ASCollections.h>
#import <AsyncDisplayKit/NSIndexSet+ASHelpers.h>
#import <AsyncDisplayKit/ASAssert.h>
#import <AsyncDisplayKit/ASDisplayNode+Beta.h>
Expand Down
Loading

0 comments on commit c9050c1

Please sign in to comment.