formatValue

Formats any value into Char accepting OutputRange, using the given FormatSpec.

Aggregates: struct, union, class, and interface are formatted by calling toString.

toString should have one of the following signatures:

void toString(W)(ref W w, scope const ref FormatSpec fmt)
void toString(W)(ref W w)
string toString();

Where W is an output range which accepts characters. The template type does not have to be called W.

The following overloads are also accepted for legacy reasons or for use in virtual functions. It's recommended that any new code forgo these overloads if possible for speed and attribute acceptance reasons.

void toString(scope void delegate(const(char)[]) sink, const ref FormatSpec fmt);
void toString(scope void delegate(const(char)[]) sink, string fmt);
void toString(scope void delegate(const(char)[]) sink);

For the class objects which have input range interface,

  • If the instance toString has overridden Object.toString, it is used.
  • Otherwise, the objects are formatted as input range.

For the struct and union objects which does not have toString,

  • If they have range interface, formatted as input range.
  • Otherwise, they are formatted like Type(field1, filed2, ...).

Otherwise, are formatted just as their type name.

void
formatValue
(
Writer
T
Char
)
(
auto ref Writer w
,
auto ref T val
,
scope const ref FormatSpec!Char f
)

Parameters

w Writer

The output range to write to.

val T

The value to write.

f FormatSpec!Char

The std.format.FormatSpec defining how to write the value.

Examples

The following code compares the use of formatValue and formattedWrite.

import std.array : appender;

auto writer1 = appender!string();
writer1.formattedWrite("%08b", 42);

auto writer2 = appender!string();
auto f = singleSpec("%08b");
writer2.formatValue(42, f);

assert(writer1.data == writer2.data && writer1.data == "00101010");

bools are formatted as "true" or "false" with %s and as 1 or 0 with integral-specific format specs.

import std.array : appender;
auto w = appender!string();
auto spec = singleSpec("%s");
formatValue(w, true, spec);

assert(w.data == "true");

null literal is formatted as "null".

import std.array : appender;
auto w = appender!string();
auto spec = singleSpec("%s");
formatValue(w, null, spec);

assert(w.data == "null");

Integrals are formatted like core.stdc.stdio.printf.

import std.array : appender;
auto w = appender!string();
auto spec = singleSpec("%d");
formatValue(w, 1337, spec);

assert(w.data == "1337");

Floating-point values are formatted like core.stdc.stdio.printf

import std.array : appender;
auto w = appender!string();
auto spec = singleSpec("%.1f");
formatValue(w, 1337.7, spec);

assert(w.data == "1337.7");

Individual characters (char, wchar, or dchar`) are formatted as Unicode characters with %s and as integers with integral-specific format specs.

import std.array : appender;
auto w = appender!string();
auto spec = singleSpec("%c");
formatValue(w, 'a', spec);

assert(w.data == "a");

Strings are formatted like core.stdc.stdio.printf

import std.array : appender;
auto w = appender!string();
auto spec = singleSpec("%s");
formatValue(w, "hello", spec);

assert(w.data == "hello");

Static-size arrays are formatted as dynamic arrays.

import std.array : appender;
auto w = appender!string();
auto spec = singleSpec("%s");
char[2] two = ['a', 'b'];
formatValue(w, two, spec);

assert(w.data == "ab");

Dynamic arrays are formatted as input ranges.

Specializations:

  • void[] is formatted like ubyte[].
  • Const array is converted to input range by removing its qualifier.
import std.array : appender;
auto w = appender!string();
auto spec = singleSpec("%s");
auto two = [1, 2];
formatValue(w, two, spec);

assert(w.data == "[1, 2]");

Associative arrays are formatted by using ':' and ", " as separators, and enclosed by '[' and ']'.

import std.array : appender;
auto w = appender!string();
auto spec = singleSpec("%s");
auto aa = ["H":"W"];
formatValue(w, aa, spec);

assert(w.data == "[\"H\":\"W\"]", w.data);

enums are formatted like their base value

import std.array : appender;
auto w = appender!string();
auto spec = singleSpec("%s");

enum A { first, second, third }

formatValue(w, A.second, spec);

assert(w.data == "second");

Formatting a struct by defining a method toString, which takes an output range.

It's recommended that any toString using output ranges use std.range.primitives.put rather than use the put method of the range directly.

1 import std.array : appender;
2 import std.range.primitives;
3 
4 static struct Point
5 {
6     int x, y;
7 
8     void toString(W)(ref W writer, scope const ref FormatSpec!char f)
9     if (isOutputRange!(W, char))
10     {
11         // std.range.primitives.put
12         put(writer, "(");
13         formatValue(writer, x, f);
14         put(writer, ",");
15         formatValue(writer, y, f);
16         put(writer, ")");
17     }
18 }
19 
20 auto w = appender!string();
21 auto spec = singleSpec("%s");
22 auto p = Point(16, 11);
23 
24 formatValue(w, p, spec);
25 assert(w.data == "(16,11)");

Another example of formatting a struct with a defined toString, this time using the scope delegate method.

This method is now discouraged for non-virtual functions. If possible, please use the output range method instead.

1 static struct Point
2 {
3     int x, y;
4 
5     void toString(scope void delegate(scope const(char)[]) @safe sink,
6                   scope const FormatSpec!char fmt) const
7     {
8         sink("(");
9         sink.formatValue(x, fmt);
10         sink(",");
11         sink.formatValue(y, fmt);
12         sink(")");
13     }
14 }
15 
16 auto p = Point(16,11);
17 assert(format("%03d", p) == "(016,011)");
18 assert(format("%02x", p) == "(10,0b)");

Pointers are formatted as hex integers.

import std.array : appender;
auto w = appender!string();
auto spec = singleSpec("%s");

auto q = cast(void*) 0xFFEECCAA;
formatValue(w, q, spec);

assert(w.data == "FFEECCAA");

SIMD vectors are formatted as arrays.

1 import core.simd;
2 import std.array : appender;
3 auto w = appender!string();
4 auto spec = singleSpec("%s");
5 
6 static if (is(float4))
7 {
8     version (X86) {}
9     else
10     {
11         float4 f4;
12         f4.array[0] = 1;
13         f4.array[1] = 2;
14         f4.array[2] = 3;
15         f4.array[3] = 4;
16 
17         formatValue(w, f4, spec);
18         assert(w.data == "[1, 2, 3, 4]");
19     }
20 }

Delegates are formatted by ReturnType delegate(Parameters) FunctionAttributes

1 import std.conv : to;
2 
3 int i;
4 
5 int foo(short k) @nogc
6 {
7     return i + k;
8 }
9 
10 @system int delegate(short) @nogc bar() nothrow pure
11 {
12     int* p = new int(1);
13     i = *p;
14     return &foo;
15 }
16 
17 assert(to!string(&bar) == "int delegate(short) @nogc delegate() pure nothrow @system");
18 assert(() @trusted { return bar()(3); }() == 4);

Meta

Suggestion Box / Bug Report