summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2018-05-11 05:44:46 +0200
committerEugen Wissner <belka@caraus.de>2018-05-14 19:23:22 +0200
commitd545d6900e91ac5a3fbab36548a5887cc1810e9c (patch)
tree8e1e508b265095999bf85a356972ffb6975d08a7
parent3ed46117d1f35894db430145274c6e01f2c36de8 (diff)
downloadtanya-d545d6900e91ac5a3fbab36548a5887cc1810e9c.tar.gz
Make HashTable Range return Pair
-rw-r--r--source/tanya/container/hashtable.d115
1 files changed, 71 insertions, 44 deletions
diff --git a/source/tanya/container/hashtable.d b/source/tanya/container/hashtable.d
index 14a63c4..21876e8 100644
--- a/source/tanya/container/hashtable.d
+++ b/source/tanya/container/hashtable.d
@@ -20,22 +20,25 @@ import tanya.hash.lookup;
import tanya.memory;
import tanya.meta.trait;
import tanya.meta.transform;
+import tanya.typecons;
/**
- * Bidirectional range that iterates over the $(D_PSYMBOL Set)'s values.
+ * Bidirectional range whose element type is a tuple of a key and the
+ * respective value.
*
* Params:
- * E = Element type.
+ * T = Type of the internal hash storage.
*/
-struct Range(E)
+struct Range(T)
{
- static if (isMutable!E)
+ private alias KV = CopyConstness!(T, T.Bucket.KV);
+ static if (isMutable!T)
{
- private alias DataRange = Array!(Bucket!(Unqual!E)).Range;
+ private alias DataRange = T.array.Range;
}
else
{
- private alias DataRange = Array!(Bucket!(Unqual!E)).ConstRange;
+ private alias DataRange = T.array.ConstRange;
}
private DataRange dataRange;
@@ -67,63 +70,61 @@ struct Range(E)
@property void popFront()
in
{
- assert(!this.dataRange.empty);
+ assert(!empty);
assert(this.dataRange.front.status == BucketStatus.used);
}
out
{
- assert(this.dataRange.empty
- || this.dataRange.back.status == BucketStatus.used);
+ assert(empty || this.dataRange.back.status == BucketStatus.used);
}
do
{
do
{
- dataRange.popFront();
+ this.dataRange.popFront();
}
- while (!dataRange.empty && dataRange.front.status != BucketStatus.used);
+ while (!empty && dataRange.front.status != BucketStatus.used);
}
@property void popBack()
in
{
- assert(!this.dataRange.empty);
+ assert(!empty);
assert(this.dataRange.back.status == BucketStatus.used);
}
out
{
- assert(this.dataRange.empty
- || this.dataRange.back.status == BucketStatus.used);
+ assert(empty || this.dataRange.back.status == BucketStatus.used);
}
do
{
do
{
- dataRange.popBack();
+ this.dataRange.popBack();
}
- while (!dataRange.empty && dataRange.back.status != BucketStatus.used);
+ while (!empty && dataRange.back.status != BucketStatus.used);
}
- @property ref inout(E) front() inout
+ @property ref inout(KV) front() inout
in
{
- assert(!this.dataRange.empty);
+ assert(!empty);
assert(this.dataRange.front.status == BucketStatus.used);
}
do
{
- return dataRange.front.key;
+ return this.dataRange.front.kv;
}
- @property ref inout(E) back() inout
+ @property ref inout(KV) back() inout
in
{
- assert(!this.dataRange.empty);
+ assert(!empty);
assert(this.dataRange.back.status == BucketStatus.used);
}
do
{
- return dataRange.back.key;
+ return this.dataRange.back.kv;
}
Range opIndex()
@@ -131,40 +132,41 @@ struct Range(E)
return typeof(return)(this.dataRange[]);
}
- Range!(const E) opIndex() const
+ Range!(const T) opIndex() const
{
return typeof(return)(this.dataRange[]);
}
}
-@nogc nothrow pure @safe unittest
-{
- import tanya.range.primitive : isForwardRange;
- static assert(is(HashTable!(string, int) a));
- static assert(is(const HashTable!(string, int)));
- static assert(isForwardRange!(HashTable!(string, int).Range));
-}
-
/**
- * Hash table.
+ * Hash table is a data structure that stores pairs of keys and values without
+ * any particular order.
+ *
+ * This $(D_PSYMBOL HashTable) is implemented using closed hashing. Hash
+ * collisions are resolved with linear probing.
+ *
+ * $(D_PARAM Key) should be hashable with $(D_PARAM hasher). $(D_PARAM hasher)
+ * is a callable that accepts an argument of type $(D_PARAM Key) and returns a
+ * hash value for it ($(D_KEYWORD size_t)).
*
* Params:
* Key = Key type.
* Value = Value type.
- * hasher = Hash function for $(D_PARAM Key).
+ * hasher = Hash function for $(D_PARAM K).
*/
struct HashTable(Key, Value, alias hasher = hash)
if (is(typeof(hasher(Key.init)) == size_t))
{
- private HashArray!(hasher, Key, Value) data;
+ private alias HashArray = .HashArray!(hasher, Key, Value);
+ private alias Buckets = HashArray.Buckets;
- private alias Buckets = typeof(this.data).Buckets;
+ private HashArray data;
/// The range types for $(D_PSYMBOL HashTable).
- alias Range = .Range!Key;
+ alias Range = .Range!HashArray;
/// ditto
- alias ConstRange = .Range!(const Key);
+ alias ConstRange = .Range!(const HashArray);
/**
* Constructor.
@@ -194,7 +196,7 @@ if (is(typeof(hasher(Key.init)) == size_t))
}
do
{
- this.data = typeof(this.data)(Buckets(allocator));
+ this.data = HashArray(Buckets(allocator));
}
/**
@@ -216,7 +218,7 @@ if (is(typeof(hasher(Key.init)) == size_t))
}
do
{
- this.data = typeof(this.data)(Buckets(init.data, allocator));
+ this.data = HashArray(Buckets(init.data, allocator));
}
/// ditto
@@ -228,7 +230,7 @@ if (is(typeof(hasher(Key.init)) == size_t))
}
do
{
- this.data = typeof(this.data)(Buckets(move(init.data), allocator));
+ this.data = HashArray(Buckets(move(init.data), allocator));
this.lengthIndex = init.lengthIndex;
init.lengthIndex = 0;
}
@@ -378,8 +380,8 @@ if (is(typeof(hasher(Key.init)) == size_t))
{
e.key = key;
}
- e.value = value;
- return e.value;
+ e.kv.value = value;
+ return e.kv.value;
}
/**
@@ -400,7 +402,7 @@ if (is(typeof(hasher(Key.init)) == size_t))
{
if (key == range.front.key)
{
- return range.front.value;
+ return range.front.kv.value;
}
}
assert(false, "Range violation");
@@ -435,7 +437,7 @@ if (is(typeof(hasher(Key.init)) == size_t))
*/
bool opBinaryRight(string op : "in")(Key key)
{
- return this.data.find(key);
+ return this.data.canFind(key);
}
/**
@@ -465,6 +467,23 @@ if (is(typeof(hasher(Key.init)) == size_t))
{
this.data.rehash(n);
}
+
+ /**
+ * Returns a bidirectional range whose element type is a tuple of a key and
+ * the respective value.
+ *
+ * Returns: A bidirectional range that iterates over the container.
+ */
+ Range opIndex()
+ {
+ return typeof(return)(this.data.array[]);
+ }
+
+ /// ditto
+ ConstRange opIndex() const
+ {
+ return typeof(return)(this.data.array[]);
+ }
}
@nogc nothrow pure @safe unittest
@@ -501,3 +520,11 @@ if (is(typeof(hasher(Key.init)) == size_t))
dinos.clear();
assert(dinos.empty);
}
+
+@nogc nothrow pure @safe unittest
+{
+ import tanya.range.primitive : isForwardRange;
+ static assert(is(HashTable!(string, int) a));
+ static assert(is(const HashTable!(string, int)));
+ static assert(isForwardRange!(HashTable!(string, int).Range));
+}