HashMap

Undocumented in source.

Destructor

~this
~this()
Undocumented in source.

Members

Aliases

StoredKeyType
alias StoredKeyType = StoredType!K
Undocumented in source.
StoredValueType
alias StoredValueType = StoredType!V
Undocumented in source.
require
alias require = getOrAdd
Undocumented in source.

Functions

byKey
auto byKey()
Undocumented in source. Be warned that the author may not have intended to support it.
byPair
auto byPair()
Undocumented in source. Be warned that the author may not have intended to support it.
byValue
auto byValue()
Undocumented in source. Be warned that the author may not have intended to support it.
clear
void clear()
Undocumented in source. Be warned that the author may not have intended to support it.
get
V get(K k, T defaultValue)

Attention: this can't return ref as default value can be rvalue

getOrAdd
V getOrAdd(K k, T defaultValue)
Undocumented in source. Be warned that the author may not have intended to support it.
length
auto length()
Undocumented in source. Be warned that the author may not have intended to support it.
opBinaryRight
V* opBinaryRight(K k)

Lookup methods

opIndex
V opIndex(K k)

Attention: you can't use this method in @nogc code. Usual aakey method. Throws exception if key not found

opIndexAssign
void opIndexAssign(V v, K k)

Modifiers

put
V* put(K k, V v)

put pair (k,v) into hash. it must be @safe, it inherits @nogc properties from K and V It can resize hashtable it is overloaded or has too much deleted entries

remove
bool remove(K k)
Undocumented in source. Be warned that the author may not have intended to support it.
size
auto size()
Undocumented in source. Be warned that the author may not have intended to support it.

Manifest constants

grow_factor
enum grow_factor;
Undocumented in source.
initial_buckets_num
enum initial_buckets_num;
Undocumented in source.
inlineValues
enum inlineValues;
Undocumented in source.

Examples

Tests test immutable struct and class as Key type

import std.experimental.logger;

globalLogLevel = LogLevel.info;
() @nogc nothrow{
    struct S {
        int s;
    }

    HashMap!(immutable S, int) hs1;
    immutable ss = S(1);
    hs1[ss] = 1;
    assert(ss in hs1 && *(ss in hs1) == 1);
    HashMap!(int, immutable S) hs2;
    hs2[1] = ss;
    assert(1 in hs2 && *(1 in hs2) == ss);
    assert(!(2 in hs2));
}();

// class
class C {
    int v;
    this(int _v) pure inout {
        v = _v;
    }

    bool opEquals(const C o) pure const @safe @nogc nothrow {
        return v == o.v;
    }

    override hash_t toHash() const @safe @nogc {
        return hash_function(v);
    }
}

HashMap!(immutable C, int) hc1;
immutable cc = new immutable C(1);
hc1[cc] = 1;
assert(hc1[cc] == 1);
HashMap!(int, immutable C) hc2;
hc2[1] = cc;
assert(hc2[1] is cc);

Test if we can work with non-@nogc opEquals for class-key. opEquals anyway must be non-@system.

class c {
    int a;
    this(int a) {
        this.a = a;
    }

    override hash_t toHash() const pure @safe {
        int[] _ = [1, 2, 3]; // this cause GC
        return hash_function(a);
    }

    bool opEquals(const c other) const pure nothrow @safe {
        auto _ = [1, 2, 3]; // this cause GC
        return this is other || this.a == other.a;
    }
}

alias K = c;
alias V = int;
HashMap!(K, V) h;
K k0 = new c(0);
V v0 = 1;
h.put(k0, v0);
int* v = k0 in h;
assert(v);
assert(*v == 1);

test byKey, byValue, byPair

import std.algorithm;
import std.array;
import std.stdio;

HashMap!(int, string) m;
m[1] = "one";
m[2] = "two";
m[10] = "ten";
assert(equal(m.byKey.array.sort, [1, 2, 10]));
assert(equal(m.byValue.array.sort, ["one", "ten", "two"]));
assert(equal(m.byPair.map!"tuple(a.key, a.value)".array.sort, [tuple(1,
        "one"), tuple(2, "two"), tuple(10, "ten")]));
m.remove(1);
m.remove(10);
assert(equal(m.byPair.map!"tuple(a.key, a.value)".array.sort, [tuple(2, "two")]));
m.remove(2);
assert(m.byPair.map!"tuple(a.key, a.value)".array.sort.length() == 0);
m.remove(2);
assert(m.byPair.map!"tuple(a.key, a.value)".array.sort.length() == 0);

compare equivalence to AA

import std.random;
import std.array;
import std.algorithm;
import std.stdio;
import std.experimental.logger;

enum iterations = 400_000;

globalLogLevel = LogLevel.info;

HashMap!(int, int) hashMap;
int[int] AA;

auto rnd = Random(unpredictableSeed);

foreach (i; 0 .. iterations) {
    int k = uniform(0, iterations, rnd);
    hashMap.put(k, i);
    AA[k] = i;
}
assert(equal(AA.keys().sort(), hashMap.byKey().array.sort()));
assert(equal(AA.values().sort(), hashMap.byValue().array.sort()));
assert(AA.length == hashMap.length);

check remove

// test removal while iterating
import std.random;
import std.array;
import std.algorithm;
import std.stdio;
import std.experimental.logger;

enum iterations = 400_000;

globalLogLevel = LogLevel.info;

HashMap!(int, int) hashMap;

auto rnd = Random(unpredictableSeed);

foreach (i; 0 .. iterations) {
    int k = uniform(0, iterations, rnd);
    hashMap[k] = i;
}
foreach (k; hashMap.byKey) {
    assert(hashMap.remove(k));
}
assert(hashMap.length == 0);

test clear

// test clear

HashMap!(int, int) hashMap;

foreach (i; 0 .. 100) {
    hashMap[i] = i;
}
hashMap.clear();
assert(hashMap.length == 0);
hashMap[1] = 1;
assert(1 in hashMap && hashMap.length == 1);

test getOrAdd with value

// test of nogc getOrAdd

HashMap!(int, int) hashMap;

foreach (i; 0 .. 100) {
    hashMap[i] = i;
}
auto v = hashMap.getOrAdd(-1, -1);
assert(-1 in hashMap && v == -1);

test getOrAdd with callable

// test of nogc getOrAdd with lazy default value

HashMap!(int, int) hashMap;

foreach (i; 0 .. 100) {
    hashMap[i] = i;
}
int v = hashMap.getOrAdd(-1, () => -1);
assert(-1 in hashMap && v == -1);
assert(hashMap.get(-1, 0) == -1); // key -1 is in hash, return value
assert(hashMap.get(-2, 0) == 0); // key -2 not in map, return default value
assert(hashMap.get(-3, () => 0) == 0); // ditto

test getOrAdd with complex data

import std.socket;

HashMap!(string, Socket) socketPool;
Socket s0 = socketPool.getOrAdd("http://example.com",
        () => new Socket(AddressFamily.INET, SocketType.STREAM));
assert(s0 !is null);
assert(s0.addressFamily == AddressFamily.INET);
Socket s1 = socketPool.getOrAdd("http://example.com",
        () => new Socket(AddressFamily.INET, SocketType.STREAM));
assert(s1 !is null);
assert(s1 is s0);

test with real class (socket)

import std.socket;

class Connection {
    Socket s;
    bool opEquals(const Connection other) const pure @safe {
        return s is other.s;
    }

    override hash_t toHash() const @safe {
        return hash_function(s.handle);
    }
}

HashMap!(Connection, string) socketPool;

test if we can handle some exotic value type

// test of nogc getOrAdd with lazy default value
// corner case when V is callable

alias F = int function() @safe @nogc nothrow;

F one = function() { return 1; };
F two = function() { return 2; };
F three = function() { return 3; };
F four = function() { return 4; };
HashMap!(int, F) hashMap;
hashMap.put(1, one);
hashMap.put(2, two);
auto p = 1 in hashMap;
assert(p);
assert((*p)() == 1);
p = 2 in hashMap;
assert(p);
assert((*p)() == 2);
auto f3 = hashMap.getOrAdd(3, () => function int() { return 3; }); // used as default()
assert(f3() == 3);
auto f4 = hashMap.getOrAdd(4, four);
assert(f4() == 4);

Meta