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

View File

@ -27,15 +27,112 @@ import tanya.memory;
*/ */
struct Range(E) struct Range(E)
{ {
private alias ContainerType = CopyConstness!(E, Array!(Bucket!(Unqual!E))); static if (isMutable!E)
private ContainerType* container; {
private alias DataRange = Array!(Bucket!(Unqual!E)).Range;
}
else
{
private alias DataRange = Array!(Bucket!(Unqual!E)).ConstRange;
}
private DataRange dataRange;
@disable this(); @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() @property Range save()
{ {
return this; 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; 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 = [ private static const size_t[41] primes = [
3, 7, 13, 23, 29, 37, 53, 71, 97, 131, 163, 193, 239, 293, 389, 521, 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, 769, 919, 1103, 1327, 1543, 2333, 3079, 4861, 6151, 12289, 24593,
@ -229,6 +344,21 @@ struct Set(T)
private DataType data; private DataType data;
private size_t lengthIndex; 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; mixin DefaultAllocator;
} }
@ -269,3 +399,15 @@ private unittest
assert(set.data[3].content == 16); assert(set.data[3].content == 16);
assert(set.data[4].status == BucketStatus.empty); 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));
}