digitalmars.D.learn - Output range of ranges to single buffer
- Jacob Carlborg (38/38) Jan 13 2016 Is it possible to somehow output a range of ranges to a single string
- Dav1d (9/13) Jan 13 2016 std.format can do it. From the site:
- H. S. Teoh via Digitalmars-d-learn (12/30) Jan 13 2016 Isn't that just a matter of replacing each of the segments with their
- =?UTF-8?Q?Ali_=c3=87ehreli?= (12/19) Jan 13 2016 And buf can be an Appender:
- Jacob Carlborg (8/16) Jan 13 2016 Aha, interesting. I didn't know formattedWrite could format an
- =?UTF-8?Q?Ali_=c3=87ehreli?= (48/50) Jan 14 2016 Here is an experiment that wraps the third party type to provide a lazy
- Jacob Carlborg (5/44) Jan 14 2016 Thanks.
- Jonathan M Davis via Digitalmars-d-learn (6/21) Jan 14 2016 You can't do toString via UFCS any more than you can overload any operat...
Is it possible to somehow output a range of ranges to a single string buffer? For example, converting an array of integers to a string with the same representation as the source code. import std.algorithm; import std.conv; import std.string; void main() { auto a = [1, 2, 3, 4, 5]; auto b = '[' ~ a.map!(e => e.to!string).join(", ") ~ ']'; assert(b == "[1, 2, 3, 4, 5]"); } The above code is straight forward. But I would like to avoid creating the intermediate strings, "e.to!string", and instead put the converted integer and the result of join directly in the same buffer. A bit more complex example: struct Foo { int a; string b; int c; string toString() { auto values = [a.to!string, b, c.to!string].join(", "); return "Foo(" ~ values ~ ')'; } } void main() { auto a = [ Foo(1, "foo", 2), Foo(3, "bar", 4) ]; auto b = '[' ~ a.map!(e => e.to!string).join(", ") ~ ']'; assert(b == "[Foo(1, foo, 2), Foo(3, bar, 4)]"); } -- /Jacob Carlborg
Jan 13 2016
On Wednesday, 13 January 2016 at 21:15:03 UTC, Jacob Carlborg wrote:Is it possible to somehow output a range of ranges to a single string buffer? For example, converting an array of integers to a string with the same representation as the source code. [...]std.format can do it. From the site: import std.stdio; void main() { writefln("My items are %(%s %).", [1,2,3]); writefln("My items are %(%s, %).", [1,2,3]); }
Jan 13 2016
On Wed, Jan 13, 2016 at 10:15:03PM +0100, Jacob Carlborg via Digitalmars-d-learn wrote:Is it possible to somehow output a range of ranges to a single string buffer? For example, converting an array of integers to a string with the same representation as the source code. import std.algorithm; import std.conv; import std.string; void main() { auto a = [1, 2, 3, 4, 5]; auto b = '[' ~ a.map!(e => e.to!string).join(", ") ~ ']'; assert(b == "[1, 2, 3, 4, 5]"); } The above code is straight forward. But I would like to avoid creating the intermediate strings, "e.to!string", and instead put the converted integer and the result of join directly in the same buffer.Isn't that just a matter of replacing each of the segments with their range equivalents? Also, std.format.formattedWrite will do writeln-formatting into a buffer (well, any output range, really) -- I'm pretty sure it doesn't allocate, at least for the simplest cases like converting an integer. So you should be able to do something like this: auto data = [ 1, 2, 3, 4, 5 ]; char[] buf = ...; formattedWrite(buf, "[%(%d, %)]", data); T -- Customer support: the art of getting your clients to pay for your own incompetence.
Jan 13 2016
On 01/13/2016 01:20 PM, H. S. Teoh via Digitalmars-d-learn wrote:std.format.formattedWrite will do writeln-formatting into a buffer (well, any output range, really) -- I'm pretty sure it doesn't allocate, at least for the simplest cases like converting an integer. So you should be able to do something like this: auto data = [ 1, 2, 3, 4, 5 ]; char[] buf = ...; formattedWrite(buf, "[%(%d, %)]", data);And buf can be an Appender: import std.stdio; import std.format; import std.array; void main() { auto data = [ 1, 2, 3, 4, 5 ]; auto buf = appender!string(); // Or appender!(char[]) if needed formattedWrite(buf, "[%(%d, %)]", data); assert(buf.data == "[1, 2, 3, 4, 5]"); } Ali
Jan 13 2016
On 2016-01-13 22:20, H. S. Teoh via Digitalmars-d-learn wrote:Isn't that just a matter of replacing each of the segments with their range equivalents? Also, std.format.formattedWrite will do writeln-formatting into a buffer (well, any output range, really) -- I'm pretty sure it doesn't allocate, at least for the simplest cases like converting an integer. So you should be able to do something like this: auto data = [ 1, 2, 3, 4, 5 ]; char[] buf = ...; formattedWrite(buf, "[%(%d, %)]", data);Aha, interesting. I didn't know formattedWrite could format an array/range directly like that. The more complex example works by defining "toString" which takes an output range (delegate). But what if I need to format a third party type that I cannot add methods to? UFCS does not seem to work. -- /Jacob Carlborg
Jan 13 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
Jan 14 2016
On 2016-01-14 17:59, Ali Çehreli wrote: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); } }Wrap the object, why didn't I think of that :)/* 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 worldThanks. -- /Jacob Carlborg
Jan 14 2016
On Thursday, January 14, 2016 08:41:23 Jacob Carlborg via Digitalmars-d-learn wrote:On 2016-01-13 22:20, H. S. Teoh via Digitalmars-d-learn wrote:You can't do toString via UFCS any more than you can overload any operators via UFCS. If a type's toString does not work how you want, or a type does not provide one, then you'll need to convert objects of that type to a string in a different way. - Jonathan M DavisIsn't that just a matter of replacing each of the segments with their range equivalents? Also, std.format.formattedWrite will do writeln-formatting into a buffer (well, any output range, really) -- I'm pretty sure it doesn't allocate, at least for the simplest cases like converting an integer. So you should be able to do something like this: auto data = [ 1, 2, 3, 4, 5 ]; char[] buf = ...; formattedWrite(buf, "[%(%d, %)]", data);Aha, interesting. I didn't know formattedWrite could format an array/range directly like that. The more complex example works by defining "toString" which takes an output range (delegate). But what if I need to format a third party type that I cannot add methods to? UFCS does not seem to work.
Jan 14 2016