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 "EOKeyValueCoding.h"
27 # include <objc/objc-api.h>
28 # include <objc/encoding.h>
31 static EONull *null = nil;
33 #if !NeXT_Foundation_LIBRARY
35 static id idMethodGetFunc(void* info1, void* info2, id self);
36 static id idIvarGetFunc(void* info1, void* info2, id self);
37 static void idMethodSetFunc(void* info1, void* info2, id self, id val);
38 static void idIvarSetFunc(void* info1, void* info2, id self, id val);
39 static id charMethodGetFunc(void* info1, void* info2, id self);
40 static id charIvarGetFunc(void* info1, void* info2, id self);
41 static void charMethodSetFunc(void* info1, void* info2, id self, id val);
42 static void charIvarSetFunc(void* info1, void* info2, id self, id val);
43 static id unsignedCharMethodGetFunc(void* info1, void* info2, id self);
44 static id unsignedCharIvarGetFunc(void* info1, void* info2, id self);
45 static void unsignedCharMethodSetFunc(void* info1, void* info2, id self, id val);
46 static void unsignedCharIvarSetFunc(void* info1, void* info2, id self, id val);
47 static id shortMethodGetFunc(void* info1, void* info2, id self);
48 static id shortIvarGetFunc(void* info1, void* info2, id self);
49 static void shortMethodSetFunc(void* info1, void* info2, id self, id val);
50 static void shortIvarSetFunc(void* info1, void* info2, id self, id val);
51 static id unsignedShortMethodGetFunc(void* info1, void* info2, id self);
52 static id unsignedShortIvarGetFunc(void* info1, void* info2, id self);
53 static void unsignedShortMethodSetFunc(void* info1, void* info2, id self, id val);
54 static void unsignedShortIvarSetFunc(void* info1, void* info2, id self, id val);
55 static id intMethodGetFunc(void* info1, void* info2, id self);
56 static id intIvarGetFunc(void* info1, void* info2, id self);
57 static void intMethodSetFunc(void* info1, void* info2, id self, id val);
58 static void intIvarSetFunc(void* info1, void* info2, id self, id val);
59 static id unsignedIntMethodGetFunc(void* info1, void* info2, id self);
60 static id unsignedIntIvarGetFunc(void* info1, void* info2, id self);
61 static void unsignedIntMethodSetFunc(void* info1, void* info2, id self, id val);
62 static void unsignedIntIvarSetFunc(void* info1, void* info2, id self, id val);
63 static id longMethodGetFunc(void* info1, void* info2, id self);
64 static id longIvarGetFunc(void* info1, void* info2, id self);
65 static void longMethodSetFunc(void* info1, void* info2, id self, id val);
66 static void longIvarSetFunc(void* info1, void* info2, id self, id val);
67 static id unsignedLongMethodGetFunc(void* info1, void* info2, id self);
68 static id unsignedLongIvarGetFunc(void* info1, void* info2, id self);
69 static void unsignedLongMethodSetFunc(void* info1, void* info2, id self, id val);
70 static void unsignedLongIvarSetFunc(void* info1, void* info2, id self, id val);
71 static id longLongMethodGetFunc(void* info1, void* info2, id self);
72 static id longLongIvarGetFunc(void* info1, void* info2, id self);
73 static void longLongMethodSetFunc(void* info1, void* info2, id self, id val);
74 static void longLongIvarSetFunc(void* info1, void* info2, id self, id val);
75 static id unsignedLongLongMethodGetFunc(void* info1, void* info2, id self);
76 static id unsignedLongLongIvarGetFunc(void* info1, void* info2, id self);
77 static void unsignedLongLongMethodSetFunc(void* info1, void* info2, id self, id val);
78 static void unsignedLongLongIvarSetFunc(void* info1, void* info2, id self, id val);
79 static id floatMethodGetFunc(void* info1, void* info2, id self);
80 static id floatIvarGetFunc(void* info1, void* info2, id self);
81 static void floatMethodSetFunc(void* info1, void* info2, id self, id val);
82 static void floatIvarSetFunc(void* info1, void* info2, id self, id val);
83 static id doubleMethodGetFunc(void* info1, void* info2, id self);
84 static id doubleIvarGetFunc(void* info1, void* info2, id self);
85 static void doubleMethodSetFunc(void* info1, void* info2, id self, id val);
86 static void doubleIvarSetFunc(void* info1, void* info2, id self, id val);
88 static Class NumberClass = Nil;
89 static Class StringClass = Nil;
91 @implementation NSObject(EOKeyValueCoding)
97 typedef struct _KeyValueMethod {
102 typedef struct _GetKeyValueBinding {
103 /* info1, info2, self */
104 id (*access)(void *, void *, id);
107 } GetKeyValueBinding;
109 typedef struct _SetKeyValueBinding {
110 /* info1, info2, self, val */
111 void (*access)(void *, void *, id, id);
114 } SetKeyValueBinding;
120 static NSMapTable* getValueBindings = NULL;
121 static NSMapTable* setValueBindings = NULL;
122 static BOOL keyValueDebug = NO;
123 static BOOL keyValueInit = NO;
129 static GetKeyValueBinding* newGetBinding(NSString* key, id instance)
131 GetKeyValueBinding *ret = NULL;
134 id (*fptr)(void*, void*, id) = NULL;
136 // Lookup method name [-(type)key]
138 Class class = [instance class];
139 unsigned clen = [key cStringLength];
143 struct objc_method* mth;
145 cbuf = malloc(clen + 1);
146 [key getCString:cbuf]; cbuf[clen] = '\0';
148 sel = sel_get_any_uid(ckey);
150 if (sel && (mth = class_get_instance_method(class, sel)) &&
151 method_get_number_of_arguments(mth) == 2) {
152 switch(*objc_skip_type_qualifiers(mth->method_types)) {
154 fptr = (id (*)(void*, void*, id))idMethodGetFunc;
157 fptr = (id (*)(void*, void*, id))charMethodGetFunc;
160 fptr = (id (*)(void*, void*, id))unsignedCharMethodGetFunc;
163 fptr = (id (*)(void*, void*, id))shortMethodGetFunc;
166 fptr = (id (*)(void*, void*, id))unsignedShortMethodGetFunc;
169 fptr = (id (*)(void*, void*, id))intMethodGetFunc;
172 fptr = (id (*)(void*, void*, id))unsignedIntMethodGetFunc;
175 fptr = (id (*)(void*, void*, id))longMethodGetFunc;
178 fptr = (id (*)(void*, void*, id))unsignedLongMethodGetFunc;
181 fptr = (id (*)(void*, void*, id))longLongMethodGetFunc;
184 fptr = (id (*)(void*, void*, id))unsignedLongLongMethodGetFunc;
187 fptr = (id (*)(void*, void*, id))floatMethodGetFunc;
190 fptr = (id (*)(void*, void*, id))doubleMethodGetFunc;
194 info1 = (void*)(mth->method_imp);
195 info2 = (void*)(mth->method_name);
198 if (cbuf) free(cbuf);
203 Class class = [instance class];
209 clen = [key cStringLength];
210 cbuf = malloc(clen + 1);
211 [key getCString:cbuf]; cbuf[clen] = '\0';
215 for (i = 0; class->ivars && i < class->ivars->ivar_count; i++) {
216 if (!Strcmp(ckey, class->ivars->ivar_list[i].ivar_name)) {
217 switch(*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type)) {
219 fptr = (id (*)(void*, void*, id))idIvarGetFunc;
222 fptr = (id (*)(void*, void*, id))charIvarGetFunc;
225 fptr = (id (*)(void*, void*, id))unsignedCharIvarGetFunc;
228 fptr = (id (*)(void*, void*, id))shortIvarGetFunc;
231 fptr = (id (*)(void*, void*, id))unsignedShortIvarGetFunc;
234 fptr = (id (*)(void*, void*, id))intIvarGetFunc;
237 fptr = (id (*)(void*, void*, id))unsignedIntIvarGetFunc;
240 fptr = (id (*)(void*, void*, id))longIvarGetFunc;
243 fptr = (id (*)(void*, void*, id))unsignedLongIvarGetFunc;
246 fptr = (id (*)(void*, void*, id))longLongIvarGetFunc;
249 fptr = (id (*)(void*, void*, id))unsignedLongLongIvarGetFunc;
252 fptr = (id (*)(void*, void*, id))floatIvarGetFunc;
255 fptr = (id (*)(void*, void*, id))doubleIvarGetFunc;
259 info2 = (void*)(class->ivars->ivar_list[i].ivar_offset);
264 class = class->super_class;
266 if (cbuf) free(cbuf);
269 // Make binding and insert into map
271 KeyValueMethod *mkey;
272 GetKeyValueBinding *bin;
274 mkey = Malloc(sizeof(KeyValueMethod));
275 bin = Malloc(sizeof(GetKeyValueBinding));
276 mkey->key = [key copy];
277 mkey->class = [instance class];
283 NSMapInsert(getValueBindings, mkey, bin);
287 // If no way to access value warn
288 if (!ret && keyValueDebug)
289 NSLog(@"cannnot get key `%@' for instance of class `%@'",
290 key, NSStringFromClass([instance class]));
295 static SetKeyValueBinding* newSetBinding(NSString* key, id instance)
297 SetKeyValueBinding *ret = NULL;
300 void (*fptr)(void*, void*, id, id) = NULL;
302 // Lookup method name [-(void)setKey:(type)arg]
304 Class class = [instance class];
305 unsigned clen = [key cStringLength];
309 struct objc_method* mth;
310 char sname[clen + 7];
312 cbuf = malloc(clen + 1);
313 [key getCString:cbuf]; cbuf[clen] = '\0';
316 // Make sel from name
317 Strcpy(sname, "set");
320 sname[3] = islower((int)sname[3]) ? toupper((int)sname[3]) : sname[3];
321 sel = sel_get_any_uid(sname);
323 if (sel && (mth = class_get_instance_method(class, sel)) &&
324 method_get_number_of_arguments(mth) == 3 &&
325 *objc_skip_type_qualifiers(mth->method_types) == _C_VOID) {
326 char* argType = (char*)(mth->method_types);
328 argType = (char*)objc_skip_argspec(argType); // skip return
329 argType = (char*)objc_skip_argspec(argType); // skip self
330 argType = (char*)objc_skip_argspec(argType); // skip SEL
332 switch(*objc_skip_type_qualifiers(argType)) {
334 fptr = (void (*)(void*, void*, id, id))idMethodSetFunc;
337 fptr = (void (*)(void*, void*, id, id))charMethodSetFunc;
340 fptr = (void (*)(void*, void*, id, id))unsignedCharMethodSetFunc;
343 fptr = (void (*)(void*, void*, id, id))shortMethodSetFunc;
346 fptr = (void (*)(void*, void*, id, id))unsignedShortMethodSetFunc;
349 fptr = (void (*)(void*, void*, id, id))intMethodSetFunc;
352 fptr = (void (*)(void*, void*, id, id))unsignedIntMethodSetFunc;
355 fptr = (void (*)(void*, void*, id, id))longMethodSetFunc;
358 fptr = (void (*)(void*, void*, id, id))unsignedLongMethodSetFunc;
361 fptr = (void (*)(void*, void*, id, id))longLongMethodSetFunc;
364 fptr = (void (*)(void*, void*, id, id))unsignedLongLongMethodSetFunc;
367 fptr = (void (*)(void*, void*, id, id))floatMethodSetFunc;
370 fptr = (void (*)(void*, void*, id, id))doubleMethodSetFunc;
374 info1 = (void*)(mth->method_imp);
375 info2 = (void*)(mth->method_name);
378 if (cbuf) free(cbuf);
382 Class class = [instance class];
383 unsigned clen = [key cStringLength];
388 cbuf = malloc(clen + 1);
389 [key getCString:cbuf]; cbuf[clen] = '\0';
393 for (i = 0; class->ivars && i < class->ivars->ivar_count; i++) {
394 if (!Strcmp(ckey, class->ivars->ivar_list[i].ivar_name)) {
395 switch(*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type)) {
397 fptr = (void (*)(void*, void*, id, id))idIvarSetFunc;
400 fptr = (void (*)(void*, void*, id, id))charIvarSetFunc;
403 fptr = (void (*)(void*, void*, id, id))unsignedCharIvarSetFunc;
406 fptr = (void (*)(void*, void*, id, id))shortIvarSetFunc;
409 fptr = (void (*)(void*, void*, id, id))unsignedShortIvarSetFunc;
412 fptr = (void (*)(void*, void*, id, id))intIvarSetFunc;
415 fptr = (void (*)(void*, void*, id, id))unsignedIntIvarSetFunc;
418 fptr = (void (*)(void*, void*, id, id))longIvarSetFunc;
421 fptr = (void (*)(void*, void*, id, id))unsignedLongIvarSetFunc;
424 fptr = (void (*)(void*, void*, id, id))longLongIvarSetFunc;
427 fptr = (void (*)(void*, void*, id, id))unsignedLongLongIvarSetFunc;
430 fptr = (void (*)(void*, void*, id, id))floatIvarSetFunc;
433 fptr = (void (*)(void*, void*, id, id))doubleIvarSetFunc;
437 info2 = (void*)(class->ivars->ivar_list[i].ivar_offset);
442 class = class->super_class;
444 if (cbuf) free(cbuf);
447 // Make binding and insert into map
449 KeyValueMethod *mkey;
450 SetKeyValueBinding *bin;
452 mkey = Malloc(sizeof(KeyValueMethod));
453 bin = Malloc(sizeof(SetKeyValueBinding));
454 mkey->key = [key copy];
455 mkey->class = [instance class];
461 NSMapInsert(setValueBindings, mkey, bin);
464 // If no way to access value warn
465 if (!ret && keyValueDebug)
466 NSLog(@"cannnot set key `%@' for instance of class `%@'",
467 key, NSStringFromClass([instance class]));
473 * MapTable initialization
476 static unsigned keyValueMapHash(NSMapTable* table, KeyValueMethod* map) {
477 return [map->key hash] + (((int)(map->class)) >> 4);
480 static BOOL keyValueMapCompare(NSMapTable* table,
481 KeyValueMethod* map1, KeyValueMethod* map2)
483 return (map1->class == map2->class) && [map1->key isEqual:map2->key];
486 static void mapRetainNothing(NSMapTable* table, KeyValueMethod* map) {
489 static void keyValueMapKeyRelease(NSMapTable* table, KeyValueMethod* map) {
494 static void keyValueMapValRelease(NSMapTable* table, void* map) {
498 static NSString* keyValueMapDescribe(NSMapTable* table, KeyValueMethod* map) {
499 if (StringClass == Nil) StringClass = [NSString class];
500 return [StringClass stringWithFormat:@"%@:%@",
501 NSStringFromClass(map->class), map->key];
504 static NSString* describeBinding(NSMapTable* table, GetKeyValueBinding* bin) {
505 if (StringClass == Nil) StringClass = [NSString class];
506 return [StringClass stringWithFormat:@"%08x:%08x", bin->info1, bin->info2];
509 static NSMapTableKeyCallBacks keyValueKeyCallbacks = {
510 (unsigned(*)(NSMapTable *, const void *))keyValueMapHash,
511 (BOOL(*)(NSMapTable *, const void *, const void *))keyValueMapCompare,
512 (void (*)(NSMapTable *, const void *anObject))mapRetainNothing,
513 (void (*)(NSMapTable *, void *anObject))keyValueMapKeyRelease,
514 (NSString *(*)(NSMapTable *, const void *))keyValueMapDescribe,
518 const NSMapTableValueCallBacks keyValueValueCallbacks = {
519 (void (*)(NSMapTable *, const void *))mapRetainNothing,
520 (void (*)(NSMapTable *, void *))keyValueMapValRelease,
521 (NSString *(*)(NSMapTable *, const void *))describeBinding
524 static void initKeyValueBindings(void)
526 getValueBindings = NSCreateMapTable(keyValueKeyCallbacks,
527 keyValueValueCallbacks, 31);
528 setValueBindings = NSCreateMapTable(keyValueKeyCallbacks,
529 keyValueValueCallbacks, 31);
537 static inline void removeAllBindings(void) {
538 NSResetMapTable(getValueBindings);
539 NSResetMapTable(setValueBindings);
542 static inline id getValue(NSString* key, id instance) {
543 KeyValueMethod mkey = { key, [instance class] };
544 GetKeyValueBinding *bin;
547 if (NumberClass == Nil)
548 NumberClass = [NSNumber class];
552 initKeyValueBindings();
554 // Get existing binding
555 bin = (GetKeyValueBinding *)NSMapGet(getValueBindings, &mkey);
557 // Create new binding
559 bin = newGetBinding(key, instance);
561 // Get value if binding is ok
563 value = bin->access(bin->info1, bin->info2, instance);
568 static inline BOOL setValue(NSString* key, id instance, id value)
570 KeyValueMethod mkey = {key, [instance class]};
571 SetKeyValueBinding* bin;
573 if (NumberClass == Nil)
574 NumberClass = [NSNumber class];
578 initKeyValueBindings();
580 // Get existing binding
581 bin = (SetKeyValueBinding *)NSMapGet(setValueBindings, &mkey);
583 // Create new binding
585 bin = newSetBinding(key, instance);
587 // Get value if binding is ok
589 bin->access(bin->info1, bin->info2, instance, value);
591 return (bin != NULL);
594 + (BOOL)accessInstanceVariablesDirectly {
598 - (void)handleTakeValue:(id)_value forUnboundKey:(NSString *)_key {
601 ui = [NSDictionary dictionaryWithObjectsAndKeys:
602 self, @"EOTargetObjectUserInfoKey",
604 @"EOTargetObjectClassUserInfoKey",
605 _key, @"EOUnknownUserInfoKey",
607 [[NSException exceptionWithName:@"EOUnknownKeyException"
608 reason:@"called -takeValue:forKey: with unknown key"
612 - (id)handleQueryWithUnboundKey:(NSString *)_key {
615 ui = [NSDictionary dictionaryWithObjectsAndKeys:
616 self, @"EOTargetObjectUserInfoKey",
617 _key, @"EOUnknownUserInfoKey",
619 [[NSException exceptionWithName:@"EOUnknownKeyException"
620 reason:@"called -valueForKey: with unknown key"
625 - (void)unableToSetNullForKey:(NSString *)_key {
626 [NSException raise:@"NSInvalidArgumentException"
628 @"EOKeyValueCoding cannot set EONull value for key %@,"
629 @"in instance of %@ class.",
630 _key, NSStringFromClass([self class])];
633 + (void)flushAllKeyBindings {
636 - (void)flushKeyBindings {
641 - (void)setKeyValueCodingWarnings:(BOOL)aFlag {
642 keyValueDebug = aFlag;
645 - (void)takeValuesFromDictionary:(NSDictionary *)dictionary {
646 NSEnumerator *keyEnum;
649 if (null == nil) null = [EONull null];
650 keyEnum = [dictionary keyEnumerator];
652 while ((key = [keyEnum nextObject])) {
655 value = [dictionary objectForKey:key];
657 /* automagically convert EONull to nil */
658 if (value == null) value = nil;
660 [self takeValue:value forKey:key];
662 #if 0 // this doesn't support overridden methods ...
663 if (!setValue(key, self, value)) {
664 [self handleTakeValue:value forUnboundKey:key];
670 - (NSDictionary *)valuesForKeys:(NSArray *)keys {
671 static Class NSDictionaryClass = Nil;
672 int n = [keys count];
674 if (NSDictionaryClass == Nil)
675 NSDictionaryClass = [NSDictionary class];
677 null = [EONull null];
680 return [NSDictionaryClass dictionary];
685 key = [keys objectAtIndex:0];
686 //value = getValue(key, self);
687 value = [self valueForKey:key];
689 /* automagically convert 'nil' to EONull */
690 if (value == nil) value = null;
692 return [NSDictionaryClass dictionaryWithObject:value forKey:key];
699 for (i = 0; i < n; i++) {
703 key = [keys objectAtIndex:i];
704 //val = getValue(key, self);
705 val = [self valueForKey:key];
707 /* automagically convert 'nil' to EONull */
708 if (val == nil) val = null;
714 return [NSDictionaryClass dictionaryWithObjects:newVals
720 - (void)takeValue:(id)_value forKey:(NSString *)_key {
721 if (!setValue(_key, self, _value)) {
722 //NSLog(@"ERROR(%s): couldn't take value for key %@", key);
723 [self handleTakeValue:_value forUnboundKey:_key];
727 - (id)valueForKey:(NSString *)key {
730 if ((val = getValue(key, self)))
738 + (BOOL)useStoredAccessor {
742 - (void)takeStoredValue:(id)_value forKey:(NSString *)_key {
743 if ([[self class] useStoredAccessor]) {
746 /* this should be different */
748 ok = setValue(_key, self, _value);
749 if (!ok) [self handleTakeValue:_value forUnboundKey:_key];
752 [self takeValue:_value forKey:_key];
755 - (id)storedValueForKey:(NSString *)_key {
756 if ([[self class] useStoredAccessor]) {
759 /* this should be different */
761 if ((val = getValue(_key, self)))
764 /* val = [self handleQueryWithUnboundKey:_key] */
769 return [self valueForKey:_key];
772 @end /* NSObject(EOKeyValueCoding) */
774 @implementation NSObject(EOKeyPathValueCoding)
776 - (void)takeValue:(id)_value forKeyPath:(NSString *)_keyPath {
781 keyPath = [_keyPath componentsSeparatedByString:@"."];
782 count = [keyPath count];
785 [self takeValue:_value forKey:_keyPath];
789 for (i = 0; i < (count - 1) ; i++) {
790 if ((target = [target valueForKey:[keyPath objectAtIndex:i]]) == nil)
795 [target takeValue:_value forKey:[keyPath lastObject]];
798 - (id)valueForKeyPath:(NSString *)_keyPath {
800 const unsigned char *buf;
801 unsigned int i, start, len;
804 if ((len = [_keyPath cStringLength]) == 0)
805 return [self valueForKey:_keyPath];
807 if (StringClass == Nil) StringClass = [NSString class];
810 buf = (const unsigned char *)[_keyPath cString];
811 if (index((const char *)buf, '.') == NULL)
812 /* no point contained .. */
813 return [self valueForKey:_keyPath];
815 for (i = start = 0; i < len; i++) {
821 ? [StringClass stringWithCString:(const char *)
822 &(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:(const char *)
837 &(buf[start]) length:(i - start)]
839 return [value valueForKey:key];
842 /* naive implementation */
843 NSEnumerator *keyPath;
848 keyPath = [[_keyPath componentsSeparatedByString:@"."] objectEnumerator];
849 while ((key = [keyPath nextObject]) && (value != nil))
850 value = [value valueForKey:key];
855 @end /* NSObject(EOKeyPathValueCoding) */
857 @implementation NSArray(EOKeyValueCoding)
859 - (id)computeSumForKey:(NSString *)_key {
860 unsigned i, cc = [self count];
861 id (*objAtIdx)(id, SEL, unsigned int);
864 if (cc == 0) return [NSNumber numberWithDouble:0.0];
866 objAtIdx = (void*)[self methodForSelector:@selector(objectAtIndex:)];
868 for (i = 0, sum = 0.0; i < cc; i++) {
871 o = objAtIdx(self, @selector(objectAtIndex:), i);
872 sum += [o doubleValue];
874 return [NSNumber numberWithDouble:sum];
877 - (id)computeAvgForKey:(NSString *)_key {
878 unsigned i, cc = [self count];
879 id (*objAtIdx)(id, SEL, unsigned int);
882 if (cc == 0) return [NSNumber numberWithDouble:0.0];
884 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
886 for (i = 0, sum = 0.0; i < cc; i++) {
889 o = objAtIdx(self, @selector(objectAtIndex:), i);
891 sum += [o doubleValue];
893 return [NSNumber numberWithDouble:(sum / (double)cc)];
896 - (id)computeCountForKey:(NSString *)_key {
897 return [NSNumber numberWithUnsignedInt:[self count]];
900 - (id)computeMaxForKey:(NSString *)_key {
901 unsigned i, cc = [self count];
902 id (*objAtIdx)(id, SEL, unsigned int);
905 if (cc == 0) return nil;
907 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
909 max = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
910 for (i = 1; i < cc; i++) {
913 ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
914 if (ov > max) max = ov;
916 return [NSNumber numberWithDouble:max];
919 - (id)computeMinForKey:(NSString *)_key {
920 unsigned i, cc = [self count];
921 id (*objAtIdx)(id, SEL, unsigned int);
924 if (cc == 0) return nil;
926 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
928 min = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
929 for (i = 1; i < cc; i++) {
932 ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
933 if (ov < min) min = ov;
935 return [NSNumber numberWithDouble:min];
938 - (id)valueForKey:(NSString *)_key {
939 if ([_key hasPrefix:@"@"]) {
940 /* process a computed function */
943 unsigned keyLen = [_key cStringLength];
947 kbuf = malloc(keyLen + 4);
948 buf = malloc(keyLen + 20);
949 [_key getCString:kbuf];
952 strcpy(buf, "compute"); bufPtr += 7;
953 *bufPtr = toupper(keyStr[1]); bufPtr++;
954 strncpy(&(buf[8]), &(keyStr[2]), keyLen - 2); bufPtr += (keyLen - 2);
955 strcpy(bufPtr, "ForKey:");
956 if (kbuf) free(kbuf);
958 sel = sel_get_any_uid(buf);
961 return sel != NULL ? [self performSelector:sel withObject:_key] : nil;
964 /* process the _key in a map function */
965 unsigned i, cc = [self count];
967 id (*objAtIdx)(id, SEL, unsigned int);
970 if ([_key isEqualToString:@"count"]) {
971 NSLog(@"WARNING(%s): USED -valueForKey(@\"count\") ON NSArray, YOU"
972 @"PROBABLY WANT TO USE @count INSTEAD !",
973 __PRETTY_FUNCTION__);
974 return [self valueForKey:@"@count"];
978 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
980 for (i = 0; i < cc; i++) {
983 o = [objAtIdx(self, @selector(objectAtIndex:), i) valueForKey:_key];
988 if (null == nil) null = [EONull null];
993 return [NSArray arrayWithObjects:objects count:cc];
997 @end /* NSArray(EOKeyValueCoding) */
999 @implementation NSDictionary(EOKeyValueCoding)
1001 - (NSDictionary *)valuesForKeys:(NSArray *)keys {
1002 int n = [keys count];
1005 return [NSDictionary dictionary];
1007 NSString *key = [keys objectAtIndex:0];
1009 return [NSDictionary dictionaryWithObject:[self objectForKey:key]
1013 NSMutableArray *newKeys, *newVals;
1016 newKeys = [NSMutableArray arrayWithCapacity:n];
1017 newVals = [NSMutableArray arrayWithCapacity:n];
1019 for (i = 0; i < n; i++) {
1020 id key = [keys objectAtIndex:i];
1021 id val = [self objectForKey:key];
1024 [newKeys addObject:key];
1025 [newVals addObject:val];
1029 return [NSDictionary dictionaryWithObjects:newVals forKeys:newKeys];
1033 - (void)takeValue:(id)_value forKey:(NSString *)_key {
1034 //#warning takeValue:forKey: is ignored in NSDictionaries !
1036 //[self handleTakeValue:_value forUnboundKey:_key];
1039 - (id)valueForKey:(NSString *)_key {
1042 if (_key == nil) // TODO: warn about nil key?
1044 if ((obj = [self objectForKey:_key]) == nil)
1047 if (null == nil) null = [[NSNull null] retain];
1054 @end /* NSDictionary(EOKeyValueCoding) */
1056 @implementation NSMutableDictionary(EOKeyValueCoding)
1058 - (void)takeValuesFromDictionary:(NSDictionary*)dictionary {
1059 [self addEntriesFromDictionary:dictionary];
1062 - (void)takeValue:(id)_value forKey:(NSString *)_key {
1063 if (_value == nil) _value = [NSNull null];
1064 [self setObject:_value forKey:_key];
1067 @end /* NSMutableDictionary(EOKeyValueCoding) */
1070 * Accessor functions
1073 /* ACCESS to keys of id type. */
1075 static id idMethodGetFunc(void* info1, void* info2, id self) {
1076 id (*fptr)(id, SEL) = (id(*)(id, SEL))info1;
1077 id val = fptr(self, (SEL)info2);
1080 static id idIvarGetFunc(void* info1, void* info2, id self) {
1081 id* ptr = (id*)((char*)self + (int)info2);
1085 static void idMethodSetFunc(void* info1, void* info2, id self, id val) {
1086 void (*fptr)(id, SEL, id) = (void(*)(id, SEL, id))info1;
1087 fptr(self, (SEL)info2, val);
1090 static void idIvarSetFunc(void* info1, void* info2, id self, id val)
1092 id* ptr = (id*)((char*)self + (int)info2);
1096 /* ACCESS to keys of char type. */
1098 static id charMethodGetFunc(void* info1, void* info2, id self)
1100 char (*fptr)(id, SEL) = (char(*)(id, SEL))info1;
1101 char val = fptr(self, (SEL)info2);
1102 return [NumberClass numberWithChar:val];
1105 static id charIvarGetFunc(void* info1, void* info2, id self)
1107 char* ptr = (char*)((char*)self + (int)info2);
1108 return [NumberClass numberWithChar:*ptr];
1111 static void charMethodSetFunc(void* info1, void* info2, id self, id val)
1113 void (*fptr)(id, SEL, char) = (void(*)(id, SEL, char))info1;
1114 fptr(self, (SEL)info2, [val charValue]);
1117 static void charIvarSetFunc(void* info1, void* info2, id self, id val)
1119 char* ptr = (char*)((char*)self + (int)info2);
1120 *ptr = [val charValue];
1124 /* ACCESS to keys of unsigned char type. */
1126 static id unsignedCharMethodGetFunc(void* info1, void* info2, id self)
1128 unsigned char (*fptr)(id, SEL) = (unsigned char(*)(id, SEL))info1;
1129 unsigned char val = fptr(self, (SEL)info2);
1130 return [NumberClass numberWithUnsignedChar:val];
1133 static id unsignedCharIvarGetFunc(void* info1, void* info2, id self)
1135 unsigned char* ptr = (unsigned char*)((char*)self + (int)info2);
1136 return [NumberClass numberWithUnsignedChar:*ptr];
1139 static void unsignedCharMethodSetFunc(void* info1, void* info2, id self, id val)
1141 void (*fptr)(id, SEL, unsigned char) = (void(*)(id, SEL, unsigned char))info1;
1142 fptr(self, (SEL)info2, [val unsignedCharValue]);
1145 static void unsignedCharIvarSetFunc(void* info1, void* info2, id self, id val)
1147 unsigned char* ptr = (unsigned char*)((char*)self + (int)info2);
1148 *ptr = [val unsignedCharValue];
1152 /* ACCESS to keys of short type. */
1154 static id shortMethodGetFunc(void* info1, void* info2, id self)
1156 short (*fptr)(id, SEL) = (short(*)(id, SEL))info1;
1157 short val = fptr(self, (SEL)info2);
1158 return [NumberClass numberWithShort:val];
1161 static id shortIvarGetFunc(void* info1, void* info2, id self)
1163 short* ptr = (short*)((char*)self + (int)info2);
1164 return [NumberClass numberWithShort:*ptr];
1167 static void shortMethodSetFunc(void* info1, void* info2, id self, id val)
1169 void (*fptr)(id, SEL, short) = (void(*)(id, SEL, short))info1;
1170 fptr(self, (SEL)info2, [val shortValue]);
1173 static void shortIvarSetFunc(void* info1, void* info2, id self, id val)
1175 short* ptr = (short*)((char*)self + (int)info2);
1176 *ptr = [val shortValue];
1180 /* ACCESS to keys of unsigned short type. */
1182 static id unsignedShortMethodGetFunc(void* info1, void* info2, id self)
1184 unsigned short (*fptr)(id, SEL) = (unsigned short(*)(id, SEL))info1;
1185 unsigned short val = fptr(self, (SEL)info2);
1186 return [NumberClass numberWithUnsignedShort:val];
1189 static id unsignedShortIvarGetFunc(void* info1, void* info2, id self)
1191 unsigned short* ptr = (unsigned short*)((char*)self + (int)info2);
1192 return [NumberClass numberWithUnsignedShort:*ptr];
1195 static void unsignedShortMethodSetFunc(void* info1, void* info2, id self, id val)
1197 void (*fptr)(id, SEL, unsigned short) = (void(*)(id, SEL, unsigned short))info1;
1198 fptr(self, (SEL)info2, [val unsignedShortValue]);
1201 static void unsignedShortIvarSetFunc(void* info1, void* info2, id self, id val)
1203 unsigned short* ptr = (unsigned short*)((char*)self + (int)info2);
1204 *ptr = [val unsignedShortValue];
1208 /* ACCESS to keys of int type. */
1210 static id intMethodGetFunc(void* info1, void* info2, id self)
1212 int (*fptr)(id, SEL) = (int(*)(id, SEL))info1;
1213 int val = fptr(self, (SEL)info2);
1214 return [NumberClass numberWithInt:val];
1217 static id intIvarGetFunc(void* info1, void* info2, id self)
1219 int* ptr = (int*)((char*)self + (int)info2);
1220 return [NumberClass numberWithInt:*ptr];
1223 static void intMethodSetFunc(void* info1, void* info2, id self, id val)
1225 void (*fptr)(id, SEL, int) = (void(*)(id, SEL, int))info1;
1226 fptr(self, (SEL)info2, [val intValue]);
1229 static void intIvarSetFunc(void* info1, void* info2, id self, id val)
1231 int* ptr = (int*)((char*)self + (int)info2);
1232 *ptr = [val intValue];
1236 /* ACCESS to keys of unsigned int type. */
1238 static id unsignedIntMethodGetFunc(void* info1, void* info2, id self)
1240 unsigned int (*fptr)(id, SEL) = (unsigned int(*)(id, SEL))info1;
1241 unsigned int val = fptr(self, (SEL)info2);
1242 return [NumberClass numberWithUnsignedInt:val];
1245 static id unsignedIntIvarGetFunc(void* info1, void* info2, id self)
1247 unsigned int* ptr = (unsigned int*)((char*)self + (int)info2);
1248 return [NumberClass numberWithUnsignedInt:*ptr];
1251 static void unsignedIntMethodSetFunc(void* info1, void* info2, id self, id val)
1253 void (*fptr)(id, SEL, unsigned int) = (void(*)(id, SEL, unsigned int))info1;
1254 fptr(self, (SEL)info2, [val unsignedIntValue]);
1257 static void unsignedIntIvarSetFunc(void* info1, void* info2, id self, id val)
1259 unsigned int* ptr = (unsigned int*)((char*)self + (int)info2);
1260 *ptr = [val unsignedIntValue];
1264 /* ACCESS to keys of long type. */
1266 static id longMethodGetFunc(void* info1, void* info2, id self)
1268 long (*fptr)(id, SEL) = (long(*)(id, SEL))info1;
1269 long val = fptr(self, (SEL)info2);
1270 return [NumberClass numberWithLong:val];
1273 static id longIvarGetFunc(void* info1, void* info2, id self)
1275 long* ptr = (long*)((char*)self + (int)info2);
1276 return [NumberClass numberWithLong:*ptr];
1279 static void longMethodSetFunc(void* info1, void* info2, id self, id val)
1281 void (*fptr)(id, SEL, long) = (void(*)(id, SEL, long))info1;
1282 fptr(self, (SEL)info2, [val longValue]);
1285 static void longIvarSetFunc(void* info1, void* info2, id self, id val)
1287 long* ptr = (long*)((char*)self + (int)info2);
1288 *ptr = [val longValue];
1292 /* unsigned long type */
1294 static id unsignedLongMethodGetFunc(void* info1, void* info2, id self) {
1295 unsigned long (*fptr)(id, SEL) = (unsigned long(*)(id, SEL))info1;
1296 unsigned long val = fptr(self, (SEL)info2);
1297 return [NumberClass numberWithUnsignedLong:val];
1300 static id unsignedLongIvarGetFunc(void* info1, void* info2, id self) {
1301 unsigned long* ptr = (unsigned long*)((char*)self + (int)info2);
1302 return [NumberClass numberWithUnsignedLong:*ptr];
1305 static void unsignedLongMethodSetFunc(void* info1, void* info2, id self, id val) {
1306 void (*fptr)(id, SEL, unsigned long) = (void(*)(id, SEL, unsigned long))info1;
1307 fptr(self, (SEL)info2, [val unsignedLongValue]);
1310 static void unsignedLongIvarSetFunc(void* info1, void* info2, id self, id val) {
1311 unsigned long* ptr = (unsigned long*)((char*)self + (int)info2);
1312 *ptr = [val unsignedLongValue];
1316 /* long long type */
1318 static id longLongMethodGetFunc(void* info1, void* info2, id self) {
1319 long long (*fptr)(id, SEL) = (long long(*)(id, SEL))info1;
1320 long long val = fptr(self, (SEL)info2);
1321 return [NumberClass numberWithLongLong:val];
1324 static id longLongIvarGetFunc(void* info1, void* info2, id self) {
1325 long long* ptr = (long long*)((char*)self + (int)info2);
1326 return [NumberClass numberWithLongLong:*ptr];
1329 static void longLongMethodSetFunc(void* info1, void* info2, id self, id val) {
1330 void (*fptr)(id, SEL, long long) = (void(*)(id, SEL, long long))info1;
1331 fptr(self, (SEL)info2, [val longLongValue]);
1334 static void longLongIvarSetFunc(void* info1, void* info2, id self, id val) {
1335 long long* ptr = (long long*)((char*)self + (int)info2);
1336 *ptr = [val longLongValue];
1340 /* unsigned long long type */
1342 static id unsignedLongLongMethodGetFunc(void* info1, void* info2, id self) {
1343 unsigned long long (*fptr)(id, SEL) = (unsigned long long(*)(id, SEL))info1;
1344 unsigned long long val = fptr(self, (SEL)info2);
1345 return [NumberClass numberWithUnsignedLongLong:val];
1348 static id unsignedLongLongIvarGetFunc(void* info1, void* info2, id self) {
1349 unsigned long long* ptr = (unsigned long long*)((char*)self + (int)info2);
1350 return [NumberClass numberWithUnsignedLongLong:*ptr];
1353 static void unsignedLongLongMethodSetFunc(void* info1, void* info2, id self, id val) {
1354 void (*fptr)(id, SEL, unsigned long long) = (void(*)(id, SEL, unsigned long long))info1;
1355 fptr(self, (SEL)info2, [val unsignedLongLongValue]);
1358 static void unsignedLongLongIvarSetFunc(void* info1, void* info2, id self, id val) {
1359 unsigned long long* ptr = (unsigned long long*)((char*)self + (int)info2);
1360 *ptr = [val unsignedLongLongValue];
1366 static id floatMethodGetFunc(void* info1, void* info2, id self) {
1367 float (*fptr)(id, SEL) = (float(*)(id, SEL))info1;
1368 float val = fptr(self, (SEL)info2);
1369 return [NumberClass numberWithFloat:val];
1372 static id floatIvarGetFunc(void* info1, void* info2, id self) {
1373 float* ptr = (float*)((char*)self + (int)info2);
1374 return [NumberClass numberWithFloat:*ptr];
1377 static void floatMethodSetFunc(void* info1, void* info2, id self, id val) {
1378 void (*fptr)(id, SEL, float) = (void(*)(id, SEL, float))info1;
1379 fptr(self, (SEL)info2, [val floatValue]);
1382 static void floatIvarSetFunc(void* info1, void* info2, id self, id val) {
1383 float* ptr = (float*)((char*)self + (int)info2);
1384 *ptr = [val floatValue];
1390 static id doubleMethodGetFunc(void* info1, void* info2, id self) {
1391 double (*fptr)(id, SEL) = (double(*)(id, SEL))info1;
1392 double val = fptr(self, (SEL)info2);
1393 return [NumberClass numberWithDouble:val];
1396 static id doubleIvarGetFunc(void* info1, void* info2, id self) {
1397 double* ptr = (double*)((char*)self + (int)info2);
1398 return [NumberClass numberWithDouble:*ptr];
1401 static void doubleMethodSetFunc(void* info1, void* info2, id self, id val) {
1402 void (*fptr)(id, SEL, double) = (void(*)(id, SEL, double))info1;
1403 fptr(self, (SEL)info2, [val doubleValue]);
1406 static void doubleIvarSetFunc(void* info1, void* info2, id self, id val) {
1407 double* ptr = (double*)((char*)self + (int)info2);
1408 *ptr = [val doubleValue];
1411 #else /* NeXT_Foundation_LIBRARY */
1413 @implementation NSArray(EOKeyValueCoding)
1415 - (id)computeSumForKey:(NSString *)_key {
1416 unsigned i, cc = [self count];
1417 id (*objAtIdx)(id, SEL, unsigned int);
1420 if (cc == 0) return [NSNumber numberWithDouble:0.0];
1422 objAtIdx = (void*)[self methodForSelector:@selector(objectAtIndex:)];
1424 for (i = 0, sum = 0.0; i < cc; i++) {
1427 o = objAtIdx(self, @selector(objectAtIndex:), i);
1428 sum += [o doubleValue];
1430 return [NSNumber numberWithDouble:sum];
1433 - (id)computeAvgForKey:(NSString *)_key {
1434 unsigned i, cc = [self count];
1435 id (*objAtIdx)(id, SEL, unsigned int);
1438 if (cc == 0) return [NSNumber numberWithDouble:0.0];
1440 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
1442 for (i = 0, sum = 0.0; i < cc; i++) {
1445 o = objAtIdx(self, @selector(objectAtIndex:), i);
1447 sum += [o doubleValue];
1449 return [NSNumber numberWithDouble:(sum / (double)cc)];
1452 - (id)computeCountForKey:(NSString *)_key {
1453 return [NSNumber numberWithUnsignedInt:[self count]];
1456 - (id)computeMaxForKey:(NSString *)_key {
1457 unsigned i, cc = [self count];
1458 id (*objAtIdx)(id, SEL, unsigned int);
1461 if (cc == 0) return nil;
1463 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
1465 max = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
1466 for (i = 1; i < cc; i++) {
1469 ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
1470 if (ov > max) max = ov;
1472 return [NSNumber numberWithDouble:max];
1475 - (id)computeMinForKey:(NSString *)_key {
1476 unsigned i, cc = [self count];
1477 id (*objAtIdx)(id, SEL, unsigned int);
1480 if (cc == 0) return nil;
1482 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
1484 min = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
1485 for (i = 1; i < cc; i++) {
1488 ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
1489 if (ov < min) min = ov;
1491 return [NSNumber numberWithDouble:min];
1494 - (id)valueForKey:(NSString *)_key {
1495 if (null == nil) null = [[EONull null] retain];
1497 if ([_key hasPrefix:@"@"]) {
1498 /* process a computed function */
1501 unsigned keyLen = [_key cStringLength];
1505 kbuf = malloc(keyLen + 1);
1506 buf = malloc(keyLen + 16);
1507 [_key getCString:kbuf];
1510 strcpy(buf, "compute"); bufPtr += 7;
1511 *bufPtr = toupper(keyStr[1]); bufPtr++;
1512 strncpy(&(buf[8]), &(keyStr[2]), keyLen - 2); bufPtr += (keyLen - 2);
1513 strcpy(bufPtr, "ForKey:");
1514 if (kbuf) free(kbuf);
1517 sel = sel_getUid(buf);
1519 sel = sel_get_any_uid(buf);
1523 return sel != NULL ? [self performSelector:sel withObject:_key] : nil;
1526 /* process the _key in a map function */
1527 unsigned i, cc = [self count];
1530 id (*objAtIdx)(id, SEL, unsigned int);
1533 if ([_key isEqualToString:@"count"]) {
1534 NSLog(@"WARNING(%s): USED -valueForKey(@\"count\") ON NSArray, YOU"
1535 @"PROBABLY WANT TO USE @count INSTEAD !",
1536 __PRETTY_FUNCTION__);
1537 return [self valueForKey:@"@count"];
1541 if (cc == 0) return [NSArray array];
1543 objects = calloc(cc + 2, sizeof(id));
1544 objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
1546 for (i = 0; i < cc; i++) {
1549 o = [objAtIdx(self, @selector(objectAtIndex:), i) valueForKey:_key];
1550 objects[i] = o ? o : null;
1553 result = [NSArray arrayWithObjects:objects count:cc];
1554 if (objects) free(objects);
1559 @end /* NSArray(EOKeyValueCoding) */
1561 #endif /* !NeXT_Foundation_LIBRARY */