Upgrade ASLayoutElementContext to an Object #trivial (#344)

* Upgrade ASLayoutElementContext to an object

* Address feedback from Huy
This commit is contained in:
Adlai Holler 2017-06-10 00:25:39 -05:00 committed by GitHub
parent 05e9bdd092
commit c9e4b98a55
3 changed files with 53 additions and 59 deletions

View File

@ -317,10 +317,10 @@ ASPrimitiveTraitCollectionDeprecatedImplementation
[self cancelLayoutTransition]; [self cancelLayoutTransition];
BOOL didCreateNewContext = NO; BOOL didCreateNewContext = NO;
ASLayoutElementContext context = ASLayoutElementGetCurrentContext(); ASLayoutElementContext *context = ASLayoutElementGetCurrentContext();
if (ASLayoutElementContextIsNull(context)) { if (context == nil) {
context = ASLayoutElementContextMake(ASLayoutElementContextDefaultTransitionID); context = [[ASLayoutElementContext alloc] init];
ASLayoutElementSetCurrentContext(context); ASLayoutElementPushContext(context);
didCreateNewContext = YES; didCreateNewContext = YES;
} }
@ -341,7 +341,7 @@ ASPrimitiveTraitCollectionDeprecatedImplementation
} }
if (didCreateNewContext) { if (didCreateNewContext) {
ASLayoutElementClearCurrentContext(); ASLayoutElementPopContext();
} }
// If our new layout's desired size for self doesn't match current size, ask our parent to update it. // If our new layout's desired size for self doesn't match current size, ask our parent to update it.
@ -457,8 +457,8 @@ ASPrimitiveTraitCollectionDeprecatedImplementation
{ {
ASDN::MutexLocker l(__instanceLock__); ASDN::MutexLocker l(__instanceLock__);
if (ASHierarchyStateIncludesLayoutPending(_hierarchyState)) { if (ASHierarchyStateIncludesLayoutPending(_hierarchyState)) {
ASLayoutElementContext context = ASLayoutElementGetCurrentContext(); ASLayoutElementContext *context = ASLayoutElementGetCurrentContext();
if (ASLayoutElementContextIsNull(context) || _pendingTransitionID != context.transitionID) { if (context == nil || _pendingTransitionID != context.transitionID) {
return YES; return YES;
} }
} }
@ -547,7 +547,9 @@ ASPrimitiveTraitCollectionDeprecatedImplementation
{ {
ASDN::MutexLocker l(__instanceLock__); ASDN::MutexLocker l(__instanceLock__);
ASLayoutElementSetCurrentContext(ASLayoutElementContextMake(transitionID)); ASLayoutElementContext *ctx = [[ASLayoutElementContext alloc] init];
ctx.transitionID = transitionID;
ASLayoutElementPushContext(ctx);
BOOL automaticallyManagesSubnodesDisabled = (self.automaticallyManagesSubnodes == NO); BOOL automaticallyManagesSubnodesDisabled = (self.automaticallyManagesSubnodes == NO);
self.automaticallyManagesSubnodes = YES; // Temporary flag for 1.9.x self.automaticallyManagesSubnodes = YES; // Temporary flag for 1.9.x
@ -558,7 +560,7 @@ ASPrimitiveTraitCollectionDeprecatedImplementation
self.automaticallyManagesSubnodes = NO; // Temporary flag for 1.9.x self.automaticallyManagesSubnodes = NO; // Temporary flag for 1.9.x
} }
ASLayoutElementClearCurrentContext(); ASLayoutElementPopContext();
} }
if (isCancelled()) { if (isCancelled()) {

View File

@ -30,69 +30,62 @@
#pragma mark - ASLayoutElementContext #pragma mark - ASLayoutElementContext
@implementation ASLayoutElementContext
- (instancetype)init
{
if (self = [super init]) {
_transitionID = ASLayoutElementContextDefaultTransitionID;
}
return self;
}
@end
CGFloat const ASLayoutElementParentDimensionUndefined = NAN; CGFloat const ASLayoutElementParentDimensionUndefined = NAN;
CGSize const ASLayoutElementParentSizeUndefined = {ASLayoutElementParentDimensionUndefined, ASLayoutElementParentDimensionUndefined}; CGSize const ASLayoutElementParentSizeUndefined = {ASLayoutElementParentDimensionUndefined, ASLayoutElementParentDimensionUndefined};
int32_t const ASLayoutElementContextInvalidTransitionID = 0; int32_t const ASLayoutElementContextInvalidTransitionID = 0;
int32_t const ASLayoutElementContextDefaultTransitionID = ASLayoutElementContextInvalidTransitionID + 1; int32_t const ASLayoutElementContextDefaultTransitionID = ASLayoutElementContextInvalidTransitionID + 1;
static inline ASLayoutElementContext _ASLayoutElementContextMake(int32_t transitionID)
{
struct ASLayoutElementContext context;
context.transitionID = transitionID;
return context;
}
static inline BOOL _IsValidTransitionID(int32_t transitionID)
{
return transitionID > ASLayoutElementContextInvalidTransitionID;
}
struct ASLayoutElementContext const ASLayoutElementContextNull = _ASLayoutElementContextMake(ASLayoutElementContextInvalidTransitionID);
BOOL ASLayoutElementContextIsNull(struct ASLayoutElementContext context)
{
return !_IsValidTransitionID(context.transitionID);
}
ASLayoutElementContext ASLayoutElementContextMake(int32_t transitionID)
{
NSCAssert(_IsValidTransitionID(transitionID), @"Invalid transition ID");
return _ASLayoutElementContextMake(transitionID);
}
pthread_key_t ASLayoutElementContextKey; pthread_key_t ASLayoutElementContextKey;
static void ASLayoutElementDestructor(void *p) {
if (p != NULL) {
ASDisplayNodeCFailAssert(@"Thread exited without clearing layout element context!");
CFBridgingRelease(p);
}
};
// pthread_key_create must be called before the key can be used. This function does that. // pthread_key_create must be called before the key can be used. This function does that.
void ASLayoutElementContextEnsureKey() void ASLayoutElementContextEnsureKey()
{ {
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
pthread_key_create(&ASLayoutElementContextKey, free); pthread_key_create(&ASLayoutElementContextKey, ASLayoutElementDestructor);
}); });
} }
void ASLayoutElementSetCurrentContext(struct ASLayoutElementContext context) void ASLayoutElementPushContext(ASLayoutElementContext *context)
{ {
ASLayoutElementContextEnsureKey(); ASLayoutElementContextEnsureKey();
ASDisplayNodeCAssert(pthread_getspecific(ASLayoutElementContextKey) == NULL, @"Nested ASLayoutElementContexts aren't supported."); // NOTE: It would be easy to support nested contexts just use an NSMutableArray here.
pthread_setspecific(ASLayoutElementContextKey, new ASLayoutElementContext(context)); ASDisplayNodeCAssertNil(ASLayoutElementGetCurrentContext(), @"Nested ASLayoutElementContexts aren't supported.");
pthread_setspecific(ASLayoutElementContextKey, CFBridgingRetain(context));
} }
struct ASLayoutElementContext ASLayoutElementGetCurrentContext() ASLayoutElementContext *ASLayoutElementGetCurrentContext()
{ {
ASLayoutElementContextEnsureKey(); ASLayoutElementContextEnsureKey();
auto heapCtx = (ASLayoutElementContext *)pthread_getspecific(ASLayoutElementContextKey); // Don't retain here. Caller will retain if it wants to!
return (heapCtx ? *heapCtx : ASLayoutElementContextNull); return (__bridge __unsafe_unretained ASLayoutElementContext *)pthread_getspecific(ASLayoutElementContextKey);
} }
void ASLayoutElementClearCurrentContext() void ASLayoutElementPopContext()
{ {
ASLayoutElementContextEnsureKey(); ASLayoutElementContextEnsureKey();
auto heapCtx = (ASLayoutElementContext *)pthread_getspecific(ASLayoutElementContextKey); ASDisplayNodeCAssertNotNil(ASLayoutElementGetCurrentContext(), @"Attempt to pop context when there wasn't a context!");
if (heapCtx != NULL) { CFBridgingRelease(pthread_getspecific(ASLayoutElementContextKey));
delete heapCtx;
}
pthread_setspecific(ASLayoutElementContextKey, NULL); pthread_setspecific(ASLayoutElementContextKey, NULL);
} }

View File

@ -23,26 +23,25 @@
#pragma mark - ASLayoutElementContext #pragma mark - ASLayoutElementContext
struct ASLayoutElementContext { NS_ASSUME_NONNULL_BEGIN
int32_t transitionID;
}; AS_SUBCLASSING_RESTRICTED
@interface ASLayoutElementContext : NSObject
@property (nonatomic) int32_t transitionID;
@end
extern int32_t const ASLayoutElementContextInvalidTransitionID; extern int32_t const ASLayoutElementContextInvalidTransitionID;
extern int32_t const ASLayoutElementContextDefaultTransitionID; extern int32_t const ASLayoutElementContextDefaultTransitionID;
extern struct ASLayoutElementContext const ASLayoutElementContextNull; // Does not currently support nesting there must be no current context.
extern void ASLayoutElementPushContext(ASLayoutElementContext * context);
extern BOOL ASLayoutElementContextIsNull(struct ASLayoutElementContext context); extern ASLayoutElementContext * _Nullable ASLayoutElementGetCurrentContext();
extern struct ASLayoutElementContext ASLayoutElementContextMake(int32_t transitionID); extern void ASLayoutElementPopContext();
extern void ASLayoutElementSetCurrentContext(struct ASLayoutElementContext context);
extern struct ASLayoutElementContext ASLayoutElementGetCurrentContext();
extern void ASLayoutElementClearCurrentContext();
NS_ASSUME_NONNULL_END
#pragma mark - ASLayoutElementLayoutDefaults #pragma mark - ASLayoutElementLayoutDefaults