[iostreams]ANNOUNCE:indent_filtering_ostream.zip in vault

The .zip file in subject is here: http://www.boostpro.com/vault/index.php?&directory=Input%20-%20Output It includes a boost/iostreams/filter/indent.hpp and boost/iostreams/utility/indent_filtering_ostream.hpp. The latter uses the former to allow indenting and undenting a stream. Is there any interest in installing this in the iostreams library? -regards, Larry

Hi, ----- Original Message ----- From: "Larry Evans" <cppljevans@suddenlink.net> To: <boost@lists.boost.org> Sent: Saturday, January 09, 2010 5:26 PM Subject: [boost] [iostreams]ANNOUNCE:indent_filtering_ostream.zip in vault
The .zip file in subject is here:
http://www.boostpro.com/vault/index.php?&directory=Input%20-%20Output
It includes a boost/iostreams/filter/indent.hpp and boost/iostreams/utility/indent_filtering_ostream.hpp.
The latter uses the former to allow indenting and undenting a stream.
Is there any interest in installing this in the iostreams library?
Definitely. On the example I see that the ++ and -- are not pairwised. int main(void) { boost::iostreams::indent_filtering_ostream<> mout(std::cout); mout<<"line1\n"; + ++mout; mout<<"line1.1"<<std::endl; + ++mout; mout<<"line1.1.1"<<std::endl; test_conversion(mout); - --mout; unsigned u=22; mout<<"line1.2:unsigned="<<u<<std::endl; float f=3.1416; mout<<"line1.3:float="<<f<<std::endl; - --mout; - --mout; mout<<"line2\n"; return 0; } Shouldn't a scoped_indent class helps on this? Best, Vicente

On 01/11/10 06:14, vicente.botet wrote:
Hi, ----- Original Message ----- From: "Larry Evans" <cppljevans@suddenlink.net> [snip] On the example I see that the ++ and -- are not pairwised. [snip]
Shouldn't a scoped_indent class helps on this?
Thanks for the feedback, Vincente. Yes, a scoped_indent would help. I think the extra -- was put in there just to show nothing bad would happen. IOW, the indententation never goes below 0. I've used something like a scoped_indent to trace code. It's called trace_scope, which is attached. The mout() is actually an earlier version of the code which didn't use the iostreams library, but works similar to the proposed code (except mout() couldn't be converted to basic:ostream&). -regards, Larry

On Mon, 11 Jan 2010, vicente.botet wrote:
From: "Larry Evans" <cppljevans@suddenlink.net>
The .zip file in subject is here:
http://www.boostpro.com/vault/index.php?&directory=Input%20-%20Output
It includes a boost/iostreams/filter/indent.hpp and boost/iostreams/utility/indent_filtering_ostream.hpp.
The latter uses the former to allow indenting and undenting a stream.
On the example I see that the ++ and -- are not pairwised. int main(void) { boost::iostreams::indent_filtering_ostream<> mout(std::cout); mout<<"line1\n"; + ++mout; mout<<"line1.1"<<std::endl; + ++mout; mout<<"line1.1.1"<<std::endl; test_conversion(mout); - --mout; unsigned u=22; mout<<"line1.2:unsigned="<<u<<std::endl; float f=3.1416; mout<<"line1.3:float="<<f<<std::endl; - --mout; - --mout; mout<<"line2\n"; return 0; }
I wrote a similar utility, but made different tradeoffs. The basic usage looks like Indentation nl; // takes optional max depth and depth/level params Indentation::Indent in(nl); // could have used a reference notation Indentation::Outdent out(nl); std::ostream os; os << nl "class x << nl << '{' << in /* or nl.in */ << nl << "int x;" << nl << "int y;" << out << nl << "};" Rationale: - operator++ and operator-- don't mix "as expected" with operator<< - distinguishes between indenting and normal newlines - possible to maintain several indentation systems Later, Daniel

On 01/12/10 11:29, dherring@ll.mit.edu wrote:
On Mon, 11 Jan 2010, vicente.botet wrote:
From: "Larry Evans" <cppljevans@suddenlink.net>
The .zip file in subject is here:
http://www.boostpro.com/vault/index.php?&directory=Input%20-%20Output
[snip] I wrote a similar utility, but made different tradeoffs. The basic usage looks like
Indentation nl; // takes optional max depth and depth/level params Indentation::Indent in(nl); // could have used a reference notation Indentation::Outdent out(nl); std::ostream os; os << nl "class x << nl << '{' << in /* or nl.in */ << nl << "int x;" << nl << "int y;" << out << nl << "};"
Rationale: - operator++ and operator-- don't mix "as expected" with operator<<
The functions provided in the indent_filtering_ostream.hpp include: indent_in indent_out which can be used just like your in and out. For example: ; ++mout ; mout<<"line1.1"<<std::endl ; mout<<indent_in<<"line1.1.1"<<std::endl ; test_conversion(mout)
- distinguishes between indenting and normal newlines
I'm not sure what this means. Does it mean that to indent a line, you have to use nl, as shown in this snippet of the code you posted:
<< nl << "int x;"
If so, then I'm not sure that's an advantage. Could you please elaborate on what you mean?
- possible to maintain several indentation systems
Could you describe when this would be an advantage? -regards, Larry

On Tue, 12 Jan 2010, Larry Evans wrote:
On 01/12/10 11:29, dherring@ll.mit.edu wrote:
On Mon, 11 Jan 2010, vicente.botet wrote:
From: "Larry Evans" <cppljevans@suddenlink.net>
The .zip file in subject is here:
http://www.boostpro.com/vault/index.php?&directory=Input%20-%20Output
[snip] I wrote a similar utility, but made different tradeoffs. The basic usage looks like
Indentation nl; // takes optional max depth and depth/level params Indentation::Indent in(nl); // could have used a reference notation Indentation::Outdent out(nl); std::ostream os; os << nl "class x << nl << '{' << in /* or nl.in */ << nl << "int x;" << nl << "int y;" << out << nl << "};"
Rationale: - operator++ and operator-- don't mix "as expected" with operator<<
The functions provided in the indent_filtering_ostream.hpp include:
indent_in indent_out
Ok, I didn't see these; I just looked at the previous email's example.
- distinguishes between indenting and normal newlines
I'm not sure what this means. Does it mean that to indent a line, you have to use nl, as shown in this snippet of the code you posted:
<< nl << "int x;"
If so, then I'm not sure that's an advantage. Could you please elaborate on what you mean?
Yes. In my work, this is a great advantage. People don't like text with trailing whitespaces, but they want blank lines for visual separation. I could see an argument for having \n indent and nl not; it may make it easier to compose indentation with output functions that do not understand it. However, my experience has been that an indenting newlines semantically belong before the line text while a traditional \n appears after the text. This creates a mismatch; a general indentation tool should probably have a (scoped) mechanism for switching behaviors. Example: (pseudo C++) // code oblivious to indentation ostream & operator<<(ostream &os, vector<int> &v) { for(x=v.begin(); x!=v.end(); x++) os << x << "\n"; return os; } // pretty printing void pretty(Struct s) { out << nl << "Struct s" << indent << nl << "x=" << s.x << nl << "vector=" << indent // one item per line << nl << s.vector << outdent << nl << "y=" << s.y << outdent; } This will give Struct s x=5 vector= 1 2 3 y=6 Note the undesired newline. But if nl appears in the traditional \n location, you have the issue of undesired indentation (the inner printer has to anticipate outdents in the outer) or extra buffering to clean such mistakes. I have had the best results by putting nl first and defining "pretty printers" that use it for each type I want to print.
- possible to maintain several indentation systems
Could you describe when this would be an advantage?
This is rarely useful, but there are times when indentation differentiates between classes of output line. This is naturally represented by having one indentation object per class. - Daniel

On 01/13/10 11:17, dherring@ll.mit.edu wrote:
On Tue, 12 Jan 2010, Larry Evans wrote:
On 01/12/10 11:29, dherring@ll.mit.edu wrote:
On Mon, 11 Jan 2010, vicente.botet wrote:
From: "Larry Evans" <cppljevans@suddenlink.net>
The .zip file in subject is here:
http://www.boostpro.com/vault/index.php?&directory=Input%20-%20Output
[snip] I wrote a similar utility, but made different tradeoffs. The basic usage looks like
Indentation nl; // takes optional max depth and depth/level params Indentation::Indent in(nl); // could have used a reference notation Indentation::Outdent out(nl); std::ostream os; os << nl "class x << nl << '{' << in /* or nl.in */ << nl << "int x;" << nl << "int y;" << out << nl << "};"
Rationale: - operator++ and operator-- don't mix "as expected" with operator<<
The functions provided in the indent_filtering_ostream.hpp include:
indent_in indent_out
Ok, I didn't see these; I just looked at the previous email's example.
- distinguishes between indenting and normal newlines
I'm not sure what this means. Does it mean that to indent a line, you have to use nl, as shown in this snippet of the code you posted:
<< nl << "int x;"
If so, then I'm not sure that's an advantage. Could you please elaborate on what you mean?
Yes. In my work, this is a great advantage. People don't like text with trailing whitespaces, but they want blank lines for visual separation.
Doesn't: os<<nl<<"\n" produce trailing whitespace whose length is the current indentation level which is stored somewhere in nl. Hmm... What's the return type from os<<nl. I'm guessing it must be typeof(nl)& because otherwise, how would the change in indentation be communicated from the <<out at the end of the output line: << nl << "int y;" << out Could you clarify how out changes the indentation? Does it modify the nl that occurs at the beginning?
I could see an argument for having \n indent and nl not; it may make it easier to compose indentation with output functions that do not understand it. However, my experience has been that an indenting newlines semantically belong before the line text while a traditional \n appears after the text. This creates a mismatch; a general indentation tool should probably have a (scoped) mechanism for switching behaviors.
Example: (pseudo C++) // code oblivious to indentation ostream & operator<<(ostream &os, vector<int> &v) { for(x=v.begin(); x!=v.end(); x++) os << x << "\n"; return os; } // pretty printing void pretty(Struct s) { out << nl << "Struct s" << indent << nl << "x=" << s.x << nl << "vector=" << indent // one item per line << nl << s.vector << outdent << nl << "y=" << s.y << outdent; }
This will give Struct s x=5 vector= 1 2 3
y=6
Note the undesired newline.
IIUC, nl outputs 1st a '\n' and *then* prints the indentation spaces? Thus the specialization of operator<< for vector<int> ends in a newline which is then followed by another newline produced by the << nl here: << nl << "y=" << s.y << outdent; Is that right. However, I don't see where the indentation for the vector comes from because there's no calls to nl in the operator<< specializtion for vector<int>. Am I missing something? Anyway, I've used the proposed boost indent_ostream (or really it's predecessor) to print out nested structures such as your Struct s in the past. IIRC, the last element printed in a struct has no trailing nl. The task of appending the nl is left to the caller. This protocol is illustrated by the attachment, whose output is: { Struct x=5 v=vector<int> 1 2 3 y=6 }
But if nl appears in the traditional \n location, you have the issue of undesired indentation (the inner printer has to anticipate outdents in the outer) or extra buffering to clean such mistakes.
OK, but I still don't see how your 'nl' and 'out' and 'in' solve the problem better than the solution shown in the attachment.
I have had the best results by putting nl first and defining "pretty printers" that use it for each type I want to print.
But I thought the pseudo code above and the supposed output demonstrate that it *does* produce the extra newline after the vector print. IOW, as I said, I don't syet ee an advantage of using 'nl,out,in'.
- possible to maintain several indentation systems
Could you describe when this would be an advantage?
This is rarely useful, but there are times when indentation differentiates between classes of output line. This is naturally represented by having one indentation object per class.
Couldn't this be handled by defining operator<< for each class? -Larry

On 01/13/10 13:46, Larry Evans wrote: [snip]
IIRC, the last element printed in a struct has no trailing nl. The task of appending the nl is left to the caller. This protocol is illustrated by the attachment,
Actually, the new attachment looks remarkably similar to your's except, instead of: << nl << element << "\n"; there's: << "\n" << element; and there's no special case to test for the last element. IOW, the newlines prefix each element on the statement instead of trail each element.

On Wed, 13 Jan 2010, Larry Evans wrote:
On 01/13/10 13:46, Larry Evans wrote: [snip]
IIRC, the last element printed in a struct has no trailing nl. The task of appending the nl is left to the caller. This protocol is illustrated by the attachment,
Actually, the new attachment looks remarkably similar to your's except, instead of:
<< nl << element << "\n";
there's:
<< "\n" << element;
and there's no special case to test for the last element. IOW, the newlines prefix each element on the statement instead of trail each element.
Yes, newline prefix is preferred when newlines trigger indentation. I'll try to get a more detailed reply; but time's tight right now. One thing to note: my previous example was meant to show the problem with mixing prefix and postfix newlines. The following output shows the value of a newline without indentation. " namespace N { struct S1 { int x; }; struct S2 { ... }; } " Note the blank line between S1 and S2. - Daniel

On Wed, 13 Jan 2010, Larry Evans wrote:
On 01/13/10 11:17, dherring@ll.mit.edu wrote:
On Tue, 12 Jan 2010, Larry Evans wrote:
On 01/12/10 11:29, dherring@ll.mit.edu wrote:
I wrote a similar utility, but made different tradeoffs. The basic usage looks like
Indentation nl; // takes optional max depth and depth/level params Indentation::Indent in(nl); // could have used a reference notation Indentation::Outdent out(nl); std::ostream os; os << nl "class x << nl << '{' << in /* or nl.in */ << nl << "int x;" << nl << "int y;" << out << nl << "};"
And assuming an initial depth of 0, this outputs " class x { int x; int y; };"
- distinguishes between indenting and normal newlines
I'm not sure what this means. Does it mean that to indent a line, you have to use nl, as shown in this snippet of the code you posted:
<< nl << "int x;"
If so, then I'm not sure that's an advantage. Could you please elaborate on what you mean?
Yes. In my work, this is a great advantage. People don't like text with trailing whitespaces, but they want blank lines for visual separation.
Doesn't:
os<<nl<<"\n"
produce trailing whitespace whose length is the current indentation level which is stored somewhere in nl. Hmm... What's the return type from os<<nl. I'm guessing it must be typeof(nl)& because otherwise, how would the change in indentation be communicated from the <<out at the end of the output line:
<< nl << "int y;" << out
Could you clarify how out changes the indentation? Does it modify the nl that occurs at the beginning?
In my implementation, [pseudocode] operator<<(\n) is an ordinary newline operator<<(nl) inserts a newline followed by the current indentation operator<<(nl.in) increments the depth of nl but produces no output operator<<(nl.out) decrements the depth of nl but produces no output Since all indentation operations occur in operator<<(), they all happen in the expected sequential order.
I could see an argument for having \n indent and nl not; it may make it easier to compose indentation with output functions that do not understand it. However, my experience has been that an indenting newlines semantically belong before the line text while a traditional \n appears after the text. This creates a mismatch; a general indentation tool should probably have a (scoped) mechanism for switching behaviors.
Example: (pseudo C++) ... However, I don't see where the indentation for the vector comes from because there's no calls to nl in the operator<< specializtion for vector<int>. Am I missing something?
I was suggesting that an implementation could hook into \n for its indentation. Mine doesn't because the semantics usually aren't right anyway. Indenting newlines work best in a prefix position; normal newlines usually appear postfix. However, a general indentation utility should probably allow \n to behave as nl. i.e. os << nl << "foo" << nl.in << nl; nl.wrap(os) << "bar\n"; // to reuse printers ignorant of indentation os << "baz\nquux"; would output " foo bar baz quux "
- possible to maintain several indentation systems
Could you describe when this would be an advantage?
This is rarely useful, but there are times when indentation differentiates between classes of output line. This is naturally represented by having one indentation object per class.
Couldn't this be handled by defining operator<< for each class?
Here "classes of output" was not meant in the C++ usage of "class" but rather "category". So you can't have a custom operator<<; indentation might be specified by a value in the object, by the identity of the object, by the identity of the containing object, ... Example you might see in a foreign language course: Tom Mary Hi! How are you? Good, and you? Fine, thank you. Which could be written as os << TomNL << "Tom" << MaryNL << "Mary" << TomNL << "Hi!" << MaryNL << "How are you?" ... Later, Daniel
participants (4)
-
dherring@ll.mit.edu
-
Larry Evans
-
Markus Werle
-
vicente.botet