$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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;