Boost logo

Boost-Commit :

From: technews_at_[hidden]
Date: 2008-05-25 18:03:23


Author: turkanis
Date: 2008-05-25 18:03:22 EDT (Sun, 25 May 2008)
New Revision: 45752
URL: http://svn.boost.org/trac/boost/changeset/45752

Log:
made tee work with input streams (fixes #791)
Text files modified:
   trunk/boost/iostreams/tee.hpp | 112 +++++++++++++++++++++++++++------------
   trunk/libs/iostreams/test/tee_test.cpp | 60 +++++++++++++++++++++
   2 files changed, 136 insertions(+), 36 deletions(-)

Modified: trunk/boost/iostreams/tee.hpp
==============================================================================
--- trunk/boost/iostreams/tee.hpp (original)
+++ trunk/boost/iostreams/tee.hpp 2008-05-25 18:03:22 EDT (Sun, 25 May 2008)
@@ -40,7 +40,8 @@
     typedef typename detail::param_type<Device>::type param_type;
     typedef typename char_type_of<Device>::type char_type;
     struct category
- : multichar_output_filter_tag,
+ : dual_use_filter_tag,
+ multichar_tag,
           closable_tag,
           flushable_tag,
           localizable_tag,
@@ -57,6 +58,18 @@
         : detail::filter_adapter<Device>(dev)
         { }
 
+ template<typename Source>
+ std::streamsize read(Source& src, char_type* s, std::streamsize n)
+ {
+ std::streamsize result = iostreams::read(src, s, n);
+ if (result != -1) {
+ std::streamsize result2 = iostreams::write(this->component(), s, result);
+ (void) result2; // Suppress 'unused variable' warning.
+ assert(result == result2);
+ }
+ return result;
+ }
+
     template<typename Sink>
     std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
     {
@@ -68,7 +81,7 @@
     }
 
     template<typename Next>
- void close(Next&)
+ void close(Next&, BOOST_IOS::openmode)
     {
         detail::close_all(this->component());
     }
@@ -86,48 +99,75 @@
 //
 // Template name: tee_device.
 // Template paramters:
-// Sink1 - A blocking Sink.
-// Sink2 - A blocking Sink.
+// Device - A blocking Device.
+// Sink - A blocking Sink.
 //
-template<typename Sink1, typename Sink2>
+template<typename Device, typename Sink>
 class tee_device {
 public:
- typedef typename detail::param_type<Sink1>::type param_type1;
- typedef typename detail::param_type<Sink2>::type param_type2;
- typedef typename detail::value_type<Sink1>::type value_type1;
- typedef typename detail::value_type<Sink2>::type value_type2;
- typedef typename char_type_of<Sink1>::type char_type;
+ typedef typename detail::param_type<Device>::type device_param;
+ typedef typename detail::param_type<Sink>::type sink_param;
+ typedef typename detail::value_type<Device>::type device_value;
+ typedef typename detail::value_type<Sink>::type sink_value;
+ typedef typename char_type_of<Device>::type char_type;
+ typedef typename
+ mpl::if_<
+ is_convertible<
+ BOOST_DEDUCED_TYPENAME
+ iostreams::category_of<Device>::type,
+ output
+ >,
+ output,
+ input
+ >::type mode;
     BOOST_STATIC_ASSERT((
         is_same<
             char_type,
- BOOST_DEDUCED_TYPENAME char_type_of<Sink2>::type
- >::value
- ));
- BOOST_STATIC_ASSERT((
- is_convertible< // Using mode_of causes failures on VC6-7.0.
- BOOST_DEDUCED_TYPENAME iostreams::category_of<Sink1>::type, output
+ BOOST_DEDUCED_TYPENAME char_type_of<Sink>::type
>::value
     ));
     BOOST_STATIC_ASSERT((
- is_convertible< // Using mode_of causes failures on VC6-7.0.
- BOOST_DEDUCED_TYPENAME iostreams::category_of<Sink2>::type, output
+ is_convertible<
+ BOOST_DEDUCED_TYPENAME iostreams::category_of<Sink>::type,
+ output
>::value
     ));
     struct category
- : output,
+ : mode,
           device_tag,
           closable_tag,
           flushable_tag,
           localizable_tag,
           optimally_buffered_tag
         { };
- tee_device(param_type1 sink1, param_type2 sink2)
- : sink1_(sink1), sink2_(sink2)
+ tee_device(device_param device, sink_param sink)
+ : dev_(device), sink_(sink)
         { }
+ std::streamsize read(char_type* s, std::streamsize n)
+ {
+ BOOST_STATIC_ASSERT((
+ is_convertible<
+ BOOST_DEDUCED_TYPENAME iostreams::category_of<Device>::type, input
+ >::value
+ ));
+ std::streamsize result1 = iostreams::read(dev_, s, n);
+ if (result1 != -1) {
+ std::streamsize result2 = iostreams::write(sink_, s, result1);
+ (void) result1; // Suppress 'unused variable' warning.
+ (void) result2;
+ assert(result1 == result2);
+ }
+ return result1;
+ }
     std::streamsize write(const char_type* s, std::streamsize n)
     {
- std::streamsize result1 = iostreams::write(sink1_, s, n);
- std::streamsize result2 = iostreams::write(sink2_, s, n);
+ BOOST_STATIC_ASSERT((
+ is_convertible<
+ BOOST_DEDUCED_TYPENAME iostreams::category_of<Device>::type, output
+ >::value
+ ));
+ std::streamsize result1 = iostreams::write(dev_, s, n);
+ std::streamsize result2 = iostreams::write(sink_, s, n);
         (void) result1; // Suppress 'unused variable' warning.
         (void) result2;
         assert(result1 == n && result2 == n);
@@ -135,38 +175,38 @@
     }
     void close()
     {
- detail::execute_all( detail::call_close_all(sink1_),
- detail::call_close_all(sink2_) );
+ detail::execute_all( detail::call_close_all(dev_),
+ detail::call_close_all(sink_) );
     }
     bool flush()
     {
- bool r1 = iostreams::flush(sink1_);
- bool r2 = iostreams::flush(sink2_);
+ bool r1 = iostreams::flush(dev_);
+ bool r2 = iostreams::flush(sink_);
         return r1 && r2;
     }
     template<typename Locale>
     void imbue(const Locale& loc)
     {
- iostreams::imbue(sink1_, loc);
- iostreams::imbue(sink2_, loc);
+ iostreams::imbue(dev_, loc);
+ iostreams::imbue(sink_, loc);
     }
     std::streamsize optimal_buffer_size() const
     {
- return (std::max) ( iostreams::optimal_buffer_size(sink1_),
- iostreams::optimal_buffer_size(sink2_) );
+ return (std::max) ( iostreams::optimal_buffer_size(dev_),
+ iostreams::optimal_buffer_size(sink_) );
     }
 private:
- value_type1 sink1_;
- value_type2 sink2_;
+ device_value dev_;
+ sink_value sink_;
 };
 
 template<typename Sink>
 tee_filter<Sink> tee(const Sink& snk)
 { return tee_filter<Sink>(snk); }
 
-template<typename Sink1, typename Sink2>
-tee_device<Sink1, Sink2> tee(const Sink1& sink1, const Sink2& sink2)
-{ return tee_device<Sink1, Sink2>(sink1, sink2); }
+template<typename Device, typename Sink>
+tee_device<Device, Sink> tee(const Device& dev, const Sink& sink)
+{ return tee_device<Device, Sink>(dev, sink); }
 
 } } // End namespaces iostreams, boost.
 

Modified: trunk/libs/iostreams/test/tee_test.cpp
==============================================================================
--- trunk/libs/iostreams/test/tee_test.cpp (original)
+++ trunk/libs/iostreams/test/tee_test.cpp 2008-05-25 18:03:22 EDT (Sun, 25 May 2008)
@@ -27,6 +27,36 @@
 void read_write_test()
 {
     {
+ test_file src1, src2;
+ temp_file dest;
+ filtering_istream first, second;
+ first.push(tee(file_sink(dest.name(), out_mode)));
+ first.push(file_source(src1.name(), in_mode));
+ second.push(file_source(src2.name(), in_mode));
+ compare_streams_in_chars(first, second); // ignore return value
+ first.reset();
+ BOOST_CHECK_MESSAGE(
+ compare_files(dest.name(), src1.name()),
+ "failed reading from a tee_filter in chars"
+ );
+ }
+
+ {
+ test_file src1, src2;
+ temp_file dest;
+ filtering_istream first, second;
+ first.push(tee(file_sink(dest.name(), out_mode)));
+ first.push(file_source(src1.name(), in_mode));
+ second.push(file_source(src2.name(), in_mode));
+ compare_streams_in_chunks(first, second); // ignore return value
+ first.reset();
+ BOOST_CHECK_MESSAGE(
+ compare_files(dest.name(), src1.name()),
+ "failed reading from a tee_filter in chunks"
+ );
+ }
+
+ {
         temp_file dest1;
         temp_file dest2;
         filtering_ostream out;
@@ -55,6 +85,36 @@
     }
 
     {
+ test_file src1, src2;
+ temp_file dest;
+ filtering_istream first, second;
+ first.push( tee( file_source(src1.name(), in_mode),
+ file_sink(dest.name(), out_mode) ) );
+ second.push(file_source(src2.name(), in_mode));
+ compare_streams_in_chars(first, second); // ignore return value
+ first.reset();
+ BOOST_CHECK_MESSAGE(
+ compare_files(dest.name(), src1.name()),
+ "failed reading from a tee_device in chars"
+ );
+ }
+
+ {
+ test_file src1, src2;
+ temp_file dest;
+ filtering_istream first, second;
+ first.push( tee( file_source(src1.name(), in_mode),
+ file_sink(dest.name(), out_mode) ) );
+ second.push(file_source(src2.name(), in_mode));
+ compare_streams_in_chunks(first, second); // ignore return value
+ first.reset();
+ BOOST_CHECK_MESSAGE(
+ compare_files(dest.name(), src1.name()),
+ "failed reading from a tee_device in chunks"
+ );
+ }
+
+ {
         temp_file dest1;
         temp_file dest2;
         filtering_ostream out;


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk