Sign in to follow this  
CoffeeMug

multiplexing ostream (please suggest improvements)

Recommended Posts

I finally got some free time and wrote a multiplexing ostream. The feature is commonly requested and the idea is to develop an ostream that will simultaniously output everything thrown at it to multiple other streams. I don't have a book about extending the stream library (except Stroustrup's C++ book but that's not much help) so I had to decipher everything myself. Below is the code and usage example. I'd like to welcome any suggestions and improvements you may have.
#ifndef _VAPOR_MULTIPLEXOR_OSTREAM_H_
#define _VAPOR_MULTIPLEXOR_OSTREAM_H_

#include <ostream>
#include <vector>
#include <boost/shared_ptr.hpp>

using namespace std;

namespace Vapor
{
	typedef boost::shared_ptr<ostream> ostreamptr;
	typedef vector<ostreamptr> streamvector;

	class multiplexor_streambuf : public streambuf
	{
	public:
		multiplexor_streambuf() : streambuf() {}

		virtual int overflow(int c)
		{
			// write the incoming character into each stream
			streamvector::iterator _b = _streams.begin(), _e = _streams.end();
			for(; _b != _e; _b++)
				(*_b)->put(c);

			return c;
		}

	public:
		streamvector _streams;
	};

	class multiplexor_ostream : public ostream
	{
	public:
		multiplexor_ostream() : ostream(new multiplexor_streambuf()), ios(0) {}
		virtual ~multiplexor_ostream() { delete rdbuf(); }

		streamvector& getostreams() { return ((multiplexor_streambuf*)rdbuf())->_streams; }
	};
};

#endif // _VAPOR_MULTIPLEXOR_OSTREAM_H_

An example of using the class:
// Create some streams
ostreamptr optr(new ofstream("log.txt"));
ostreamptr optr2(new ofstream("log2.txt"));

// Create and configure multiplexor_ostream
multiplexor_ostream stream;
stream.getostreams().push_back(optr);
stream.getostreams().push_back(optr2);

// "testing123" will be written to two files.
stream << "testing123" << endl;
[Edited by - CoffeeMug on December 2, 2004 8:39:14 AM]

Share this post


Link to post
Share on other sites
Quote:
I don't have a book about extending the stream library (except Stroustrup's C++ book but that's not much help) so I had to decipher everything myself.


Here's one, if you even want to complete your library.

Share this post


Link to post
Share on other sites
Thanks. I found this already (I think through one of your posts, actually) and I will definetly buy it when I have some more free time. There are so few people with deep iostreams knowledge, it's amazing (considering we're talking about such a commonly used standard library).

Share this post


Link to post
Share on other sites
This implementation calls a (virtual) overflow() function for every character thrown at the stream. Not a big deal for things like logging (which is mostly what this class was designed for) but it would still be nice to optimize this away. I am considering switching to stringbuf or setting a larger size for streambuf.

Share this post


Link to post
Share on other sites
Quote:
Original post by CoffeeMug
This implementation calls a (virtual) overflow() function for every character thrown at the stream. Not a big deal for things like logging (which is mostly what this class was designed for) but it would still be nice to optimize this away. I am considering switching to stringbuf or setting a larger size for streambuf.


You know, I think the cost of the virtual overflow() is completely swamped by the actual cost of the I/O. One optimization you can possibly add is to redefine xsputn() (function handling the sending of multiple characters), which by default repeatedly calls sputc(). Since your stream buffer is passing the data to other buffers, you could have its xsputn() call their xsputn() (unless it's private, I didn't check).

Share this post


Link to post
Share on other sites
Quote:
Original post by Fruny
You know, I think the cost of the virtual overflow() is completely swamped by the actual cost of the I/O.

Well, if there's 5kb of data before every flush, that's five thousand virtual calls for every I/O. Anyway, I'm not too worried about it but I'll see if I can implement your suggestion. So far the system works great for logging to multiple destinations.

Share this post


Link to post
Share on other sites
I thought the whole point of the template streambuf parameter is so that you wouldn't have to deal with the virtual calls because you specify the exact type:


template<class CharT>
class multi_streambuf
{
// implement
};

template<class CharT,class BuffT = multi_streambuf<CharT> >
class multi_ostream : public std::ostream
{
// implement
};

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by daerid
I thought the whole point of the template streambuf parameter is so that you wouldn't have to deal with the virtual calls because you specify the exact type:

*** Source Snippet Removed ***


And how do you mean that is supposed to remove the need for virtual functions in this case?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this