Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A very fast sortUsingDescriptors: #1560

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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--)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and everywhere else, please separate all control structures (and their bracketed code blocks) from surrounding code with a blank line.

{
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this has been merged already, but we might want to make this function more readable. All the one letter variable names are very hard to translate to a meaning and this function will be very hard to maintain for everybody that hasn't written it and even for the original author 3 months from now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree completely. Maybe the original author would be kind enough to make it more readable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm the one who submitted the merge-sort function and it's a port from C. I can't find the original source right now but i'll keep searching.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a port from C

That was obvious. ;-)

{
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