Skip to content

Commit b7395ea

Browse files
authored
std.conv: add writeText, writeWText, writeDText (#10652)
* std.conv: factor out writeTextImpl from textImpl * std.conv: add writeText, writeWText, writeDText These are variants of text, wtext, and dtext that write their output to an output range instead of returning a string. Fixes #10550 * Add changelog entry for writeText
1 parent 4ec4e54 commit b7395ea

File tree

2 files changed

+117
-20
lines changed

2 files changed

+117
-20
lines changed

changelog/write-text.dd

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Add `writeText`, `writeWText`, and `writeDText` to `std.conv`
2+
3+
These functions are variants of the existing `text`, `wtext`, and `dtext`
4+
functions. Instead of returning a string, they write their output to an output
5+
range.
6+
7+
Like `text`, `writeText` can accept an
8+
$(LINK2 $(ROOT_DIR)spec/istring.html, interpolated expression sequence) as an
9+
argument.
10+
11+
Example:
12+
13+
---
14+
import std.conv : writeText;
15+
import std.array : appender;
16+
17+
auto output = appender!string();
18+
output.writeText(i"2 + 2 == $(2 + 2)");
19+
assert(output.data == "2 + 2 == 4");
20+
---

std/conv.d

+97-20
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ $(TR $(TD Strings) $(TD
1919
$(LREF text)
2020
$(LREF wtext)
2121
$(LREF dtext)
22+
$(LREF writeText)
23+
$(LREF writeWText)
24+
$(LREF writeDText)
2225
$(LREF hexString)
2326
))
2427
$(TR $(TD Numeric) $(TD
@@ -5076,6 +5079,75 @@ if (T.length > 0) { return textImpl!dstring(args); }
50765079
assert(text(dg4) == "bool delegate(bool, int) @trusted");
50775080
}
50785081

5082+
/// Convenience functions for writing arguments to an output range as text.
5083+
void writeText(Sink, T...)(ref Sink sink, T args)
5084+
if (isOutputRange!(Sink, char) && T.length > 0)
5085+
{
5086+
sink.writeTextImpl!string(args);
5087+
}
5088+
5089+
/// ditto
5090+
void writeWText(Sink, T...)(ref Sink sink, T args)
5091+
if (isOutputRange!(Sink, wchar) && T.length > 0)
5092+
{
5093+
sink.writeTextImpl!wstring(args);
5094+
}
5095+
5096+
/// ditto
5097+
void writeDText(Sink, T...)(ref Sink sink, T args)
5098+
if (isOutputRange!(Sink, dchar) && T.length > 0)
5099+
{
5100+
sink.writeTextImpl!dstring(args);
5101+
}
5102+
5103+
///
5104+
@safe unittest
5105+
{
5106+
import std.array : appender;
5107+
5108+
auto output = appender!string();
5109+
output.writeText("The answer is ", 42);
5110+
5111+
assert(output.data == "The answer is 42");
5112+
}
5113+
5114+
///
5115+
@safe unittest
5116+
{
5117+
import std.array : appender;
5118+
5119+
const color = "red";
5120+
auto output = appender!string();
5121+
output.writeText(i"My favorite color is $(color)");
5122+
5123+
assert(output.data == "My favorite color is red");
5124+
}
5125+
5126+
@safe unittest
5127+
{
5128+
auto capp = appender!string();
5129+
auto wapp = appender!wstring();
5130+
auto dapp = appender!dstring();
5131+
5132+
capp.writeText(42, ' ', 1.5, ": xyz");
5133+
wapp.writeWText(42, ' ', 1.5, ": xyz");
5134+
dapp.writeDText(42, ' ', 1.5, ": xyz");
5135+
5136+
assert(capp.data == "42 1.5: xyz"c);
5137+
assert(wapp.data == "42 1.5: xyz"w);
5138+
assert(dapp.data == "42 1.5: xyz"d);
5139+
}
5140+
5141+
// Check range API compliance using OutputRange interface
5142+
@system unittest
5143+
{
5144+
import std.range.interfaces : OutputRange, outputRangeObject;
5145+
import std.range : nullSink;
5146+
5147+
OutputRange!char testOutput = outputRangeObject!char(nullSink);
5148+
testOutput.writeText(42, ' ', 1.5, ": xyz");
5149+
}
5150+
50795151
private S textImpl(S, U...)(U args)
50805152
{
50815153
static if (U.length == 0)
@@ -5096,30 +5168,35 @@ private S textImpl(S, U...)(U args)
50965168
// assume that on average, parameters will have less
50975169
// than 20 elements
50985170
app.reserve(U.length * 20);
5099-
// Must be static foreach because of https://issues.dlang.org/show_bug.cgi?id=21209
5100-
static foreach (arg; args)
5101-
{
5102-
static if (
5103-
isSomeChar!(typeof(arg))
5104-
|| isSomeString!(typeof(arg))
5105-
|| ( isInputRange!(typeof(arg)) && isSomeChar!(ElementType!(typeof(arg))) )
5106-
)
5107-
app.put(arg);
5108-
else static if (
5109-
5110-
is(immutable typeof(arg) == immutable uint) || is(immutable typeof(arg) == immutable ulong) ||
5111-
is(immutable typeof(arg) == immutable int) || is(immutable typeof(arg) == immutable long)
5112-
)
5113-
// https://issues.dlang.org/show_bug.cgi?id=17712#c15
5114-
app.put(textImpl!(S)(arg));
5115-
else
5116-
app.put(to!S(arg));
5117-
}
5118-
5171+
app.writeTextImpl!S(args);
51195172
return app.data;
51205173
}
51215174
}
51225175

5176+
private void writeTextImpl(S, Sink, U...)(ref Sink sink, U args)
5177+
if (isSomeString!S && isOutputRange!(Sink, ElementEncodingType!S))
5178+
{
5179+
// Must be static foreach because of https://issues.dlang.org/show_bug.cgi?id=21209
5180+
static foreach (arg; args)
5181+
{
5182+
static if (
5183+
isSomeChar!(typeof(arg))
5184+
|| isSomeString!(typeof(arg))
5185+
|| ( isInputRange!(typeof(arg)) && isSomeChar!(ElementType!(typeof(arg))) )
5186+
)
5187+
put(sink, arg);
5188+
else static if (
5189+
5190+
is(immutable typeof(arg) == immutable uint) || is(immutable typeof(arg) == immutable ulong) ||
5191+
is(immutable typeof(arg) == immutable int) || is(immutable typeof(arg) == immutable long)
5192+
)
5193+
// https://issues.dlang.org/show_bug.cgi?id=17712#c15
5194+
put(sink, textImpl!(S)(arg));
5195+
else
5196+
put(sink, to!S(arg));
5197+
}
5198+
}
5199+
51235200

51245201
/***************************************************************
51255202
The `octal` facility provides a means to declare a number in base 8.

0 commit comments

Comments
 (0)