summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml4
-rw-r--r--source/tanya/format.d94
-rw-r--r--source/tanya/range/adapter.d54
3 files changed, 109 insertions, 43 deletions
diff --git a/.travis.yml b/.travis.yml
index 60125aa..a358fb0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,7 +23,7 @@ matrix:
include:
- name: D-Scanner
d: dmd-$LATEST
- env: DSCANNER=0.5.11
+ env: DSCANNER=0.6.0
os: linux
- name: DDoc
d: dmd-$LATEST
@@ -32,7 +32,7 @@ matrix:
allow_failures:
- name: D-Scanner
d: dmd-$LATEST
- env: DSCANNER=0.5.11
+ env: DSCANNER=0.6.0
os: linux
addons:
diff --git a/source/tanya/format.d b/source/tanya/format.d
index fa46945..eade00a 100644
--- a/source/tanya/format.d
+++ b/source/tanya/format.d
@@ -30,7 +30,7 @@
*
* More advanced formatting is currently not implemented.
*
- * Copyright: Eugene Wissner 2017-2018.
+ * Copyright: Eugene Wissner 2017-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
@@ -47,8 +47,7 @@ static import tanya.memory.op;
import tanya.meta.metafunction;
import tanya.meta.trait;
import tanya.meta.transform;
-import tanya.range.array;
-import tanya.range.primitive;
+import tanya.range;
import tanya.typecons : Tuple;
// Returns the last part of buffer with converted number.
@@ -1989,7 +1988,7 @@ private const(char)[] real2String(double value,
}
}
-private void formatReal(T)(ref T arg, ref String result)
+private void formatReal(T, OR)(ref T arg, OR result)
if (isFloatingPoint!T)
{
char[512] buffer; // Big enough for e+308 or e-307.
@@ -2017,11 +2016,11 @@ if (isFloatingPoint!T)
if (negative)
{
- result.insertBack('-');
+ put(result, "-");
}
if (decimalPoint == special)
{
- result.insertBack(realString);
+ put(result, realString);
return;
}
@@ -2181,11 +2180,11 @@ if (isFloatingPoint!T)
// Get the length that we've copied.
length = cast(uint) (buffer.length - bufferSlice.length);
- result.insertBack(buffer[64 .. length]); // Number.
- result.insertBack(tail[1 .. tail[0] + 1]); // Tail.
+ put(result, buffer[64 .. length]); // Number.
+ put(result, tail[1 .. tail[0] + 1]); // Tail.
}
-private void formatStruct(T)(ref T arg, ref String result)
+private void formatStruct(T, OR)(ref T arg, OR result)
if (is(T == struct))
{
template pred(alias f)
@@ -2202,24 +2201,24 @@ if (is(T == struct))
}
alias fields = Filter!(pred, __traits(allMembers, T));
- result.insertBack(T.stringof);
- result.insertBack('(');
+ put(result, T.stringof);
+ put(result, "(");
static if (fields.length > 0)
{
printToString!"{}"(result, __traits(getMember, arg, fields[0]));
foreach (field; fields[1 .. $])
{
- result.insertBack(", ");
+ put(result, ", ");
printToString!"{}"(result, __traits(getMember, arg, field));
}
}
- result.insertBack(')');
+ put(result, ")");
}
-private void formatRange(T)(ref T arg, ref String result)
+private void formatRange(T, OR)(ref T arg, OR result)
if (isInputRange!T && !isInfinite!T)
{
- result.insertBack('[');
+ put(result, "[");
if (!arg.empty)
{
printToString!"{}"(result, arg.front);
@@ -2227,24 +2226,24 @@ if (isInputRange!T && !isInfinite!T)
}
foreach (e; arg)
{
- result.insertBack(", ");
+ put(result, ", ");
printToString!"{}"(result, e);
}
- result.insertBack(']');
+ put(result, "]");
}
-private ref String printToString(string fmt, Args...)(return ref String result,
- auto ref Args args)
+private void printToString(string fmt, OR, Args...)(ref OR result,
+ auto ref Args args)
{
alias Arg = Args[0];
static if (is(Unqual!Arg == typeof(null))) // null
{
- result.insertBack("null");
+ put(result, "null");
}
else static if (is(Unqual!Arg == bool)) // Boolean
{
- result.insertBack(args[0] ? "true" : "false");
+ put(result, args[0] ? "true" : "false");
}
else static if (is(Arg == enum)) // Enum
{
@@ -2252,19 +2251,19 @@ private ref String printToString(string fmt, Args...)(return ref String result,
{
if (args[0] == __traits(getMember, Arg, m))
{
- result.insertBack(m);
+ put(result, m);
}
}
}
else static if (isSomeChar!Arg || isSomeString!Arg) // String or char
{
- result.insertBack(args[0]);
+ put(result, args[0]);
}
else static if (isInputRange!Arg
&& !isInfinite!Arg
&& isSomeChar!(ElementType!Arg)) // Stringish range
{
- result.insertBack(args[0]);
+ put(result, args[0]);
}
else static if (isInputRange!Arg && !isInfinite!Arg)
{
@@ -2276,25 +2275,25 @@ private ref String printToString(string fmt, Args...)(return ref String result,
{
if (args[0] is null)
{
- result.insertBack("null");
+ put(result, "null");
}
else
{
- result.insertBack(args[0].stringify()[]);
+ put(result, args[0].stringify()[]);
}
}
else
{
- result.insertBack(args[0].stringify()[]);
+ put(result, args[0].stringify()[]);
}
}
else static if (is(Arg == class))
{
- result.insertBack(args[0] is null ? "null" : args[0].toString());
+ put(result, args[0] is null ? "null" : args[0].toString());
}
else static if (is(Arg == interface))
{
- result.insertBack(Arg.classinfo.name);
+ put(result, Arg.classinfo.name);
}
else static if (is(Arg == struct))
{
@@ -2302,7 +2301,7 @@ private ref String printToString(string fmt, Args...)(return ref String result,
}
else static if (is(Arg == union))
{
- result.insertBack(Arg.stringof);
+ put(result, Arg.stringof);
}
else static if (isFloatingPoint!Arg) // Float
{
@@ -2321,21 +2320,19 @@ private ref String printToString(string fmt, Args...)(return ref String result,
}
while (address != 0);
- result.insertBack("0x");
- result.insertBack(buffer[position .. $]);
+ put(result, "0x");
+ put(result, buffer[position .. $]);
}
else static if (isIntegral!Arg) // Integer
{
char[21] buffer;
- result.insertBack(integral2String(args[0], buffer));
+ put(result, integral2String(args[0], buffer));
}
else
{
static assert(false,
"Formatting type " ~ Arg.stringof ~ " is not supported");
}
-
- return result;
}
/**
@@ -2351,28 +2348,47 @@ private ref String printToString(string fmt, Args...)(return ref String result,
String format(string fmt, Args...)(auto ref Args args)
{
String formatted;
+ sformat!fmt(backInserter(formatted), args);
+ return formatted;
+}
+/**
+ * Produces a string according to the specified format and writes it into an
+ * output range. $(D_PSYMBOL sformat) writes the final string in chunks, so the
+ * output range should be in output range for `const(char)[]`.
+ *
+ * Params:
+ * fmt = Format.
+ * R = Output range type.
+ * output = Output range.
+ * args = Arguments.
+ *
+ * Returns: $(D_PARAM output).
+ */
+R sformat(string fmt, R, Args...)(return R output, auto ref Args args)
+if (isOutputRange!(R, const(char)[]))
+{
alias Specs = ParseFmt!fmt;
enum bool FormatSpecFilter(alias spec) = is(typeof(spec) == FormatSpec);
static assert((Filter!(FormatSpecFilter, ParseFmt!fmt)).length == Args.length,
- "Number of the arguments doesn't match the format strign");
+ "Number of the arguments doesn't match the format string");
foreach (spec; Specs)
{
static if (FormatSpecFilter!spec)
{
- printToString!"{}"(formatted, args[spec.position]);
+ printToString!"{}"(output, args[spec.position]);
}
else static if (isSomeString!(typeof(spec)))
{
- formatted.insertBack(spec);
+ put(output, spec);
}
else
{
static assert(false, "Format string parsed incorrectly");
}
}
- return formatted;
+ return output;
}
// doesn't print the first argument repeatedly
diff --git a/source/tanya/range/adapter.d b/source/tanya/range/adapter.d
index ec2e5d9..7c3cb5e 100644
--- a/source/tanya/range/adapter.d
+++ b/source/tanya/range/adapter.d
@@ -3,9 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
- * Range adapters.
+ * Range adapters transform some data structures into ranges.
*
- * Copyright: Eugene Wissner 2018.
+ * Copyright: Eugene Wissner 2018-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
@@ -13,3 +13,53 @@
* tanya/range/adapter.d)
*/
module tanya.range.adapter;
+
+import tanya.functional;
+import tanya.meta.trait;
+import tanya.range;
+
+version (unittest)
+{
+ static struct Container
+ {
+ void insertBack(const(char)[])
+ {
+ }
+ }
+}
+
+package (tanya) auto backInserter(Container)(return ref Container container)
+if (hasMember!(Container, "insertBack"))
+{
+ static struct BackInserter
+ {
+ private Container* container;
+
+ this(ref Container container) @trusted
+ {
+ this.container = &container;
+ }
+
+ void opCall(T)(auto ref T data)
+ {
+ this.container.insertBack(forward!data);
+ }
+ }
+ return BackInserter(container);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ auto func()()
+ {
+ Container container;
+ return backInserter(container);
+ }
+ static assert(!is(typeof(func!())));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ Container container;
+ static assert(isOutputRange!(typeof(backInserter(container)), string));
+}