1 //Written in the D programming language
2 /*
3 * Hash table which can store more than one value for a key
4 *
5 * Copyright 2009-2014 Jaypha
6 *
7 * Distributed under the Boost Software License, Version 1.0.
8 * (See http://www.boost.org/LICENSE_1_0.txt)
9 *
10 * Authors: Jason den Dulk
11 */
12
13 module jaypha.container.hash;
14
15
16 //----------------------------------------------------------------------------
17 struct Hash(T)
18 //----------------------------------------------------------------------------
19 {
20 // () operator
21 T[] opCall(string i) { return a[i]; }
22
23 // [] operator
24 T opIndex(string i) { return a[i][0]; }
25
26 // []= operator
27 void opIndexAssign(T v, string i) { a[i] = [v]; }
28 void opIndexAssign(T[] v, string i) { a[i] = v; }
29
30 // "in" operator
31 T[]* opIn_r(string i) { return (i in a); }
32
33 //--------------------------------------------------------------------------
34
35 @property T[][string] all() { return a; }
36
37 //--------------------------------------------------------------------------
38
39 @property T[string] toArray()
40 {
41 T[string] ret;
42 foreach (s,x;a)
43 ret[s] = x[0];
44 return ret;
45 }
46
47 //--------------------------------------------------------------------------
48
49 @property ulong length() { return a.length; }
50
51 //--------------------------------------------------------------------------
52
53 @property string[] keys() { return a.keys; }
54 @property T[][] values() { return a.values; }
55
56 //--------------------------------------------------------------------------
57
58 // TODO does rehash modify the original array? If not then use the other one.
59 Hash!(T) rehash() { a.rehash; return this; }
60 //Hash!(T) rehash() { Hash p; p.a = a.rehash; return p; }
61
62 //--------------------------------------------------------------------------
63 // Deep copy constructor.
64 this(this) { foreach (i,v; a) a[i] = v.dup; }
65
66 //--------------------------------------------------------------------------
67
68 void add(string i, T v) { if (!(i in a)) a[i]=[]; a[i] ~= v; }
69 void remove(string i) { a.remove(i); }
70
71 //--------------------------------------------------------------------------
72 // foreach (v;h)
73
74 int opApply(int delegate(ref T[]) dg)
75 {
76 int result = 0;
77 foreach (v; a)
78 {
79 result = dg(v);
80 if (result) break;
81 }
82 return result;
83 }
84
85 //--------------------------------------------------------------------------
86 // foreach (i,v;h)
87
88 int opApply(int delegate(ref string, ref T[]) dg)
89 {
90 int result = 0;
91 foreach (i, v; a)
92 {
93 result = dg(i, v);
94 if (result) break;
95 }
96 return result;
97 }
98
99 //--------------------------------------------------------------------------
100
101 void clear() { a = a.init; }
102
103 //--------------------------------------------------------------------------
104
105 private:
106 T[][string] a;
107 }
108
109 //----------------------------------------------------------------------------
110 // Alias for string based hashes, which are the most common.
111
112 alias Hash!(string) StrHash;
113
114 //----------------------------------------------------------------------------
115
116 unittest
117 {
118 import std.stdio;
119
120 StrHash a;
121 a["one"] = "4";
122 assert(a["one"] == "4");
123 a.add("two","3");
124 a.add("one","5");
125
126 assert(a["one"] == "4");
127 assert(a["two"] == "3");
128 assert(a("one") == ["4","5"]);
129
130 a["one"] = ["8","9","10"];
131 assert(a["one"] == "8");
132 assert(a("one") == ["8","9","10"]);
133 assert(a.length == 2);
134 assert(a("one").length == 3);
135 }
136
137 //----------------------------------------------------------------------------
138