]> err.no Git - sope/blob - sope-core/EOControl/EOSortOrdering.m
fixed gcc 4.1 warnings
[sope] / sope-core / EOControl / EOSortOrdering.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21
22 #include "EOSortOrdering.h"
23 #include "EOKeyValueCoding.h"
24 #include <EOControl/EONull.h>
25 #include "common.h"
26
27 #if GNU_RUNTIME
28 #  include <objc/objc.h>
29 #endif
30
31 #ifndef SEL_EQ
32 #  if GNU_RUNTIME
33 #    define SEL_EQ(sel1,sel2) sel_eq(sel1,sel2)
34 #  else
35 #    define SEL_EQ(sel1,sel2) (sel1 == sel2)
36 #  endif
37 #endif
38
39 #if !NeXT_RUNTIME
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:);
48 #endif
49
50 @implementation EOSortOrdering
51 /*"
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.
55 "*/
56
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];
60 }
61
62 /*" 
63   Initialize a sort-ordering object with the specified key and sort selector
64 "*/
65 - (id)initWithKey:(NSString *)_key selector:(SEL)_selector {
66   if ((self = [super init])) {
67     self->key      = [_key copyWithZone:[self zone]];
68     self->selector = _selector;
69   }
70   return self;
71 }
72
73 - (void)dealloc {
74   [self->key release];
75   [super dealloc];
76 }
77
78 /* accessors */
79
80 /*"
81   Returns the key the ordering sorts with.
82 "*/
83 - (NSString *)key {
84   return self->key;
85 }
86
87 /*"
88   Returns the selector the ordering sorts with.
89 "*/
90 - (SEL)selector {
91   return self->selector;
92 }
93
94 /* equality */
95
96 - (BOOL)isEqualToSortOrdering:(EOSortOrdering *)_sortOrdering {
97   if (!SEL_EQ([_sortOrdering selector], [self selector]))
98     return NO;
99   if (![[_sortOrdering key] isEqualToString:[self key]])
100     return NO;
101   return YES;
102 }
103 - (BOOL)isEqual:(id)_other {
104   if ([_other isKindOfClass:[EOSortOrdering class]])
105     return [self isEqualToSortOrdering:_other];
106
107   return NO;
108 }
109
110 /* remapping keys */
111
112 - (EOSortOrdering *)sortOrderingByApplyingKeyMap:(NSDictionary *)_map {
113   NSString *k;
114   
115   k = [_map objectForKey:self->key];
116   return [EOSortOrdering sortOrderingWithKey:(k ? k : self->key)
117                          selector:self->selector];
118 }
119
120 /* key/value archiving */
121
122 - (id)initWithKeyValueUnarchiver:(EOKeyValueUnarchiver *)_unarchiver {
123   if ((self = [super init]) != nil) {
124     NSString *s;
125     
126     self->key = [[_unarchiver decodeObjectForKey:@"key"] copy];
127     
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);
133     }
134   }
135   return self;
136 }
137 - (void)encodeWithKeyValueArchiver:(EOKeyValueArchiver *)_archiver {
138   [_archiver encodeObject:[self key] forKey:@"key"];
139   [_archiver encodeObject:NSStringFromSelector([self selector])
140              forKey:@"selectorName"];
141 }
142
143 /* description */
144
145 - (NSString *)description {
146   return [NSString stringWithFormat:
147                      @"<0x%p[%@]: key=%@ selector=%@>",
148                      self, NSStringFromClass([self class]),
149                      [self key], NSStringFromSelector([self selector])];
150 }
151
152 @end /* EOSortOrdering */
153
154 @implementation NSArray(EOSortOrdering)
155
156 /*" 
157   Sort the array using the sort-orderings contained in the argument. If no
158   orderings are given, a copy of self is returned.
159 "*/
160 - (NSArray *)sortedArrayUsingKeyOrderArray:(NSArray *)_orderings {
161   NSMutableArray *m      = nil;
162   NSArray        *result = nil;
163   
164   if ([_orderings count] == 0)
165     return [[self copy] autorelease];
166   
167   m = [self mutableCopy];
168   [m sortUsingKeyOrderArray:_orderings];
169   result = [m copy];
170   [m release]; m = nil;
171   return [result autorelease];
172 }
173
174 @end /* NSArray(EOSortOrdering) */
175
176 @implementation NSMutableArray(EOSortOrdering)
177
178 typedef struct {
179   EOSortOrdering *orderings[10]; /* max depth 10 */
180   short          count;
181 } EOSortOrderingContext;
182
183 static EONull *null = nil;
184
185 static int keyOrderComparator(id o1, id o2, EOSortOrderingContext *context) {
186   short i;
187
188   for (i = 0; i < context->count; i++) {
189     NSString *key;
190     SEL      sel;
191     id       v1, v2;
192     int      (*ccmp)(id, SEL, id);
193     int      result;
194
195     key = [context->orderings[i] key];
196     sel = [context->orderings[i] selector];
197     
198     v1 = [o1 valueForKeyPath:key];
199     v2 = [o2 valueForKeyPath:key];
200
201     if (v1 == v2)
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);
211     else
212       result = (int)[v1 performSelector:sel withObject:v2];
213
214     if (result != NSOrderedSame)
215       return result;
216   }
217   return NSOrderedSame;
218 }
219
220 /*" 
221   Sort the array using the sort-orderings contained in the argument.
222 "*/
223 - (void)sortUsingKeyOrderArray:(NSArray *)_orderings {
224   NSEnumerator          *e        = nil;
225   EOSortOrdering        *ordering = nil;
226   EOSortOrderingContext ctx;
227   int                   i;
228   
229   NSAssert([_orderings count] < 10, @"max sort descriptor count is 10!");
230   
231   e = [_orderings objectEnumerator];
232   for (i = 0; (ordering = [e nextObject]) && (i < 10); i++)
233     ctx.orderings[i] = ordering;
234
235   ctx.count = i;
236
237   if (null == nil) null = [EONull null];
238   [self sortUsingFunction:(void *)keyOrderComparator context:&ctx];
239 }
240
241 @end /* NSMutableArray(EOSortOrdering) */
242
243 @implementation EONull(EOSortOrdering)
244
245 /*" 
246   Compares the null object, "nil" and "self" are considered of the same order,
247   otherwise null is considered of lower order.
248 "*/
249 - (int)compareAscending:(id)_object {
250   if (_object == self) return NSOrderedSame;
251   if (_object == nil)  return NSOrderedSame;
252   return NSOrderedDescending;
253 }
254
255 /*" 
256   Compares the null object, "nil" and "self" are considered of the same order,
257   otherwise null is considered of higher order.
258 "*/
259 - (int)compareDescending:(id)_object {
260   if (_object == self) return NSOrderedSame;
261   if (_object == nil)  return NSOrderedSame;
262   return NSOrderedAscending;
263 }
264
265 @end /* EONull(EOSortOrdering) */
266
267 @implementation NSNumber(EOSortOrdering)
268
269 static Class NumClass = Nil;
270
271 - (int)compareAscending:(id)_object {
272   if (_object == self) return NSOrderedSame;
273   if (NumClass == Nil) NumClass = [NSNumber class];
274   
275   if ([_object isKindOfClass:NumClass])
276     return [self compare:_object];
277   else
278     return [_object compareDescending:self];
279 }
280
281 - (int)compareDescending:(id)_object {
282   int result;
283   
284   result = [self compareAscending:_object];
285   
286   if (result == NSOrderedAscending)
287     return NSOrderedDescending;
288   else if (result == NSOrderedDescending)
289     return NSOrderedAscending;
290   else
291     return NSOrderedSame;
292 }
293
294 @end /* NSNumber(EOSortOrdering) */
295
296 @implementation NSString(EOSortOrdering)
297
298 - (int)compareAscending:(id)_object {
299   if (_object == self) return NSOrderedSame;
300   return [self compare:[_object stringValue]];
301 }
302 - (int)compareCaseInsensitiveAscending:(id)_object {
303   if (_object == self) return NSOrderedSame;
304   return [self caseInsensitiveCompare:[_object stringValue]];
305 }
306
307 - (int)compareDescending:(id)_object {
308   int result;
309   
310   if (_object == self) return NSOrderedSame;
311   
312   result = [self compareAscending:_object];
313   
314   if (result == NSOrderedAscending)
315     return NSOrderedDescending;
316   else if (result == NSOrderedDescending)
317     return NSOrderedAscending;
318   else
319     return NSOrderedSame;
320 }
321
322 - (int)compareCaseInsensitiveDescending:(id)_object {
323   int result;
324   
325   if (_object == self) return NSOrderedSame;
326   result = [self compareCaseInsensitiveAscending:_object];
327   
328   if (result == NSOrderedAscending)
329     return NSOrderedDescending;
330   else if (result == NSOrderedDescending)
331     return NSOrderedAscending;
332   else
333     return NSOrderedSame;
334 }
335
336 @end /* NSString(EOSortOrdering) */
337
338 @implementation NSDate(EOSortOrdering)
339
340 static Class DateClass = Nil;
341
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];
347 }
348 - (int)compareDescending:(id)_object {
349   int result;
350
351   if (_object == self) return NSOrderedSame;
352
353   if (DateClass == Nil) DateClass = [NSDate class];
354   if (![_object isKindOfClass:DateClass]) return NSOrderedDescending;
355   
356   result = [self compare:_object];
357   
358   if (result == NSOrderedAscending)
359     return NSOrderedDescending;
360   else if (result == NSOrderedDescending)
361     return NSOrderedAscending;
362   else
363     return NSOrderedSame;
364 }
365
366 @end /* NSDate(EOSortOrdering) */