mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
Fix linking
This commit is contained in:
177
submodules/AsyncDisplayKit/Source/NSArray+Diffing.mm
Normal file
177
submodules/AsyncDisplayKit/Source/NSArray+Diffing.mm
Normal file
@@ -0,0 +1,177 @@
|
||||
//
|
||||
// NSArray+Diffing.mm
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/NSArray+Diffing.h>
|
||||
#import <UIKit/NSIndexPath+UIKitAdditions.h>
|
||||
#import <AsyncDisplayKit/ASAssert.h>
|
||||
#import <unordered_map>
|
||||
|
||||
@implementation NSArray (Diffing)
|
||||
|
||||
typedef BOOL (^compareBlock)(id _Nonnull lhs, id _Nonnull rhs);
|
||||
|
||||
- (void)asdk_diffWithArray:(NSArray *)array insertions:(NSIndexSet **)insertions deletions:(NSIndexSet **)deletions
|
||||
{
|
||||
[self asdk_diffWithArray:array insertions:insertions deletions:deletions moves:nil compareBlock:[NSArray defaultCompareBlock]];
|
||||
}
|
||||
|
||||
- (void)asdk_diffWithArray:(NSArray *)array insertions:(NSIndexSet **)insertions deletions:(NSIndexSet **)deletions
|
||||
compareBlock:(compareBlock)comparison
|
||||
{
|
||||
[self asdk_diffWithArray:array insertions:insertions deletions:deletions moves:nil compareBlock:comparison];
|
||||
}
|
||||
|
||||
- (void)asdk_diffWithArray:(NSArray *)array insertions:(NSIndexSet **)insertions deletions:(NSIndexSet **)deletions
|
||||
moves:(NSArray<NSIndexPath *> **)moves
|
||||
{
|
||||
[self asdk_diffWithArray:array insertions:insertions deletions:deletions moves:moves
|
||||
compareBlock:[NSArray defaultCompareBlock]];
|
||||
}
|
||||
|
||||
- (void)asdk_diffWithArray:(NSArray *)array insertions:(NSIndexSet **)insertions deletions:(NSIndexSet **)deletions
|
||||
moves:(NSArray<NSIndexPath *> **)moves compareBlock:(compareBlock)comparison
|
||||
{
|
||||
struct NSObjectHash
|
||||
{
|
||||
std::size_t operator()(id <NSObject> k) const { return (std::size_t) [k hash]; };
|
||||
};
|
||||
struct NSObjectCompare
|
||||
{
|
||||
bool operator()(id <NSObject> lhs, id <NSObject> rhs) const { return (bool) [lhs isEqual:rhs]; };
|
||||
};
|
||||
std::unordered_multimap<unowned id, NSUInteger, NSObjectHash, NSObjectCompare> potentialMoves;
|
||||
|
||||
NSAssert(comparison != nil, @"Comparison block is required");
|
||||
NSAssert(moves == nil || comparison == [NSArray defaultCompareBlock], @"move detection requires isEqual: and hash (no custom compare)");
|
||||
NSMutableArray<NSIndexPath *> *moveIndexPaths = nil;
|
||||
NSMutableIndexSet *insertionIndexes = nil, *deletionIndexes = nil;
|
||||
if (moves) {
|
||||
moveIndexPaths = [NSMutableArray new];
|
||||
}
|
||||
NSMutableIndexSet *commonIndexes = [self _asdk_commonIndexesWithArray:array compareBlock:comparison];
|
||||
|
||||
if (deletions || moves) {
|
||||
deletionIndexes = [NSMutableIndexSet indexSet];
|
||||
NSUInteger i = 0;
|
||||
for (id element in self) {
|
||||
if (![commonIndexes containsIndex:i]) {
|
||||
[deletionIndexes addIndex:i];
|
||||
}
|
||||
if (moves) {
|
||||
potentialMoves.insert(std::pair<id, NSUInteger>(element, i));
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if (insertions || moves) {
|
||||
insertionIndexes = [NSMutableIndexSet indexSet];
|
||||
NSArray *commonObjects = [self objectsAtIndexes:commonIndexes];
|
||||
for (NSUInteger i = 0, j = 0; j < array.count; j++) {
|
||||
auto moveFound = potentialMoves.find(array[j]);
|
||||
NSUInteger movedFrom = NSNotFound;
|
||||
if (moveFound != potentialMoves.end() && moveFound->second != j) {
|
||||
movedFrom = moveFound->second;
|
||||
potentialMoves.erase(moveFound);
|
||||
[moveIndexPaths addObject:[NSIndexPath indexPathForItem:j inSection:movedFrom]];
|
||||
}
|
||||
if (i < commonObjects.count && j < array.count && comparison(commonObjects[i], array[j])) {
|
||||
i++;
|
||||
} else {
|
||||
if (movedFrom != NSNotFound) {
|
||||
// moves will coalesce a delete / insert - the insert is just not done, and here we remove the delete:
|
||||
[deletionIndexes removeIndex:movedFrom];
|
||||
// OR a move will have come from the LCS:
|
||||
if ([commonIndexes containsIndex:movedFrom]) {
|
||||
[commonIndexes removeIndex:movedFrom];
|
||||
commonObjects = [self objectsAtIndexes:commonIndexes];
|
||||
}
|
||||
} else {
|
||||
[insertionIndexes addIndex:j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (moves) {*moves = moveIndexPaths;}
|
||||
if (deletions) {*deletions = deletionIndexes;}
|
||||
if (insertions) {*insertions = insertionIndexes;}
|
||||
}
|
||||
|
||||
// https://github.com/raywenderlich/swift-algorithm-club/tree/master/Longest%20Common%20Subsequence is not exactly this code (obviously), but
|
||||
// is a good commentary on the algorithm.
|
||||
- (NSMutableIndexSet *)_asdk_commonIndexesWithArray:(NSArray *)array compareBlock:(BOOL (^)(id lhs, id rhs))comparison
|
||||
{
|
||||
NSAssert(comparison != nil, @"Comparison block is required");
|
||||
|
||||
NSInteger selfCount = self.count;
|
||||
NSInteger arrayCount = array.count;
|
||||
|
||||
// Allocate the diff map in the heap so we don't blow the stack for large arrays.
|
||||
NSInteger **lengths = NULL;
|
||||
lengths = (NSInteger **)malloc(sizeof(NSInteger*) * (selfCount+1));
|
||||
if (lengths == NULL) {
|
||||
ASDisplayNodeFailAssert(@"Failed to allocate memory for diffing");
|
||||
return nil;
|
||||
}
|
||||
// Fill in a LCS length matrix:
|
||||
for (NSInteger i = 0; i <= selfCount; i++) {
|
||||
lengths[i] = (NSInteger *)malloc(sizeof(NSInteger) * (arrayCount+1));
|
||||
if (lengths[i] == NULL) {
|
||||
ASDisplayNodeFailAssert(@"Failed to allocate memory for diffing");
|
||||
return nil;
|
||||
}
|
||||
id selfObj = i > 0 ? self[i-1] : nil;
|
||||
for (NSInteger j = 0; j <= arrayCount; j++) {
|
||||
if (i == 0 || j == 0) {
|
||||
lengths[i][j] = 0;
|
||||
} else if (comparison(selfObj, array[j-1])) {
|
||||
lengths[i][j] = 1 + lengths[i-1][j-1];
|
||||
} else {
|
||||
lengths[i][j] = MAX(lengths[i-1][j], lengths[i][j-1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Backtrack to fill in indices based on length matrix:
|
||||
NSMutableIndexSet *common = [NSMutableIndexSet indexSet];
|
||||
NSInteger i = selfCount, j = arrayCount;
|
||||
while(i > 0 && j > 0) {
|
||||
if (comparison(self[i-1], array[j-1])) {
|
||||
[common addIndex:(i-1)];
|
||||
i--; j--;
|
||||
} else if (lengths[i-1][j] > lengths[i][j-1]) {
|
||||
i--;
|
||||
} else {
|
||||
j--;
|
||||
}
|
||||
}
|
||||
|
||||
for (NSInteger i = 0; i <= selfCount; i++) {
|
||||
free(lengths[i]);
|
||||
}
|
||||
free(lengths);
|
||||
return common;
|
||||
}
|
||||
|
||||
static compareBlock defaultCompare = nil;
|
||||
|
||||
+ (compareBlock)defaultCompareBlock
|
||||
{
|
||||
static dispatch_once_t onceToken;
|
||||
|
||||
dispatch_once(&onceToken, ^{
|
||||
defaultCompare = ^BOOL(id lhs, id rhs) {
|
||||
return [lhs isEqual:rhs];
|
||||
};
|
||||
});
|
||||
|
||||
return defaultCompare;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user