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 <NGObjWeb/WOComponent.h>
23 #include <NGObjWeb/WOAssociation.h>
26 @implementation WOComponent(OptimizedSynching)
29 optimized component synchronization. Uses extensive runtime caching.
32 static Class lastEnumClass = Nil;
33 static id (*nextKey)(id, SEL);
34 static Class lastWocDictClass = Nil;
35 static id (*wocObjForKey)(id, SEL, id);
39 #define CHK_ENUM_CACHE \
40 if (lastEnumClass != *(Class *)keys) {\
41 lastEnumClass = *(Class *)keys;\
42 nextKey = (void*)[keys methodForSelector:@selector(nextObject)];\
45 #define CHK_WOCDICT_CACHE \
46 if (lastWocDictClass != *(Class *)self->wocBindings) {\
47 lastWocDictClass = *(Class *)self->wocBindings;\
48 wocObjForKey = (void*)[self->wocBindings methodForSelector:@selector(objectForKey:)];\
53 #define CHK_ENUM_CACHE \
54 if (lastEnumClass != *(Class *)keys) {\
55 lastEnumClass = *(Class *)keys;\
57 method_get_imp(class_get_instance_method(*(Class *)keys, \
58 @selector(nextObject)));\
61 #define CHK_WOCDICT_CACHE \
62 if (lastWocDictClass != *(Class *)self->wocBindings) {\
63 lastWocDictClass = *(Class *)self->wocBindings;\
64 wocObjForKey = (void*)\
65 method_get_imp(class_get_instance_method(*(Class *)self->wocBindings, \
66 @selector(objectForKey:)));\
71 void WOComponent_syncFromParent(WOComponent *self, WOComponent *_parent) {
74 void (*takeValue)(id, SEL, id, NSString *);
76 if ((keys = [self->wocBindings keyEnumerator]) == nil)
82 takeValue = (void *)[self methodForSelector:@selector(takeValue:forKey:)];
84 takeValue = (void*)method_get_imp(class_get_instance_method(self->isa,
85 @selector(takeValue:forKey:)));
88 while ((key = nextKey(keys, @selector(nextObject)))) {
89 static Class lastAssocClass = Nil; // THREAD
90 static id (*valInComp)(id, SEL, WOComponent *);
91 register WOAssociation *binding;
94 binding = wocObjForKey(self->wocBindings, @selector(objectForKey:), key);
96 if (*(Class *)binding != lastAssocClass) {
97 lastAssocClass = *(Class *)binding;
100 [binding methodForSelector:@selector(valueInComponent:)];
103 method_get_imp(class_get_instance_method(*(Class *)binding,
104 @selector(valueInComponent:)));
108 // TODO: this is somewhat inefficient because -valueInComponent: does
109 // value=>object coercion and then takeValue:forKey: does the
110 // reverse coercion. We could improve performance for base values
111 // if we implement takeValue:forKey: on our own and just pass over
112 // the raw value (ie [self setIntA:[assoc intValueComponent:self]])
114 value = valInComp(binding, @selector(valueInComponent:), _parent);
116 // TODO: this is a bit problematic in bool contexts if the input
117 // parameter is a string because ObjC doesn't know about bool
118 // and will evaluate the string as a char value
119 // (this is common if you use const:mykey="YES" in WOx)
120 takeValue(self, @selector(takeValue:forKey:), value, key);
124 void WOComponent_syncToParent(WOComponent *self, WOComponent *_parent) {
127 id (*getValue)(id, SEL, NSString *);
129 if ((keys = [self->wocBindings keyEnumerator]) == nil)
136 getValue = (void *)[self methodForSelector:@selector(valueForKey:)];
138 getValue = (void*)method_get_imp(class_get_instance_method(self->isa,
139 @selector(valueForKey:)));
142 while ((key = nextKey(keys, @selector(nextObject)))) {
143 static Class lastAssocClass = Nil;
144 static BOOL (*isSettable)(id, SEL);
145 static void (*setValInComp)(id, SEL, id, WOComponent *);
146 register WOAssociation *binding;
149 binding = wocObjForKey(self->wocBindings, @selector(objectForKey:), key);
151 if (*(Class *)binding != lastAssocClass) {
152 lastAssocClass = *(Class *)binding;
156 (void*)[binding methodForSelector:@selector(isValueSettable)];
158 (void*)[binding methodForSelector:@selector(setValue:inComponent:)];
161 method_get_imp(class_get_instance_method(*(Class *)binding,
162 @selector(isValueSettable)));
163 setValInComp = (void*)
164 method_get_imp(class_get_instance_method(*(Class *)binding,
165 @selector(setValue:inComponent:)));
169 if (!isSettable(binding, @selector(isValueSettable)))
172 value = getValue(self, @selector(valueForKey:), key);
174 setValInComp(binding, @selector(setValue:inComponent:), value, _parent);
178 @end /* WOComponent(OptimizedSynching) */