/** @example format.cc * * An example of using the string formatting system, including various * differences from C such as user defined type and range formatting. */ #include #include #include #include #include #include #include using namespace ostd; using namespace ostd::string_literals; struct Foo { }; /* implementing formatting for custom objects */ template<> struct ostd::format_traits { template static void to_format(Foo const &, R &writer, format_spec const &fs) { switch (fs.spec()) { case 'i': range_put_all(writer, "Foo_i"_sr); break; default: range_put_all(writer, "Foo_s"_sr); break; } if (fs.flags() & FMT_FLAG_AT) { range_put_all(writer, "_esc"_sr); } } }; int main() { std::vector x = { 5, 10, 15, 20 }; /* prints [5|10|15|20] (using | as the delimiter and %s for each item), * the syntax for ranges is %(CONTENTS%) where CONTENTS is a sequence * up until and including the last format mark followed by a delimiter, * so for example "%s, " has "%s" for formatting and ", " for the delimiter * and "%d: %s, " has "%d: %s" for format and ", " for the delimiter; if * you need to specify a complicated manual delimiter, you can use the * "FORMAT%|DELIMITER" syntax, where %(%s, %) equals %(%s%|, %) */ writeln("-- range format --"); writefln("[%(%s|%)]", x); /* prints a range with default format {item, item, item, ...} * you can enable item escaping by passing the @ flag */ writeln("\n-- range default format --"); writefln("%s", x); int y[] = { 2, 4, 8, 16, 32 }; /* prints { 2, 4, 8, 16, 32 } using ", " as the delimiter */ writeln("\n-- range format of static array --"); writefln("{ %(%s, %) }", y); /* nested range printing - prints each item of the main * range with [ %(%s, %) ] and ",\n" as the delimiter */ writeln("\n-- range format of nested range --"); writefln("[\n%([ %(%s, %) ]%|,\n%)\n]", map(range(10), [](int v) { return range(v + 1); })); std::unordered_map m = { { "foo", 5 }, { "bar", 10 }, { "baz", 15 } }; /* prints something like { "baz": 15, "bar": 10, "foo": 5 }, note that * the tuple is expanded into two formats (using the # flag) and the * items are escaped with the @ flag (applies to strings and chars) */ writeln("\n-- range format of hash table --"); writefln("{ %#(%@s: %d, %) }", m); /* not escaped, you get { baz: 15, bar: 10, foo: 5} */ writeln("\n-- range format of hash table (no escape) --"); writefln("{ %#(%s: %d, %) }", m); /* no expansion of the items, print entire tuple with default format, * gets you something like { <"baz", 15>, <"bar", 10>, <"foo", 5> } * because the default tuple format is */ writeln("\n-- range format of hash table (no item expansion) --"); writefln("{ %(%@s, %) }", m); /* as the @ flag enables escaping on strings and chars, * you can use it standalone outside of range/tuple format */ writeln("\n-- format item escaping --"); writefln("not escaped: %s, escaped: %@s", "foo", "bar"); std::tuple tup{ "hello world", 1337, 3.14f, "test" }; /* you can expand tuples similarly to ranges, with % where * CONTENTS is a regular format string like if the tuple was formatted * separately with each item of the tuple passed as a separate argument */ writeln("\n-- tuple format --"); writefln("the tuple contains %<%@s, %d, %f, %s%>.", tup); writeln("\n-- tuple default format --"); writefln("auto tuple: %s", tup); writeln("\n-- tuple default format (escaped) --"); writefln("auto tuple with escape: %@s", tup); std::tuple xt[] = { std::make_tuple(5, 3.14f, "foo"), std::make_tuple(3, 1.23f, "bar"), std::make_tuple(9, 8.66f, "baz") }; /* formatting a range of tuples, with each tuple expanded using # */ writeln("\n-- range of tuples format --"); writefln("[ %#(<%d|%f|%@s>%|, %) ]", xt); /* formatting custom objects, the information about the format mark * is passed into the to_format function and the object can read it */ writeln("\n-- custom object format --"); writefln("%s", Foo{}); writefln("%i", Foo{}); writefln("%@s", Foo{}); writefln("%@i", Foo{}); auto s = appender(); /* formatting into a string sink (can be any output range, but * appender makes sure the capacity is unlimited so it's safe) */ writeln("\n-- format into a string --"); format(s, "hello %s", "world"); writeln(s.get()); /* locale specific formatting */ writeln("\n-- number format with C locale --"); writefln( "\"%d\", \"%f\", \"%X\"", 123456789, 12345.6789123, 0x123456789ABCDEF ); cout.imbue(std::locale{""}); writefln("\n-- number format with system locale --"); writefln( "\"%d\", \"%f\", \"%X\"", 123456789, 12345.6789123, 0x123456789ABCDEF ); } /* output: -- range format -- [5|10|15|20] -- range default format -- {5, 10, 15, 20} -- range format of static array -- { 2, 4, 8, 16, 32 } -- range format of nested range -- [ [ 0 ], [ 0, 1 ], [ 0, 1, 2 ], [ 0, 1, 2, 3 ], [ 0, 1, 2, 3, 4 ], [ 0, 1, 2, 3, 4, 5 ], [ 0, 1, 2, 3, 4, 5, 6 ], [ 0, 1, 2, 3, 4, 5, 6, 7 ], [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ], [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ] ] -- range format of hash table -- { "baz": 15, "bar": 10, "foo": 5 } -- range format of hash table (no escape) -- { baz: 15, bar: 10, foo: 5 } -- range format of hash table (no item expansion) -- { <"baz", 15>, <"bar", 10>, <"foo", 5> } -- format item escaping -- not escaped: foo, escaped: "bar" -- tuple format -- the tuple contains "hello world", 1337, 3.140000, test. -- tuple default format -- auto tuple: -- tuple default format (escaped) -- auto tuple with escape: <"hello world", 1337, 3.14, "test"> -- range of tuples format -- [ <5|3.140000|"foo">, <3|1.230000|"bar">, <9|8.660000|"baz"> ] -- custom object format -- Foo_s Foo_i Foo_s_esc Foo_i_esc -- format into a string -- hello world -- number format with C locale -- "123456789", "12345.678912", "123456789ABCDEF" -- number format with system locale -- "123 456 789", "12 345,678912", "123 456 789 ABC DEF" */