Merge remote-tracking branch 'upstream/master' into CPTableViewLion

This commit is contained in:
cacaodev
2012-06-10 08:57:30 +02:00
4 changed files with 393 additions and 97 deletions
+165 -52
View File
@@ -334,7 +334,16 @@
- (void)sortUsingDescriptors:(CPArray)descriptors
{
[self sortUsingFunction:compareObjectsUsingDescriptors context:descriptors];
var i = [descriptors count],
jsDescriptors = [];
// Revert the order of the descriptors
while (i--)
{
var d = [descriptors objectAtIndex:i];
[jsDescriptors addObject:{ "k": [d key], "a": [d ascending], "s": [d selector]}];
}
sortArrayUsingJSDescriptors(self, jsDescriptors);
}
/*!
@@ -344,46 +353,7 @@
*/
- (void)sortUsingFunction:(Function)aFunction context:(id)aContext
{
var h,
i,
j,
k,
l,
m,
n = [self count],
o;
var A,
B = [];
for (h = 1; h < n; h += h)
{
for (m = n - 1 - h; m >= 0; m -= h + h)
{
l = m - h + 1;
if (l < 0)
l = 0;
for (i = 0, j = l; j <= m; i++, j++)
B[i] = self[j];
for (i = 0, k = l; k < j && j <= m + h; k++)
{
A = self[j];
o = aFunction(A, B[i], aContext);
if (o >= 0)
self[k] = B[i++];
else
{
self[k] = A;
j++;
}
}
while (k < j)
self[k++] = B[i++];
}
}
sortArrayUsingFunction(self, aFunction, aContext);
}
/*!
@@ -392,7 +362,7 @@
*/
- (void)sortUsingSelector:(SEL)aSelector
{
[self sortUsingFunction:selectorCompare context:aSelector];
sortArrayUsingFunction(self, selectorCompare, aSelector);
}
@end
@@ -408,20 +378,163 @@
@end
var selectorCompare = function selectorCompare(object1, object2, selector)
var selectorCompare = function(object1, object2, selector)
{
return [object1 performSelector:selector withObject:object2];
};
// sort using sort descriptors
var compareObjectsUsingDescriptors= function compareObjectsUsingDescriptors(lhs, rhs, descriptors)
var sortArrayUsingFunction = function(array, aFunction, aContext)
{
var result = CPOrderedSame,
i = 0,
n = [descriptors count];
var h,
i,
j,
k,
l,
m,
n = array.length,
o;
while (i < n && result === CPOrderedSame)
result = [descriptors[i++] compareObject:lhs withObject:rhs];
var A,
B = [];
return result;
};
for (h = 1; h < n; h += h)
{
for (m = n - 1 - h; m >= 0; m -= h + h)
{
l = m - h + 1;
if (l < 0)
l = 0;
for (i = 0, j = l; j <= m; i++, j++)
B[i] = array[j];
for (i = 0, k = l; k < j && j <= m + h; k++)
{
A = array[j];
o = aFunction(A, B[i], aContext);
if (o >= 0)
array[k] = B[i++];
else
{
array[k] = A;
j++;
}
}
while (k < j)
array[k++] = B[i++];
}
}
}
// Observe that the sort descriptors has the reversed order by the caller
var sortArrayUsingJSDescriptors = function(a, d)
{
var h,
i,
j,
k,
l,
m,
n = a.length,
dl = d.length - 1,
o,
c = {};
var A,
B = [],
C1,
C2,
cn,
aUID,
bUID,
key,
dd;
if (dl < 0)
return;
for (h = 1; h < n; h += h)
{
for (m = n - 1 - h; m >= 0; m -= h + h)
{
l = m - h + 1;
if (l < 0)
l = 0;
for (i = 0, j = l; j <= m; i++, j++)
B[i] = a[j];
for (i = 0, k = l; k < j && j <= m + h; k++)
{
A = a[j];
aUID = A._UID;
if (!aUID)
aUID = [A UID];
C1 = c[aUID];
if (!C1)
{
C1 = {};
cn = dl;
do
{
key = d[cn].k;
C1[key] = [A valueForKey:key];
} while (cn--)
c[aUID] = C1;
}
bUID = B[i]._UID;
if (!bUID)
bUID = [B[i] UID];
C2 = c[bUID];
if (!C2)
{
C2 = {};
cn = dl;
do
{
key = d[cn].k;
C2[key] = [B[i] valueForKey:key];
} while (cn--)
c[bUID] = C2;
}
cn = dl;
do
{
dd = d[cn];
key = dd.k;
o = objj_msgSend(C1[key], dd.s, C2[key]);
if (o && !dd.a)
o = -o;
} while (cn-- && o == CPOrderedSame)
if (o >= 0)
a[k] = B[i++];
else
{
a[k] = A;
j++;
}
}
while (k < j)
a[k++] = B[i++];
}
}
}
+213 -45
View File
@@ -1,72 +1,136 @@
var FILE = require("file");
@import <Foundation/CPArray.j>
@import <Foundation/CPString.j>
@import <Foundation/CPNumber.j>
@import <Foundation/CPSortDescriptor.j>
var ELEMENTS = 100,
REPEATS = 10;
@implementation CPArrayPerformanceTest : OJTestCase
- (void)testSortUsingDescriptorsSpeed
{
var array = [self makeUnsorted];
var descriptors = [
[CPSortDescriptor sortDescriptorWithKey:"a" ascending:NO],
[CPSortDescriptor sortDescriptorWithKey:"b" ascending:YES]
];
var start = (new Date).getTime();
for (var i = 0; i < REPEATS; ++i)
{
var sorted = [array sortedArrayUsingDescriptors:descriptors];
[self checkSorted:sorted];
}
var end = (new Date).getTime();
CPLog.warn(_cmd + ": " + (end - start) + "ms");
CPArray descriptors;
}
- (void)testSortUsingNativeSort
- (void)setUp
{
var array = [self makeUnsorted];
var descriptors = [
[CPSortDescriptor sortDescriptorWithKey:"a" ascending:NO],
[CPSortDescriptor sortDescriptorWithKey:"b" ascending:YES]
];
[CPSortDescriptor sortDescriptorWithKey:"a" ascending:NO],
[CPSortDescriptor sortDescriptorWithKey:"b" ascending:YES]
];
}
function sortFunction(lhs, rhs)
{
return ([lhs a] === [rhs a]) ? ([lhs b] - [rhs b]) : ([rhs a] - [lhs a]);
}
- (void)testAlmostSortedNumericUsingMergeSort
{
CPLog.warn("\nNUMERIC ALMOST SORTED");
var a = [self makeUnsorted],
sorted = [self sort:a usingSortSelector:@selector(sortedArrayUsingDescriptors:) withObject:descriptors];
[self checkAlmostSorted:sorted];
}
var start = (new Date).getTime();
- (void)testAlmostSortedNumericUsingNativeSort
{
var a = [self makeUnsorted],
sorted = [self sort:a usingSortSelector:@selector(_native_sortedArrayUsingDescriptors:) withObject:descriptors];
[self checkAlmostSorted:sorted];
}
- (void)testRandomNumericUsingMergeSort
{
CPLog.warn("\nNUMERIC RANDOM");
var a = [self makeRandomNumeric],
sorted = [self sort:a usingSortSelector:@selector(sortedArrayUsingDescriptors:) withObject:descriptors];
[self checkRandomSorted:sorted];
}
- (void)testRandomNumericUsingNativeSort
{
var a = [self makeRandomNumeric],
sorted = [self sort:a usingSortSelector:@selector(_native_sortedArrayUsingDescriptors:) withObject:descriptors];
[self checkRandomSorted:sorted];
}
- (void)testRandomTextUsingMergeSort
{
CPLog.warn("\nTEXT RANDOM");
var a = [self makeRandomText],
sorted = [self sort:a usingSortSelector:@selector(sortedArrayUsingDescriptors:) withObject:descriptors];
[self checkRandomSorted:sorted];
}
- (void)testRandomTextUsingNativeSort
{
var a = [self makeRandomText],
sorted = [self sort:a usingSortSelector:@selector(_native_sortedArrayUsingDescriptors:) withObject:descriptors];
[self checkRandomSorted:sorted];
}
- (void)testAlmostSortedNumericUsingMergeSelectorSort
{
CPLog.warn("\nNUMERIC ALMOST SORTED (SELECTOR)");
var a = [self makeUnsorted],
sorted = [self sort:a usingSortSelector:@selector(sortedArrayUsingSelector:) withObject:@selector(compareAAscendingThenBDescending:)];
[self checkAlmostSorted:sorted];
}
- (void)testAlmostSortedNumericUsingNativeSelectorSort
{
var a = [self makeUnsorted],
sorted = [self sort:a usingSortSelector:@selector(_native_sortedArrayUsingSelector:) withObject:@selector(compareAAscendingThenBDescending:)];
[self checkAlmostSorted:sorted];
}
- (void)testRandomNumericUsingMergeSelectorSort
{
CPLog.warn("\nNUMERIC RANDOM (SELECTOR)");
var a = [self makeRandomNumeric],
sorted = [self sort:a usingSortSelector:@selector(sortedArrayUsingSelector:) withObject:@selector(compareAAscendingThenBDescending:)];
[self checkRandomSorted:sorted];
}
- (void)testRandomNumericUsingNativeSelectorSort
{
var a = [self makeRandomNumeric],
sorted = [self sort:a usingSortSelector:@selector(_native_sortedArrayUsingSelector:) withObject:@selector(compareAAscendingThenBDescending:)];
[self checkRandomSorted:sorted];
}
- (void)testRandomTextUsingMergeSelectorSort
{
CPLog.warn("\nTEXT RANDOM (SELECTOR)");
var a = [self makeRandomText],
sorted = [self sort:a usingSortSelector:@selector(sortedArrayUsingSelector:) withObject:@selector(compareAAscendingThenBDescending:)];
[self checkRandomSorted:sorted];
}
- (void)testRandomTextUsingNativeSelectorSort
{
var a = [self makeRandomText],
sorted = [self sort:a usingSortSelector:@selector(_native_sortedArrayUsingSelector:) withObject:@selector(compareAAscendingThenBDescending:)];
[self checkRandomSorted:sorted];
}
- (CPArray)sort:(CPArray)anArray usingSortSelector:(SEL)aSelector withObject:(id)anObject
{
var sorted,
start = (new Date).getTime();
for (var i = 0; i < REPEATS; ++i)
{
var sorted = [array copy];
sorted.sort(sortFunction)
[self checkSorted:sorted];
}
sorted = [anArray performSelector:aSelector withObject:anObject];
var end = (new Date).getTime();
CPLog.warn(_cmd+": " + (end - start) + "ms");
CPLog.warn(aSelector + ": " + (end - start) + "ms");
return sorted;
}
- (CPArray)makeUnsorted
{
var array = [];
for (var i=0; i < ELEMENTS; ++i)
for (var i = 0; i < ELEMENTS; ++i)
{
var s = [Sortable new];
@@ -79,12 +143,49 @@ var ELEMENTS = 100,
return array;
}
- (void)checkSorted:(CPArray)sorted
- (CPArray)makeRandomNumeric
{
var array = [];
for (var i = 0; i < ELEMENTS; i++)
{
var s = [Sortable new],
n1 = ROUND(RAND() * ELEMENTS),
n2 = ROUND(RAND() * ELEMENTS);
[s setA:n1];
[s setB:n2];
array.push(s);
}
return array;
}
- (CPArray)makeRandomText
{
var the_big_sort = FILE.read(FILE.join(FILE.dirname(module.path), "the_big_sort.txt"), { charset:"UTF-8" }),
words = the_big_sort.split(" ", ELEMENTS),
wordcount = words.length,
array = [];
for (var i = 0; i < wordcount - 1; i++)
{
var s = [Sortable new];
[s setA:words[i]];
[s setB:words[i + 1]];
array.push(s);
}
return array;
}
- (void)checkAlmostSorted:(CPArray)sorted
{
// Verify it really got sorted.
for (var j=0; j < ELEMENTS; ++j)
for (var j = 0; j < sorted.length; ++j)
{
var expectedA = 4-FLOOR(j * 5 / ELEMENTS);
var expectedA = 4 - FLOOR(j * 5 / ELEMENTS);
if (sorted[j].a != expectedA)
[self fail:"a out of order: " + expectedA + " != " + sorted[j].a];
@@ -96,6 +197,66 @@ var ELEMENTS = 100,
}
}
- (void)checkRandomSorted:(CPArray)sorted
{
// Verify that it really got sorted.
for (var j = 0; j < sorted.length - 1; ++j)
{
if ([sorted[j].a compare:sorted[j + 1].a] == CPOrderedAscending)
[self fail:"a out of order: " + sorted[j].a + " > " + sorted[j + 1].a];
if ([sorted[j].a compare:sorted[j + 1].a] == CPOrderedSame && [sorted[j].b compare: sorted[j + 1].b] == CPOrderedDescending)
[self fail:"b out of order: " + sorted[j].b + " < " + sorted[j + 1].b];
}
}
@end
@implementation CPArray (NativeSort)
- (CPArray)_native_sortedArrayUsingDescriptors:(CPArray)descriptors
{
var sorted = [self copy];
[sorted _native_sortUsingDescriptors:descriptors];
return sorted;
}
- (CPArray)_native_sortUsingDescriptors:(CPArray)descriptors
{
var count = [descriptors count];
sort(function(lhs, rhs)
{
var i = 0,
result = CPOrderedSame;
while (i < count)
if ((result = [descriptors[i++] compareObject:lhs withObject:rhs]) !== CPOrderedSame)
return result;
return result;
});
}
- (CPArray)_native_sortedArrayUsingSelector:(SEL)aSelector
{
var sorted = [self copy];
[sorted _native_sortUsingSelector:aSelector];
return sorted;
}
- (CPArray)_native_sortUsingSelector:(SEL)aSelector
{
sort(function(lhs, rhs)
{
return [lhs performSelector:aSelector withObject:rhs];
});
}
@end
@implementation Sortable : CPObject
@@ -104,4 +265,11 @@ var ELEMENTS = 100,
int b @accessors;
}
- (int)compareAAscendingThenBDescending:(Sortable)other
{
var aResult = [a compare:other.a];
return aResult === CPOrderedSame ? [b compare:other.b] : -aResult;
}
@end
+14
View File
@@ -539,6 +539,20 @@
[self assertTrue:d.indexOf("y: 6") !== -1 message:"Can't find 'y: 6' in description of array " + d];
}
- (void)testSortUsingDescriptorsWithDifferentSelectors
{
var a = [CPDictionary dictionaryWithJSObject:{"a": "AB", "b": "ba"}],
b = [CPDictionary dictionaryWithJSObject:{"a": "aa", "b": "BB"}],
array = [a, b],
d1 = [[CPSortDescriptor sortDescriptorWithKey:@"a" ascending:YES selector:@selector(compare:)]],
d2 = [[CPSortDescriptor sortDescriptorWithKey:@"a" ascending:YES selector:@selector(caseInsensitiveCompare:)]],
s1 = [array sortedArrayUsingDescriptors:d1],
s2 = [array sortedArrayUsingDescriptors:d2];
[self assertTrue:s1[0] === a message:s1[0] + " is larger then " + a + " when sorting case sensitive"];
[self assertTrue:s2[1] === a message:s2[1] + " is larger then " + a + " when sorting case insensitive"];
}
@end
@implementation AlwaysEqual : CPObject
File diff suppressed because one or more lines are too long