2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo 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 OGo 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 OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include "EOKeyValueCoding.h"
28 # include <objc/objc-api.h>
29 # include <objc/encoding.h>
32 static EONull *null = nil;
34 #if !NeXT_Foundation_LIBRARY
36 static id idMethodGetFunc(void* info1, void* info2, id self);
37 static id idIvarGetFunc(void* info1, void* info2, id self);
38 static void idMethodSetFunc(void* info1, void* info2, id self, id val);
39 static void idIvarSetFunc(void* info1, void* info2, id self, id val);
40 static id charMethodGetFunc(void* info1, void* info2, id self);
41 static id charIvarGetFunc(void* info1, void* info2, id self);
42 static void charMethodSetFunc(void* info1, void* info2, id self, id val);
43 static void charIvarSetFunc(void* info1, void* info2, id self, id val);
44 static id unsignedCharMethodGetFunc(void* info1, void* info2, id self);
45 static id unsignedCharIvarGetFunc(void* info1, void* info2, id self);
46 static void unsignedCharMethodSetFunc(void* info1, void* info2, id self, id val);
47 static void unsignedCharIvarSetFunc(void* info1, void* info2, id self, id val);
48 static id shortMethodGetFunc(void* info1, void* info2, id self);
49 static id shortIvarGetFunc(void* info1, void* info2, id self);
50 static void shortMethodSetFunc(void* info1, void* info2, id self, id val);
51 static void shortIvarSetFunc(void* info1, void* info2, id self, id val);
52 static id unsignedShortMethodGetFunc(void* info1, void* info2, id self);
53 static id unsignedShortIvarGetFunc(void* info1, void* info2, id self);
54 static void unsignedShortMethodSetFunc(void* info1, void* info2, id self, id val);
55 static void unsignedShortIvarSetFunc(void* info1, void* info2, id self, id val);
56 static id intMethodGetFunc(void* info1, void* info2, id self);
57 static id intIvarGetFunc(void* info1, void* info2, id self);
58 static void intMethodSetFunc(void* info1, void* info2, id self, id val);
59 static void intIvarSetFunc(void* info1, void* info2, id self, id val);
60 static id unsignedIntMethodGetFunc(void* info1, void* info2, id self);
61 static id unsignedIntIvarGetFunc(void* info1, void* info2, id self);
62 static void unsignedIntMethodSetFunc(void* info1, void* info2, id self, id val);
63 static void unsignedIntIvarSetFunc(void* info1, void* info2, id self, id val);
64 static id longMethodGetFunc(void* info1, void* info2, id self);
65 static id longIvarGetFunc(void* info1, void* info2, id self);
66 static void longMethodSetFunc(void* info1, void* info2, id self, id val);
67 static void longIvarSetFunc(void* info1, void* info2, id self, id val);
68 static id unsignedLongMethodGetFunc(void* info1, void* info2, id self);
69 static id unsignedLongIvarGetFunc(void* info1, void* info2, id self);
70 static void unsignedLongMethodSetFunc(void* info1, void* info2, id self, id val);
71 static void unsignedLongIvarSetFunc(void* info1, void* info2, id self, id val);
72 static id longLongMethodGetFunc(void* info1, void* info2, id self);
73 static id longLongIvarGetFunc(void* info1, void* info2, id self);
74 static void longLongMethodSetFunc(void* info1, void* info2, id self, id val);
75 static void longLongIvarSetFunc(void* info1, void* info2, id self, id val);
76 static id unsignedLongLongMethodGetFunc(void* info1, void* info2, id self);
77 static id unsignedLongLongIvarGetFunc(void* info1, void* info2, id self);
78 static void unsignedLongLongMethodSetFunc(void* info1, void* info2, id self, id val);
79 static void unsignedLongLongIvarSetFunc(void* info1, void* info2, id self, id val);
80 static id floatMethodGetFunc(void* info1, void* info2, id self);
81 static id floatIvarGetFunc(void* info1, void* info2, id self);
82 static void floatMethodSetFunc(void* info1, void* info2, id self, id val);
83 static void floatIvarSetFunc(void* info1, void* info2, id self, id val);
84 static id doubleMethodGetFunc(void* info1, void* info2, id self);
85 static id doubleIvarGetFunc(void* info1, void* info2, id self);
86 static void doubleMethodSetFunc(void* info1, void* info2, id self, id val);
87 static void doubleIvarSetFunc(void* info1, void* info2, id self, id val);
89 static Class NumberClass = Nil;
90 static Class StringClass = Nil;
92 @implementation NSObject(EOKeyValueCoding)
98 typedef struct _KeyValueMethod {
103 typedef struct _GetKeyValueBinding {
104 /* info1, info2, self */
105 id (*access)(void *, void *, id);
108 } GetKeyValueBinding;
110 typedef struct _SetKeyValueBinding {
111 /* info1, info2, self, val */
112 void (*access)(void *, void *, id, id);
115 } SetKeyValueBinding;
121 static NSMapTable* getValueBindings = NULL;
122 static NSMapTable* setValueBindings = NULL;
123 static BOOL keyValueDebug = NO;
124 static BOOL keyValueInit = NO;
130 static GetKeyValueBinding* newGetBinding(NSString* key, id instance)
132 GetKeyValueBinding *ret = NULL;
135 id (*fptr)(void*, void*, id) = NULL;
137 // Lookup method name [-(type)key]
139 Class class = [instance class];
140 unsigned clen = [key cStringLength];
144 struct objc_method* mth;
146 cbuf = malloc(clen + 1);
147 [key getCString:cbuf]; cbuf[clen] = '\0';
149 sel = sel_get_any_uid(ckey);
151 if (sel && (mth = class_get_instance_method(class, sel)) &&
152 method_get_number_of_arguments(mth) == 2) {
153 switch(*objc_skip_type_qualifiers(mth->method_types)) {
155 fptr = (id (*)(void*, void*, id))idMethodGetFunc;
158 fptr = (id (*)(void*, void*, id))charMethodGetFunc;
161 fptr = (id (*)(void*, void*, id))unsignedCharMethodGetFunc;
164 fptr = (id (*)(void*, void*, id))shortMethodGetFunc;
167 fptr = (id (*)(void*, void*, id))unsignedShortMethodGetFunc;
170 fptr = (id (*)(void*, void*, id))intMethodGetFunc;
173 fptr = (id (*)(void*, void*, id))unsignedIntMethodGetFunc;
176 fptr = (id (*)(void*, void*, id))longMethodGetFunc;
179 fptr = (id (*)(void*, void*, id))unsignedLongMethodGetFunc;
182 fptr = (id (*)(void*, void*, id))longLongMethodGetFunc;
185 fptr = (id (*)(void*, void*, id))unsignedLongLongMethodGetFunc;
188 fptr = (id (*)(void*, void*, id))floatMethodGetFunc;
191 fptr = (id (*)(void*, void*, id))doubleMethodGetFunc;
195 info1 = (void*)(mth->method_imp);
196 info2 = (void*)(mth->method_name);
199 if (cbuf) free(cbuf);
204 Class class = [instance class];
210 clen = [key cStringLength];
211 cbuf = malloc(clen + 1);
212 [key getCString:cbuf]; cbuf[clen] = '\0';
216 for (i = 0; class->ivars && i < class->ivars->ivar_count; i++) {
217 if (!Strcmp(ckey, class->ivars->ivar_list[i].ivar_name)) {
218 switch(*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type)) {
220 fptr = (id (*)(void*, void*, id))idIvarGetFunc;
223 fptr = (id (*)(void*, void*, id))charIvarGetFunc;
226 fptr = (id (*)(void*, void*, id))unsignedCharIvarGetFunc;
229 fptr = (id (*)(void*, void*, id))shortIvarGetFunc;
232 fptr = (id (*)(void*, void*, id))unsignedShortIvarGetFunc;
235 fptr = (id (*)(void*, void*, id))intIvarGetFunc;
238 fptr = (id (*)(void*, void*, id))unsignedIntIvarGetFunc;
241 fptr = (id (*)(void*, void*, id))longIvarGetFunc;
244 fptr = (id (*)(void*, void*, id))unsignedLongIvarGetFunc;
247 fptr = (id (*)(void*, void*, id))longLongIvarGetFunc;
250 fptr = (id (*)(void*, void*, id))unsignedLongLongIvarGetFunc;
253 fptr = (id (*)(void*, void*, id))floatIvarGetFunc;
256 fptr = (id (*)(void*, void*, id))doubleIvarGetFunc;
260 info2 = (void*)(class->ivars->ivar_list[i].ivar_offset);
265 class = class->super_class;
267 if (cbuf) free(cbuf);
270 // Make binding and insert into map
272 KeyValueMethod *mkey;
273 GetKeyValueBinding *bin;
275 mkey = Malloc(sizeof(KeyValueMethod));
276 bin = Malloc(sizeof(GetKeyValueBinding));
277 mkey->key = [key copy];
278 mkey->class = [instance class];
284 NSMapInsert(getValueBindings, mkey, bin);
288 // If no way to access value warn
289 if (!ret && keyValueDebug)
290 NSLog(@"cannnot get key `%@' for instance of class `%@'",
291 key, NSStringFromClass([instance class]));
296 static SetKeyValueBinding* newSetBinding(NSString* key, id instance)
298 SetKeyValueBinding *ret = NULL;
301 void (*fptr)(void*, void*, id, id) = NULL;
303 // Lookup method name [-(void)setKey:(type)arg]
305 Class class = [instance class];
306 unsigned clen = [key cStringLength];
310 struct objc_method* mth;
311 char sname[clen + 7];
313 cbuf = malloc(clen + 1);
314 [key getCString:cbuf]; cbuf[clen] = '\0';
317 // Make sel from name
318 Strcpy(sname, "set");
321 sname[3] = islower((int)sname[3]) ? toupper((int)sname[3]) : sname[3];
322 sel = sel_get_any_uid(sname);
324 if (sel && (mth = class_get_instance_method(class, sel)) &&
325 method_get_number_of_arguments(mth) == 3 &&
326 *objc_skip_type_qualifiers(mth->method_types) == _C_VOID) {
327 char* argType = (char*)(mth->method_types);
329 argType = (char*)objc_skip_argspec(argType); // skip return
330 argType = (char*)objc_skip_argspec(argType); // skip self
331 argType = (char*)objc_skip_argspec(argType); // skip SEL
333 switch(*objc_skip_type_qualifiers(argType)) {
335 fptr = (void (*)(void*, void*, id, id))idMethodSetFunc;
338 fptr = (void (*)(void*, void*, id, id))charMethodSetFunc;
341 fptr = (void (*)(void*, void*, id, id))unsignedCharMethodSetFunc;
344 fptr = (void (*)(void*, void*, id, id))shortMethodSetFunc;
347 fptr = (void (*)(void*, void*, id, id))unsignedShortMethodSetFunc;
350 fptr = (void (*)(void*, void*, id, id))intMethodSetFunc;
353 fptr = (void (*)(void*, void*, id, id))unsignedIntMethodSetFunc;
356 fptr = (void (*)(void*, void*, id, id))longMethodSetFunc;
359 fptr = (void (*)(void*, void*, id, id))unsignedLongMethodSetFunc;
362 fptr = (void (*)(void*, void*, id, id))longLongMethodSetFunc;
365 fptr = (void (*)(void*, void*, id, id))unsignedLongLongMethodSetFunc;
368 fptr = (void (*)(void*, void*, id, id))floatMethodSetFunc;
371 fptr = (void (*)(void*, void*, id, id))doubleMethodSetFunc;
375 info1 = (void*)(mth->method_imp);
376 info2 = (void*)(mth->method_name);
379 if (cbuf) free(cbuf);
383 Class class = [instance class];
384 unsigned clen = [key cStringLength];
389 cbuf = malloc(clen + 1);
390 [key getCString:cbuf]; cbuf[clen] = '\0';
394 for (i = 0; class->ivars && i < class->ivars->ivar_count; i++) {
395 if (!Strcmp(ckey, class->ivars->ivar_list[i].ivar_name)) {
396 switch(*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type)) {
398 fptr = (void (*)(void*, void*, id, id))idIvarSetFunc;
401 fptr = (void (*)(void*, void*, id, id))charIvarSetFunc;
404 fptr = (void (*)(void*, void*, id, id))unsignedCharIvarSetFunc;
407 fptr = (void (*)(void*, void*, id, id))shortIvarSetFunc;
410 fptr = (void (*)(void*, void*, id, id))unsignedShortIvarSetFunc;
413 fptr = (void (*)(void*, void*, id, id))intIvarSetFunc;
416 fptr = (void (*)(void*, void*, id, id))unsignedIntIvarSetFunc;
419 fptr = (void (*)(void*, void*, id, id))longIvarSetFunc;
422 fptr = (void (*)(void*, void*, id, id))unsignedLongIvarSetFunc;
425 fptr = (void (*)(void*, void*, id, id))longLongIvarSetFunc;
428 fptr = (void (*)(void*, void*, id, id))unsignedLongLongIvarSetFunc;
431 fptr = (void (*)(void*, void*, id, id))floatIvarSetFunc;
434 fptr = (void (*)(void*, void*, id, id))doubleIvarSetFunc;
438 info2 = (void*)(class->ivars->ivar_list[i].ivar_offset);
443 class = class->super_class;
445 if (cbuf) free(cbuf);
448 // Make binding and insert into map
450 KeyValueMethod *mkey;
451 SetKeyValueBinding *bin;
453 mkey = Malloc(sizeof(KeyValueMethod));
454 bin = Malloc(sizeof(SetKeyValueBinding));
455 mkey->key = [key copy];
456 mkey->class = [instance class];
462 NSMapInsert(setValueBindings, mkey, bin);
465 // If no way to access value warn
466 if (!ret && keyValueDebug)
467 NSLog(@"cannnot set key `%@' for instance of class `%@'",
468 key, NSStringFromClass([instance class]));
474 * MapTable initialization
477 static unsigned keyValueMapHash(NSMapTable* table, KeyValueMethod* map) {
478 return [map->key hash] + (((int)(map->class)) >> 4);
481 static BOOL keyValueMapCompare(NSMapTable* table,
482 KeyValueMethod* map1, KeyValueMethod* map2)
484 return (map1->class == map2->class) && [map1->key isEqual:map2->key];
487 static void mapRetainNothing(NSMapTable* table, KeyValueMethod* map) {
490 static void keyValueMapKeyRelease(NSMapTable* table, KeyValueMethod* map) {
495 static void keyValueMapValRelease(NSMapTable* table, void* map) {
499 static NSString* keyValueMapDescribe(NSMapTable* table, KeyValueMethod* map) {
500 if (StringClass == Nil) StringClass = [NSString class];
501 return [StringClass stringWithFormat:@"%@:%@",
502 NSStringFromClass(map->class), map->key];
505 static NSString* describeBinding(NSMapTable* table, GetKeyValueBinding* bin) {
506 if (StringClass == Nil) StringClass = [NSString class];
507 return [StringClass stringWithFormat:@"%08x:%08x", bin->info1, bin->info2];
510 static NSMapTableKeyCallBacks keyValueKeyCallbacks = {
511 (unsigned(*)(NSMapTable *, const void *))keyValueMapHash,
512 (BOOL(*)(NSMapTable *, const void *, const void *))keyValueMapCompare,
513 (void (*)(NSMapTable *, const void *anObject))mapRetainNothing,
514 (void (*)(NSMapTable *, void *anObject))keyValueMapKeyRelease,
515 (NSString *(*)(NSMapTable *, const void *))keyValueMapDescribe,
519 const NSMapTableValueCallBacks keyValueValueCallbacks = {
520 (void (*)(NSMapTable *, const void *))mapRetainNothing,
521 (void (*)(NSMapTable *, void *))keyValueMapValRelease,
522 (NSString *(*)(NSMapTable *, const void *))describeBinding
525 static void initKeyValueBindings(void)
527 getValueBindings = NSCreateMapTable(keyValueKeyCallbacks,
528 keyValueValueCallbacks, 31);
529 setValueBindings = NSCreateMapTable(keyValueKeyCallbacks,
530 keyValueValueCallbacks, 31);
538 static inline void removeAllBindings(void) {
539 NSResetMapTable(getValueBindings);
540 NSResetMapTable(setValueBindings);
543 static inline id getValue(NSString* key, id instance) {
544 KeyValueMethod mkey = { key, [instance class] };
545 GetKeyValueBinding *bin;
548 if (NumberClass == Nil)
549 NumberClass = [NSNumber class];
553 initKeyValueBindings();
555 // Get existing binding
556 bin = (GetKeyValueBinding *)NSMapGet(getValueBindings, &mkey);
558 // Create new binding
560 bin = newGetBinding(key, instance);
562 // Get value if binding is ok
564 value = bin->access(bin->info1, bin->info2, instance);
569 static inline BOOL setValue(NSString* key, id instance, id value)
571 KeyValueMethod mkey = {key, [instance class]};
572 SetKeyValueBinding* bin;
574 if (NumberClass == Nil)
575 NumberClass = [NSNumber class];
579 initKeyValueBindings();
581 // Get existing binding
582 bin = (SetKeyValueBinding *)NSMapGet(setValueBindings, &mkey);
584 // Create new binding
586 bin = newSetBinding(key, instance);
588 // Get value if binding is ok
590 bin->access(bin->info1, bin->info2, instance, value);
592 return (bin != NULL);
595 + (BOOL)accessInstanceVariablesDirectly {
599 - (void)handleTakeValue:(id)_value forUnboundKey:(NSString *)_key {
602 ui = [NSDictionary dictionaryWithObjectsAndKeys:
603 self, @"EOTargetObjectUserInfoKey",
605 @"EOTargetObjectClassUserInfoKey",
606 _key, @"EOUnknownUserInfoKey",
608 [[NSException exceptionWithName:@"EOUnknownKeyException"
609 reason:@"called -takeValue:forKey: with unknown key"
613 - (id)handleQueryWithUnboundKey:(NSString *)_key {
616 ui = [NSDictionary dictionaryWithObjectsAndKeys:
617 self, @"EOTargetObjectUserInfoKey",
618 _key, @"EOUnknownUserInfoKey",
620 [[NSException exceptionWithName:@"EOUnknownKeyException"
621 reason:@"called -valueForKey: with unknown key"
626 - (void)unableToSetNullForKey:(NSString *)_key {
627 [NSException raise:@"NSInvalidArgumentException"
629 @"EOKeyValueCoding cannot set EONull value for key %@,"
630 @"in instance of %@ class.",
631 _key, NSStringFromClass([self class])];
634 + (void)flushAllKeyBindings {
637 - (void)flushKeyBindings {
642 - (void)setKeyValueCodingWarnings:(BOOL)aFlag {
643 keyValueDebug = aFlag;
646 - (void)takeValuesFromDictionary:(NSDictionary *)dictionary {
647 NSEnumerator *keyEnum;
650 if (null == nil) null = [EONull null];
651 keyEnum = [dictionary keyEnumerator];
653 while ((key = [keyEnum nextObject])) {
656 value = [dictionary objectForKey:key];
658 /* automagically convert EONull to nil */
659 if (value == null) value = nil;
661 [self takeValue:value forKey:key];
663 #if 0 // this doesn't support overridden methods ...
664 if (!setValue(key, self, value)) {
665 [self handleTakeValue:value forUnboundKey:key];
671 - (NSDictionary *)valuesForKeys:(NSArray *)keys {
672 static Class NSDictionaryClass = Nil;
673 int n = [keys count];
675 if (NSDictionaryClass == Nil)
676 NSDictionaryClass = [NSDictionary class];
678 null = [EONull null];
681 return [NSDictionaryClass dictionary];
686 key = [keys objectAtIndex:0];
687 //value = getValue(key, self);
688 value = [self valueForKey:key];
690 /* automagically convert 'nil' to EONull */
691 if (value == nil) value = null;
693 return [NSDictionaryClass dictionaryWithObject:value forKey:key];
700 for (i = 0; i < n; i++) {
704 key = [keys objectAtIndex:i];
705 //val = getValue(key, self);
706 val = [self valueForKey:key];
708 /* automagically convert 'nil' to EONull */
709 if (val == nil) val = null;
715 return [NSDictionaryClass dictionaryWithObjects:newVals
721 - (void)takeValue:(id)_value forKey:(NSString *)_key {
722 if (!setValue(_key, self, _value)) {
723 //NSLog(@"ERROR(%s): couldn't take value for key %@", key);
724 [self handleTakeValue:_value forUnboundKey:_key];
728 - (id)valueForKey:(NSString *)key {
731 if ((val = getValue(key, self)))
739 + (BOOL)useStoredAccessor {
743 - (void)takeStoredValue:(id)_value forKey:(NSString *)_key {
744 if ([[self class] useStoredAccessor]) {
747 /* this should be different */
749 ok = setValue(_key, self, _value);
750 if (!ok) [self handleTakeValue:_value forUnboundKey:_key];
753 [self takeValue:_value forKey:_key];
756 - (id)storedValueForKey:(NSString *)_key {
757 if ([[self class] useStoredAccessor]) {
760 /* this should be different */
762 if ((val = getValue(_key, self)))
765 /* val = [self handleQueryWithUnboundKey:_key] */
770 return [self valueForKey:_key];
773 @end /* NSObject(EOKeyValueCoding) */
775 @implementation NSObject(EOKeyPathValueCoding)
777 - (void)takeValue:(id)_value forKeyPath:(NSString *)_keyPath {
782 keyPath = [_keyPath componentsSeparatedByString:@"."];
783 count = [keyPath count];
786 [self takeValue:_value forKey:_keyPath];
790 for (i = 0; i < (count - 1) ; i++) {
791 if ((target = [target valueForKey:[keyPath objectAtIndex:i]]) == nil)
796 [target takeValue:_value forKey:[keyPath lastObject]];
799 - (id)valueForKeyPath:(NSString *)_keyPath {
801 const unsigned char *buf;
802 unsigned int i, start, len;
805 if ((len = [_keyPath cStringLength]) == 0)
806 return [self valueForKey:_keyPath];
808 if (StringClass == Nil) StringClass = [NSString class];
811 buf = [_keyPath cString];
812 if (index(buf, '.') == NULL)
813 /* no point contained .. */
814 return [self valueForKey:_keyPath];
816 for (i = start = 0; i < len; i++) {
822 ? [StringClass stringWithCString:&(buf[start]) length:(i - start)]
825 if ((value = [value valueForKey:key]) == nil)
828 start = (i + 1); /* next part is after the pt */
831 /* check last part */
836 ? [StringClass stringWithCString:&(buf[start]) length:(i - start)]
838 return [value valueForKey:key];
841 /* naive implementation */
842 NSEnumerator *keyPath;
847 keyPath = [[_keyPath componentsSeparatedByString:@"."] objectEnumerator];
848 while ((key = [keyPath nextObject]) && (value != nil))
849 value = [value valueForKey:key];
854 @end /* NSObject(EOKeyPathValueCoding) */
856 @implementation NSArray(EOKeyValueCoding)
858 - (id)computeSumForKey:(NSString *)_key {
859 unsigned i, cc = [self count];
860 id (*objAtIdx)(id, SEL, unsigned int);
863 if (cc == 0) return [NSNumber numberWithDouble:0.0];
865 objAtIdx = (void*)[self methodForSelector:@selector(objectAtIndex:)];
867 for (i = 0, sum = 0.0; i < cc; i++) {
870 o = objAtIdx(self, @selector(objectAtIndex:), i);
871 sum += [o doubleValue];
873 return [NSNumber numberWithDouble:sum];
876 - (id)computeAvgForKey:(NSString *)_key {
877 unsigned i, cc = [self count];
878 id (*objAtIdx)(id, SEL, unsigned int);
881 if (cc == 0) return [NSNumber numberWithDouble:0.0];
883 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
885 for (i = 0, sum = 0.0; i < cc; i++) {
888 o = objAtIdx(self, @selector(objectAtIndex:), i);
890 sum += [o doubleValue];
892 return [NSNumber numberWithDouble:(sum / (double)cc)];
895 - (id)computeCountForKey:(NSString *)_key {
896 return [NSNumber numberWithUnsignedInt:[self count]];
899 - (id)computeMaxForKey:(NSString *)_key {
900 unsigned i, cc = [self count];
901 id (*objAtIdx)(id, SEL, unsigned int);
904 if (cc == 0) return nil;
906 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
908 max = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
909 for (i = 1; i < cc; i++) {
912 ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
913 if (ov > max) max = ov;
915 return [NSNumber numberWithDouble:max];
918 - (id)computeMinForKey:(NSString *)_key {
919 unsigned i, cc = [self count];
920 id (*objAtIdx)(id, SEL, unsigned int);
923 if (cc == 0) return nil;
925 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
927 min = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
928 for (i = 1; i < cc; i++) {
931 ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
932 if (ov < min) min = ov;
934 return [NSNumber numberWithDouble:min];
937 - (id)valueForKey:(NSString *)_key {
938 if ([_key hasPrefix:@"@"]) {
939 /* process a computed function */
942 unsigned keyLen = [_key cStringLength];
946 kbuf = malloc(keyLen + 4);
947 buf = malloc(keyLen + 20);
948 [_key getCString:kbuf];
951 strcpy(buf, "compute"); bufPtr += 7;
952 *bufPtr = toupper(keyStr[1]); bufPtr++;
953 strncpy(&(buf[8]), &(keyStr[2]), keyLen - 2); bufPtr += (keyLen - 2);
954 strcpy(bufPtr, "ForKey:");
955 if (kbuf) free(kbuf);
957 sel = sel_get_any_uid(buf);
960 return sel != NULL ? [self performSelector:sel withObject:_key] : nil;
963 /* process the _key in a map function */
964 unsigned i, cc = [self count];
966 id (*objAtIdx)(id, SEL, unsigned int);
969 if ([_key isEqualToString:@"count"]) {
970 NSLog(@"WARNING(%s): USED -valueForKey(@\"count\") ON NSArray, YOU"
971 @"PROBABLY WANT TO USE @count INSTEAD !",
972 __PRETTY_FUNCTION__);
973 return [self valueForKey:@"@count"];
977 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
979 for (i = 0; i < cc; i++) {
982 o = [objAtIdx(self, @selector(objectAtIndex:), i) valueForKey:_key];
987 if (null == nil) null = [EONull null];
992 return [NSArray arrayWithObjects:objects count:cc];
996 @end /* NSArray(EOKeyValueCoding) */
998 @implementation NSDictionary(EOKeyValueCoding)
1000 - (NSDictionary *)valuesForKeys:(NSArray *)keys {
1001 int n = [keys count];
1004 return [NSDictionary dictionary];
1006 NSString *key = [keys objectAtIndex:0];
1008 return [NSDictionary dictionaryWithObject:[self objectForKey:key]
1012 NSMutableArray *newKeys, *newVals;
1015 newKeys = [NSMutableArray arrayWithCapacity:n];
1016 newVals = [NSMutableArray arrayWithCapacity:n];
1018 for (i = 0; i < n; i++) {
1019 id key = [keys objectAtIndex:i];
1020 id val = [self objectForKey:key];
1023 [newKeys addObject:key];
1024 [newVals addObject:val];
1028 return [NSDictionary dictionaryWithObjects:newVals forKeys:newKeys];
1032 - (void)takeValue:(id)_value forKey:(NSString *)_key {
1033 //#warning takeValue:forKey: is ignored in NSDictionaries !
1035 //[self handleTakeValue:_value forUnboundKey:_key];
1038 - (id)valueForKey:(id)_key {
1041 if (_key == nil) // TODO: warn about nil key?
1043 if ((obj = [self objectForKey:_key]) == nil)
1046 if (null == nil) null = [[NSNull null] retain];
1053 @end /* NSDictionary(EOKeyValueCoding) */
1055 @implementation NSMutableDictionary(EOKeyValueCoding)
1057 - (void)takeValuesFromDictionary:(NSDictionary*)dictionary {
1058 [self addEntriesFromDictionary:dictionary];
1061 - (void)takeValue:(id)_value forKey:(id)_key {
1062 if (_value == nil) _value = [NSNull null];
1063 [self setObject:_value forKey:_key];
1066 @end /* NSMutableDictionary(EOKeyValueCoding) */
1069 * Accessor functions
1072 /* ACCESS to keys of id type. */
1074 static id idMethodGetFunc(void* info1, void* info2, id self) {
1075 id (*fptr)(id, SEL) = (id(*)(id, SEL))info1;
1076 id val = fptr(self, (SEL)info2);
1079 static id idIvarGetFunc(void* info1, void* info2, id self) {
1080 id* ptr = (id*)((char*)self + (int)info2);
1084 static void idMethodSetFunc(void* info1, void* info2, id self, id val) {
1085 void (*fptr)(id, SEL, id) = (void(*)(id, SEL, id))info1;
1086 fptr(self, (SEL)info2, val);
1089 static void idIvarSetFunc(void* info1, void* info2, id self, id val)
1091 id* ptr = (id*)((char*)self + (int)info2);
1095 /* ACCESS to keys of char type. */
1097 static id charMethodGetFunc(void* info1, void* info2, id self)
1099 char (*fptr)(id, SEL) = (char(*)(id, SEL))info1;
1100 char val = fptr(self, (SEL)info2);
1101 return [NumberClass numberWithChar:val];
1104 static id charIvarGetFunc(void* info1, void* info2, id self)
1106 char* ptr = (char*)((char*)self + (int)info2);
1107 return [NumberClass numberWithChar:*ptr];
1110 static void charMethodSetFunc(void* info1, void* info2, id self, id val)
1112 void (*fptr)(id, SEL, char) = (void(*)(id, SEL, char))info1;
1113 fptr(self, (SEL)info2, [val charValue]);
1116 static void charIvarSetFunc(void* info1, void* info2, id self, id val)
1118 char* ptr = (char*)((char*)self + (int)info2);
1119 *ptr = [val charValue];
1123 /* ACCESS to keys of unsigned char type. */
1125 static id unsignedCharMethodGetFunc(void* info1, void* info2, id self)
1127 unsigned char (*fptr)(id, SEL) = (unsigned char(*)(id, SEL))info1;
1128 unsigned char val = fptr(self, (SEL)info2);
1129 return [NumberClass numberWithUnsignedChar:val];
1132 static id unsignedCharIvarGetFunc(void* info1, void* info2, id self)
1134 unsigned char* ptr = (unsigned char*)((char*)self + (int)info2);
1135 return [NumberClass numberWithUnsignedChar:*ptr];
1138 static void unsignedCharMethodSetFunc(void* info1, void* info2, id self, id val)
1140 void (*fptr)(id, SEL, unsigned char) = (void(*)(id, SEL, unsigned char))info1;
1141 fptr(self, (SEL)info2, [val unsignedCharValue]);
1144 static void unsignedCharIvarSetFunc(void* info1, void* info2, id self, id val)
1146 unsigned char* ptr = (unsigned char*)((char*)self + (int)info2);
1147 *ptr = [val unsignedCharValue];
1151 /* ACCESS to keys of short type. */
1153 static id shortMethodGetFunc(void* info1, void* info2, id self)
1155 short (*fptr)(id, SEL) = (short(*)(id, SEL))info1;
1156 short val = fptr(self, (SEL)info2);
1157 return [NumberClass numberWithShort:val];
1160 static id shortIvarGetFunc(void* info1, void* info2, id self)
1162 short* ptr = (short*)((char*)self + (int)info2);
1163 return [NumberClass numberWithShort:*ptr];
1166 static void shortMethodSetFunc(void* info1, void* info2, id self, id val)
1168 void (*fptr)(id, SEL, short) = (void(*)(id, SEL, short))info1;
1169 fptr(self, (SEL)info2, [val shortValue]);
1172 static void shortIvarSetFunc(void* info1, void* info2, id self, id val)
1174 short* ptr = (short*)((char*)self + (int)info2);
1175 *ptr = [val shortValue];
1179 /* ACCESS to keys of unsigned short type. */
1181 static id unsignedShortMethodGetFunc(void* info1, void* info2, id self)
1183 unsigned short (*fptr)(id, SEL) = (unsigned short(*)(id, SEL))info1;
1184 unsigned short val = fptr(self, (SEL)info2);
1185 return [NumberClass numberWithUnsignedShort:val];
1188 static id unsignedShortIvarGetFunc(void* info1, void* info2, id self)
1190 unsigned short* ptr = (unsigned short*)((char*)self + (int)info2);
1191 return [NumberClass numberWithUnsignedShort:*ptr];
1194 static void unsignedShortMethodSetFunc(void* info1, void* info2, id self, id val)
1196 void (*fptr)(id, SEL, unsigned short) = (void(*)(id, SEL, unsigned short))info1;
1197 fptr(self, (SEL)info2, [val unsignedShortValue]);
1200 static void unsignedShortIvarSetFunc(void* info1, void* info2, id self, id val)
1202 unsigned short* ptr = (unsigned short*)((char*)self + (int)info2);
1203 *ptr = [val unsignedShortValue];
1207 /* ACCESS to keys of int type. */
1209 static id intMethodGetFunc(void* info1, void* info2, id self)
1211 int (*fptr)(id, SEL) = (int(*)(id, SEL))info1;
1212 int val = fptr(self, (SEL)info2);
1213 return [NumberClass numberWithInt:val];
1216 static id intIvarGetFunc(void* info1, void* info2, id self)
1218 int* ptr = (int*)((char*)self + (int)info2);
1219 return [NumberClass numberWithInt:*ptr];
1222 static void intMethodSetFunc(void* info1, void* info2, id self, id val)
1224 void (*fptr)(id, SEL, int) = (void(*)(id, SEL, int))info1;
1225 fptr(self, (SEL)info2, [val intValue]);
1228 static void intIvarSetFunc(void* info1, void* info2, id self, id val)
1230 int* ptr = (int*)((char*)self + (int)info2);
1231 *ptr = [val intValue];
1235 /* ACCESS to keys of unsigned int type. */
1237 static id unsignedIntMethodGetFunc(void* info1, void* info2, id self)
1239 unsigned int (*fptr)(id, SEL) = (unsigned int(*)(id, SEL))info1;
1240 unsigned int val = fptr(self, (SEL)info2);
1241 return [NumberClass numberWithUnsignedInt:val];
1244 static id unsignedIntIvarGetFunc(void* info1, void* info2, id self)
1246 unsigned int* ptr = (unsigned int*)((char*)self + (int)info2);
1247 return [NumberClass numberWithUnsignedInt:*ptr];
1250 static void unsignedIntMethodSetFunc(void* info1, void* info2, id self, id val)
1252 void (*fptr)(id, SEL, unsigned int) = (void(*)(id, SEL, unsigned int))info1;
1253 fptr(self, (SEL)info2, [val unsignedIntValue]);
1256 static void unsignedIntIvarSetFunc(void* info1, void* info2, id self, id val)
1258 unsigned int* ptr = (unsigned int*)((char*)self + (int)info2);
1259 *ptr = [val unsignedIntValue];
1263 /* ACCESS to keys of long type. */
1265 static id longMethodGetFunc(void* info1, void* info2, id self)
1267 long (*fptr)(id, SEL) = (long(*)(id, SEL))info1;
1268 long val = fptr(self, (SEL)info2);
1269 return [NumberClass numberWithLong:val];
1272 static id longIvarGetFunc(void* info1, void* info2, id self)
1274 long* ptr = (long*)((char*)self + (int)info2);
1275 return [NumberClass numberWithLong:*ptr];
1278 static void longMethodSetFunc(void* info1, void* info2, id self, id val)
1280 void (*fptr)(id, SEL, long) = (void(*)(id, SEL, long))info1;
1281 fptr(self, (SEL)info2, [val longValue]);
1284 static void longIvarSetFunc(void* info1, void* info2, id self, id val)
1286 long* ptr = (long*)((char*)self + (int)info2);
1287 *ptr = [val longValue];
1291 /* unsigned long type */
1293 static id unsignedLongMethodGetFunc(void* info1, void* info2, id self) {
1294 unsigned long (*fptr)(id, SEL) = (unsigned long(*)(id, SEL))info1;
1295 unsigned long val = fptr(self, (SEL)info2);
1296 return [NumberClass numberWithUnsignedLong:val];
1299 static id unsignedLongIvarGetFunc(void* info1, void* info2, id self) {
1300 unsigned long* ptr = (unsigned long*)((char*)self + (int)info2);
1301 return [NumberClass numberWithUnsignedLong:*ptr];
1304 static void unsignedLongMethodSetFunc(void* info1, void* info2, id self, id val) {
1305 void (*fptr)(id, SEL, unsigned long) = (void(*)(id, SEL, unsigned long))info1;
1306 fptr(self, (SEL)info2, [val unsignedLongValue]);
1309 static void unsignedLongIvarSetFunc(void* info1, void* info2, id self, id val) {
1310 unsigned long* ptr = (unsigned long*)((char*)self + (int)info2);
1311 *ptr = [val unsignedLongValue];
1315 /* long long type */
1317 static id longLongMethodGetFunc(void* info1, void* info2, id self) {
1318 long long (*fptr)(id, SEL) = (long long(*)(id, SEL))info1;
1319 long long val = fptr(self, (SEL)info2);
1320 return [NumberClass numberWithLongLong:val];
1323 static id longLongIvarGetFunc(void* info1, void* info2, id self) {
1324 long long* ptr = (long long*)((char*)self + (int)info2);
1325 return [NumberClass numberWithLongLong:*ptr];
1328 static void longLongMethodSetFunc(void* info1, void* info2, id self, id val) {
1329 void (*fptr)(id, SEL, long long) = (void(*)(id, SEL, long long))info1;
1330 fptr(self, (SEL)info2, [val longLongValue]);
1333 static void longLongIvarSetFunc(void* info1, void* info2, id self, id val) {
1334 long long* ptr = (long long*)((char*)self + (int)info2);
1335 *ptr = [val longLongValue];
1339 /* unsigned long long type */
1341 static id unsignedLongLongMethodGetFunc(void* info1, void* info2, id self) {
1342 unsigned long long (*fptr)(id, SEL) = (unsigned long long(*)(id, SEL))info1;
1343 unsigned long long val = fptr(self, (SEL)info2);
1344 return [NumberClass numberWithUnsignedLongLong:val];
1347 static id unsignedLongLongIvarGetFunc(void* info1, void* info2, id self) {
1348 unsigned long long* ptr = (unsigned long long*)((char*)self + (int)info2);
1349 return [NumberClass numberWithUnsignedLongLong:*ptr];
1352 static void unsignedLongLongMethodSetFunc(void* info1, void* info2, id self, id val) {
1353 void (*fptr)(id, SEL, unsigned long long) = (void(*)(id, SEL, unsigned long long))info1;
1354 fptr(self, (SEL)info2, [val unsignedLongLongValue]);
1357 static void unsignedLongLongIvarSetFunc(void* info1, void* info2, id self, id val) {
1358 unsigned long long* ptr = (unsigned long long*)((char*)self + (int)info2);
1359 *ptr = [val unsignedLongLongValue];
1365 static id floatMethodGetFunc(void* info1, void* info2, id self) {
1366 float (*fptr)(id, SEL) = (float(*)(id, SEL))info1;
1367 float val = fptr(self, (SEL)info2);
1368 return [NumberClass numberWithFloat:val];
1371 static id floatIvarGetFunc(void* info1, void* info2, id self) {
1372 float* ptr = (float*)((char*)self + (int)info2);
1373 return [NumberClass numberWithFloat:*ptr];
1376 static void floatMethodSetFunc(void* info1, void* info2, id self, id val) {
1377 void (*fptr)(id, SEL, float) = (void(*)(id, SEL, float))info1;
1378 fptr(self, (SEL)info2, [val floatValue]);
1381 static void floatIvarSetFunc(void* info1, void* info2, id self, id val) {
1382 float* ptr = (float*)((char*)self + (int)info2);
1383 *ptr = [val floatValue];
1389 static id doubleMethodGetFunc(void* info1, void* info2, id self) {
1390 double (*fptr)(id, SEL) = (double(*)(id, SEL))info1;
1391 double val = fptr(self, (SEL)info2);
1392 return [NumberClass numberWithDouble:val];
1395 static id doubleIvarGetFunc(void* info1, void* info2, id self) {
1396 double* ptr = (double*)((char*)self + (int)info2);
1397 return [NumberClass numberWithDouble:*ptr];
1400 static void doubleMethodSetFunc(void* info1, void* info2, id self, id val) {
1401 void (*fptr)(id, SEL, double) = (void(*)(id, SEL, double))info1;
1402 fptr(self, (SEL)info2, [val doubleValue]);
1405 static void doubleIvarSetFunc(void* info1, void* info2, id self, id val) {
1406 double* ptr = (double*)((char*)self + (int)info2);
1407 *ptr = [val doubleValue];
1410 #else /* NeXT_Foundation_LIBRARY */
1412 @implementation NSArray(EOKeyValueCoding)
1414 - (id)computeSumForKey:(NSString *)_key {
1415 unsigned i, cc = [self count];
1416 id (*objAtIdx)(id, SEL, unsigned int);
1419 if (cc == 0) return [NSNumber numberWithDouble:0.0];
1421 objAtIdx = (void*)[self methodForSelector:@selector(objectAtIndex:)];
1423 for (i = 0, sum = 0.0; i < cc; i++) {
1426 o = objAtIdx(self, @selector(objectAtIndex:), i);
1427 sum += [o doubleValue];
1429 return [NSNumber numberWithDouble:sum];
1432 - (id)computeAvgForKey:(NSString *)_key {
1433 unsigned i, cc = [self count];
1434 id (*objAtIdx)(id, SEL, unsigned int);
1437 if (cc == 0) return [NSNumber numberWithDouble:0.0];
1439 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
1441 for (i = 0, sum = 0.0; i < cc; i++) {
1444 o = objAtIdx(self, @selector(objectAtIndex:), i);
1446 sum += [o doubleValue];
1448 return [NSNumber numberWithDouble:(sum / (double)cc)];
1451 - (id)computeCountForKey:(NSString *)_key {
1452 return [NSNumber numberWithUnsignedInt:[self count]];
1455 - (id)computeMaxForKey:(NSString *)_key {
1456 unsigned i, cc = [self count];
1457 id (*objAtIdx)(id, SEL, unsigned int);
1460 if (cc == 0) return nil;
1462 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
1464 max = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
1465 for (i = 1; i < cc; i++) {
1468 ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
1469 if (ov > max) max = ov;
1471 return [NSNumber numberWithDouble:max];
1474 - (id)computeMinForKey:(NSString *)_key {
1475 unsigned i, cc = [self count];
1476 id (*objAtIdx)(id, SEL, unsigned int);
1479 if (cc == 0) return nil;
1481 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
1483 min = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
1484 for (i = 1; i < cc; i++) {
1487 ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
1488 if (ov < min) min = ov;
1490 return [NSNumber numberWithDouble:min];
1493 - (id)valueForKey:(NSString *)_key {
1494 if (null == nil) null = [[EONull null] retain];
1496 if ([_key hasPrefix:@"@"]) {
1497 /* process a computed function */
1500 unsigned keyLen = [_key cStringLength];
1504 kbuf = malloc(keyLen + 1);
1505 buf = malloc(keyLen + 16);
1506 [_key getCString:kbuf];
1509 strcpy(buf, "compute"); bufPtr += 7;
1510 *bufPtr = toupper(keyStr[1]); bufPtr++;
1511 strncpy(&(buf[8]), &(keyStr[2]), keyLen - 2); bufPtr += (keyLen - 2);
1512 strcpy(bufPtr, "ForKey:");
1513 if (kbuf) free(kbuf);
1516 sel = sel_getUid(buf);
1518 sel = sel_get_any_uid(buf);
1522 return sel != NULL ? [self performSelector:sel withObject:_key] : nil;
1525 /* process the _key in a map function */
1526 unsigned i, cc = [self count];
1529 id (*objAtIdx)(id, SEL, unsigned int);
1532 if ([_key isEqualToString:@"count"]) {
1533 NSLog(@"WARNING(%s): USED -valueForKey(@\"count\") ON NSArray, YOU"
1534 @"PROBABLY WANT TO USE @count INSTEAD !",
1535 __PRETTY_FUNCTION__);
1536 return [self valueForKey:@"@count"];
1540 if (cc == 0) return [NSArray array];
1542 objects = calloc(cc + 2, sizeof(id));
1543 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
1545 for (i = 0; i < cc; i++) {
1548 o = [objAtIdx(self, @selector(objectAtIndex:), i) valueForKey:_key];
1549 objects[i] = o ? o : null;
1552 result = [NSArray arrayWithObjects:objects count:cc];
1553 if (objects) free(objects);
1558 @end /* NSArray(EOKeyValueCoding) */
1560 #endif /* !NeXT_Foundation_LIBRARY */