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/WOAssociation.h>
23 #include "WOValueAssociation.h"
24 #include "WOKeyPathAssociation.h"
25 #include <NGObjWeb/WOApplication.h>
26 #include <NGObjWeb/WOContext.h>
29 @interface WOContext(Cursor)
33 #if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY || \
34 COCOA_Foundation_LIBRARY
35 @interface NSObject(Missing)
36 - (void)subclassResponsibility:(SEL)cmd;
37 - (void)notImplemented:(SEL)cmd;
41 @implementation WOAssociation
43 static Class WOKeyPathAssociationClass = Nil;
50 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
52 static BOOL didInit = NO;
56 s = [ud stringForKey:@"WOKeyPathAssociationClass"];
59 NSLog(@"Note: using different class for keypath associations: %@", s);
61 WOKeyPathAssociationClass = NSClassFromString(s);
63 if (WOKeyPathAssociationClass == Nil)
64 WOKeyPathAssociationClass = [WOKeyPathAssociation class];
67 + (WOAssociation *)associationWithKeyPath:(NSString *)_keyPath {
68 static int WOCacheKeyPathAssociations = -1;
69 static NSMapTable *cache = NULL;
70 static unsigned cacheHits = 0;
71 static unsigned cacheMisses = 0;
74 if (WOCacheKeyPathAssociations == -1) {
75 WOCacheKeyPathAssociations =
76 [[[NSUserDefaults standardUserDefaults]
77 objectForKey:@"WOKeyPathAssociationsCacheSize"]
79 if (WOCacheKeyPathAssociations > 0) {
80 cache = NSCreateMapTable(NSObjectMapKeyCallBacks,
81 NSObjectMapValueCallBacks,
82 WOCacheKeyPathAssociations);
87 if ((a = NSMapGet(cache, _keyPath))) {
90 printf("%s: cache hits: %d, misses: %d, size:%d\n",
92 cacheHits, cacheMisses, NSCountMapTable(cache));
94 return [[a retain] autorelease];
99 if (cacheMisses > 1000) {
100 if (cacheHits < cacheMisses) {
102 "%s: disabling association cache "
103 "(%d cache misses vs %d cache hits)\n",
104 __PRETTY_FUNCTION__, cacheMisses, cacheHits);
105 if (cache) NSFreeMapTable(cache);
111 a = [[WOKeyPathAssociationClass alloc] initWithKeyPath:_keyPath];
114 NSMapInsert(cache, _keyPath, a);
116 return [a autorelease];
118 + (WOAssociation *)associationWithValue:(id)_value {
119 static int WOCacheValueAssociations = -1;
120 static NSMapTable *cache = NULL;
121 static unsigned cacheHits = 0;
122 static unsigned cacheMisses = 0;
123 static NSNumber *boolYes = nil;
124 static NSNumber *boolNo = nil;
127 if (_value == nil) return nil;
130 boolYes = [[NSNumber numberWithBool:YES] retain];
132 boolNo = [[NSNumber numberWithBool:NO] retain];
134 if (boolYes == _value) {
135 static WOAssociation *yesAssoc = nil;
138 yesAssoc = [[_WOBoolValueAssociation associationWithBool:YES] retain];
142 if (boolNo == _value) {
143 static WOAssociation *noAssoc = nil;
146 noAssoc = [[_WOBoolValueAssociation associationWithBool:NO] retain];
151 if (![_value conformsToProtocol:@protocol(NSCopying)])
152 /* if the value can't be copied, it shouldn't be cached ! */
153 return [WOValueAssociation associationWithValue:_value];
155 _value = [[_value copyWithZone:NULL] autorelease];
157 if (WOCacheValueAssociations == -1) {
158 WOCacheValueAssociations =
159 [[[NSUserDefaults standardUserDefaults]
160 objectForKey:@"WOValueAssociationsCacheSize"]
162 if (WOCacheValueAssociations > 0) {
163 cache = NSCreateMapTable(NSObjectMapKeyCallBacks,
164 NSObjectMapValueCallBacks,
165 WOCacheValueAssociations);
170 if ((a = NSMapGet(cache, _value))) {
173 printf("%s: cache hits: %d, misses: %d, size:%d\n",
175 cacheHits, cacheMisses, NSCountMapTable(cache));
177 return [[a retain] autorelease];
182 if (cacheMisses > 1000) {
183 if (cacheHits < cacheMisses) {
185 "%s: disabling association cache "
186 "(%d cache misses vs %d cache hits)",
187 __PRETTY_FUNCTION__, cacheMisses, cacheHits);
188 if (cache) NSFreeMapTable(cache);
194 a = [WOValueAssociation associationWithValue:_value];
197 NSMapInsert(cache, _value, a);
204 - (void)setValue:(id)_value {
206 [self setValue:_value
207 inComponent:[[[WOApplication application] context] component]];
211 return [self valueInComponent:
212 [[[WOApplication application] context] component]];
215 - (void)setValue:(id)_value inComponent:(WOComponent *)_component {
216 [self subclassResponsibility:_cmd];
218 - (id)valueInComponent:(WOComponent *)_component {
219 [self subclassResponsibility:_cmd];
223 - (void)setValue:(id)_value inContext:(WOContext *)_ctx {
224 [self setValue:_value inComponent:(id)[_ctx cursor]];
226 - (id)valueInContext:(WOContext *)_ctx {
227 return [self valueInComponent:(id)[_ctx cursor]];
230 - (BOOL)isValueConstant {
231 [self subclassResponsibility:_cmd];
234 - (BOOL)isValueSettable {
235 [self subclassResponsibility:_cmd];
241 - (NSString *)description {
242 return [NSString stringWithFormat:@"<0x%p[%@]>",
243 self, NSStringFromClass([self class])];
248 - (void)setUnsignedCharValue:(unsigned char)_v inComponent:(WOComponent *)_c {
249 [self setValue:[NSNumber numberWithUnsignedChar:_v] inComponent:_c];
251 - (void)setCharValue:(signed char)_val inComponent:(WOComponent *)_component {
252 [self setValue:[NSNumber numberWithChar:_val] inComponent:_component];
254 - (void)setUnsignedIntValue:(unsigned int)_v inComponent:(WOComponent *)_c {
255 [self setValue:[NSNumber numberWithUnsignedInt:_v] inComponent:_c];
257 - (void)setIntValue:(signed int)_value inComponent:(WOComponent *)_component {
258 [self setValue:[NSNumber numberWithInt:_value] inComponent:_component];
260 - (void)setBoolValue:(BOOL)_value inComponent:(WOComponent *)_component {
261 [self setValue:[NSNumber numberWithBool:_value] inComponent:_component];
264 - (unsigned char)unsignedCharValueInComponent:(WOComponent *)_component {
265 return [[self valueInComponent:_component] unsignedCharValue];
267 - (signed char)charValueInComponent:(WOComponent *)_component {
268 return [(id<NGBaseTypeValues>)[self valueInComponent:_component] charValue];
270 - (unsigned int)unsignedIntValueInComponent:(WOComponent *)_component {
271 return [[self valueInComponent:_component] unsignedIntValue];
273 - (signed int)intValueInComponent:(WOComponent *)_component {
274 return [[self valueInComponent:_component] intValue];
276 - (BOOL)boolValueInComponent:(WOComponent *)_component {
277 return [[self valueInComponent:_component] boolValue];
280 - (void)setStringValue:(NSString *)_v inComponent:(WOComponent *)_component {
281 [self setValue:_v inComponent:_component];
283 - (NSString *)stringValueInComponent:(WOComponent *)_component {
284 return [[self valueInComponent:_component] stringValue];
287 /* special context values */
289 - (void)setUnsignedCharValue:(unsigned char)_v inContext:(WOContext *)_c {
290 [self setUnsignedCharValue:_v inComponent:(id)[_c cursor]];
292 - (void)setCharValue:(signed char)_value inContext:(WOContext *)_ctx {
293 [self setCharValue:_value inComponent:(id)[_ctx cursor]];
295 - (void)setUnsignedIntValue:(unsigned int)_v inContext:(WOContext *)_c {
296 [self setUnsignedIntValue:_v inComponent:(id)[_c cursor]];
298 - (void)setIntValue:(signed int)_value inContext:(WOContext *)_ctx {
299 [self setIntValue:_value inComponent:(id)[_ctx cursor]];
301 - (void)setBoolValue:(BOOL)_value inContext:(WOContext *)_ctx {
302 [self setBoolValue:_value inComponent:(id)[_ctx cursor]];
305 - (unsigned char)unsignedCharValueInContext:(WOContext *)_ctx {
306 return [self unsignedCharValueInComponent:[_ctx cursor]];
308 - (signed char)charValueInContext:(WOContext *)_ctx {
309 return [self charValueInComponent:[_ctx cursor]];
311 - (unsigned int)unsignedIntValueInContext:(WOContext *)_ctx {
312 return [self unsignedIntValueInComponent:[_ctx cursor]];
314 - (signed int)intValueInContext:(WOContext *)_ctx {
315 return [self intValueInComponent:[_ctx cursor]];
317 - (BOOL)boolValueInContext:(WOContext *)_ctx {
318 return [self boolValueInComponent:[_ctx cursor]];
321 - (void)setStringValue:(NSString *)_v inContext:(WOContext *)_ctx {
322 [self setValue:_v inComponent:[_ctx cursor]];
324 - (NSString *)stringValueInContext:(WOContext *)_ctx {
325 return [[self valueInComponent:(id)[_ctx cursor]] stringValue];
330 - (id)copyWithZone:(NSZone *)_zone {
331 // WOAssociations are immutable
332 return [self retain];
337 - (unsigned int)unsignedIntValue {
338 [self notImplemented:_cmd];
341 - (signed int)intValue {
342 [self notImplemented:_cmd];
345 - (float)floatValue {
346 [self notImplemented:_cmd];
350 [self notImplemented:_cmd];
354 - (NSString *)stringValue {
355 [self notImplemented:_cmd];
359 @end /* WOAssociation */