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