Map with maintained insertion order

Andrej Mitrovic andrej.mitrovich at gmail.com
Fri Mar 23 18:13:55 PDT 2012


On 3/23/12, Andrej Mitrovic <andrej.mitrovich at gmail.com> wrote:
> Does someone have a map implementation that maintains the insertion
> order of the keys?

Here's a sloppy implementation:

module test;

import std.stdio;
import std.traits;

template KeyType(V : V[K], K)
    if (isAssociativeArray!(V[K]))
{
    alias K KeyType;
}

template ValueType(V : V[K], K)
    if (isAssociativeArray!(V[K]))
{
    alias V ValueType;
}

template BaseElement(T : U[], U)
{
    alias U BaseElement;
}

struct LinkedHash(T)
    if (isAssociativeArray!T)
{
    alias KeyType!T Key;
    alias ValueType!T Value;

    static if (isArray!Value)
        template isValue(T) { enum bool isValue = (is(T == Value) ||
is(BaseElement!Value == T)); }
    else
        template isValue(T) { enum bool isValue = is(T == Value); }

    Value[] payload;
    size_t[Key] keyToIndex;
    Key[size_t] indexToKey;
    size_t lastIndex;

    size_t getNewIndex()
    {
        payload.length = payload.length + 1;
        return lastIndex++;
    }

    size_t* getKeyIndex(string key)
    {
        if (auto index = key in keyToIndex)
            return index;
        else
            return null;
    }

    Value opIndex(in Key key)
    {
        if (auto index = getKeyIndex(key))
            return payload[*index];
        else
            assert(0, "Key '" ~ key ~ "' not found.");
    }

    void opIndexAssign(V)(V value, Key key)
        if (isValue!V)
    {
        if (auto index = getKeyIndex(key))
            payload[*index] = value;
        else
        {
            auto index = getNewIndex();
            payload[index] = value;
            keyToIndex[key] = index;
            indexToKey[index] = key;
        }
    }

    void opIndexOpAssign(string op, V)(V value, Key key)
        if (isValue!V)
    {
        if (auto index = getKeyIndex(key))
            mixin("payload[*index] " ~ op ~ "= value;");
        else
        {
            auto index = getNewIndex();
            mixin("payload[index] " ~ op ~ "= value;");
            keyToIndex[key] = index;
            indexToKey[index] = key;
        }
    }

    int opApply(scope int delegate(ref Key, ref Value) dg)
    {
        foreach (index; 0 .. lastIndex)
        {
            auto result = dg(indexToKey[index], payload[index]);
                if (result)
                    return result;
        }

        return 0;
    }
}

void main()
{
    auto names = ["1", "2", "3", "4", "5", "6", "7", "8"];

    LinkedHash!(string[string]) stringMap;
    foreach (name; names)
        stringMap[name] ~= "test";

    foreach (key, val; stringMap)
        writefln("%s: %s", key, val);

    LinkedHash!(string[][string]) stringArrMap;
    stringArrMap["100"] = ["foo"];
    stringArrMap["101"] ~= "bar";

    foreach (name; names)
        stringArrMap[name] ~= "test";

    foreach (key, val; stringArrMap)
        writefln("%s: %s", key, val);
}


More information about the Digitalmars-d-learn mailing list