]> err.no Git - sope/blob - sope-appserver/NGObjWeb/WOComponent+Sync.m
fixed duplicate -awake
[sope] / sope-appserver / NGObjWeb / WOComponent+Sync.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 <NGObjWeb/WOComponent.h>
23 #include <NGObjWeb/WOAssociation.h>
24 #include "common.h"
25
26 @implementation WOComponent(OptimizedSynching)
27
28 /*
29   optimized component synchronization. Uses extensive runtime caching.
30 */
31
32 static Class lastEnumClass = Nil;
33 static id (*nextKey)(id, SEL);
34 static Class lastWocDictClass = Nil;
35 static id (*wocObjForKey)(id, SEL, id);
36
37 #if NeXT_RUNTIME
38
39 #define CHK_ENUM_CACHE \
40   if (lastEnumClass != *(Class *)keys) {\
41     lastEnumClass = *(Class *)keys;\
42     nextKey = (void*)[keys methodForSelector:@selector(nextObject)];\
43   }
44
45 #define CHK_WOCDICT_CACHE \
46   if (lastWocDictClass != *(Class *)self->wocBindings) {\
47     lastWocDictClass = *(Class *)self->wocBindings;\
48     wocObjForKey = (void*)[self->wocBindings methodForSelector:@selector(objectForKey:)];\
49   }
50
51 #else
52
53 #define CHK_ENUM_CACHE \
54   if (lastEnumClass != *(Class *)keys) {\
55     lastEnumClass = *(Class *)keys;\
56     nextKey = (void*)\
57       method_get_imp(class_get_instance_method(*(Class *)keys, \
58         @selector(nextObject)));\
59   }
60
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:)));\
67   }
68
69 #endif
70
71 void WOComponent_syncFromParent(WOComponent *self, WOComponent *_parent) {
72   NSEnumerator *keys;
73   NSString     *key;
74   void (*takeValue)(id, SEL, id, NSString *);
75   
76   if ((keys = [self->wocBindings keyEnumerator]) == nil)
77     return;
78   
79   CHK_ENUM_CACHE;
80   CHK_WOCDICT_CACHE;
81 #if NeXT_RUNTIME
82   takeValue = (void *)[self methodForSelector:@selector(takeValue:forKey:)];
83 #else  
84   takeValue = (void*)method_get_imp(class_get_instance_method(self->isa,
85                 @selector(takeValue:forKey:)));
86 #endif
87   
88   while ((key = nextKey(keys, @selector(nextObject)))) {
89     static   Class lastAssocClass = Nil; // THREAD
90     static   id    (*valInComp)(id, SEL, WOComponent *);
91     register WOAssociation *binding;
92     register id value;
93     
94     binding = wocObjForKey(self->wocBindings, @selector(objectForKey:), key);
95     
96     if (*(Class *)binding != lastAssocClass) {
97       lastAssocClass = *(Class *)binding;
98 #if NeXT_RUNTIME
99       valInComp = (void *)
100         [binding methodForSelector:@selector(valueInComponent:)];
101 #else
102       valInComp = (void *)
103         method_get_imp(class_get_instance_method(*(Class *)binding,
104           @selector(valueInComponent:)));
105 #endif
106     }
107     
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]])
113     
114     value = valInComp(binding, @selector(valueInComponent:), _parent);
115
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);
121   }
122 }
123
124 void WOComponent_syncToParent(WOComponent *self, WOComponent *_parent) {
125   NSEnumerator *keys;
126   NSString     *key;
127   id (*getValue)(id, SEL, NSString *);
128   
129   if ((keys = [self->wocBindings keyEnumerator]) == nil)
130     return;
131   
132   CHK_ENUM_CACHE;
133   CHK_WOCDICT_CACHE;
134
135 #if NeXT_RUNTIME
136   getValue = (void *)[self methodForSelector:@selector(valueForKey:)];
137 #else
138   getValue = (void*)method_get_imp(class_get_instance_method(self->isa,
139                 @selector(valueForKey:)));
140 #endif
141   
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;
147     register id value;
148     
149     binding = wocObjForKey(self->wocBindings, @selector(objectForKey:), key);
150
151     if (*(Class *)binding != lastAssocClass) {
152       lastAssocClass = *(Class *)binding;
153
154 #if NeXT_RUNTIME
155       isSettable   = 
156         (void*)[binding methodForSelector:@selector(isValueSettable)];
157       setValInComp = 
158         (void*)[binding methodForSelector:@selector(setValue:inComponent:)];
159 #else
160       isSettable = (void*)
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:)));
166 #endif
167     }
168     
169     if (!isSettable(binding, @selector(isValueSettable)))
170       continue;
171     
172     value = getValue(self, @selector(valueForKey:), key);
173     
174     setValInComp(binding, @selector(setValue:inComponent:), value, _parent);
175   }
176 }
177
178 @end /* WOComponent(OptimizedSynching) */