summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2017-05-30 15:52:18 +0200
committerEugen Wissner <belka@caraus.de>2017-05-30 15:52:18 +0200
commit2815b53a88330534de4756db11960aee72fd7da2 (patch)
tree13bd442f051d1376b4cfa2e31f75a40ed827fea8 /source
parent6c0588164a242e4f538e4d0cfd72dd0f5a469c43 (diff)
downloadtanya-2815b53a88330534de4756db11960aee72fd7da2.tar.gz
Implement Set Range
Diffstat (limited to 'source')
-rw-r--r--source/tanya/container/entry.d8
-rw-r--r--source/tanya/container/set.d146
2 files changed, 150 insertions, 4 deletions
diff --git a/source/tanya/container/entry.d b/source/tanya/container/entry.d
index e3b6ea8..0df388f 100644
--- a/source/tanya/container/entry.d
+++ b/source/tanya/container/entry.d
@@ -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;
}
diff --git a/source/tanya/container/set.d b/source/tanya/container/set.d
index f26e679..f459770 100644
--- a/source/tanya/container/set.d
+++ b/source/tanya/container/set.d
@@ -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));
+}