www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to forward format specifiers ?

reply Element 126 <dlang.element126 gmail.com> writes:
I am trying to define custom format specifiers (as described here [1]) 
for the following wrapper struct :

import std.stdio;
import std.format: formattedWrite, FormatSpec;
import std.string: format;

struct wrapper(T) {

	private T val;

	public this(T newVal) pure { val = newVal; }

	public void toString(
		scope void delegate(const(char)[]) sink,
		FormatSpec!char fmt
	) const
	{
		formattedWrite(sink, /+ Format string +/ , val);
	}
}

unittest {

	immutable uint base = 16;
	auto a = wrapper!uint(base);
	assert(format("%x", a) == format("%x", base));
	assert(format("%08x", a) == format("%08x", base));
}

More precisely, I want to forward the format specifier fmt received by 
wrapper!T.toString to formattedWrite.

Since formattedWrite expects a const(char)[] "string" as its second 
argument, I first naively tried to use :

	formattedWrite(sink, to!string(fmt), val);

but to!string(fmt) gives something similar to :
	
	address = 7FFFE91C54C0
	width = 0
	precision = 2147483646
	spec = x
	indexStart = 0
	indexEnd = 0
	flDash = false
	flZero = false
	flSpace = false
	flPlus = false
	flHash = false
	nested =
	trailing =

instead of the original format string, thus causing toString to fail at 
runtime.

The documentation for std.format [2] mentions a second prototype (among 
four) for toString :

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

So I tried to modify wrapper!T.toString as follows :

	public void toString(
		scope void delegate(const(char)[]) sink,
		string fmt
	) const
	{
		formattedWrite(sink, fmt, val);
	}

but this one throws exception at runtime :

std.format.FormatException /usr/include/dlang/dmd/std/format.d(2537): 
Expected '%s' format specifier for type 'wrapper!uint'.

I can make it work for simple cases by manually creating the format 
string using format() with the FormatSpec attributes, but this approach 
is not generic and will fail for complex format strings.

I've certainly missed something, but I can't figure out what is the 
right way to do it. What did I do wrong here ?

I remember having seen the "void toString(scope void delegate(/*...*/), 
/*...*/) const" prototypes being deprecated, but I don't know where it 
was. Maybe there is a better solution now ?


[1] http://wiki.dlang.org/Defining_custom_print_format_specifiers
[2] http://dlang.org/phobos-prerelease/std_format.html#.formatValue
Jun 29 2014
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 06/29/2014 04:55 AM, Element 126 wrote:

 I've certainly missed something
formatValue passes your tests: import std.stdio; import std.format: formattedWrite, FormatSpec, formatValue; import std.string: format; struct wrapper(T) { private T val; public this(T newVal) pure { val = newVal; } public void toString( scope void delegate(const(char)[]) sink, FormatSpec!char fmt ) const { formatValue(sink, val, fmt); // <-- HERE } } unittest { immutable uint base = 16; auto a = wrapper!uint(base); assert(format("%x", a) == format("%x", base)); assert(format("%08x", a) == format("%08x", base)); } void main() {} Ali
Jun 29 2014
parent reply Element 126 <dlang.element126 gmail.com> writes:
On 06/29/2014 04:22 PM, Ali Çehreli wrote:
 On 06/29/2014 04:55 AM, Element 126 wrote:

  > I've certainly missed something

 formatValue passes your tests:

 import std.stdio;
 import std.format: formattedWrite, FormatSpec, formatValue;
 import std.string: format;

 struct wrapper(T) {

      private T val;

      public this(T newVal) pure { val = newVal; }

      public void toString(
          scope void delegate(const(char)[]) sink,
          FormatSpec!char fmt
      ) const
      {
          formatValue(sink, val, fmt);    // <-- HERE
      }
 }

 unittest {

      immutable uint base = 16;
      auto a = wrapper!uint(base);
      assert(format("%x", a) == format("%x", base));
      assert(format("%08x", a) == format("%08x", base));
 }

 void main()
 {}

 Ali
Thanks a lot ! I just checked if it also worked for structs and classes and it does the job perfectly. I have used formattedWrite for months without noticing formatValue, even though it was on the wiki. Maybe I should add an example to the documentation of std.format. formatValue is present but without any example, compared to the extensive documentation of formattedWrite.
Jun 29 2014
parent "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Sun, Jun 29, 2014 at 06:08:24PM +0200, Element 126 via Digitalmars-d-learn
wrote:
[...]
 I have used formattedWrite for months without noticing formatValue,
 even though it was on the wiki.
 Maybe I should add an example to the documentation of std.format.
 formatValue is present but without any example, compared to the
 extensive documentation of formattedWrite.
Please do! We need all the help we can get to improve Phobos documentation. T -- "Real programmers can write assembly code in any language. :-)" -- Larry Wall
Jun 29 2014