I'm having some trouble trying to implement a custom stream class to generate nicely indented code in an output file. I've searched online extensively but there doesn't seem to be a consensus on the best way to achieve this. Some people talk about deriving the stream, others talk about deriving the buffer, yet others suggest the use of locales/facets etc.
Essentially, I'm finding myself writing a lot of code like this:
ofstream myFile();
myFile.open("test.php");
myFile << "<html>" << endl <<
"\t<head>" << endl <<
"\t\t<title>Hello world</title>" << endl <<
"\t</head>" << endl <<
"</html>" << endl;
When the tabs start to add up it looks horrible, and it seems like it would be nice to have something like this:
ind_ofstream myFile();
myFile.open("test.php");
myFile << "<html>" << ind_inc << ind_endl <<
"<head>" << ind_inc << ind_endl <<
"<title>Hello world</title>" << ind_dec << ind_endl <<
"</head>" << ind_dec << ind_endl <<
"</html>" << ind_endl;
i.e. create a derived stream class which would keep track of its current indent depth, then some manipulators to increase/decrease the indent depth, and a manipulator to write a newline followed by however many tabs.
So here's my shot at implementing the class & manipulators:
ind_ofstream.h
class ind_ofstream : public ofstream
{
public:
ind_ofstream();
void incInd();
void decInd();
size_t getInd();
private:
size_t _ind;
};
ind_ofstream& inc_ind(ind_ofstream& is);
ind_ofstream& dec_ind(ind_ofstream& is);
ind_ofstream& endl_ind(ind_ofstream& is);
ind_ofstream.cpp
ind_ofstream::ind_ofstream() : ofstream() {_ind = 0;}
void ind_ofstream::incInd() {_ind++;}
void ind_ofstream::decInd() {if(_ind > 0 ) _ind--;}
size_t ind_ofstream::getInd() {return _ind;}
ind_ofstream& inc_ind(ind_ofstream& is)
{
is.incInd();
return is;
}
ind_ofstream& dec_ind(ind_ofstream& is)
{
is.decInd();
return is;
}
ind_ofstream& endl_ind(ind_ofstream& is)
{
size_t i = is.getInd();
is << endl;
while(i-- > 0) is << "\t";
return is;
}
This builds, but doesn't generate the expected output; any attempt to use the custom manipulators results in them being cast to a boolean for some reason and "1" written to the file. Do I need to overload the << operator for my new class? (I haven't been able to find a way of doing this that builds)
Thanks!
p.s.
1) I've omitted the #includes, using namespace etc from my code snippets to save space.
2) I'm aiming to be able to use an interface similar to the one in my second code snippet. If after reading the whole post, you think that's a bad idea, please explain why and provide an alternative.
The iostreams support adding custom data to them, so you don't need to write a full derived class just to add an indentation level that will be operated on by manipulators. This is a little-known feature of iostreams, but comes in handy here.
You would write your manipulators like this:
/* Helper function to get a storage index in a stream */
int get_indent_index() {
/* ios_base::xalloc allocates indices for custom-storage locations. These indices are valid for all streams */
static int index = ios_base::xalloc();
return index;
}
ios_base& inc_ind(ios_base& stream) {
/* The iword(index) function gives a reference to the index-th custom storage location as a integer */
stream.iword(get_indent_index())++;
return stream;
}
ios_base& dec_ind(ios_base& stream) {
/* The iword(index) function gives a reference to the index-th custom storage location as a integer */
stream.iword(get_indent_index())--;
return stream;
}
template<class charT, class traits>
basic_ostream<charT, traits>& endl_ind(basic_ostream<charT, traits>& stream) {
int indent = stream.iword(get_indent_index());
stream.put(stream.widen('\n');
while (indent) {
stream.put(stream.widen('\t');
indent--;
}
stream.flush();
return stream;
}
I have combined Bart van Ingen Schenau's solution with a facet, to allow pushing and popping of indentation levels to existing output streams. The code is available on github: https://github.com/spacemoose/ostream_indenter, and there's a more thorough demo/test in the repository, but basically it allows you to do the following:
/// This probably has to be called once for every program:
// http://stackoverflow.com/questions/26387054/how-can-i-use-stdimbue-to-set-the-locale-for-stdwcout
std::ios_base::sync_with_stdio(false);
std::cout << "I want to push indentation levels:\n" << indent_manip::push
<< "To arbitrary depths\n" << indent_manip::push
<< "and pop them\n" << indent_manip::pop
<< "back down\n" << indent_manip::pop
<< "like this.\n" << indent_manip::pop;
To produce:
I want to push indentation levels:
To arbitrary depths
and pop them
back down
like this.
I had to do a kind of nasty trick, so I'm interested in hearing feedback on the codes utility.
Related
I have some C++ console programs that display progress information on the last line of output, at regular intervals.
This progress line is cleared prior to writing the next real output (or updated progress information); this could be from a number of different places in the source, and I'm currently clearing the progress line on each one, e.g.:
cout << clearline << "Some real output" << endl;
...
cout << clearline << "Some other real output" << endl;
...
cout << clearline << setw(4) << ++icount << ") " << ... << endl;
...
cout << clearline << "Progress info number " << ++iprog << flush;
Here, 'clearline' is some (system dependent) string like "\r\33[2K" which clears the current last line.
I would prefer something cleaner, that localises source changes to the actual line that's going to be cleared, like simply:
cout << "Progress info number " << ++iprog << flush << defer_clearline;
where 'defer_clearline' causes the writing of 'clearline' to be deferred until just prior to the next cout output, wherever and whatever that happens to be. I then wouldn't need to use 'clearline' on all the other lines.
I thought it might be possible to do this if 'defer_clearline' is a manipulator, and/or using xalloc() and iword().
But I've not managed to get anything that works.
Is it possible to do this sort of thing, and if so how?
2020-12-30: edited to include missing 'flush's.
You can pretty easily setup an std::cout wrapper:
// Declare the empty struct clear_line and instantiate the object cls
struct clear_line { } cls;
class out {
private:
std::ostream &strm = std::cout;
bool is_next_clear = false;
public:
template <typename T>
out& operator<<(const T& obj) {
if(is_next_clear) {
strm << std::endl << std::endl << std::endl; // clear logic
is_next_clear = false;
}
strm << obj;
return *this;
}
out& operator<<(const clear_line& _) {
is_next_clear = true;
return *this;
}
};
This pretty simply stores an is_next_clear bool for whether or not the next regular output should be cleared. Then, in the general case (the templated operator<<()), we run your clear logic and flip the is_next_clear flag if applicable. Then just output as usual.
Then, the operator<<() is overloaded for the case of a clear_line object. So if one of those is sent, we know to flip the is_next_clear flag, but not actually output anything.
Here's an example use:
int main() {
out o;
o << "Some real output" << cls;
o << "Some other real output";
return 0;
}
Here it is in action: https://ideone.com/0Dzwlv
If you want to use endl, you'll need to add a special overload for it as this answer suggests: https://stackoverflow.com/a/1134467/2602718
// this is the type of std::cout
typedef std::basic_ostream<char, std::char_traits<char> > CoutType;
// this is the function signature of std::endl
typedef CoutType& (*StandardEndLine)(CoutType&);
// define an operator<< to take in std::endl
out& operator<<(StandardEndLine manip)
{
// call the function, but we cannot return its value
manip(strm);
return *this;
}
Live example: https://ideone.com/ACUMOo
I need a C++ function that dumps some text data (multiple lines) to the console:
void DumpData() const
{
std::cout << "My Data 1" << std::endl;
std::cout << "My Data 2" << std::endl;
}
This should be the default behaviour, however, it must also be possible to pass some other stream object that would be used instead of std::cout, something like this:
void DumpData(std::ostream& Stream = std::cout) const
{
Stream << "My Data 1" << std::endl;
Stream << "My Data 2" << std::endl;
}
Now to my questions:
What is the correct type I should use for the paramter (std::ostream& in this example)?
What is the default value, can I use = std::cout directly?
Moreover (3.), after the call to this function, if I pass my own stream object, I need to iterate over all strings in this stream line by line. What would be the best way to achieve this?
Why don't you just try it yourself?
Here's you code in Coliru for std::cout and std::stringstream as an example (constness of DumpData removed obviously):
#include <iostream>
#include <sstream>
void DumpData(std::ostream& Stream = std::cout)
{
Stream << "My Data 1" << std::endl;
Stream << "My Data 2" << std::endl;
}
int main() {
DumpData();
std::stringstream ss;
DumpData(ss);
std::string l;
while(std::getline(ss, l)) {
std::cout << l << std::endl;
}
return 0;
}
Output is what you expected.
1 and 2 are correct. Your other option is to use std::ostringstream, but since std::cout is a std::ostream you would need to define another function with this signature.
To iterate the custom output, I would convert the stream to a string, then use some kind of string splitting to read each line.
Adding to #Jay 's answer, you could use a template parameter to be able to use a variety of streams such as std::stringstream or a std::iostream as long as the template parameter supports the << operator.
template <typename T> // = decltype(something)
void DumpData(T& Stream = std::cout) const
{
Stream << "My Data 1" << std::endl;
Stream << "My Data 2" << std::endl;
}
You can take it one step further by ensuring the type T provided overloads the operator <<.
Also in some cases, certain (possibly custom) streams may not be able to support std::endl so it might be safer to default to using \n which is always nicer since it avoid unnecessary flushes.
Let's say Ì have some class and added output functionality by overloading the left-shift operator:
struct Foo
{
int i = 1;
std::string s = "hello";
};
auto& operator<<(std::ostream& os, Foo const& foo)
{
os<<foo.i<<"\n";
os<<foo.s<<"\n";
return os;
}
What is a good way to indent the output?
Example: If I write
std::cout<<" "<<Foo{}<<std::endl;
the output is:
1
hello
Obviously, hello is not indented. Is there an easy way to indent the whole output (and not just the first element)?
You're serializing the Foo object right? So logically the serialized string of Foo is an implementation detail of Foo. You could write your own stream class or something along those lines but that is overengineering the problem.
auto& operator<<(std::ostream& os, Foo const& foo)
{
auto s = "\t" + std::to_string(foo.i) + "\n"
"\t" + foo.s;
return (os << s);
}
int main()
{
std::cout << Foo{} << "\n";
}
You can use the standard library manipulator setw to set the width of a field, which often results in indenting the text. Here's how you use it:
cout << std::setw(10) << "Viola!" << std::endl;
This will print the word "Viola!" indented by 4 spaces. Why 4 spaces? The parameter to setw() determines the entire width of the "field", which includes the 6 characters in "Viola!".
By default, setw() will align the text to the right, but can be made to align left by using another manipulator left. Here's an example:
cout << std::setw(10) << std::left << "Viola!" << std::endl;
This will output the string "Viola!" with no indentation, but with 4 spaces after it.
That should answer your original question about a good way to indent, and setw() is not just a good way, but the standard way.
The second question asks about how to have persistent indentation, and the answer is that there is not an easy way. The easiest approach is to add the call to setw() (or whichever indentation method that you use) in each of the calls to cout.
In addition to those answers, you should consider replacing the use of "\n" in your calls to cout with a call to endl. endl is the "end of line" manipulator, and makes your code work properly with any output stream. The code would look like this:
auto& operator<<(std::ostream& os, Foo const& foo)
{
os << foo.i << std::endl;
os << foo.s << std::endl;
return os;
}
It is a pain to do an endline between each value with OFSTREAM.
Here's an example of what I've got:
ofstream fout("~/xample.txt");
fout << val1;
fout << endl;
fout << val2;
I want to be able to do, instead,
ofstream fout("xample.txt");
fout << val1;
fout << val2;
I don't care how the file is stored because I will write a configuration wizard anyways.
If fout << val1 << endl; does not work with you, you might be able to inherit ofstream and create your own stream that adds endl automatically. But also you can drink water from fire hydrant.
It is a pain ...
Besides you could simply write
fout << val1 << endl;
fout << val2 << endl;
you may use any other whitespace character value to delimit your values in the output file:
fout << val1 << ' ';
fout << val2 << ' ';
// ... more value outputs
fout << endl;
Shouldn't matter for the file size, but number of lines definitely.
UPDATE:
As you're asking how to extend the formatting behavior on std::ostream:
I don't think it's a good idea to use inheritance from std::streambuf, std::ostream, et al., and try to (re-)implement the interfaces themselves (as usually never it's a good idea inheriting STL classes, can be done though). I'd say the intended way is to use stream manipulators for such.
To automate appending the endl or any other delimiter you could write a small parameterized stream manipulator (at least this solution is copy/paste and IDE intellisense friendly):
template<typename T>
class auto_delim_manip
{
public:
auto_delim_manip(T value_, char delim_)
: value(value_)
, delim(delim_) {}
void put(std::ostream& os) const {
os << value << delim;
os.flush();
}
private:
T value;
char delim;
};
template<typename T>
auto_delim_manip<T> auto_delim(T value, char delim = '\n') {
return auto_delim_manip<T>(value,delim);
}
template<typename T>
std::ostream& operator<<(std::ostream& os, const auto_delim_manip<T>& autoDelim)
{
autoDelim.put(os);
return os;
}
int main() {
cout << auto_delim(5.2) << auto_delim(3) << auto_delim("Hello!");
return 0;
}
Output:
5.2
3
Hello!
Check the running sample here.
If you have a large number of values, simply put 'endl' on the same line as your output and loop through all of your data. Such as:
for(int i = 0; i < numValues; ++i) {
fout << values[i] << endl;
}
I'm not aware of a built-in way to automate this, but it's honestly not that much work to add line endings manually.
Is there an easy way to indent the output going to an ofstream object? I have a C++ character array that is null terminate and includes newlines. I'd like to output this to the stream but indent each line with two spaces. Is there an easy way to do this with the stream manipulators like you can change the base for integer output with special directives to the stream or do I have to manually process the array and insert the extra spaces manually at each line break detected?
Seems like the string::right() manipulator is close:
http://www.cplusplus.com/reference/iostream/manipulators/right/
Thanks.
-William
This is the perfect situation to use a facet.
A custom version of the codecvt facet can be imbued onto a stream.
So your usage would look like this:
int main()
{
/* Imbue std::cout before it is used */
std::ios::sync_with_stdio(false);
std::cout.imbue(std::locale(std::locale::classic(), new IndentFacet()));
std::cout << "Line 1\nLine 2\nLine 3\n";
/* You must imbue a file stream before it is opened. */
std::ofstream data;
data.imbue(indentLocale);
data.open("PLOP");
data << "Loki\nUses Locale\nTo do something silly\n";
}
The definition of the facet is slightly complex.
But the whole point is that somebody using the facet does not need to know anything about the formatting. The formatting is applied independent of how the stream is being used.
#include <locale>
#include <algorithm>
#include <iostream>
#include <fstream>
class IndentFacet: public std::codecvt<char,char,std::mbstate_t>
{
public:
explicit IndentFacet(size_t ref = 0): std::codecvt<char,char,std::mbstate_t>(ref) {}
typedef std::codecvt_base::result result;
typedef std::codecvt<char,char,std::mbstate_t> parent;
typedef parent::intern_type intern_type;
typedef parent::extern_type extern_type;
typedef parent::state_type state_type;
int& state(state_type& s) const {return *reinterpret_cast<int*>(&s);}
protected:
virtual result do_out(state_type& tabNeeded,
const intern_type* rStart, const intern_type* rEnd, const intern_type*& rNewStart,
extern_type* wStart, extern_type* wEnd, extern_type*& wNewStart) const
{
result res = std::codecvt_base::noconv;
for(;(rStart < rEnd) && (wStart < wEnd);++rStart,++wStart)
{
// 0 indicates that the last character seen was a newline.
// thus we will print a tab before it. Ignore it the next
// character is also a newline
if ((state(tabNeeded) == 0) && (*rStart != '\n'))
{
res = std::codecvt_base::ok;
state(tabNeeded) = 1;
*wStart = '\t';
++wStart;
if (wStart == wEnd)
{
res = std::codecvt_base::partial;
break;
}
}
// Copy the next character.
*wStart = *rStart;
// If the character copied was a '\n' mark that state
if (*rStart == '\n')
{
state(tabNeeded) = 0;
}
}
if (rStart != rEnd)
{
res = std::codecvt_base::partial;
}
rNewStart = rStart;
wNewStart = wStart;
return res;
}
// Override so the do_out() virtual function is called.
virtual bool do_always_noconv() const throw()
{
return false; // Sometime we add extra tabs
}
};
See: Tom's notes below
Well this is not the answer I'm looking for, but in case there is no such answer, here is a way to do this manually:
void
indentedOutput(ostream &outStream, const char *message, bool &newline)
{
while (char cur = *message) {
if (newline) {
outStream << " ";
newline = false;
}
outStream << cur;
if (cur == '\n') {
newline = true;
}
++message;
}
}
A way to add such feature would be to write a filtering streambuf (i.e. a streambuf which forwards the IO operation to another streambuf but manipulate the data transfered) which add the indentation as part of its filter operation. I gave an example of writing a streambuf here and boost provides a library to help in that.
If your case, the overflow() member would simply test for '\n' and then add the indent just after if needed (exactly what you have done in your indentedOuput function, excepted that newline would be a member of the streambuf). You could probably have a setting to increase or decrease the indent size (perhaps accessible via a manipulator, the manipulator would have to do a dynamic_cast to ensure that the streambuf associated to the stream is of the correct type; there is a mechanism to add user data to stream -- basic_ios::xalloc, iword and pword -- but here we want to act on the streambuf).
I've had good success with Martin's codecvt facet based suggestion, but I had problems using it on std::cout on OSX, since by default this stream uses a basic_streambuf based streambuf which ignores the imbued facet. The following line switches std::cout and friends to use a basic_filebuf based streambuf, which will use the imbued facet.
std::ios::sync_with_stdio(false);
With the associated side effect that the iostream standard stream objects may operate independently of the standard C streams.
Another note is since this facet does not have a static std::locale::id, which meant that calling std::has_facet<IndentFacet> on the locale always returned true. Adding a std::local::id meant that the facet was not used, since basic_filebuf looks for the base class template.
There is no simple way, but a lot has been written about the complex
ways to achieve this. Read this article for a good explanation of
the topic. Here is another article, unfortunately in German. But
its source code should help you.
For example you could write a function which logs a recursive structure. For each level of recursion the indentation is increased:
std::ostream& operator<<(std::ostream& stream, Parameter* rp)
{
stream << "Parameter: " << std::endl;
// Get current indent
int w = format::get_indent(stream);
stream << "Name: " << rp->getName();
// ... log other attributes as well
if ( rp->hasParameters() )
{
stream << "subparameter (" << rp->getNumParameters() << "):\n";
// Change indent for sub-levels in the hierarchy
stream << format::indent(w+4);
// write sub parameters
stream << rp->getParameters();
}
// Now reset indent
stream << format::indent(w);
return stream;
}
I have generalized Loki Astarti's solution to work with arbitrary indentation levels. The solution has a nice, easy to use interface, but the actual implementation is a little fishy. It can be found on github:https://github.com/spacemoose/ostream_indenter
There's a more involved demo in the github repo, but given:
#include "indent_facet.hpp"
/// This probably has to be called once for every program:
// http://stackoverflow.com/questions/26387054/how-can-i-use-stdimbue-to-set-the-locale-for-stdwcout
std::ios_base::sync_with_stdio(false);
// This is the demo code:
std::cout << "I want to push indentation levels:\n" << indent_manip::push
<< "To arbitrary depths\n" << indent_manip::push
<< "and pop them\n" << indent_manip::pop
<< "back down\n" << indent_manip::pop
<< "like this.\n" << indent_manip::pop;
}
It produces the following output:
I want to push indentation levels:
To arbitrary depths
and pop them
back down
like this.
I would appreciate any feedback as to the utility of the code.
Simple whitespace manipulator
struct Whitespace
{
Whitespace(int n)
: n(n)
{
}
int n;
};
std::ostream& operator<<(std::ostream& stream, const Whitespace &ws)
{
for(int i = 0; i < ws.n; i++)
{
stream << " ";
}
return stream;
}