Skip to content

Commit

Permalink
Merge pull request #1560 from mrcarlberg/cappuccino
Browse files Browse the repository at this point in the history
---

I needed to sort a lot of objects and was not impressed by the speed.
Sharing my improvements...
  • Loading branch information
aljungberg committed Jun 10, 2012
2 parents fcf6208 + 0696b22 commit e232b18
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 35 deletions.
196 changes: 161 additions & 35 deletions Foundation/CPArray/CPMutableArray.j
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/*!
Expand All @@ -343,14 +352,46 @@
@param aContext an object that will be passed to \c aFunction with comparison
*/
- (void)sortUsingFunction:(Function)aFunction context:(id)aContext
{
sortArrayUsingFunction(self, aFunction, aContext);
}

/*!
Sorts the receiver array using an Objective-J method as a comparator.
@param aSelector the selector for the method to call for comparison
*/
- (void)sortUsingSelector:(SEL)aSelector
{
sortArrayUsingFunction(self, selectorCompare, aSelector);
}

@end

@implementation CPArray (CPMutableCopying)

- (id)mutableCopy
{
var r = [CPMutableArray new];
[r addObjectsFromArray:self];
return r;
}

@end

var selectorCompare = function(object1, object2, selector)
{
return [object1 performSelector:selector withObject:object2];
};

var sortArrayUsingFunction = function(array, aFunction, aContext)
{
var h,
i,
j,
k,
l,
m,
n = [self count],
n = array.length,
o;

var A,
Expand All @@ -365,56 +406,30 @@
l = 0;

for (i = 0, j = l; j <= m; i++, j++)
B[i] = self[j];
B[i] = array[j];

for (i = 0, k = l; k < j && j <= m + h; k++)
{
A = self[j];
A = array[j];
o = aFunction(A, B[i], aContext);

if (o >= 0)
self[k] = B[i++];
array[k] = B[i++];
else
{
self[k] = A;
array[k] = A;
j++;
}
}

while (k < j)
self[k++] = B[i++];
array[k++] = B[i++];
}
}
}

/*!
Sorts the receiver array using an Objective-J method as a comparator.
@param aSelector the selector for the method to call for comparison
*/
- (void)sortUsingSelector:(SEL)aSelector
{
[self sortUsingFunction:selectorCompare context:aSelector];
}

@end

@implementation CPArray (CPMutableCopying)

- (id)mutableCopy
{
var r = [CPMutableArray new];
[r addObjectsFromArray:self];
return r;
}

@end

var selectorCompare = function selectorCompare(object1, object2, selector)
{
return [object1 performSelector:selector withObject:object2];
};

// sort using sort descriptors
var compareObjectsUsingDescriptors= function compareObjectsUsingDescriptors(lhs, rhs, descriptors)
var compareObjectsUsingDescriptors = function(lhs, rhs, descriptors)
{
var result = CPOrderedSame,
i = 0,
Expand All @@ -425,3 +440,114 @@ var compareObjectsUsingDescriptors= function compareObjectsUsingDescriptors(lhs,

return result;
};

// 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++];
}
}
}
14 changes: 14 additions & 0 deletions Tests/Foundation/CPArrayTest.j
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit e232b18

Please sign in to comment.