summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2018-05-30 18:39:27 +0200
committerEugen Wissner <belka@caraus.de>2018-05-30 18:50:52 +0200
commitbfe0748a631a3f4606f97cb932af40b3851242c8 (patch)
tree35b4bd500cc8863ccd65543c26901c2bcbc347d4
parent61814d53833b5f66e14d57f3c71b5e6425067ce7 (diff)
downloadtanya-bfe0748a631a3f4606f97cb932af40b3851242c8.tar.gz
Insert a range into the hash table and set
-rw-r--r--source/tanya/container/hashtable.d146
-rw-r--r--source/tanya/container/set.d95
2 files changed, 239 insertions, 2 deletions
diff --git a/source/tanya/container/hashtable.d b/source/tanya/container/hashtable.d
index b1a347d..d25c75b 100644
--- a/source/tanya/container/hashtable.d
+++ b/source/tanya/container/hashtable.d
@@ -20,6 +20,7 @@ import tanya.hash.lookup;
import tanya.memory;
import tanya.meta.trait;
import tanya.meta.transform;
+import tanya.range.primitive;
/**
* Bidirectional range whose element type is a tuple of a key and the
@@ -225,6 +226,8 @@ if (is(typeof(hasher(Key.init)) == size_t))
* S = Source set type.
* init = Source set.
* allocator = Allocator.
+ *
+ * Precondition: $(D_INLINECODE allocator !is null).
*/
this(S)(ref S init, shared Allocator allocator = defaultAllocator)
if (is(Unqual!S == HashTable))
@@ -250,6 +253,71 @@ if (is(typeof(hasher(Key.init)) == size_t))
}
/**
+ * Constructs the hash table from a forward range.
+ *
+ * Params:
+ * R = Range type.
+ * range = Forward range.
+ * allocator = Allocator.
+ *
+ * Precondition: $(D_INLINECODE allocator !is null).
+ */
+ this(R)(R range, shared Allocator allocator = defaultAllocator)
+ if (isForwardRange!R && is(ElementType!R == KeyValue))
+ in
+ {
+ assert(allocator !is null);
+ }
+ do
+ {
+ this(allocator);
+ insert(range);
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ alias KeyValue = HashTable!(string, int).KeyValue;
+
+ KeyValue[2] range = [KeyValue("one", 1), KeyValue("two", 2)];
+ auto hashTable = HashTable!(string, int)(range[]);
+
+ assert(hashTable["one"] == 1);
+ assert(hashTable["two"] == 2);
+ }
+
+ /**
+ * Initializes the hash table from a static array.
+ *
+ * Params:
+ * n = Array size.
+ * array = Static array.
+ * allocator = Allocator.
+ *
+ * Precondition: $(D_INLINECODE allocator !is null).
+ */
+ this(size_t n)(KeyValue[n] array,
+ shared Allocator allocator = defaultAllocator)
+ in
+ {
+ assert(allocator !is null);
+ }
+ do
+ {
+ insert(array[]);
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ alias KeyValue = HashTable!(string, int).KeyValue;
+ auto hashTable = HashTable!(string, int)([KeyValue("one", 1), KeyValue("two", 2)]);
+
+ assert(hashTable["one"] == 1);
+ assert(hashTable["two"] == 2);
+ }
+
+ /**
* Assigns another hash table.
*
* If $(D_PARAM that) is passed by reference, it will be copied.
@@ -392,8 +460,7 @@ if (is(typeof(hasher(Key.init)) == size_t))
{
e.key = key;
}
- e.kv.value = value;
- return e.kv.value;
+ return e.kv.value = value;
}
///
@@ -412,6 +479,81 @@ if (is(typeof(hasher(Key.init)) == size_t))
}
/**
+ * Inserts a new element in the hash table.
+ *
+ * If the element with the same key was already in the table, it reassigns
+ * it with the new value, but $(D_PSYMBOL insert) returns `0`. Otherwise
+ * `1` is returned.
+ *
+ * Params:
+ * keyValue = Key/value pair.
+ *
+ * Returns: The number of the inserted elements with a unique key.
+ */
+ size_t insert(KeyValue keyValue)
+ {
+ auto e = ((ref v) @trusted => &this.data.insert(v))(keyValue.key);
+ size_t inserted;
+ if (e.status != BucketStatus.used)
+ {
+ e.key = keyValue.key;
+ inserted = 1;
+ }
+ e.kv.value = keyValue.value;
+ return inserted;
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ HashTable!(string, int) hashTable;
+
+ assert(hashTable.insert(hashTable.KeyValue("number", 1)) == 1);
+ assert(hashTable["number"] == 1);
+ assert(hashTable.insert(hashTable.KeyValue("number", 2)) == 0);
+ assert(hashTable["number"] == 2);
+ }
+
+ /**
+ * Inserts a forward range of key/value pairs into the hash table.
+ *
+ * If some of the elements in the $(D_PARAM range) have the same key, they
+ * are reassigned but are not counted as inserted elements. So the value
+ * returned by this function will be less than the range length.
+ *
+ * Params:
+ * R = Range type.
+ * range = Forward range.
+ *
+ * Returns: The number of the inserted elements with a unique key.
+ */
+ size_t insert(R)(R range)
+ if (isForwardRange!R && is(ElementType!R == KeyValue))
+ {
+ size_t count;
+ foreach (e; range)
+ {
+ count += insert(e);
+ }
+ return count;
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ HashTable!(string, int) hashTable;
+
+ hashTable.KeyValue[2] range = [
+ hashTable.KeyValue("one", 1),
+ hashTable.KeyValue("two", 2),
+ ];
+
+ assert(hashTable.insert(range[]) == 2);
+ assert(hashTable["one"] == 1);
+ assert(hashTable["two"] == 2);
+ }
+
+ /**
* Find the element with the key $(D_PARAM key).
*
* Params:
diff --git a/source/tanya/container/set.d b/source/tanya/container/set.d
index b8fd0e6..9ee1472 100644
--- a/source/tanya/container/set.d
+++ b/source/tanya/container/set.d
@@ -22,6 +22,7 @@ import tanya.hash.lookup;
import tanya.memory;
import tanya.meta.trait;
import tanya.meta.transform;
+import tanya.range.primitive;
/**
* Bidirectional range that iterates over the $(D_PSYMBOL Set)'s values.
@@ -222,6 +223,8 @@ if (is(typeof(hasher(T.init)) == size_t))
* S = Source set type.
* init = Source set.
* allocator = Allocator.
+ *
+ * Precondition: $(D_INLINECODE allocator !is null).
*/
this(S)(ref S init, shared Allocator allocator = defaultAllocator)
if (is(Unqual!S == Set))
@@ -247,6 +250,66 @@ if (is(typeof(hasher(T.init)) == size_t))
}
/**
+ * Initializes the set from a forward range.
+ *
+ * Params:
+ * R = Range type.
+ * range = Forward range.
+ * allocator = Allocator.
+ *
+ * Precondition: $(D_INLINECODE allocator !is null).
+ */
+ this(R)(R range, shared Allocator allocator = defaultAllocator)
+ if (isForwardRange!R && isImplicitlyConvertible!(ElementType!R, T))
+ in
+ {
+ assert(allocator !is null);
+ }
+ do
+ {
+ insert(range);
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ int[2] range = [1, 2];
+ Set!int set = Set!int(range[]);
+
+ assert(1 in set);
+ assert(2 in set);
+ }
+
+ /**
+ * Initializes the set from a static array.
+ *
+ * Params:
+ * n = Array size.
+ * array = Static array.
+ * allocator = Allocator.
+ *
+ * Precondition: $(D_INLINECODE allocator !is null).
+ */
+ this(size_t n)(T[n] array, shared Allocator allocator = defaultAllocator)
+ in
+ {
+ assert(allocator !is null);
+ }
+ do
+ {
+ insert(array[]);
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ Set!int set = Set!int([1, 2]);
+
+ assert(1 in set);
+ assert(2 in set);
+ }
+
+ /**
* Assigns another set.
*
* If $(D_PARAM that) is passed by reference, it will be copied.
@@ -410,6 +473,38 @@ if (is(typeof(hasher(T.init)) == size_t))
}
/**
+ * Inserts the value from a forward range into the set.
+ *
+ * Params:
+ * R = Range type.
+ * range = Forward range.
+ *
+ * Returns: The number of new elements inserted.
+ */
+ size_t insert(R)(R range)
+ if (isForwardRange!R && isImplicitlyConvertible!(ElementType!R, T))
+ {
+ size_t count;
+ foreach (e; range)
+ {
+ count += insert(e);
+ }
+ return count;
+ }
+
+ ///
+ @nogc nothrow pure @safe unittest
+ {
+ Set!int set;
+
+ int[3] range = [2, 1, 2];
+
+ assert(set.insert(range[]) == 2);
+ assert(1 in set);
+ assert(2 in set);
+ }
+
+ /**
* Removes an element.
*
* Params: