Files
cappuccino/Foundation/CPDictionary.j
T
2008-09-30 17:29:56 -07:00

419 lines
10 KiB
Plaintext
Executable File

/*
* CPDictionary.j
* Foundation
*
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
//import "CPRange.j"
import "CPObject.j"
import "CPEnumerator.j"
import "CPException.j"
/* @ignore */
@implementation _CPDictionaryValueEnumerator : CPEnumerator
{
CPEnumerator _keyEnumerator;
CPDictionary _dictionary;
}
- (id)initWithDictionary:(CPDictionary)aDictionary
{
self = [super init];
if (self)
{
_keyEnumerator = [aDictionary keyEnumerator];
_dictionary = aDictionary;
}
return self;
}
- (id)nextObject
{
var key = [_keyEnumerator nextObject];
if (!key)
return nil;
return [_dictionary objectForKey:key];
}
@end
/*
A dictionary is the standard way of passing around key-value pairs in
the Cappuccino framework. It is similar to the
<a href="http://java.sun.com/javase/6/docs/api/index.html">Java map interface</a>,
except all keys are <objj>CPString</objj>s and values can be any
Cappuccino or JavaScript object.</p>
<p>If you are familiar with dictionaries in Cocoa, you'll notice that
there is no CPMutableDictionary class. The regular <objj>CPDictionary</objj>
has <code>setObject:</code> and <code>removeObjectForKey:</code> methods.
In Cappuccino there is no distinction between immutable and mutable classes.
They are all mutable.
*/
@implementation CPDictionary : CPObject
{
}
/*
@ignore
*/
+ (id)alloc
{
return new objj_dictionary();
}
/*
Returns a new empty <objj>CPDictionary</objj>.
*/
+ (id)dictionary
{
return [[self alloc] init];
}
/*
Returns a new dictionary, initialized with the contents of <code>aDictionary</code>.
@param aDictionary the dictionary to copy key-value pairs from
@return the new <objj>CPDictionary</objj>
*/
+ (id)dictionaryWithDictionary:(CPDictionary)aDictionary
{
return [[self alloc] initWithDictionary:aDictionary];
}
/*
Creates a new dictionary with single key-value pair.
@param anObject the object for the paring
@param aKey the key for the pairing
@return the new <objj>CPDictionary</objj>
*/
+ (id)dictionaryWithObject:(id)anObject forKey:(id)aKey
{
return [[self alloc] initWithObjects:[anObject] forKeys:[aKey]];
}
/*
Creates a dictionary with multiple key-value pairs.
@param objects the objects to place in the dictionary
@param keys the keys for each of the objects
@throws CPInvalidArgumentException if the number of objects and keys is different
@return the new <objj>CPDictionary</objj>
*/
+ (id)dictionaryWithObjects:(CPArray)objects forKeys:(CPArray)keys
{
return [[self alloc] initWithObjects:objects forKeys:keys];
}
/*
Initializes the dictionary with the contents of another dictionary.
@param aDictionary the dictionary to copy key-value pairs from
@return the initialized dictionary
*/
- (id)initWithDictionary:(CPDictionary)aDictionary
{
var key = "",
dictionary = [[CPDictionary alloc] init];
for (key in aDictionary._buckets)
[dictionary setObject:[aDictionary objectForKey:key] forKey:key];
return dictionary;
}
/*
Initializes the dictionary from the arrays of keys and objects.
@param objects the objects to put in the dictionary
@param keyArray the keys for the objects to put in the dictionary
@throws CPInvalidArgumentException if the number of objects and keys is different
@return the initialized dictionary
*/
- (id)initWithObjects:(CPArray)objects forKeys:(CPArray)keyArray
{
self = [super init];
if ([objects count] != [keyArray count])
[CPException raise:CPInvalidArgumentException reason:"Counts are different.("+[objects count]+"!="+[keyArray count]+")"];
if (self)
{
var i = [keyArray count];
while (i--)
[self setObject:objects[i] forKey:keyArray[i]];
}
return self;
}
/*
Returns the number of entries in the dictionary
*/
- (int)count
{
return count;
}
/*
Returns an array of keys for all the entries in the dictionary.
*/
- (CPArray)allKeys
{
return _keys;
}
/*
Returns an array of values for all the entries in the dictionary.
*/
- (CPArray)allValues
{
var index = _keys.length,
values = [];
while (index--)
values.push(dictionary_getValue(self, [_keys[index]]));
return values;
}
/*
Returns an enumerator that enumerates over all the dictionary's keys.
*/
- (CPEnumerator)keyEnumerator
{
return [_keys objectEnumerator];
}
/*
Returns an enumerator that enumerates over all the dictionary's values.
*/
- (CPEnumerator)objectEnumerator
{
return [[_CPDictionaryValueEnumerator alloc] initWithDictionary:self];
}
/*
Instance.isEqualToDictionary(aDictionary)
{
if(this.count()!=aDictionary.count()) return NO;
var i= this._keys.count();
while(i--) if(this.objectForKey(this._keys[i])!=aDictionary.objectForKey(this._keys[i])) return NO;
return YES;
}
Instance.allKeys()
{
return this._keys;
}
Instance.allKeysForObject(anObject)
{
var i= 0,
keys= CPArray.array(),
count= this.count();
while((i= this._objects.indexOfObjectInRage(0, count-i))!=CPNotFound) keys.addObject(this._keys[i]);
return keys;
}
Instance.allValues()
{
return this._objects;
}
Instance.keyEnumerator()
{
return this._keys.objectEnumerator();
}
Instance.keysSortedByValueUsingSelector(aSelector)
{
var dictionary= this,
objectSelector= function(rhs)
{
return aSelector.apply(dictionary.objectForKey(this), [dictionary.objectForKey(rhs)]);
};
return this._keys.sortedArrayUsingSelector(objectSelector);
}
Instance.objectEnumerator()
{
return this._objects.objectEnumerator();
}
*/
/*
Returns the object for the entry with key <code>aKey</code>.
@param aKey the key for the object's entry
@return the object for the entry
*/
- (id)objectForKey:(CPString)aKey
{
// We should really do this with inlining or something of that nature.
return _buckets[aKey];
//return dictionary_getValue(self, aKey);
}
/*
Instance.objectsForKeys(keys, aNotFoundMarker)
{
var i= keys.length,
objects= CPArray.array();
while(i--)
{
var object= this.objectForKey(keys[i]);
objects.addObject(object==nil?aNotFoundMarker:object);
}
return objects;
}
Instance.valueForKey(aKey)
{
if(aKey.length && aKey[0]=="@") return this.objectForKey(aKey.substr(1));
return base.valueForKey(aKey);
}
//
Instance.addEntriesFromDictionary(aDictionary)
{
var key,
keyEnumerator= aDictionary.keyEnumerator();
while(key= keyEnumerator.nextObject()) this.setObjectForKey(aDictionary.objectForKey(key), key);
}
*/
/*
Removes all the entries from the dictionary.
*/
- (void)removeAllObjects
{
_keys = [];
count = 0;
_buckets = {};
}
/*
Removes the entry for the specified key.
@param aKey the key of the entry to be removed
*/
- (void)removeObjectForKey:(id)aKey
{
dictionary_removeValue(self, aKey);
}
/*
Instance.removeObjectForKey(aKey)
{
var entry= this._dictionary[aKey];
if(entry)
{
var range= CPMakeRange(entry.index, 1);
this._keys.removeObjectsInRange(range);
this._objects.removeObjectsInRange(range);
delete this._dictionary[aKey];
}
}
Instance.setDictionary(aDictionary)
{
this._keys= CPArray.arrayWithArray(aDictionary.allKeys());
this._objects= CPArray.arrayWithArray(aDictionary.allValues());
this._dictionary= { };
var i= this._keys.count();
while(i--) this._dictionary[this._keys[i]]= { object: this._objects[i], index: i };
}
*/
/*
Adds an entry into the dictionary.
@param anObject the object for the entry
@param aKey the entry's key
*/
- (void)setObject:(id)anObject forKey:(id)aKey
{
dictionary_setValue(self, aKey, anObject);
}
/*
Instance.setValueForKey(aValue, aKey)
{
if(!aValue) this.removeObjectForKey(aKey);
else this.setObjectForKey(aValue, aKey);
}
Instance.copy()
{
return CPDictionary.alloc().dictionaryWithDictionary(this);
}
*/
/*
Returns a human readable description of the dictionary.
*/
- (CPString)description
{
var description = @"CPDictionary {\n";
var i = _keys.length;
while (i--)
description += _keys[i] +":"+[_buckets[_keys[i]] description]+"\n";
description += "}";
return description;
}
@end
@implementation CPDictionary (CPCoding)
/*
Initializes the dictionary by unarchiving the data from a coder.
@param aCoder the coder from which the data will be unarchived.
@return the initialized dictionary
*/
- (id)initWithCoder:(CPCoder)aCoder
{
return [aCoder _decodeDictionaryOfObjectsForKey:@"CP.objects"];
}
/*
Archives the dictionary to a provided coder.
@param aCoder the coder to which the dictionary data will be archived.
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder _encodeDictionaryOfObjects:self forKey:@"CP.objects"];
}
@end
objj_dictionary.prototype.isa = CPDictionary;