diff options
| author | Eugen Wissner <belka@caraus.de> | 2018-05-30 18:39:27 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2018-05-30 18:50:52 +0200 |
| commit | bfe0748a631a3f4606f97cb932af40b3851242c8 (patch) | |
| tree | 35b4bd500cc8863ccd65543c26901c2bcbc347d4 | |
| parent | 61814d53833b5f66e14d57f3c71b5e6425067ce7 (diff) | |
| download | tanya-bfe0748a631a3f4606f97cb932af40b3851242c8.tar.gz | |
Insert a range into the hash table and set
| -rw-r--r-- | source/tanya/container/hashtable.d | 146 | ||||
| -rw-r--r-- | source/tanya/container/set.d | 95 |
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: |
