Report a bug
If you spot a problem with this page, click here to create a GitHub issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

mir.format

@nogc Formatting Utilities

License:
Authors:
Ilya Yaroshenko
Examples:
mir.conv: to extension.
import mir.conv: to;
import mir.small_string;
alias S = SmallString!32;

// Floating-point numbers are formatted to
// the shortest precise exponential notation.
assert(123.0.to!S == "123.0");
assert(123.to!(immutable S) == "123");
assert(true.to!S == "true");
assert(true.to!string == "true");

assert((cast(S)"str")[] == "str");
Examples:
mir.conv: to extension.
import mir.conv: to;
import mir.small_string;
alias S = SmallString!32;

auto str = S("str");
assert(str.to!(const(char)[]) == "str"); // GC allocated result
assert(str.to!(char[]) == "str"); // GC allocated result
Examples:
ditto
import mir.conv: to;
import mir.small_string;
alias S = SmallString!32;

// Floating-point numbers are formatted to
// the shortest precise exponential notation.
assert(123.0.to!string == "123.0");
assert(123.to!(char[]) == "123");

assert(S("str").to!string == "str"); // GC allocated result
string text(string separator = "", Args...)(auto ref Args args)
if (Args.length > 0);
Concatenated string results
Examples:
const i = 100;
assert(text("str ", true, " ", i, " ", 124.1) == "str true 100 124.1", text("str ", true, " ", 100, " ", 124.1));
assert(text!" "("str", true, 100, 124.1) == "str true 100 124.1");
struct GetData;
enum GetData getData;
struct _stringBuf(C);

alias stringBuf = _stringBuf!char._stringBuf;

alias wstringBuf = _stringBuf!wchar._stringBuf;

alias dstringBuf = _stringBuf!dchar._stringBuf;
ScopedBuffer!(C, 256) buffer;
template StreamFormatOp(C)
Examples:
auto name = "D";
auto ver = 2.0;
assert(stringBuf() << "Hi " << name << ver << "!\n" << getData == "Hi D2.0!\n");
Examples:
auto name = "D"w;
auto ver = 2;
assert(wstringBuf() << "Hi "w << name << ver << "!\n"w << getData == "Hi D2!\n"w);
Examples:
auto name = "D"d;
auto ver = 2UL;
assert(dstringBuf() << "Hi "d  << name << ver << "!\n"d << getData == "Hi D2!\n");
ref scope typeof(this) opBinary(string op : "<<", T)(ref const T c);
ref scope typeof(this) opBinary(string op : "<<", T)(const T c);

scope const(C)[] opBinary(string op : "<<", T : GetData)(const T c);
struct NumericSpec;
Mir's numeric format specification

Note the specification isn't complete an may be extended in the future.

enum Format: int;
human
Human-frindly precise output.
Examples:
0.000001, 600000.0, but 1e-7 and 6e7.
exponent
Precise output with explicit exponent.
Examples:
1e-6, 6e6, 1.23456789e-100.
Format format;
char separatorChar;
Default valus is '\0' (no separators)
char exponentChar;
Defaults to 'e'
bool plus;
Adds '+' to positive numbers and +0.
ubyte separatorCount;
Separator count
enum NumericSpec exponent;
Precise output with explicit exponent.
Examples:
1e-6, 6e6, 1.23456789e-100.
enum NumericSpec human;
Human-frindly precise output.
struct FormatSpec;
C's compatible format specifier.
bool dash;
bool plus;
bool space;
bool hash;
bool zero;
char format;
char separator;
ubyte unitSize;
int width;
int precision;
enum SwitchLU: bool;
lower
upper
struct FormattedFloating(T) if (is(T == float) || is(T == double) || is(T == real));

FormattedFloating!T withFormat(T)(const T value, FormatSpec spec);
Wrapper to format floating point numbers using C's library.
T value;
FormatSpec spec;
const scope void toString(C = char, W)(ref scope W w)
if (isSomeChar!C);
struct HexAddress(T) if (isUnsigned!T && !is(T == enum));
T value;
SwitchLU switchLU;
const scope void toString(C = char, W)(ref scope W w)
if (isSomeChar!C);
enum EscapeFormat: int;
Escaped string formats
json
JSON escaped string format
ionClob
Amzn Ion CLOB format
ionSymbol
Amzn Ion symbol format
ion
Amzn Ion string format
ref W printEscaped(C, EscapeFormat escapeFormat = EscapeFormat.ion, W)(return ref scope W w, scope const(C)[] str)
if (isOutputRange!(W, C));
Examples:
import mir.format: stringBuf;
stringBuf w;
assert(w.printEscaped("Hi \a\v\0\f\t\b \\\r\n" ~ `"@nogc"`).data == `Hi \a\v\0\f\t\b \\\r\n\"@nogc\"`);
w.reset;
assert(w.printEscaped("\x03").data == `\x03`, w.data);
ref W put_xXX(C = char, W)(return ref scope W w, char c)
if (isSomeChar!C);
Decodes char c to the form u00XX, where XX is 2 hexadecimal characters.
ref W put_uXXXX(C = char, W)(return ref scope W w, char c)
if (isSomeChar!C);
Decodes char c to the form u00XX, where XX is 2 hexadecimal characters.
ref W put_uXXXX(C = char, W)(return ref scope W w, ushort c)
if (isSomeChar!C);
Decodes ushort c to the form uXXXX, where XXXX is 2 hexadecimal characters.
ref W printElement(C, EscapeFormat escapeFormat = EscapeFormat.ion, W)(return ref scope W w, scope const(C)[] c)
if (isSomeChar!C);
ref W printElement(C = char, EscapeFormat escapeFormat = EscapeFormat.ion, W, T)(return ref scope W w, auto ref scope const T c)
if (!isSomeString!T);
ref W print(C = char, W, Args...)(return ref scope W w, auto ref scope const Args args)
if (isSomeChar!C && (Args.length > 1));
Multiargument overload.
ref W print(C = char, W, T)(return ref scope W w, const T c)
if (isSomeChar!C && is(T == enum));
Prints enums
Examples:
enum Flag
{
    no,
    yes,
}

import mir.appender: scopedBuffer;
auto w = scopedBuffer!char;
w.print(Flag.yes);
assert(w.data == "yes", w.data);
ref W print(C = char, W)(return ref scope W w, bool c)
if (isSomeChar!C);
Prints boolean
Examples:
import mir.appender: scopedBuffer;
auto w = scopedBuffer!char;
assert(w.print(true).data == `true`, w.data);
w.reset;
assert(w.print(false).data == `false`, w.data);
ref W print(C = char, W, V, K)(return ref scope W w, scope const V[K] c)
if (isSomeChar!C);
Prints associative array
Examples:
import mir.appender: scopedBuffer;
auto w = scopedBuffer!char;
w.print(["a": 1, "b": 2]);
assert(w.data == `["a": 1, "b": 2]` || w.data == `["b": 2, "a": 1]`, w.data);
ref W print(C = char, W, T)(return ref scope W w, scope const(T)[] c)
if (isSomeChar!C && !isSomeChar!T);
Prints array
Examples:
import mir.appender: scopedBuffer;
auto w = scopedBuffer!char;
string[2] array = ["a\na", "b"];
assert(w.print(array[]).data == `["a\na", "b"]`, w.data);
ref W print(C = char, W)(return ref scope W w, char c)
if (isSomeChar!C);
Prints escaped character in the form 'c'.
Examples:
import mir.appender: scopedBuffer;
auto w = scopedBuffer!char;
assert(w
    .print('\n')
    .print('\'')
    .print('a')
    .print('\xF4')
    .data == `'\n''\'''a''\xF4'`);
ref W print(C = char, W)(return ref scope W w, scope const(C)[] c)
if (isSomeChar!C);
Prints some string
ref W print(C = char, W, I)(return ref scope W w, const I c)
if (isSomeChar!C && isIntegral!I && !is(I == enum));
Prints integers
ref W print(C = char, W, T)(return ref scope W w, const T c, NumericSpec spec = NumericSpec.init)
if (isSomeChar!C && is(T == float) || is(T == double) || is(T == real));
Prints floating point numbers
Examples:
Human friendly precise output (default)
auto spec = NumericSpec.human;
stringBuf buffer;

void check(double num, string value)
{
    assert(buffer.print(num, spec).data == value, buffer.data); buffer.reset;
}

check(-0.0, "-0.0");
check(0.0, "0.0");
check(-0.01, "-0.01");
check(0.0125, "0.0125");
check(0.000003, "0.000003");
check(-3e-7, "-3e-7");
check(123456.0, "123456.0");
check(123456.1, "123456.1");
check(12.3456, "12.3456");
check(-0.123456, "-0.123456");
check(0.1234567, "0.1234567");
check(0.01234567, "0.01234567");
check(0.001234567, "0.001234567");
check(1.234567e-4, "1.234567e-4");
check(-1234567.0, "-1.234567e+6");
check(123456.7890123, "123456.7890123");
check(1234567.890123, "1.234567890123e+6");
check(1234567890123.0, "1.234567890123e+12");
check(0.30000000000000004, "0.30000000000000004");
check(0.030000000000000002, "0.030000000000000002");
check(0.0030000000000000005, "0.0030000000000000005");
check(3.0000000000000003e-4, "3.0000000000000003e-4");
check(+double.nan, "nan");
check(-double.nan, "nan");
check(+double.infinity, "+inf");
check(-double.infinity, "-inf");

spec.separatorChar = ',';

check(-0.0, "-0.0");
check(0.0, "0.0");
check(-0.01, "-0.01");
check(0.0125, "0.0125");
check(0.000003, "0.000003");
check(-3e-7, "-3e-7");
check(123456.0, "123,456.0");
check(123456e5, "12,345,600,000.0");
check(123456.1, "123,456.1");
check(12.3456, "12.3456");
check(-0.123456, "-0.123456");
check(0.1234567, "0.1234567");
check(0.01234567, "0.01234567");
check(0.001234567, "0.001234567");
check(1.234567e-4, "0.0001234567");
check(-1234567.0, "-1,234,567.0");
check(123456.7890123, "123,456.7890123");
check(1234567.890123, "1,234,567.890123");
check(123456789012.0, "123,456,789,012.0");
check(1234567890123.0, "1.234567890123e+12");
check(0.30000000000000004, "0.30000000000000004");
check(0.030000000000000002, "0.030000000000000002");
check(0.0030000000000000005, "0.0030000000000000005");
check(3.0000000000000003e-4, "0.00030000000000000003");
check(3.0000000000000005e-6, "0.0000030000000000000005");
check(3.0000000000000004e-7, "3.0000000000000004e-7");
check(+double.nan, "nan");
check(-double.nan, "nan");
check(+double.infinity, "+inf");
check(-double.infinity, "-inf");

spec.separatorChar = '_';
spec.separatorCount = 2;
check(123456e5, "1_23_45_60_00_00.0");

spec.plus = true;
check(0.0125, "+0.0125");
check(-0.0125, "-0.0125");
ref W print(C = char, W, T)(return ref scope W w, ref const T c)
if (isSomeChar!C && is(T == struct) || is(T == union) && !is(T : NumericSpec));

ref W print(C = char, W, T)(return ref scope W w, scope const T c)
if (isSomeChar!C && is(T == struct) || is(T == union));
Prints structs and unions
Examples:
static struct A { scope void toString(C, W)(scope ref W w) const { w.put(C('a')); } }
static struct S { scope void toString(W)(scope ref W w) const { w.put("s"); } }
static struct D { scope void toString(Dg)(scope Dg sink) const { sink("d"); } }
static struct F { scope const(char)[] toString()() const return { return "f"; } }
static struct G { const(char)[] s = "g"; alias s this; }

import mir.appender: scopedBuffer;
auto w = scopedBuffer!char;
assert(stringBuf() << A() << S() << D() << F() << G() << getData == "asdfg");
ref W print(C = char, W, T)(return ref scope W w, scope const T c)
if (isSomeChar!C && is(T == class) || is(T == interface));
Prints classes and interfaces
Examples:
static class A { void toString(C, W)(scope ref W w) const { w.put(C('a')); } }
static class S { void toString(W)(scope ref W w) const { w.put("s"); } }
static class D { void toString(Dg)(scope Dg sink) const { sink("d"); } }
static class F { const(char)[] toString()() const return { return "f"; } }
static class G { const(char)[] s = "g"; alias s this; }

assert(stringBuf() << new A() << new S() << new D() << new F() << new G() << getData == "asdfg");
ref W printStaticString(C, size_t N, W)(return ref scope W w, ref scope const C[N] c)
if (isSomeChar!C && is(C == char) || is(C == wchar) || is(C == dchar));
ref W printZeroPad(C = char, W, I)(return ref scope W w, const I c, size_t minimalLength)
if (isSomeChar!C && isIntegral!I && !is(I == enum));
Examples:
import mir.appender;
auto w = scopedBuffer!char;

w.printZeroPad(-123, 5);
w.put(' ');
w.printZeroPad(123, 5);

assert(w.data == "-0123 00123", w.data);
size_t printBoolean(C)(bool c, ref C[5] buf)
if (is(C == char) || is(C == wchar) || is(C == dchar));