On 03/24/2012 01:20 AM, H. S. Teoh wrote:
On Fri, Mar 23, 2012 at 10:53:10PM +0100, Timon Gehr wrote:
On 03/23/2012 10:07 PM, Timon Gehr wrote:

I see. An alternative solution (one that does not make AAs depend on
Phobos and is more slick) would be to use the const qualified key type
for lookup (that is what const is for) and to have immutable keys for
stores. For types that define .idup, there would be another overload of
opIndexAssign that can take a const qualified key.

Proof of concept:
[...]

Hmm. I decided that perhaps the full-fledged std.conv.to is a bit of an
overkill, so I revised the AA code to compromise between needing
std.conv.to and still deliver what Andrei wants.

Basically, I have a template that defines AA key compatibility, where
compatibility means that given an AA with key type Key and a key k of
type K, k is considered compatible if:

- k==K.init is valid (i.e. they can be compared);
- (At least) one of the following holds:
    - is(immutable(K) == immutable(Key))
    - is(typeof(k.idup) == Key)
    - Key is a static array of length N, and k[0..N] is valid.
    - is(K : Key)

For the first case (is(immutable(K)==immutable(Key)), which means K and
Key have the "same representation") and the second case (K.idup yields
Key), we can basically assume that K.toHash() is consistent with
Key.toHash(). When creating a new entry, we just assign K to Key, or
K.idup to Key as necessary.

For the third case, we can just slice the input array when comparing or
assigning to a new entry (this will throw an Error if the input array
has the wrong length). I decided to be permissive and compute the hash
on the entire array, if the length doesn't match it will fail anyway, so
it's OK to lookup an array of mismatching length in an AA with static
array keys, as long as you don't try to store the key into it.

Lastly, if is(K : Key) holds but none of the others do, then convert the
key before computing the hash:

        Key key = k;    // implicit conversion
        return key.toHash();

This ensures the int->double conversion works correctly. Creating a new
entry can just use straight assignment, due to the implicit conversion.

I've added these changes on github in a branch:

        https://github.com/quickfur/New-AA-implementation/tree/keyconv

Andrei, please try it out and see if it works on the cases you have in
mind. :-)


T


This solution creates unnecessary template bloat for every implicit conversion, duplicates compiler logic, and I think it does not work correctly because of other issues. I have refined my proof of concept.

Consider this:

template getConstQual(T){
        static if(is(T _ == immutable(U),U)) alias const(getConstQual!U) r;
        else static if(is(T _ == const(U),U)) alias const(getConstQual!U) r;
        else static if(is(T _ == inout(U),U)) alias const(getConstQual!U) r;
        else static if(is(T _ == shared(U),U)) alias const(getConstQual!U) r;
        else static if(is(T _ == U[],U)) alias const(getConstQual!U[]) r;
        else static if(is(T _ == U*,U)) alias const(getConstQual!U*) r;
        else alias const(T) r;
        alias r getConstQual;
}

struct AA(Key, Value) if(is(Key==immutable(Key))){
        Value[Key] payload;
        auto opIndex(getConstQual!Key k){return payload[cast(immutable)k];}
        auto opIndexAssign(Value v, Key k){return payload[cast(immutable)k]=v;}
        static if(is(typeof(getConstQual!Key.init.idup):Key)){
                auto opIndexAssign(Value v, getConstQual!Key k){
                        if(auto p = (cast(immutable)k) in payload) return *p=v;
                        return this[k.idup]=v;
                }
        }
}
template AA(Key, Value) if(!is(Key==immutable(Key))&&is(Key:immutable(Key))){
        alias AA!(immutable(Key), Value) AA;
}


void main() {
        AA!(immutable(double)[], int) aa;
        aa[[1.0,2.0,3.0]]=2; // works, with no .idup!
        aa[[1,2,3]]=2;       // ditto
        AA!(dstring,int) ab;
        ab["123"]=2;         // just works
        char[3] c= "123";
        AA!(short,int) ac;
        ac[2]=2;             // so does this
}

This nicely resolves all the implementation problems you have encountered/will encounter, because it does not rely on IFTI. I think you should follow this strategy.






Reply via email to