1 // Robert Burner Schadek rburners@gmail.com LGPL3 2 module fixedsizehashmap; 3 4 import std.algorithm : sort; 5 import std.range : isRandomAccessRange; 6 import std.conv : to; 7 8 struct FashMap(K,V,const size_t cap = 64) { 9 struct Pair(N,M) { 10 N key; 11 M value; 12 13 this(N k, M v) { 14 this.key = k; 15 this.value = v; 16 } 17 } 18 19 private: 20 size_t search(K key) const @trusted nothrow { 21 try { 22 int imax = to!(int)(this.length - cast(size_t)1); 23 int imin = 0; 24 while(imin <= imax) { 25 // calculate the midpoint for roughly equal partition 26 int imid = to!int(imin + ((imax - imin) / 2)); 27 if(data[cast(size_t)imid].key == key) { 28 // key found at index imid 29 return cast(size_t)imid; 30 // determine which subarray to search 31 } else if(data[cast(size_t)imid].key < key) { 32 // change min index to search 33 // upper subarray 34 imin = imid + 1; 35 } else { 36 // change max index to 37 // search lower subarray 38 imax = imid - 1; 39 } 40 } 41 } catch(Exception e) { 42 } 43 return size_t.max; 44 } 45 46 Pair!(K,V)[cap] data; 47 size_t len; 48 49 public: 50 @property pure size_t length() const @safe nothrow { 51 return this.len; 52 } 53 54 @property pure size_t capacity() const @safe nothrow { 55 return cap; 56 } 57 58 @property pure size_t empty() const @safe nothrow { 59 return this.len == 0; 60 } 61 62 bool insert(K k, V v) @trusted { 63 if(this.len == capacity) { 64 throw new Exception("FashMap full, can not insert more element"); 65 } 66 if(this.search(k) != size_t.max) { 67 return false; 68 } else { 69 this.data[this.len] = Pair!(K,V)(k, v); 70 this.len++; 71 sort!("a.key < b.key")(this.data[0 .. this.len]); 72 return true; 73 } 74 } 75 76 bool contains(K k) const @trusted nothrow { 77 auto i = search(k); 78 return i != size_t.max; 79 } 80 81 ref Pair!(K,V) opIndex(K k) @trusted { 82 auto i = search(k); 83 if(i != size_t.max) { 84 return this.data[i]; 85 } else { 86 throw new Exception("FashMap index out of bound"); 87 } 88 } 89 90 ref const(Pair!(K,V)) opIndex(K k) const @trusted { 91 auto i = search(k); 92 if(i != size_t.max) { 93 return this.data[i]; 94 } else { 95 throw new Exception("FashMap index out of bound"); 96 } 97 } 98 99 int opApply(int delegate(ref const K, ref V) dg) { 100 int result = 0; 101 foreach(ref it; this.data[0 .. this.len]) { 102 result = dg(it.key, it.value); 103 if(result) { 104 break; 105 } 106 } 107 108 return result; 109 } 110 } 111 112 unittest { 113 FashMap!(string,int) m; 114 assert(m.insert("foo", 1)); 115 assert(m.length == 1); 116 assert(m.contains("foo")); 117 assert(m["foo"].value == 1); 118 assert((cast(const)m)["foo"].value == 1); 119 assert(m.insert("bar", 2)); 120 assert(m.contains("foo")); 121 assert(m.contains("bar")); 122 assert(m.length == 2); 123 foreach(ref const string k, ref int v; m) { 124 assert(k == "foo" || k == "bar"); 125 assert(v == 1 || v == 2); 126 } 127 }