Mimicking C++'s indexing behavior in D associative arrays
FG via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Wed Feb 18 01:24:48 PST 2015
>> // Assume bar is some associative array of type Foo[string]
>> Foo* value = key in bar;
>> if (!value) {
>> bar[key] = Foo.init;
>> value = &bar[key];
>> }
>> This seems sub-optimal, given that in involves three hashes (two lookups
>> and one insertion). Is there a more efficient or cleaner way to do so?
>
> So basically:
>
> Foo v = bar.get(key, Foo.init)
> bar[key] = v;
>
> Get is like an ordinary index but it will return the given value if it does not exist in the AA.
>
> Of course you probably want to create a new UFCS function to wrap your check + default initialize if it doesn't exist.
>
> T grab(T, U)(T[U] aa, U key) if (is(T == struct)) {
> if (key !in aa)
> aa[key] = new T;
> return aa[key];
> }
You are searching for the key twice and the original example used pointers.
There is a function called _aaGetX in the runtime that has exactly the required behaviour:
// Get pointer to value in associative array indexed by key.
// Add entry for key if it is not already there.
void* _aaGetX(AA* aa, const TypeInfo keyti, in size_t valuesize, in void* pkey)
however, using it in normal code could be considered a hack, because it belongs to the internal implementation of associative arrays. Anyway, while waiting for a better solution to present itself, we might as well have a look at this very dirty one. ;)
extern(C) void* _aaGetX(void* aa, const TypeInfo keyti, in size_t valuesize, in void* pkey);
V* aaGet(K, V)(V[K] arr, K key) {
return cast(V*)_aaGetX(cast(void*)&arr, typeid(K), V.sizeof, cast(void*)&key);
}
unittest {
int[int] arr = [1: 10, 2: 20, 3: 30];
int *val = arr.aaGet(3); // an existing value
assert(*val == 30);
val = arr.aaGet(4); // aa[4] will be created
assert(*val == int.init);
assert(arr[4] == int.init);
}
More information about the Digitalmars-d-learn
mailing list