Port Set ranges for HashTable
This commit is contained in:
parent
00dbb224f7
commit
3ed46117d1
@ -18,43 +18,40 @@ import tanya.container.array;
|
|||||||
import tanya.container.entry;
|
import tanya.container.entry;
|
||||||
import tanya.hash.lookup;
|
import tanya.hash.lookup;
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
import tanya.range.primitive;
|
import tanya.meta.trait;
|
||||||
import tanya.typecons;
|
import tanya.meta.transform;
|
||||||
|
|
||||||
/*struct Range(T)
|
/**
|
||||||
|
* Bidirectional range that iterates over the $(D_PSYMBOL Set)'s values.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* E = Element type.
|
||||||
|
*/
|
||||||
|
struct Range(E)
|
||||||
{
|
{
|
||||||
static if (is(T == const))
|
static if (isMutable!E)
|
||||||
{
|
{
|
||||||
private alias Buckets = T.buckets.ConstRange;
|
private alias DataRange = Array!(Bucket!(Unqual!E)).Range;
|
||||||
private alias Bucket = typeof(T.buckets[0]).ConstRange;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
private alias Buckets = T.buckets.Range;
|
private alias DataRange = Array!(Bucket!(Unqual!E)).ConstRange;
|
||||||
private alias Bucket = typeof(T.buckets[0]).Range;
|
|
||||||
}
|
}
|
||||||
private alias E = ElementType!Bucket;
|
private DataRange dataRange;
|
||||||
|
|
||||||
private Buckets buckets;
|
@disable this();
|
||||||
private Bucket bucket;
|
|
||||||
|
|
||||||
private bool findNextBucket()
|
private this(DataRange dataRange)
|
||||||
{
|
{
|
||||||
while (!this.buckets.empty)
|
while (!dataRange.empty && dataRange.front.status != BucketStatus.used)
|
||||||
{
|
{
|
||||||
if (!this.buckets.front.empty)
|
dataRange.popFront();
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
this.buckets.popFront();
|
|
||||||
}
|
}
|
||||||
return false;
|
while (!dataRange.empty && dataRange.back.status != BucketStatus.used)
|
||||||
}
|
{
|
||||||
|
dataRange.popBack();
|
||||||
private this(Buckets buckets)
|
}
|
||||||
{
|
this.dataRange = dataRange;
|
||||||
this.buckets = buckets;
|
|
||||||
this.bucket = findNextBucket() ? this.buckets.front[] : Bucket.init;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@property Range save()
|
@property Range save()
|
||||||
@ -64,36 +61,89 @@ import tanya.typecons;
|
|||||||
|
|
||||||
@property bool empty() const
|
@property bool empty() const
|
||||||
{
|
{
|
||||||
return this.buckets.empty;
|
return this.dataRange.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@property void popFront()
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(!this.dataRange.empty);
|
||||||
|
assert(this.dataRange.front.status == BucketStatus.used);
|
||||||
|
}
|
||||||
|
out
|
||||||
|
{
|
||||||
|
assert(this.dataRange.empty
|
||||||
|
|| this.dataRange.back.status == BucketStatus.used);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
dataRange.popFront();
|
||||||
|
}
|
||||||
|
while (!dataRange.empty && dataRange.front.status != BucketStatus.used);
|
||||||
|
}
|
||||||
|
|
||||||
|
@property void popBack()
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(!this.dataRange.empty);
|
||||||
|
assert(this.dataRange.back.status == BucketStatus.used);
|
||||||
|
}
|
||||||
|
out
|
||||||
|
{
|
||||||
|
assert(this.dataRange.empty
|
||||||
|
|| this.dataRange.back.status == BucketStatus.used);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
dataRange.popBack();
|
||||||
|
}
|
||||||
|
while (!dataRange.empty && dataRange.back.status != BucketStatus.used);
|
||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(E) front() inout
|
@property ref inout(E) front() inout
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(!empty);
|
assert(!this.dataRange.empty);
|
||||||
|
assert(this.dataRange.front.status == BucketStatus.used);
|
||||||
}
|
}
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
return this.bucket.front;
|
return dataRange.front.key;
|
||||||
}
|
}
|
||||||
|
|
||||||
void popFront()
|
@property ref inout(E) back() inout
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(!empty);
|
assert(!this.dataRange.empty);
|
||||||
|
assert(this.dataRange.back.status == BucketStatus.used);
|
||||||
}
|
}
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
this.bucket = findNextBucket() ? this.buckets.front[] : Bucket.init;
|
return dataRange.back.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
Range opIndex()
|
||||||
|
{
|
||||||
|
return typeof(return)(this.dataRange[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Range!(const E) opIndex() const
|
||||||
|
{
|
||||||
|
return typeof(return)(this.dataRange[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
static assert(is(HashTable!(string, int)));
|
import tanya.range.primitive : isForwardRange;
|
||||||
|
static assert(is(HashTable!(string, int) a));
|
||||||
static assert(is(const HashTable!(string, int)));
|
static assert(is(const HashTable!(string, int)));
|
||||||
static assert(isForwardRange!(Range!(HashTable!(string, int))));
|
static assert(isForwardRange!(HashTable!(string, int).Range));
|
||||||
}*/
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash table.
|
* Hash table.
|
||||||
@ -106,33 +156,34 @@ import tanya.typecons;
|
|||||||
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))
|
||||||
{
|
{
|
||||||
/* Forward range for $(D_PSYMBOL HashTable).
|
|
||||||
alias Range = .Range!HashTable;
|
|
||||||
|
|
||||||
/// ditto
|
|
||||||
alias ConstRange = .Range!(const HashTable);*/
|
|
||||||
|
|
||||||
private HashArray!(hasher, Key, Value) data;
|
private HashArray!(hasher, Key, Value) data;
|
||||||
|
|
||||||
private alias Buckets = typeof(this.data).Buckets;
|
private alias Buckets = typeof(this.data).Buckets;
|
||||||
|
|
||||||
|
/// The range types for $(D_PSYMBOL HashTable).
|
||||||
|
alias Range = .Range!Key;
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
alias ConstRange = .Range!(const Key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new hash table.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* size = Initial, approximate hash table size.
|
* n = Minimum number of buckets.
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*
|
*
|
||||||
* Precondition: `allocator !is null`.
|
* Precondition: $(D_INLINECODE allocator !is null).
|
||||||
*/
|
*/
|
||||||
this(size_t size, shared Allocator allocator = defaultAllocator)
|
this(size_t n, shared Allocator allocator = defaultAllocator)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(allocator !is null);
|
assert(allocator !is null);
|
||||||
}
|
}
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
this.data = typeof(this.data)(Buckets(size, allocator));
|
this(allocator);
|
||||||
|
rehash(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
@ -147,31 +198,68 @@ if (is(typeof(hasher(Key.init)) == size_t))
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of elements in the container.
|
* Initializes this $(D_PARAM HashTable) from another one.
|
||||||
*
|
*
|
||||||
* Returns: The number of elements in the container.
|
* If $(D_PARAM init) is passed by reference, it will be copied.
|
||||||
|
* If $(D_PARAM init) is passed by value, it will be moved.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* S = Source set type.
|
||||||
|
* init = Source set.
|
||||||
|
* allocator = Allocator.
|
||||||
*/
|
*/
|
||||||
@property size_t length() const
|
this(S)(ref S init, shared Allocator allocator = defaultAllocator)
|
||||||
|
if (is(Unqual!S == HashTable))
|
||||||
|
in
|
||||||
{
|
{
|
||||||
return this.data.length;
|
assert(allocator !is null);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
this.data = typeof(this.data)(Buckets(init.data, allocator));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
this(S)(S init, shared Allocator allocator = defaultAllocator)
|
||||||
|
if (is(S == HashTable))
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(allocator !is null);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
this.data = typeof(this.data)(Buckets(move(init.data), allocator));
|
||||||
|
this.lengthIndex = init.lengthIndex;
|
||||||
|
init.lengthIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells whether the container contains any elements.
|
* Assigns another hash table.
|
||||||
*
|
*
|
||||||
* Returns: Whether the container is empty.
|
* If $(D_PARAM that) is passed by reference, it will be copied.
|
||||||
|
* If $(D_PARAM that) is passed by value, it will be moved.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* S = Content type.
|
||||||
|
* that = The value should be assigned.
|
||||||
|
*
|
||||||
|
* Returns: $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
@property bool empty() const
|
ref typeof(this) opAssign(S)(ref S that)
|
||||||
|
if (is(Unqual!S == HashTable))
|
||||||
{
|
{
|
||||||
return length == 0;
|
this.data = that.data;
|
||||||
|
this.data.lengthIndex = that.data.lengthIndex;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// ditto
|
||||||
* Removes all elements.
|
ref typeof(this) opAssign(S)(S that) @trusted
|
||||||
*/
|
if (is(S == HashTable))
|
||||||
void clear()
|
|
||||||
{
|
{
|
||||||
this.data.clear();
|
swap(this.data, that.data);
|
||||||
|
swap(this.lengthIndex, that.lengthIndex);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -190,19 +278,86 @@ if (is(typeof(hasher(Key.init)) == size_t))
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum amount of elements this $(D_PSYMBOL Set) can hold without
|
* Maximum amount of elements this $(D_PSYMBOL HashTable) can hold without
|
||||||
* resizing and rehashing. Note that it doesn't mean that the
|
* resizing and rehashing. Note that it doesn't mean that the
|
||||||
* $(D_PSYMBOL Set) will hold $(I exactly) $(D_PSYMBOL capacity) elements.
|
* $(D_PSYMBOL Set) will hold $(I exactly) $(D_PSYMBOL capacity) elements.
|
||||||
* $(D_PSYMBOL capacity) tells the size of the container under a best-case
|
* $(D_PSYMBOL capacity) tells the size of the container under a best-case
|
||||||
* distribution of elements.
|
* distribution of elements.
|
||||||
*
|
*
|
||||||
* Returns: $(D_PSYMBOL Set) capacity.
|
* Returns: $(D_PSYMBOL HashTable) capacity.
|
||||||
*/
|
*/
|
||||||
@property size_t capacity() const
|
@property size_t capacity() const
|
||||||
{
|
{
|
||||||
return this.data.capacity;
|
return this.data.capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
HashTable!(string, int) hashTable;
|
||||||
|
assert(hashTable.capacity == 0);
|
||||||
|
|
||||||
|
hashTable["eight"] = 8;
|
||||||
|
assert(hashTable.capacity == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of elements in the container.
|
||||||
|
*
|
||||||
|
* Returns: The number of elements in the container.
|
||||||
|
*/
|
||||||
|
@property size_t length() const
|
||||||
|
{
|
||||||
|
return this.data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
HashTable!(string, int) hashTable;
|
||||||
|
assert(hashTable.length == 0);
|
||||||
|
|
||||||
|
hashTable["eight"] = 8;
|
||||||
|
assert(hashTable.length == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells whether the container contains any elements.
|
||||||
|
*
|
||||||
|
* Returns: Whether the container is empty.
|
||||||
|
*/
|
||||||
|
@property bool empty() const
|
||||||
|
{
|
||||||
|
return length == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
HashTable!(string, int) hashTable;
|
||||||
|
assert(hashTable.empty);
|
||||||
|
hashTable["five"] = 5;
|
||||||
|
assert(!hashTable.empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all elements.
|
||||||
|
*/
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
this.data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
HashTable!(string, int) hashTable;
|
||||||
|
hashTable["five"] = 5;
|
||||||
|
assert(!hashTable.empty);
|
||||||
|
hashTable.clear();
|
||||||
|
assert(hashTable.empty);
|
||||||
|
}
|
||||||
|
|
||||||
/// The maximum number of buckets the container can have.
|
/// The maximum number of buckets the container can have.
|
||||||
enum size_t maxBucketCount = primes[$ - 1];
|
enum size_t maxBucketCount = primes[$ - 1];
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user