「C++/ライブラリ/multi_stream」の編集履歴(バックアップ)一覧に戻る

C++/ライブラリ/multi_stream - (2008/12/15 (月) 10:45:41) のソース

***概要
複数のostreamへ出力するストリームラッパクラス。~
コンストラクタの引数の展開にBoostを使ってるので要Boost。~
手書きすればBoostなしでも可。

***使い方
#codehighlight(C++){{

void func()
{
	std::ofstream of;
	of.open("somefile")
	util::multi_ostream(std::cout, of);
	mt << "foobar" << std::endl; // 標準出力とファイルに"foobar"が出力される
}
}}

***コード
#codehighlight(C++){{
/** @file multi_stream.h
 *  @breif 複数のostreamへ出力するストリームクラス
 */
#ifndef UTIL_MULTI_STREAM_H
#define UTIL_MULTI_STREAM_H

#include <iostream>
#include <vector>

#include <boost/preprocessor.hpp>

namespace util {

namespace detail {

//! コンストラクタで受け付けるostreamの最大数
#define ARGUMENT_MAX_COUNT 5

#define OSTREAM_ARRAY_ASSIGNMENT(z, n, data) outs_[n]=BOOST_PP_CAT(&os, n);

#define BOOST_PP_LOCAL_MACRO(n) \
basic_multi_streambuf(BOOST_PP_ENUM_PARAMS(n, std::basic_ostream<Ch BOOST_PP_COMMA() Tr>& os)) \
	: outs_(n), buf_(16) \
{ \
	setp(&(buf_[0]), (&(buf_[0])+buf_.size())); \
	BOOST_PP_REPEAT(n, OSTREAM_ARRAY_ASSIGNMENT, ~) \
}

#define BOOST_PP_LOCAL_LIMITS (1, BOOST_PP_EXPAND(ARGUMENT_MAX_COUNT)) 

/* 複数のostreamへ出力するためのstreambufクラス */
template <class Ch, class Tr=std::char_traits<Ch> >
class basic_multi_streambuf : public std::basic_streambuf<Ch,Tr> {
public:
	typedef typename std::basic_streambuf<Ch, Tr>::int_type int_type;

#include BOOST_PP_LOCAL_ITERATE()

	void add(std::basic_ostream<Ch, Tr>& os)
	{
		outs_.push_back(&os);
	}
	
	~basic_multi_streambuf()
	{}

protected:

	int_type overflow(int_type c=Tr::eof())
	{
		if(c!=Tr::eof()) {
			const size_t pos = pptr()-pbase();
			if(buf_.size() <= pos+1) {
				buf_.resize(2*buf_.size());
				setp(&(buf_[0]), (&(buf_[0])+buf_.size()));
				pbump(pos);
			}
			*pptr() = Tr::to_char_type(c);
			pbump(1);
            return Tr::not_eof(c);
		}
		return Tr::eof();
	}

	int sync()
	{
		const size_t pos = pptr()-pbase();
		for(ostreams::iterator it=outs_.begin(); it!=outs_.end(); ++it) {
			(*it)->write(&(buf_[0]), pos);
			(*it)->flush();
		}
		pbump(pbase()-pptr());
		return 0;
	}

private:
	explicit basic_multi_streambuf<Ch, Tr>(const basic_multi_streambuf<Ch, Tr>&);
	basic_multi_streambuf<Ch, Tr> &operator=(const basic_multi_streambuf<Ch, Tr>&);

	typedef std::vector<std::basic_ostream<Ch,Tr>* > ostreams;
    ostreams outs_;
	std::vector<Ch> buf_;
};


#define BOOST_PP_LOCAL_MACRO(n) \
basic_multi_ostream(BOOST_PP_ENUM_PARAMS(n, std::basic_ostream<Ch BOOST_PP_COMMA() Tr>& os)) \
	: std::basic_iostream<Ch,Tr>(&streambuf_), streambuf_(BOOST_PP_ENUM_PARAMS(n, os)) \
{}

#define BOOST_PP_LOCAL_LIMITS (1, BOOST_PP_EXPAND(ARGUMENT_MAX_COUNT)) 

/* 複数のostreamへ出力するためのラッパークラス */
template <class Ch, class Tr=std::char_traits<Ch> >
class basic_multi_ostream : public std::basic_iostream<Ch,Tr> {
public:

#include BOOST_PP_LOCAL_ITERATE()

	~basic_multi_ostream()
	{}

	void add(std::basic_ostream<Ch, Tr>& os)
	{
		streambuf_.add(os);
	}

private:
	explicit basic_multi_ostream(const basic_multi_ostream&);
	basic_multi_ostream &operator=(const basic_multi_ostream&);

	basic_multi_streambuf<Ch, Tr> streambuf_;
};

}

typedef detail::basic_multi_ostream<char> multi_ostream;
typedef detail::basic_multi_ostream<wchar_t> multi_wostream;


#undef ARGUMENT_MAX_COUNT
#undef OSTREAM_ARRAY_ASSIGNMENT

}

#endif
}}
目安箱バナー