2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "EOSortOrdering.h"
23 #include "EOKeyValueCoding.h"
24 #include <EOControl/EONull.h>
28 # include <objc/objc.h>
33 # define SEL_EQ(sel1,sel2) sel_eq(sel1,sel2)
35 # define SEL_EQ(sel1,sel2) (sel1 == sel2)
40 EOControl_DECLARE SEL EOCompareAscending =
41 @selector(compareAscending:);
42 EOControl_DECLARE SEL EOCompareDescending =
43 @selector(compareDescending:);
44 EOControl_DECLARE SEL EOCompareCaseInsensitiveAscending =
45 @selector(compareCaseInsensitiveAscending:);
46 EOControl_DECLARE SEL EOCompareCaseInsensitiveDescending =
47 @selector(compareCaseInsensitiveDescending:);
50 @implementation EOSortOrdering
52 This class specifies a sort-ordering as used with
53 EOFetchSpecification. It takes a key and a sort
54 selector which is used for comparision.
57 /*" Create a sort-ordering object with the specified key and sort selector "*/
58 + (EOSortOrdering *)sortOrderingWithKey:(NSString *)_key selector:(SEL)_sel {
59 return [[[self alloc] initWithKey:_key selector:_sel] autorelease];
63 Initialize a sort-ordering object with the specified key and sort selector
65 - (id)initWithKey:(NSString *)_key selector:(SEL)_selector {
66 if ((self = [super init])) {
67 self->key = [_key copyWithZone:[self zone]];
68 self->selector = _selector;
81 Returns the key the ordering sorts with.
88 Returns the selector the ordering sorts with.
91 return self->selector;
96 - (BOOL)isEqualToSortOrdering:(EOSortOrdering *)_sortOrdering {
97 if (!SEL_EQ([_sortOrdering selector], [self selector]))
99 if (![[_sortOrdering key] isEqualToString:[self key]])
103 - (BOOL)isEqual:(id)_other {
104 if ([_other isKindOfClass:[EOSortOrdering class]])
105 return [self isEqualToSortOrdering:_other];
112 - (EOSortOrdering *)sortOrderingByApplyingKeyMap:(NSDictionary *)_map {
115 k = [_map objectForKey:self->key];
116 return [EOSortOrdering sortOrderingWithKey:(k ? k : self->key)
117 selector:self->selector];
120 /* key/value archiving */
122 - (id)initWithKeyValueUnarchiver:(EOKeyValueUnarchiver *)_unarchiver {
123 if ((self = [super init]) != nil) {
126 self->key = [[_unarchiver decodeObjectForKey:@"key"] copy];
128 if ((s = [_unarchiver decodeObjectForKey:@"selector"]) != nil)
129 self->selector = NSSelectorFromString(s);
130 else if ((s = [_unarchiver decodeObjectForKey:@"selectorName"]) != nil) {
131 if (![s hasSuffix:@":"]) s = [s stringByAppendingString:@":"];
132 self->selector = NSSelectorFromString(s);
137 - (void)encodeWithKeyValueArchiver:(EOKeyValueArchiver *)_archiver {
138 [_archiver encodeObject:[self key] forKey:@"key"];
139 [_archiver encodeObject:NSStringFromSelector([self selector])
140 forKey:@"selectorName"];
145 - (NSString *)description {
146 return [NSString stringWithFormat:
147 @"<0x%p[%@]: key=%@ selector=%@>",
148 self, NSStringFromClass([self class]),
149 [self key], NSStringFromSelector([self selector])];
152 @end /* EOSortOrdering */
154 @implementation NSArray(EOSortOrdering)
157 Sort the array using the sort-orderings contained in the argument. If no
158 orderings are given, a copy of self is returned.
160 - (NSArray *)sortedArrayUsingKeyOrderArray:(NSArray *)_orderings {
161 NSMutableArray *m = nil;
162 NSArray *result = nil;
164 if ([_orderings count] == 0)
165 return [[self copy] autorelease];
167 m = [self mutableCopy];
168 [m sortUsingKeyOrderArray:_orderings];
170 [m release]; m = nil;
171 return [result autorelease];
174 @end /* NSArray(EOSortOrdering) */
176 @implementation NSMutableArray(EOSortOrdering)
179 EOSortOrdering *orderings[10]; /* max depth 10 */
181 } EOSortOrderingContext;
183 static EONull *null = nil;
185 static int keyOrderComparator(id o1, id o2, EOSortOrderingContext *context) {
188 for (i = 0; i < context->count; i++) {
192 int (*ccmp)(id, SEL, id);
195 key = [context->orderings[i] key];
196 sel = [context->orderings[i] selector];
198 v1 = [o1 valueForKeyPath:key];
199 v2 = [o2 valueForKeyPath:key];
202 result = NSOrderedSame;
203 else if ((v1 == nil) || (v1 == null))
204 result = (sel == EOCompareAscending)
205 ? NSOrderedAscending : NSOrderedDescending;
206 else if ((v2 == nil) || (v2 == null))
207 result = (sel == EOCompareAscending)
208 ? NSOrderedDescending : NSOrderedAscending;
209 else if ((ccmp = (void *)[v1 methodForSelector:sel]))
210 result = ccmp(v1, sel, v2);
212 result = (unsigned long)[v1 performSelector:sel withObject:v2];
214 if (result != NSOrderedSame)
217 return NSOrderedSame;
221 Sort the array using the sort-orderings contained in the argument.
223 - (void)sortUsingKeyOrderArray:(NSArray *)_orderings {
224 NSEnumerator *e = nil;
225 EOSortOrdering *ordering = nil;
226 EOSortOrderingContext ctx;
229 NSAssert([_orderings count] < 10, @"max sort descriptor count is 10!");
231 e = [_orderings objectEnumerator];
232 for (i = 0; (ordering = [e nextObject]) && (i < 10); i++)
233 ctx.orderings[i] = ordering;
237 if (null == nil) null = [EONull null];
238 [self sortUsingFunction:(void *)keyOrderComparator context:&ctx];
241 @end /* NSMutableArray(EOSortOrdering) */
243 @implementation EONull(EOSortOrdering)
246 Compares the null object, "nil" and "self" are considered of the same order,
247 otherwise null is considered of lower order.
249 - (int)compareAscending:(id)_object {
250 if (_object == self) return NSOrderedSame;
251 if (_object == nil) return NSOrderedSame;
252 return NSOrderedDescending;
256 Compares the null object, "nil" and "self" are considered of the same order,
257 otherwise null is considered of higher order.
259 - (int)compareDescending:(id)_object {
260 if (_object == self) return NSOrderedSame;
261 if (_object == nil) return NSOrderedSame;
262 return NSOrderedAscending;
265 @end /* EONull(EOSortOrdering) */
267 @implementation NSNumber(EOSortOrdering)
269 static Class NumClass = Nil;
271 - (int)compareAscending:(id)_object {
272 if (_object == self) return NSOrderedSame;
273 if (NumClass == Nil) NumClass = [NSNumber class];
275 if ([_object isKindOfClass:NumClass])
276 return [self compare:_object];
278 return [_object compareDescending:self];
281 - (int)compareDescending:(id)_object {
284 result = [self compareAscending:_object];
286 if (result == NSOrderedAscending)
287 return NSOrderedDescending;
288 else if (result == NSOrderedDescending)
289 return NSOrderedAscending;
291 return NSOrderedSame;
294 @end /* NSNumber(EOSortOrdering) */
296 @implementation NSString(EOSortOrdering)
298 - (int)compareAscending:(id)_object {
299 if (_object == self) return NSOrderedSame;
300 return [self compare:[_object stringValue]];
302 - (int)compareCaseInsensitiveAscending:(id)_object {
303 if (_object == self) return NSOrderedSame;
304 return [self caseInsensitiveCompare:[_object stringValue]];
307 - (int)compareDescending:(id)_object {
310 if (_object == self) return NSOrderedSame;
312 result = [self compareAscending:_object];
314 if (result == NSOrderedAscending)
315 return NSOrderedDescending;
316 else if (result == NSOrderedDescending)
317 return NSOrderedAscending;
319 return NSOrderedSame;
322 - (int)compareCaseInsensitiveDescending:(id)_object {
325 if (_object == self) return NSOrderedSame;
326 result = [self compareCaseInsensitiveAscending:_object];
328 if (result == NSOrderedAscending)
329 return NSOrderedDescending;
330 else if (result == NSOrderedDescending)
331 return NSOrderedAscending;
333 return NSOrderedSame;
336 @end /* NSString(EOSortOrdering) */
338 @implementation NSDate(EOSortOrdering)
340 static Class DateClass = Nil;
342 - (int)compareAscending:(id)_object {
343 if (_object == self) return NSOrderedSame;
344 if (DateClass == Nil) DateClass = [NSDate class];
345 if (![_object isKindOfClass:DateClass]) return NSOrderedAscending;
346 return [self compare:_object];
348 - (int)compareDescending:(id)_object {
351 if (_object == self) return NSOrderedSame;
353 if (DateClass == Nil) DateClass = [NSDate class];
354 if (![_object isKindOfClass:DateClass]) return NSOrderedDescending;
356 result = [self compare:_object];
358 if (result == NSOrderedAscending)
359 return NSOrderedDescending;
360 else if (result == NSOrderedDescending)
361 return NSOrderedAscending;
363 return NSOrderedSame;
366 @end /* NSDate(EOSortOrdering) */