-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce ASIntegerMap, improve our changeset handling
Rename to ASIntegerMap License header
- Loading branch information
Adlai Holler
committed
Jul 5, 2017
1 parent
4a1aea2
commit 1f994f2
Showing
8 changed files
with
375 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// | ||
// ASIntegerMap.h | ||
// Texture | ||
// | ||
// Copyright (c) 2017-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> | ||
#import <AsyncDisplayKit/ASBaseDefines.h> | ||
|
||
NS_ASSUME_NONNULL_BEGIN | ||
|
||
/** | ||
* An objective-C wrapper for unordered_map. | ||
*/ | ||
AS_SUBCLASSING_RESTRICTED | ||
@interface ASIntegerMap : NSObject <NSCopying> | ||
|
||
/** | ||
* Creates an map based on the specified update to an array. | ||
* | ||
* If oldCount is 0, returns the empty map. | ||
* If deleted and inserted are empty, returns the identity map. | ||
*/ | ||
+ (ASIntegerMap *)mapForUpdateWithOldCount:(NSInteger)oldCount | ||
deleted:(NSIndexSet *)deleted | ||
inserted:(NSIndexSet *)inserted; | ||
|
||
/** | ||
* A singleton that maps each integer to itself. Its inverse is itself. | ||
*/ | ||
@property (class, atomic, readonly) ASIntegerMap *identityMap; | ||
|
||
/** | ||
* A singleton that returns NSNotFound for all keys. Its inverse is itself. | ||
*/ | ||
@property (class, atomic, readonly) ASIntegerMap *emptyMap; | ||
|
||
/** | ||
* Retrieves the integer for a given key, or NSNotFound if the key is not found. | ||
* | ||
* @param key A key to lookup the value for. | ||
*/ | ||
- (NSInteger)integerForKey:(NSInteger)key; | ||
|
||
/** | ||
* Create and return a map with the inverse mapping. | ||
*/ | ||
- (ASIntegerMap *)inverseMap; | ||
|
||
@end | ||
|
||
NS_ASSUME_NONNULL_END |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
// | ||
// ASIntegerMap.mm | ||
// Texture | ||
// | ||
// Copyright (c) 2017-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 "ASIntegerMap.h" | ||
#import <unordered_map> | ||
#import <NSIndexSet+ASHelpers.h> | ||
#import <AsyncDisplayKit/ASObjectDescriptionHelpers.h> | ||
|
||
/** | ||
* This is just a friendly Objective-C interface to unordered_map<NSInteger, NSInteger> | ||
*/ | ||
@interface ASIntegerMap () <ASDescriptionProvider> | ||
@end | ||
|
||
@implementation ASIntegerMap { | ||
std::unordered_map<NSInteger, NSInteger> _map; | ||
BOOL _isIdentity; | ||
BOOL _isEmpty; | ||
} | ||
|
||
#pragma mark - Singleton | ||
|
||
+ (ASIntegerMap *)identityMap | ||
{ | ||
static ASIntegerMap *identityMap; | ||
static dispatch_once_t onceToken; | ||
dispatch_once(&onceToken, ^{ | ||
identityMap = [[ASIntegerMap alloc] init]; | ||
identityMap->_isIdentity = YES; | ||
}); | ||
return identityMap; | ||
} | ||
|
||
+ (ASIntegerMap *)emptyMap | ||
{ | ||
static ASIntegerMap *emptyMap; | ||
static dispatch_once_t onceToken; | ||
dispatch_once(&onceToken, ^{ | ||
emptyMap = [[ASIntegerMap alloc] init]; | ||
emptyMap->_isEmpty = YES; | ||
}); | ||
return emptyMap; | ||
} | ||
|
||
+ (ASIntegerMap *)mapForUpdateWithOldCount:(NSInteger)oldCount deleted:(NSIndexSet *)deletions inserted:(NSIndexSet *)insertions | ||
{ | ||
if (oldCount == 0) { | ||
return ASIntegerMap.emptyMap; | ||
} | ||
|
||
if (deletions.count == 0 && insertions.count == 0) { | ||
return ASIntegerMap.identityMap; | ||
} | ||
|
||
ASIntegerMap *result = [[ASIntegerMap alloc] init]; | ||
// Start with the old indexes | ||
NSMutableIndexSet *indexes = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(0, oldCount)]; | ||
|
||
// Descending order, shift deleted ranges left | ||
[deletions enumerateRangesWithOptions:NSEnumerationReverse usingBlock:^(NSRange range, BOOL * _Nonnull stop) { | ||
[indexes shiftIndexesStartingAtIndex:NSMaxRange(range) by:-range.length]; | ||
}]; | ||
|
||
// Ascending order, shift inserted ranges right | ||
[insertions enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) { | ||
[indexes shiftIndexesStartingAtIndex:range.location by:range.length]; | ||
}]; | ||
|
||
__block NSInteger oldIndex = 0; | ||
[indexes enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) { | ||
// Note we advance oldIndex unconditionally, not newIndex | ||
for (NSInteger newIndex = range.location; newIndex < NSMaxRange(range); oldIndex++) { | ||
if ([deletions containsIndex:oldIndex]) { | ||
// index was deleted, do nothing, just let oldIndex advance. | ||
} else { | ||
// assign the next index for this item. | ||
result->_map[oldIndex] = newIndex++; | ||
} | ||
} | ||
}]; | ||
return result; | ||
} | ||
|
||
- (NSInteger)integerForKey:(NSInteger)key | ||
{ | ||
if (_isIdentity) { | ||
return key; | ||
} else if (_isEmpty) { | ||
return NSNotFound; | ||
} | ||
|
||
auto result = _map.find(key); | ||
return result != _map.end() ? result->second : NSNotFound; | ||
} | ||
|
||
- (ASIntegerMap *)inverseMap | ||
{ | ||
if (_isIdentity || _isEmpty) { | ||
return self; | ||
} | ||
|
||
auto result = [[ASIntegerMap alloc] init]; | ||
for (auto it = _map.begin(); it != _map.end(); it++) { | ||
result->_map[it->second] = it->first; | ||
} | ||
return result; | ||
} | ||
|
||
#pragma mark - NSCopying | ||
|
||
- (id)copyWithZone:(NSZone *)zone | ||
{ | ||
return self; | ||
} | ||
|
||
#pragma mark - Description | ||
|
||
- (NSMutableArray<NSDictionary *> *)propertiesForDescription | ||
{ | ||
NSMutableArray *result = [NSMutableArray array]; | ||
|
||
if (_isIdentity) { | ||
[result addObject:@{ @"map": @"<identity>" }]; | ||
} else if (_isEmpty) { | ||
[result addObject:@{ @"map": @"<empty>" }]; | ||
} else { | ||
// { 1->2 3->4 5->6 } | ||
NSMutableString *str = [NSMutableString string]; | ||
for (auto it = _map.begin(); it != _map.end(); it++) { | ||
[str appendFormat:@" %zd->%zd", it->first, it->second]; | ||
} | ||
// Remove leading space | ||
if (str.length > 0) { | ||
[str deleteCharactersInRange:NSMakeRange(0, 1)]; | ||
} | ||
[result addObject:@{ @"map": str }]; | ||
} | ||
|
||
return result; | ||
} | ||
|
||
- (NSString *)description | ||
{ | ||
return ASObjectDescriptionMakeWithoutObject([self propertiesForDescription]); | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.