API 0.9.5
Foundation/CPDictionary.j
Go to the documentation of this file.
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;
 All Classes Files Functions Variables Defines