Merge pull request #3140 from daboe01/new-CPMapTable

New: CPMapTable.j
This commit is contained in:
Martin Carlberg
2025-09-05 11:42:10 +02:00
committed by GitHub
2 changed files with 278 additions and 0 deletions
+125
View File
@@ -0,0 +1,125 @@
@import "CPObject.j"
@import "CPEnumerator.j"
@import "CPDictionary.j"
@import "CPArray.j"
/*!
@class CPMapTable
@ingroup foundation
A mutable collection modeled after NSDictionary that allows for arbitrary
objects or values to be used as keys. This implementation uses the native
ECMAScript 6 Map object for its underlying storage.
*/
@implementation CPMapTable : CPObject
{
// The underlying ES6 Map to store the key-value pairs.
id _map;
}
/*!
Initializes a new, empty CPMapTable.
*/
- (id)init
{
if (self = [super init])
{
_map = new Map();
}
return self;
}
#pragma mark -
#pragma mark Accessing Content
/*!
Returns the value associated with a given key.
@param aKey The key for which to return the corresponding value.
@return The value associated with aKey, or nil if no value is associated with aKey.
*/
- (id)objectForKey:(id)aKey
{
var value = _map.get(aKey);
return value === undefined ? nil : value;
}
/*!
Returns an enumerator object that lets you access each key in the map table.
@return A CPEnumerator object for the keys in the map table.
*/
- (CPEnumerator)keyEnumerator
{
return [[..._map.keys()] objectEnumerator];
}
/*!
Returns an enumerator object that lets you access each value in the map table.
@return A CPEnumerator object for the values in the map table.
*/
- (CPEnumerator)objectEnumerator
{
return [[..._map.values()] objectEnumerator];
}
/*!
Returns the number of key-value pairs in the map table.
@return The number of entries in the map table.
*/
- (unsigned int)count
{
return _map.size;
}
#pragma mark -
#pragma mark Manipulating Content
/*!
Adds a given key-value pair to the map table.
If aKey already exists in the map table, anObject takes its place.
@param anObject The value for aKey.
@param aKey The key for anObject.
*/
- (void)setObject:(id)anObject forKey:(id)aKey
{
_map.set(aKey, anObject);
}
/*!
Removes a given key and its associated value from the map table.
@param aKey The key to remove.
*/
- (void)removeObjectForKey:(id)aKey
{
_map.delete(aKey);
}
/*!
Empties the map table of its entries.
*/
- (void)removeAllObjects
{
_map.clear();
}
#pragma mark -
#pragma mark Creating a Dictionary Representation
/*!
Returns a dictionary representation of the map table.
Note: This will only work correctly if all keys are strings.
@return A CPDictionary containing the entries of the map table.
*/
- (CPDictionary)dictionaryRepresentation
{
var dictionary = [CPDictionary dictionary];
for (var [key, value] of _map.entries())
{
[dictionary setObject:value forKey:key];
}
return dictionary;
}
@end
+153
View File
@@ -0,0 +1,153 @@
@import <Foundation/CPMapTable.j>
@import <Foundation/CPDictionary.j>
@import <Foundation/CPEnumerator.j>
@import <Foundation/CPMutableArray.j>
@import <OJUnit/OJTestCase.j>
@implementation CPMapTableTest : OJTestCase
{
CPMapTable map_table;
id objectKey;
}
- (void)setUp
{
map_table = [[CPMapTable alloc] init];
objectKey = [[CPObject alloc] init];
}
- (void)testInit
{
[self assert:[map_table count] equals:0];
}
- (void)testSetObjectForKey
{
[map_table setObject:@"value1" forKey:@"key1"];
[self assert:[map_table count] equals:1];
[self assert:[map_table objectForKey:@"key1"] equals:@"value1"];
[map_table setObject:@"value2" forKey:123];
[self assert:[map_table count] equals:2];
[self assert:[map_table objectForKey:123] equals:@"value2"];
[map_table setObject:@"value3" forKey:objectKey];
[self assert:[map_table count] equals:3];
[self assert:[map_table objectForKey:objectKey] equals:@"value3"];
// Test overriding a value
[map_table setObject:@"newValue" forKey:@"key1"];
[self assert:[map_table count] equals:3];
[self assert:[map_table objectForKey:@"key1"] equals:@"newValue"];
}
- (void)testObjectForKey
{
[self assertNull:[map_table objectForKey:@"nonExistentKey"]];
[map_table setObject:@"value1" forKey:@"key1"];
[self assert:[map_table objectForKey:@"key1"] equals:@"value1"];
}
- (void)testCount
{
[self assert:[map_table count] equals:0];
[map_table setObject:@"value1" forKey:@"key1"];
[self assert:[map_table count] equals:1];
[map_table setObject:@"value2" forKey:@"key2"];
[self assert:[map_table count] equals:2];
[map_table removeObjectForKey:@"key1"];
[self assert:[map_table count] equals:1];
}
- (void)testRemoveObjectForKey
{
[map_table setObject:@"value1" forKey:@"key1"];
[map_table setObject:@"value2" forKey:123];
[map_table removeObjectForKey:@"key1"];
[self assert:[map_table count] equals:1];
[self assertNull:[map_table objectForKey:@"key1"]];
[self assert:[map_table objectForKey:123] equals:@"value2"];
[map_table removeObjectForKey:123];
[self assert:[map_table count] equals:0];
[self assertNull:[map_table objectForKey:123]];
}
- (void)testRemoveAllObjects
{
[map_table setObject:@"value1" forKey:@"key1"];
[map_table setObject:@"value2" forKey:@"key2"];
[map_table removeAllObjects];
[self assert:[map_table count] equals:0];
[self assertNull:[map_table objectForKey:@"key1"]];
[self assertNull:[map_table objectForKey:@"key2"]];
}
- (void)testKeyEnumeratorOnEmptyMap
{
[self assert:[map_table count] equals:0 message:@"Pre-condition failed: map should be empty."];
[self assertNull:[[map_table keyEnumerator] nextObject]];
}
- (void)testKeyEnumeratorOnPopulatedMap
{
[map_table setObject:@"value1" forKey:@"key1"];
[map_table setObject:@"value2" forKey:123];
[map_table setObject:@"value3" forKey:objectKey];
var foundKeys = [CPMutableArray array],
enumerator = [map_table keyEnumerator],
aKey;
while (aKey = [enumerator nextObject])
[foundKeys addObject:aKey];
[self assert:[foundKeys count] equals:3];
[self assertTrue:[foundKeys containsObject:@"key1"]];
[self assertTrue:[foundKeys containsObject:123]];
[self assertTrue:[foundKeys containsObject:objectKey]];
}
- (void)testObjectEnumeratorOnEmptyMap
{
[self assert:[map_table count] equals:0 message:@"Pre-condition failed: map should be empty."];
[self assertNull:[[map_table objectEnumerator] nextObject]];
}
- (void)testObjectEnumeratorOnPopulatedMap
{
[map_table setObject:@"value1" forKey:@"key1"];
[map_table setObject:@"value2" forKey:123];
[map_table setObject:@"value3" forKey:objectKey];
var foundValues = [CPMutableArray array],
enumerator = [map_table objectEnumerator],
aValue;
while (aValue = [enumerator nextObject])
[foundValues addObject:aValue];
[self assert:[foundValues count] equals:3];
[self assertTrue:[foundValues containsObject:@"value1"]];
[self assertTrue:[foundValues containsObject:@"value2"]];
[self assertTrue:[foundValues containsObject:@"value3"]];
}
- (void)testDictionaryRepresentation
{
[map_table setObject:@"value1" forKey:@"key1"];
[map_table setObject:@"value2" forKey:@"key2"];
var dictionary = [map_table dictionaryRepresentation];
[self assert:[dictionary count] equals:2];
[self assert:[dictionary objectForKey:@"key1"] equals:@"value1"];
[self assert:[dictionary objectForKey:@"key2"] equals:@"value2"];
}
@end