Insert a range into the hash table and set

This commit is contained in:
Eugen Wissner 2018-05-30 18:39:27 +02:00
parent 61814d5383
commit bfe0748a63
2 changed files with 239 additions and 2 deletions

View File

@ -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))
@ -249,6 +252,71 @@ if (is(typeof(hasher(Key.init)) == size_t))
this.data.move(init.data, allocator);
}
/**
* 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.
*
@ -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;
}
///
@ -411,6 +478,81 @@ if (is(typeof(hasher(Key.init)) == size_t))
assert("Pachycephalosaurus" in hashTable);
}
/**
* 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).
*

View File

@ -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))
@ -246,6 +249,66 @@ if (is(typeof(hasher(T.init)) == size_t))
this.data.move(init.data, allocator);
}
/**
* 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.
*
@ -409,6 +472,38 @@ if (is(typeof(hasher(T.init)) == size_t))
assert(set.insert(8) == 1);
}
/**
* 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.
*