summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2018-11-12 07:54:52 +0100
committerEugen Wissner <belka@caraus.de>2018-11-12 07:54:52 +0100
commit9e6f5c3105c05bf6e5ff33dbd2b3d2015cdb9e53 (patch)
tree9c70e3971f835d252ab7db6e7a8b5b8ac1d3eb7a /source
parent3f667823689475912700e1f7fb5a356c0bab461e (diff)
downloadtanya-9e6f5c3105c05bf6e5ff33dbd2b3d2015cdb9e53.tar.gz
Add algorithm.mutation.rotate
Diffstat (limited to 'source')
-rw-r--r--source/tanya/algorithm/mutation.d86
-rw-r--r--source/tanya/container/array.d12
-rw-r--r--source/tanya/container/string.d8
3 files changed, 95 insertions, 11 deletions
diff --git a/source/tanya/algorithm/mutation.d b/source/tanya/algorithm/mutation.d
index 99ba239..9c05826 100644
--- a/source/tanya/algorithm/mutation.d
+++ b/source/tanya/algorithm/mutation.d
@@ -607,3 +607,89 @@ if (isInputRange!Range && hasLvalueElements!Range)
assert(counter == 2);
}
+
+/**
+ * Rotates the elements of a union of two ranges.
+ *
+ * Performs a left rotation on the given ranges, as if it would be a signle
+ * range, so that [`front.front`, `back.front`$(RPAREN) is a valid range, that
+ * is $(D_PARAM back) would continue $(D_PARAM front).
+ *
+ * The elements are moved so, that the first element of $(D_PARAM back) becomes
+ * the first element of $(D_PARAM front) without changing the relative order of
+ * their elements.
+ *
+ * Params:
+ * Range = Range type.
+ * front = Left half.
+ * back = Right half.
+ */
+void rotate(Range)(Range front, Range back)
+if (isForwardRange!Range && hasSwappableElements!Range)
+{
+ auto next = back.save();
+
+ while (!front.empty && !next.empty && !sameHead(front, next))
+ {
+ swap(front.front, next.front);
+ front.popFront();
+ next.popFront();
+
+ if (next.empty)
+ {
+ next = back.save();
+ }
+ else if (front.empty)
+ {
+ front = back.save();
+ back = next.save();
+ }
+ }
+}
+
+///
+@nogc nothrow pure @safe unittest
+{
+ import tanya.algorithm.comparison : equal;
+
+ const int[7] expected = [1, 2, 3, 4, 5, 6, 7];
+ int[7] actual = [5, 6, 3, 4, 1, 2, 7];
+
+ rotate(actual[0 .. 2], actual[4 .. 6]);
+ assert(equal(actual[], expected[]));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ import tanya.algorithm.comparison : equal;
+
+ const int[5] expected = [1, 2, 3, 4, 5];
+ int[5] actual = [4, 5, 1, 2, 3];
+
+ rotate(actual[0 .. 2], actual[2 .. $]);
+ assert(equal(actual[], expected[]));
+}
+
+// Doesn't cause an infinite loop if back is shorter than the front
+@nogc nothrow pure @safe unittest
+{
+ import tanya.algorithm.comparison : equal;
+
+ const int[5] expected = [1, 2, 3, 4, 5];
+ int[5] actual = [3, 4, 5, 1, 2];
+
+ rotate(actual[0 .. 3], actual[3 .. $]);
+ assert(equal(actual[], expected[]));
+}
+
+// Doesn't call .front on an empty front
+@nogc nothrow pure @safe unittest
+{
+ import tanya.algorithm.comparison : equal;
+
+ const int[2] expected = [2, 8];
+ int[2] actual = expected;
+
+ rotate(actual[0 .. 0], actual[]);
+ assert(equal(actual[], expected[]));
+}
diff --git a/source/tanya/container/array.d b/source/tanya/container/array.d
index e0556dd..c2e35e2 100644
--- a/source/tanya/container/array.d
+++ b/source/tanya/container/array.d
@@ -15,7 +15,6 @@
module tanya.container.array;
import core.checkedint;
-import std.algorithm.mutation : bringToFront;
import tanya.algorithm.comparison;
import tanya.algorithm.mutation;
import tanya.exception;
@@ -804,10 +803,11 @@ struct Array(T)
}
do
{
- const oldLen = length;
- const offset = r.end - this.data;
+ const oldLength = length;
+ const after = r.end - this.data;
const inserted = insertBack(el);
- bringToFront(this.data[offset .. oldLen], this.data[oldLen .. length]);
+
+ rotate(this.data[after .. oldLength], this.data[oldLength .. length]);
return inserted;
}
@@ -846,7 +846,7 @@ struct Array(T)
{
moveBack(el);
}
- bringToFront(this.data[offset .. oldLen], this.data[oldLen .. length]);
+ rotate(this.data[offset .. oldLen], this.data[oldLen .. length]);
return 1;
}
@@ -902,7 +902,7 @@ struct Array(T)
{
moveBack(el);
}
- bringToFront(this.data[offset .. oldLen], this.data[oldLen .. length]);
+ rotate(this.data[offset .. oldLen], this.data[oldLen .. length]);
return 1;
}
diff --git a/source/tanya/container/string.d b/source/tanya/container/string.d
index e8c2d71..abe60e1 100644
--- a/source/tanya/container/string.d
+++ b/source/tanya/container/string.d
@@ -26,7 +26,6 @@
*/
module tanya.container.string;
-import std.algorithm.mutation : bringToFront;
import tanya.algorithm.comparison;
import tanya.algorithm.mutation;
import tanya.hash.lookup;
@@ -1531,11 +1530,10 @@ struct String
do
{
const oldLength = length;
- const rangeEnd = r.end - this.data;
+ const after = r.end - this.data;
const inserted = insertBack(el);
- auto containerEnd = this.data + oldLength;
- bringToFront(ByCodeUnit!char(this, this.data + rangeEnd, containerEnd),
- ByCodeUnit!char(this, containerEnd, this.data + length));
+
+ rotate(this.data[after .. oldLength], this.data[oldLength .. length]);
return inserted;
}