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