container.Set and HashTable: Fix constructors

This commit is contained in:
Eugen Wissner 2018-05-17 05:31:14 +02:00
parent 385ec19e2f
commit c511b97b1b
4 changed files with 126 additions and 18 deletions

View File

@ -26,7 +26,7 @@ Tanya consists of the following packages and (top-level) modules:
* `algorithm`: Collection of generic algorithms. * `algorithm`: Collection of generic algorithms.
* `async`: Event loop (epoll, kqueue and IOCP). * `async`: Event loop (epoll, kqueue and IOCP).
* `container`: Queue, Array, Singly and doubly linked lists, Buffers, UTF-8 * `container`: Queue, Array, Singly and doubly linked lists, Buffers, UTF-8
string, Hash table. string, Set, Hash table.
* `conv`: This module provides functions for converting between different * `conv`: This module provides functions for converting between different
types. types.
* `encoding`: This package provides tools to work with text encodings. * `encoding`: This package provides tools to work with text encodings.

View File

@ -16,7 +16,9 @@ module tanya.container.entry;
import tanya.algorithm.mutation; import tanya.algorithm.mutation;
import tanya.container.array; import tanya.container.array;
import tanya.memory.allocator;
import tanya.meta.trait; import tanya.meta.trait;
import tanya.meta.transform;
import tanya.typecons; import tanya.typecons;
package struct SEntry(T) package struct SEntry(T)
@ -119,6 +121,49 @@ package struct HashArray(alias hasher, K, V = void)
size_t lengthIndex; size_t lengthIndex;
size_t length; size_t length;
this(shared Allocator allocator)
in
{
assert(allocator !is null);
}
do
{
this.array = Buckets(allocator);
}
this(T)(ref T data, shared Allocator allocator)
if (is(Unqual!T == HashArray))
in
{
assert(allocator !is null);
}
do
{
this.array = Buckets(data.array, allocator);
this.lengthIndex = data.lengthIndex;
this.length = data.length;
}
// Move constructor
void move(ref HashArray data, shared Allocator allocator)
in
{
assert(allocator !is null);
}
do
{
this.array = Buckets(.move(data.array), allocator);
this.lengthIndex = data.lengthIndex;
this.length = data.length;
}
void swap(ref HashArray data)
{
.swap(this.array, data.array);
.swap(this.lengthIndex, data.lengthIndex);
.swap(this.length, data.length);
}
/* /*
* Returns bucket position for `hash`. `0` may mean the 0th position or an * Returns bucket position for `hash`. `0` may mean the 0th position or an
* empty `buckets` array. * empty `buckets` array.
@ -189,7 +234,7 @@ package struct HashArray(alias hasher, K, V = void)
return false; // Rehashing failed. return false; // Rehashing failed.
} }
} }
move(storage, this.array); .move(storage, this.array);
return true; return true;
} }

View File

@ -151,7 +151,7 @@ struct Range(T)
* Params: * Params:
* Key = Key type. * Key = Key type.
* Value = Value type. * Value = Value type.
* hasher = Hash function for $(D_PARAM K). * hasher = Hash function for $(D_PARAM Key).
*/ */
struct HashTable(Key, Value, alias hasher = hash) struct HashTable(Key, Value, alias hasher = hash)
if (is(typeof(hasher(Key.init)) == size_t)) if (is(typeof(hasher(Key.init)) == size_t))
@ -170,6 +170,13 @@ if (is(typeof(hasher(Key.init)) == size_t))
/// ditto /// ditto
alias ConstRange = .Range!(const HashArray); alias ConstRange = .Range!(const HashArray);
invariant
{
assert(this.data.lengthIndex < primes.length);
assert(this.data.array.length == 0
|| this.data.array.length == primes[this.data.lengthIndex]);
}
/** /**
* Constructor. * Constructor.
* *
@ -190,6 +197,13 @@ if (is(typeof(hasher(Key.init)) == size_t))
rehash(n); rehash(n);
} }
///
@nogc nothrow pure @safe unittest
{
auto hashTable = HashTable!(string, int)(5);
assert(hashTable.capacity == 7);
}
/// ditto /// ditto
this(shared Allocator allocator) this(shared Allocator allocator)
in in
@ -198,7 +212,7 @@ if (is(typeof(hasher(Key.init)) == size_t))
} }
do do
{ {
this.data = HashArray(Buckets(allocator)); this.data = HashArray(allocator);
} }
/** /**
@ -220,7 +234,7 @@ if (is(typeof(hasher(Key.init)) == size_t))
} }
do do
{ {
this.data = HashArray(Buckets(init.data, allocator)); this.data = HashArray(init.data, allocator);
} }
/// ditto /// ditto
@ -232,9 +246,7 @@ if (is(typeof(hasher(Key.init)) == size_t))
} }
do do
{ {
this.data = HashArray(Buckets(move(init.data), allocator)); this.data.move(init.data, allocator);
this.lengthIndex = init.lengthIndex;
init.lengthIndex = 0;
} }
/** /**
@ -261,8 +273,7 @@ if (is(typeof(hasher(Key.init)) == size_t))
ref typeof(this) opAssign(S)(S that) @trusted ref typeof(this) opAssign(S)(S that) @trusted
if (is(S == HashTable)) if (is(S == HashTable))
{ {
swap(this.data, that.data); this.data.swap(that.data);
swap(this.lengthIndex, that.lengthIndex);
return this; return this;
} }
@ -576,3 +587,27 @@ if (is(typeof(hasher(Key.init)) == size_t))
static assert(is(const HashTable!(string, int))); static assert(is(const HashTable!(string, int)));
static assert(isForwardRange!(HashTable!(string, int).Range)); static assert(isForwardRange!(HashTable!(string, int).Range));
} }
// Constructs by reference
@nogc nothrow pure @safe unittest
{
auto hashTable1 = HashTable!(string, int)(7);
auto hashTable2 = HashTable!(string, int)(hashTable1);
assert(hashTable1.length == hashTable2.length);
assert(hashTable1.capacity == hashTable2.capacity);
}
// Constructs by value
@nogc nothrow pure @safe unittest
{
auto hashTable = HashTable!(string, int)(HashTable!(string, int)(7));
assert(hashTable.capacity == 7);
}
// Assigns by value
@nogc nothrow pure @safe unittest
{
HashTable!(string, int) hashTable;
hashTable = HashTable!(string, int)(7);
assert(hashTable.capacity == 7);
}

View File

@ -194,6 +194,13 @@ if (is(typeof(hasher(T.init)) == size_t))
rehash(n); rehash(n);
} }
///
@nogc nothrow pure @safe unittest
{
auto set = Set!int(5);
assert(set.capacity == 7);
}
/// ditto /// ditto
this(shared Allocator allocator) this(shared Allocator allocator)
in in
@ -202,7 +209,7 @@ if (is(typeof(hasher(T.init)) == size_t))
} }
do do
{ {
this.data = HashArray(Buckets(allocator)); this.data = HashArray(allocator);
} }
/** /**
@ -224,7 +231,7 @@ if (is(typeof(hasher(T.init)) == size_t))
} }
do do
{ {
this.data = HashArray(Buckets(init.data, allocator)); this.data = HashArray(init.data, allocator);
} }
/// ditto /// ditto
@ -236,9 +243,7 @@ if (is(typeof(hasher(T.init)) == size_t))
} }
do do
{ {
this.data = HashArray(Buckets(move(init.data), allocator)); this.data.move(init.data, allocator);
this.lengthIndex = init.lengthIndex;
init.lengthIndex = 0;
} }
/** /**
@ -257,7 +262,7 @@ if (is(typeof(hasher(T.init)) == size_t))
if (is(Unqual!S == Set)) if (is(Unqual!S == Set))
{ {
this.data = that.data; this.data = that.data;
this.lengthIndex = that.lengthIndex; this.data.lengthIndex = that.data.lengthIndex;
return this; return this;
} }
@ -265,8 +270,7 @@ if (is(typeof(hasher(T.init)) == size_t))
ref typeof(this) opAssign(S)(S that) @trusted ref typeof(this) opAssign(S)(S that) @trusted
if (is(S == Set)) if (is(S == Set))
{ {
swap(this.data, that.data); this.data.swap(that.data);
swap(this.lengthIndex, that.lengthIndex);
return this; return this;
} }
@ -598,3 +602,27 @@ if (is(typeof(hasher(T.init)) == size_t))
auto set = Set!int(8); auto set = Set!int(8);
assert(set.capacity == 13); assert(set.capacity == 13);
} }
// Constructs by reference
@nogc nothrow pure @safe unittest
{
auto set1 = Set!int(7);
auto set2 = Set!int(set1);
assert(set1.length == set2.length);
assert(set1.capacity == set2.capacity);
}
// Constructs by value
@nogc nothrow pure @safe unittest
{
auto set = Set!int(Set!int(7));
assert(set.capacity == 7);
}
// Assigns by value
@nogc nothrow pure @safe unittest
{
Set!int set;
set = Set!int(7);
assert(set.capacity == 7);
}