Implement Set Range

This commit is contained in:
Eugen Wissner 2017-05-30 15:52:18 +02:00
parent 6c0588164a
commit 2815b53a88
2 changed files with 150 additions and 4 deletions

View File

@ -12,6 +12,7 @@
*/
module tanya.container.entry;
import std.traits;
import tanya.typecons;
package struct SEntry(T)
@ -63,14 +64,17 @@ package struct Bucket(T)
this.status = BucketStatus.used;
}
@property ref T content()
@property ref inout(T) content() inout
{
return this.content_;
}
void remove()
{
this.content = T.init;
static if (hasElaborateDestructor!T)
{
destroy(this.content);
}
this.status = BucketStatus.deleted;
}

View File

@ -27,15 +27,112 @@ import tanya.memory;
*/
struct Range(E)
{
private alias ContainerType = CopyConstness!(E, Array!(Bucket!(Unqual!E)));
private ContainerType* container;
static if (isMutable!E)
{
private alias DataRange = Array!(Bucket!(Unqual!E)).Range;
}
else
{
private alias DataRange = Array!(Bucket!(Unqual!E)).ConstRange;
}
private DataRange dataRange;
@disable this();
private this(DataRange dataRange)
{
while (!dataRange.empty && dataRange.front.status != BucketStatus.used)
{
dataRange.popFront();
}
while (!dataRange.empty && dataRange.back.status != BucketStatus.used)
{
dataRange.popBack();
}
this.dataRange = dataRange;
}
@property Range save()
{
return this;
}
@property bool empty() const
{
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);
}
body
{
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);
}
body
{
do
{
dataRange.popBack();
}
while (!dataRange.empty && dataRange.back.status != BucketStatus.used);
}
@property ref inout(E) front() inout
in
{
assert(!this.dataRange.empty);
assert(this.dataRange.front.status == BucketStatus.used);
}
body
{
return dataRange.front.content;
}
@property ref inout(E) back() inout
in
{
assert(!this.dataRange.empty);
assert(this.dataRange.back.status == BucketStatus.used);
}
body
{
return dataRange.back.content;
}
Range opIndex()
{
return typeof(return)(this.dataRange[]);
}
Range!(const E) opIndex() const
{
return typeof(return)(this.dataRange[]);
}
}
/**
@ -95,6 +192,24 @@ struct Set(T)
return this.data.length;
}
/**
* Iterates over the $(D_PSYMBOL Set) and counts the elements.
*
* Returns: Count of elements within the $(D_PSYMBOL Set).
*/
@property size_t length() const
{
size_t count;
foreach (ref e; this.data[])
{
if (e.status == BucketStatus.used)
{
++count;
}
}
return count;
}
private static const size_t[41] primes = [
3, 7, 13, 23, 29, 37, 53, 71, 97, 131, 163, 193, 239, 293, 389, 521,
769, 919, 1103, 1327, 1543, 2333, 3079, 4861, 6151, 12289, 24593,
@ -229,6 +344,21 @@ struct Set(T)
private DataType data;
private size_t lengthIndex;
/**
* Returns: A bidirectional range that iterates over the $(D_PSYMBOL Set)'s
* elements.
*/
Range opIndex()
{
return typeof(return)(data[]);
}
/// Ditto.
ConstRange opIndex() const
{
return typeof(return)(data[]);
}
mixin DefaultAllocator;
}
@ -269,3 +399,15 @@ private unittest
assert(set.data[3].content == 16);
assert(set.data[4].status == BucketStatus.empty);
}
// Static checks.
private unittest
{
import std.range.primitives;
static assert(isBidirectionalRange!(Set!int.ConstRange));
static assert(isBidirectionalRange!(Set!int.Range));
static assert(!isInfinite!(Set!int.Range));
static assert(!hasLength!(Set!int.Range));
}