![]() |
API 0.9.5
|
00001 /* 00002 * CPDictionary.j 00003 * Foundation 00004 * 00005 * Created by Francisco Tolmasky. 00006 * Copyright 2008, 280 North, Inc. 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 00024 /* @ignore */ 00025 @implementation _CPDictionaryValueEnumerator : CPEnumerator 00026 { 00027 CPEnumerator _keyEnumerator; 00028 CPDictionary _dictionary; 00029 } 00030 00031 - (id)initWithDictionary:(CPDictionary)aDictionary 00032 { 00033 self = [super init]; 00034 00035 if (self) 00036 { 00037 _keyEnumerator = [aDictionary keyEnumerator]; 00038 _dictionary = aDictionary; 00039 } 00040 00041 return self; 00042 } 00043 00044 - (id)nextObject 00045 { 00046 var key = [_keyEnumerator nextObject]; 00047 00048 if (!key) 00049 return nil; 00050 00051 return [_dictionary objectForKey:key]; 00052 } 00053 00054 @end 00055 00073 @implementation CPDictionary : CPObject 00074 { 00075 id __doxygen__; 00076 } 00077 00078 /* 00079 @ignore 00080 */ 00081 + (id)alloc 00082 { 00083 var result = new CFMutableDictionary(); 00084 result.isa = [self class]; 00085 return result; 00086 } 00087 00091 + (id)dictionary 00092 { 00093 return [[self alloc] init]; 00094 } 00095 00101 + (id)dictionaryWithDictionary:(CPDictionary)aDictionary 00102 { 00103 return [[self alloc] initWithDictionary:aDictionary]; 00104 } 00105 00112 + (id)dictionaryWithObject:(id)anObject forKey:(id)aKey 00113 { 00114 return [[self alloc] initWithObjects:[anObject] forKeys:[aKey]]; 00115 } 00116 00124 + (id)dictionaryWithObjects:(CPArray)objects forKeys:(CPArray)keys 00125 { 00126 return [[self alloc] initWithObjects:objects forKeys:keys]; 00127 } 00128 00134 + (id)dictionaryWithJSObject:(JSObject)object 00135 { 00136 return [self dictionaryWithJSObject:object recursively:NO]; 00137 } 00138 00144 + (id)dictionaryWithJSObject:(JSObject)object recursively:(BOOL)recursively 00145 { 00146 var key = "", 00147 dictionary = [[self alloc] init]; 00148 00149 for (key in object) 00150 { 00151 if (!object.hasOwnProperty(key)) 00152 continue; 00153 00154 var value = object[key]; 00155 00156 if (value === null) 00157 { 00158 [dictionary setObject:[CPNull null] forKey:key]; 00159 continue; 00160 } 00161 00162 if (recursively) 00163 { 00164 if (value.constructor === Object) 00165 value = [CPDictionary dictionaryWithJSObject:value recursively:YES]; 00166 else if ([value isKindOfClass:CPArray]) 00167 { 00168 var newValue = [], 00169 i = 0, 00170 count = value.length; 00171 00172 for (; i < count; i++) 00173 { 00174 var thisValue = value[i]; 00175 00176 if (thisValue === null) 00177 { 00178 newValue.push([CPNull null]); 00179 } 00180 else 00181 { 00182 if (thisValue.constructor === Object) 00183 newValue.push([CPDictionary dictionaryWithJSObject:thisValue recursively:YES]); 00184 else 00185 newValue.push(thisValue); 00186 } 00187 } 00188 00189 value = newValue; 00190 } 00191 } 00192 00193 [dictionary setObject:value forKey:key]; 00194 } 00195 00196 return dictionary; 00197 } 00198 00216 + (id)dictionaryWithObjectsAndKeys:(id)firstObject, ... 00217 { 00218 arguments[0] = [self alloc]; 00219 arguments[1] = @selector(initWithObjectsAndKeys:); 00220 00221 return objj_msgSend.apply(this, arguments); 00222 } 00223 00229 - (id)initWithDictionary:(CPDictionary)aDictionary 00230 { 00231 var key = "", 00232 dictionary = [[CPDictionary alloc] init]; 00233 00234 for (key in aDictionary._buckets) 00235 [dictionary setObject:[aDictionary objectForKey:key] forKey:key]; 00236 00237 return dictionary; 00238 } 00239 00247 - (id)initWithObjects:(CPArray)objects forKeys:(CPArray)keyArray 00248 { 00249 self = [super init]; 00250 00251 if ([objects count] != [keyArray count]) 00252 [CPException raise:CPInvalidArgumentException reason:"Counts are different.(" + [objects count] + "!=" + [keyArray count] + ")"]; 00253 00254 if (self) 00255 { 00256 var i = [keyArray count]; 00257 00258 while (i--) 00259 [self setObject:objects[i] forKey:keyArray[i]]; 00260 } 00261 00262 return self; 00263 } 00264 00279 - (id)initWithObjectsAndKeys:(id)firstObject, ... 00280 { 00281 var argCount = arguments.length; 00282 00283 if (argCount % 2 !== 0) 00284 [CPException raise:CPInvalidArgumentException reason:"Key-value count is mismatched. (" + argCount + " arguments passed)"]; 00285 00286 self = [super init]; 00287 00288 if (self) 00289 { 00290 // The arguments array contains self and _cmd, so the first object is at position 2. 00291 var index = 2; 00292 00293 for (; index < argCount; index += 2) 00294 { 00295 var value = arguments[index]; 00296 00297 if (value === nil) 00298 break; 00299 00300 [self setObject:value forKey:arguments[index + 1]]; 00301 } 00302 } 00303 00304 return self; 00305 } 00306 00310 - (CPDictionary)copy 00311 { 00312 return [CPDictionary dictionaryWithDictionary:self]; 00313 } 00314 00318 - (int)count 00319 { 00320 return _count; 00321 } 00322 00326 - (CPArray)allKeys 00327 { 00328 return [_keys copy]; 00329 } 00330 00334 - (CPArray)allValues 00335 { 00336 var index = _keys.length, 00337 values = []; 00338 00339 while (index--) 00340 values.push(self.valueForKey(_keys[index])); 00341 00342 return values; 00343 } 00344 00353 - (CPArray)allKeysForObject:(id)anObject 00354 { 00355 var count = _keys.length, 00356 index = 0, 00357 matchingKeys = [], 00358 thisKey = nil, 00359 thisValue = nil; 00360 00361 for (; index < count; ++index) 00362 { 00363 thisKey = _keys[index]; 00364 thisValue = _buckets[thisKey]; 00365 if (thisValue.isa && anObject && anObject.isa && [thisValue respondsToSelector:@selector(isEqual:)] && [thisValue isEqual:anObject]) 00366 matchingKeys.push(thisKey); 00367 else if (thisValue === anObject) 00368 matchingKeys.push(thisKey); 00369 } 00370 00371 return matchingKeys; 00372 } 00373 00374 - (CPArray)keysSortedByValueUsingSelector:(SEL)theSelector 00375 { 00376 return [[self allKeys] sortedArrayUsingFunction:function(a, b) { 00377 a = [self objectForKey:a]; 00378 b = [self objectForKey:b]; 00379 00380 return [a performSelector:theSelector withObject:b]; 00381 }]; 00382 } 00383 00387 - (CPEnumerator)keyEnumerator 00388 { 00389 return [_keys objectEnumerator]; 00390 } 00391 00395 - (CPEnumerator)objectEnumerator 00396 { 00397 return [[_CPDictionaryValueEnumerator alloc] initWithDictionary:self]; 00398 } 00399 00403 - (BOOL)isEqualToDictionary:(CPDictionary)aDictionary 00404 { 00405 if (self === aDictionary) 00406 return YES; 00407 00408 var count = [self count]; 00409 00410 if (count !== [aDictionary count]) 00411 return NO; 00412 00413 var index = count; 00414 00415 while (index--) 00416 { 00417 var currentKey = _keys[index], 00418 lhsObject = _buckets[currentKey], 00419 rhsObject = aDictionary._buckets[currentKey]; 00420 00421 if (lhsObject === rhsObject) 00422 continue; 00423 00424 if (lhsObject && lhsObject.isa && rhsObject && rhsObject.isa && [lhsObject respondsToSelector:@selector(isEqual:)] && [lhsObject isEqual:rhsObject]) 00425 continue; 00426 00427 return NO; 00428 } 00429 00430 return YES; 00431 } 00432 00433 - (BOOL)isEqual:(id)anObject 00434 { 00435 if (self === anObject) 00436 return YES; 00437 00438 if (![anObject isKindOfClass:[CPDictionary class]]) 00439 return NO; 00440 00441 return [self isEqualToDictionary:anObject]; 00442 } 00443 00444 /* 00445 Instance.allKeysForObject(anObject) 00446 { 00447 var i= 0, 00448 keys= CPArray.array(), 00449 count= this.count(); 00450 00451 while ((i= this._objects.indexOfObjectInRage(0, count-i))!=CPNotFound) keys.addObject(this._keys[i]); 00452 00453 return keys; 00454 } 00455 00456 Instance.keysSortedByValueUsingSelector(aSelector) 00457 { 00458 var dictionary= this, 00459 objectSelector= function(rhs) 00460 { 00461 return aSelector.apply(dictionary.objectForKey(this), [dictionary.objectForKey(rhs)]); 00462 }; 00463 00464 return this._keys.sortedArrayUsingSelector(objectSelector); 00465 } 00466 */ 00472 - (id)objectForKey:(id)aKey 00473 { 00474 var object = _buckets[aKey]; 00475 00476 return (object === undefined) ? nil : object; 00477 } 00478 /* 00479 Instance.objectsForKeys(keys, aNotFoundMarker) 00480 { 00481 var i= keys.length, 00482 objects= CPArray.array(); 00483 00484 while (i--) 00485 { 00486 var object= this.objectForKey(keys[i]); 00487 objects.addObject(object==nil?aNotFoundMarker:object); 00488 } 00489 00490 return objects; 00491 } 00492 00493 Instance.valueForKey(aKey) 00494 { 00495 if (aKey.length && aKey[0]=="@") return this.objectForKey(aKey.substr(1)); 00496 00497 return base.valueForKey(aKey); 00498 } 00499 */ 00503 - (void)removeAllObjects 00504 { 00505 self.removeAllValues(); 00506 } 00507 00512 - (void)removeObjectForKey:(id)aKey 00513 { 00514 self.removeValueForKey(aKey); 00515 } 00516 00521 - (void)removeObjectsForKeys:(CPArray)keysForRemoval 00522 { 00523 var index = keysForRemoval.length; 00524 00525 while (index--) 00526 [self removeObjectForKey:keysForRemoval[index]]; 00527 } 00528 00529 /* 00530 Instance.setDictionary(aDictionary) 00531 { 00532 this._keys= CPArray.arrayWithArray(aDictionary.allKeys()); 00533 this._objects= CPArray.arrayWithArray(aDictionary.allValues()); 00534 00535 this._dictionary= { }; 00536 00537 var i= this._keys.count(); 00538 while (i--) this._dictionary[this._keys[i]]= { object: this._objects[i], index: i }; 00539 } 00540 */ 00546 - (void)setObject:(id)anObject forKey:(id)aKey 00547 { 00548 self.setValueForKey(aKey, anObject); 00549 } 00550 00554 - (void)addEntriesFromDictionary:(CPDictionary)aDictionary 00555 { 00556 if (!aDictionary) 00557 return; 00558 00559 var keys = [aDictionary allKeys], 00560 index = [keys count]; 00561 00562 while (index--) 00563 { 00564 var key = keys[index]; 00565 00566 [self setObject:[aDictionary objectForKey:key] forKey:key]; 00567 } 00568 } 00569 00573 - (CPString)description 00574 { 00575 return self.toString(); 00576 } 00577 00578 - (BOOL)containsKey:(id)aKey 00579 { 00580 var value = [self objectForKey:aKey]; 00581 return ((value !== nil) && (value !== undefined)); 00582 } 00583 @end 00584 00585 @implementation CPDictionary (CPCoding) 00586 00587 /* 00588 Initializes the dictionary by unarchiving the data from a coder. 00589 @param aCoder the coder from which the data will be unarchived. 00590 @return the initialized dictionary 00591 */ 00592 - (id)initWithCoder:(CPCoder)aCoder 00593 { 00594 return [aCoder _decodeDictionaryOfObjectsForKey:@"CP.objects"]; 00595 } 00596 00601 - (void)encodeWithCoder:(CPCoder)aCoder 00602 { 00603 [aCoder _encodeDictionaryOfObjects:self forKey:@"CP.objects"]; 00604 } 00605 00606 @end 00607 00616 @implementation CPMutableDictionary : CPDictionary 00617 { 00618 id __doxygen__; 00619 } 00620 00621 @end 00622 00623 CFDictionary.prototype.isa = CPDictionary; 00624 CFMutableDictionary.prototype.isa = CPMutableDictionary;