Output range of ranges to single buffer

Ali Çehreli via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Jan 14 08:59:15 PST 2016


On 01/13/2016 11:41 PM, Jacob Carlborg wrote:

 > what if I need to format a third party type that I cannot add
 > methods to? UFCS does not seem to work.

Here is an experiment that wraps the third party type to provide a lazy 
toString:

import std.stdio;
import std.format;
import std.array;
import std.algorithm;
import std.range;

/* Wraps an element and provides a lazy toString that dispatches the 
work to a
  * user-provided 'formatter' function. E is the element type. */
struct Formatted(alias formatter, E) {
     E element;

     void toString(void delegate(const(char)[]) sink) const {
         formatter(sink, element);
     }
}

/* Adapts a range by converting the elements to 'Formatted'. R is the range
  * type. */
auto formatted(alias formatter, R)(R range) {
     return range.map!(e => Formatted!(formatter, ElementType!R)(e));
}

/* A third party test type that does not have a lazy toString member
  * function. */
struct Foo {
     double d;
     string s;
}

void main() {
	auto data = [ Foo(1.5, "hello"), Foo(2.5, "world") ];

     auto buf = appender!string();
	formattedWrite(buf, "%(%s\n%)",
                    data.formatted!(
                        (sink, a) => formattedWrite(sink, "%s and %s",
                                                    a.d, a.s)));

     writeln(buf.data);
}

Prints the objects according to the user's lambda:

1.5 and hello
2.5 and world

It would be great if the user could provide just the format and accessed 
the members:

     data.formatted!("%s and %s", a.d, a.s); // <-- ERROR

But I couldn't get it working because the compiler does not know what 
'a' is at that point. It might be acceptable to provide a lambda per 
member but then it gets to cluttered:

     data.formatted!("%s and %s", a => a.d, a => a.s); // Might work

Ali



More information about the Digitalmars-d-learn mailing list