Boost logo

Boost-Commit :

From: technews_at_[hidden]
Date: 2007-12-14 14:30:13


Author: turkanis
Date: 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
New Revision: 42047
URL: http://svn.boost.org/trac/boost/changeset/42047

Log:
I. Changed signature and specification of boost::iostreams::close(),
   and made corresponding changes throughout the iostreams library.
   New spec is:
   
   template<typename T>
   void close(T& t);

     Convenience function for closing a device; calls close(t, in) and
     close(t, out).

   template<typename T>
   void close(T& t, openmode which);

   template<typename T, typename Sink>
   void close(T& t, Sink& snk, openmode which);

     These two functions should only be called by the library implementation
     or by advanced users. The openmode parameter must always equal in or
     out, never in | out.

     There are three cases:

     1. If T is not closable and which == out, calls boost::iostreams::flush

     2. If T operates on a single sequence, and is NOT a dual-use filter:

        a. If which == in and the mode of T is convertible to input but
           not to output, calls t.close() (or t.close(snk))

        b. If which == out and the mode of T is not convertible to input or
           is convertible to input and to output, calls t.close()
           (or t.close(snk))

        The effect of a. and b. is that for any T in this category,
        close() is called exactly once.

     3. If T operates on two sequences or is a dual-use filter, calls
        t.close(which) (or t.close(snk, which))

     If multiple operations that might throw must be called in the course
     of closing a filter or device, all of the operations are attempted
     and the first exception thrown by any of the operations is rethrown

  The new test close_test.cpp contains 95 checks verifying that the operation
  behaves as sepcified.

  This affects the following files:

    chain.hpp
    close.hpp
    code_converter.hpp
    combine.hpp
    compose.hpp
    copy.hpp
    detail/adapter/basic_adapter.hpp [removed]
    detail/adapter/device_adapter.hpp [new]
    detail/adapter/direct_adapter.hpp
    detail/adapter/filter_adapter.hpp [new]
    detail/adapter/mode_adapter.hpp
    detail/broken_overload_resolution/stream_buffer.hpp
    detail/closer.hpp [removed]
    detail/config/limits.hpp
    detail/execute.hpp [new]
    detail/functional.hpp [new]
    detail/streambuf/direct_streambuf.hpp
    detail/streambuf/indirect_streambuf.hpp
    detail/streambuf/linked_streambuf.hpp
    detail/vc6/close.hpp
    device/null.hpp
    filter/aggregate.hpp
    filter/bzip2.hpp
    filter/gzip.hpp
    filter/line.hpp
    filter/newline.hpp
    filter/symmetric.hpp
    filter/test.hpp
    invert.hpp
    restrict.hpp
    tee.hpp
    example/finite_state_filter.hpp
    test/Jamfile.v2
    test/close_test.cpp [new]
    test/code_converter_test.cpp
    test/execute_test.cpp [new]
    test/operation_sequence_test.cpp [new]

II. When exceptions are caught and ignored, we now use catch (...)
    uniformly instead of catch (std::exception&). This affects the
    following files:

    stream_buffer.hpp
    src/mapped_file.cpp

III. Unnecessary dependence on Boost.Range has been eliminated. This
     affects the following files:

    detail/is_iterator_range.hpp
    detail/resolve.hpp
    traits.hpp
    test/Jamfile.v2
    test/filtering_stream_test.cpp
    test/offset_test.cpp
    test/seek_test.hpp
    test/seekable_filter_test.cpp
    test/sequence_test.cpp [new]
    test/wide_stream_test.cpp

IV. There are several fixes to the documentation. This affects the
    following files:

    doc/classes/symmetric_filter.html
    doc/guide/concepts.html
    doc/guide/modes.html
    doc/tutorial/container_device.html [serious error in algorithm]
    doc/tutorial/dictionary_filters.html [unused member variable]
    doc/tutorial/multichar_filters.html

V. Other changes include:

    stream.hpp [missing include directive]
    example/container_device.hpp [serious error in algorithm]
    example/container_device_example.cpp [outdated naming]
    example/container_sink_example.cpp [outdated naming]
    example/container_source_example.cpp [outdated naming]
    example/dictionary_filter.hpp [unused member variable]
    test/compose_test.cpp [added comments]
    test/example_test.cpp [reformatted]
Added:
   trunk/boost/iostreams/detail/adapter/device_adapter.hpp (contents, props changed)
   trunk/boost/iostreams/detail/adapter/filter_adapter.hpp (contents, props changed)
   trunk/boost/iostreams/detail/execute.hpp (contents, props changed)
   trunk/boost/iostreams/detail/functional.hpp (contents, props changed)
   trunk/libs/iostreams/test/close_test.cpp (contents, props changed)
   trunk/libs/iostreams/test/detail/closable.hpp (contents, props changed)
   trunk/libs/iostreams/test/detail/operation_sequence.hpp (contents, props changed)
   trunk/libs/iostreams/test/execute_test.cpp (contents, props changed)
   trunk/libs/iostreams/test/operation_sequence_test.cpp (contents, props changed)
   trunk/libs/iostreams/test/sequence_test.cpp (contents, props changed)
Removed:
   trunk/boost/iostreams/detail/adapter/basic_adapter.hpp
   trunk/boost/iostreams/detail/closer.hpp
Text files modified:
   trunk/boost/iostreams/chain.hpp | 51 ++++++++++----
   trunk/boost/iostreams/close.hpp | 74 ++++++++++++++++++++-
   trunk/boost/iostreams/code_converter.hpp | 40 ++++++-----
   trunk/boost/iostreams/combine.hpp | 16 ++--
   trunk/boost/iostreams/compose.hpp | 114 +++++++++++++++++++++++++--------
   trunk/boost/iostreams/copy.hpp | 70 ++++++++++++++++----
   trunk/boost/iostreams/detail/adapter/direct_adapter.hpp | 2
   trunk/boost/iostreams/detail/adapter/mode_adapter.hpp | 9 ++
   trunk/boost/iostreams/detail/broken_overload_resolution/stream_buffer.hpp | 2
   trunk/boost/iostreams/detail/config/limits.hpp | 4 +
   trunk/boost/iostreams/detail/is_iterator_range.hpp | 15 ++++
   trunk/boost/iostreams/detail/resolve.hpp | 14 ++-
   trunk/boost/iostreams/detail/streambuf/direct_streambuf.hpp | 25 +++---
   trunk/boost/iostreams/detail/streambuf/indirect_streambuf.hpp | 45 +++++-------
   trunk/boost/iostreams/detail/streambuf/linked_streambuf.hpp | 50 ++++++++++++--
   trunk/boost/iostreams/detail/vc6/close.hpp | 8 +-
   trunk/boost/iostreams/device/null.hpp | 3
   trunk/boost/iostreams/filter/aggregate.hpp | 33 ++++-----
   trunk/boost/iostreams/filter/bzip2.hpp | 11 ++
   trunk/boost/iostreams/filter/gzip.hpp | 47 ++++++++-----
   trunk/boost/iostreams/filter/line.hpp | 25 ++++---
   trunk/boost/iostreams/filter/newline.hpp | 136 ++++++++++++++++++++++-----------------
   trunk/boost/iostreams/filter/symmetric.hpp | 39 +++++-----
   trunk/boost/iostreams/filter/test.hpp | 1
   trunk/boost/iostreams/invert.hpp | 14 ++-
   trunk/boost/iostreams/restrict.hpp | 15 ++--
   trunk/boost/iostreams/stream.hpp | 1
   trunk/boost/iostreams/stream_buffer.hpp | 2
   trunk/boost/iostreams/tee.hpp | 26 ++++---
   trunk/boost/iostreams/traits.hpp | 12 ++-
   trunk/libs/iostreams/doc/classes/symmetric_filter.html | 2
   trunk/libs/iostreams/doc/guide/concepts.html | 10 +-
   trunk/libs/iostreams/doc/guide/modes.html | 4
   trunk/libs/iostreams/doc/tutorial/container_device.html | 4
   trunk/libs/iostreams/doc/tutorial/container_sink.html | 4
   trunk/libs/iostreams/doc/tutorial/container_source.html | 4
   trunk/libs/iostreams/doc/tutorial/dictionary_filters.html | 1
   trunk/libs/iostreams/doc/tutorial/multichar_filters.html | 2
   trunk/libs/iostreams/doc/tutorial/shell_comments_filters.html | 2
   trunk/libs/iostreams/example/container_device.hpp | 2
   trunk/libs/iostreams/example/container_device_example.cpp | 6
   trunk/libs/iostreams/example/container_sink_example.cpp | 6
   trunk/libs/iostreams/example/container_source_example.cpp | 8 +-
   trunk/libs/iostreams/example/dictionary_filter.hpp | 1
   trunk/libs/iostreams/example/finite_state_filter.hpp | 9 +-
   trunk/libs/iostreams/src/mapped_file.cpp | 2
   trunk/libs/iostreams/test/Jamfile.v2 | 4 +
   trunk/libs/iostreams/test/code_converter_test.cpp | 61 ++++++++++++++++-
   trunk/libs/iostreams/test/compose_test.cpp | 4 +
   trunk/libs/iostreams/test/example_test.cpp | 12 +-
   trunk/libs/iostreams/test/filtering_stream_test.cpp | 10 --
   trunk/libs/iostreams/test/offset_test.cpp | 1
   trunk/libs/iostreams/test/seek_test.hpp | 16 +++-
   trunk/libs/iostreams/test/seekable_filter_test.cpp | 18 ++--
   trunk/libs/iostreams/test/wide_stream_test.cpp | 18 ++--
   55 files changed, 733 insertions(+), 382 deletions(-)

Modified: trunk/boost/iostreams/chain.hpp
==============================================================================
--- trunk/boost/iostreams/chain.hpp (original)
+++ trunk/boost/iostreams/chain.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -11,7 +11,6 @@
 # pragma once
 #endif
 
-#include <algorithm> // for_each.
 #include <cassert>
 #include <exception>
 #include <functional> // unary_function.
@@ -38,7 +37,8 @@
 #include <boost/static_assert.hpp>
 #include <boost/type_traits/is_convertible.hpp>
 #include <boost/type.hpp>
-#if BOOST_WORKAROUND(BOOST_MSVC, < 1310)
+#include <boost/iostreams/detail/execute.hpp> // VC6.5 requires this
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1310) // #include order
 # include <boost/mpl/int.hpp>
 #endif
 
@@ -229,7 +229,8 @@
                     policy_type,
                     BOOST_IOSTREAMS_CHAR_TRAITS(char_type),
                     Alloc, Mode
- > facade_type;
+ > streambuf_t;
+ typedef typename list_type::iterator iterator;
         BOOST_STATIC_ASSERT((is_convertible<category, Mode>::value));
         if (is_complete())
             throw std::logic_error("chain complete");
@@ -242,12 +243,20 @@
             pback_size != -1 ?
                 pback_size :
                 pimpl_->pback_size_;
- std::auto_ptr<facade_type>
- buf(new facade_type(t, buffer_size, pback_size));
+ std::auto_ptr<streambuf_t>
+ buf(new streambuf_t(t, buffer_size, pback_size));
         list().push_back(buf.get());
         buf.release();
- if (is_device<policy_type>::value)
+ if (is_device<policy_type>::value) {
             pimpl_->flags_ |= f_complete | f_open;
+ for ( iterator first = list().begin(),
+ last = list().end();
+ first != last;
+ ++first )
+ {
+ (*first)->set_needs_close();
+ }
+ }
         if (prev) prev->set_next(list().back());
         notify();
     }
@@ -261,7 +270,7 @@
 
     static void close(streambuf_type* b, BOOST_IOS::openmode m)
     {
- if (m & BOOST_IOS::out)
+ if (m == BOOST_IOS::out && is_convertible<Mode, output>::value)
             b->BOOST_IOSTREAMS_PUBSYNC();
         b->close(m);
     }
@@ -295,23 +304,35 @@
               pback_size_(default_pback_buffer_size),
               flags_(f_auto_close)
             { }
- ~chain_impl() { try { close(); reset(); } catch (std::exception&) { } }
+ ~chain_impl() { try { close(); reset(); } catch (...) { } }
         void close()
             {
                 if ((flags_ & f_open) != 0) {
+ flags_ &= ~f_open;
                     stream_buffer< basic_null_device<Ch, Mode> > null;
                     if ((flags_ & f_complete) == 0) {
                         null.open(basic_null_device<Ch, Mode>());
                         set_next(links_.back(), &null);
                     }
                     links_.front()->BOOST_IOSTREAMS_PUBSYNC();
- if (is_convertible<Mode, input>::value)
- std::for_each( links_.rbegin(), links_.rend(),
- closer(BOOST_IOS::in) );
- if (is_convertible<Mode, output>::value)
- std::for_each( links_.begin(), links_.end(),
- closer(BOOST_IOS::out) );
- flags_ &= ~f_open;
+ try {
+ boost::iostreams::detail::execute_foreach(
+ links_.rbegin(), links_.rend(),
+ closer(BOOST_IOS::in)
+ );
+ } catch (...) {
+ try {
+ boost::iostreams::detail::execute_foreach(
+ links_.begin(), links_.end(),
+ closer(BOOST_IOS::out)
+ );
+ } catch (...) { }
+ throw;
+ }
+ boost::iostreams::detail::execute_foreach(
+ links_.begin(), links_.end(),
+ closer(BOOST_IOS::out)
+ );
                 }
             }
         void reset()

Modified: trunk/boost/iostreams/close.hpp
==============================================================================
--- trunk/boost/iostreams/close.hpp (original)
+++ trunk/boost/iostreams/close.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -16,12 +16,16 @@
 #include <boost/iostreams/categories.hpp>
 #include <boost/iostreams/flush.hpp>
 #include <boost/iostreams/detail/adapter/non_blocking_adapter.hpp>
+#include <boost/iostreams/detail/ios.hpp> // BOOST_IOS
 #include <boost/iostreams/detail/wrap_unwrap.hpp>
 #include <boost/iostreams/operations_fwd.hpp>
 #include <boost/iostreams/traits.hpp>
 #include <boost/mpl/identity.hpp>
 #include <boost/mpl/if.hpp>
 #include <boost/type_traits/is_convertible.hpp>
+#include <boost/type_traits/is_integral.hpp>
+#include <boost/type_traits/remove_cv.hpp>
+#include <boost/type_traits/remove_reference.hpp>
 
 // Must come last.
 #include <boost/iostreams/detail/config/disable_warnings.hpp>
@@ -40,12 +44,31 @@
 } // End namespace detail.
 
 template<typename T>
+void close(T& t);
+
+template<typename T>
 void close(T& t, BOOST_IOS::openmode which)
-{ detail::close_impl<T>::close(detail::unwrap(t), which); }
+{
+ assert(which == BOOST_IOS::in || which == BOOST_IOS::out);
+ detail::close_impl<T>::close(detail::unwrap(t), which);
+}
+
+//template<typename T, typename Sink>
+//void close( T& t, Sink& snk,
+// typename
+// boost::disable_if<
+// boost::is_convertible<Sink, BOOST_IOS::openmode>
+// >::type* = 0 )
+//{
+// detail::close_all(t, snk);
+//}
 
 template<typename T, typename Sink>
 void close(T& t, Sink& snk, BOOST_IOS::openmode which)
-{ detail::close_impl<T>::close(detail::unwrap(t), snk, which); }
+{
+ assert(which == BOOST_IOS::in || which == BOOST_IOS::out);
+ detail::close_impl<T>::close(detail::unwrap(t), snk, which);
+}
 
 namespace detail {
 
@@ -83,14 +106,14 @@
     template<typename T>
     static void close(T& t, BOOST_IOS::openmode which)
     {
- if ((which & BOOST_IOS::out) != 0)
+ if (which == BOOST_IOS::out)
             iostreams::flush(t);
     }
 
     template<typename T, typename Sink>
     static void close(T& t, Sink& snk, BOOST_IOS::openmode which)
     {
- if ((which & BOOST_IOS::out) != 0) {
+ if (which == BOOST_IOS::out) {
             non_blocking_adapter<Sink> nb(snk);
             iostreams::flush(t, nb);
         }
@@ -106,7 +129,7 @@
         typedef typename category_of<T>::type category;
         const bool in = is_convertible<category, input>::value &&
                         !is_convertible<category, output>::value;
- if (in == ((which & BOOST_IOS::in) != 0))
+ if (in == (which == BOOST_IOS::in))
             t.close();
     }
     template<typename T, typename Sink>
@@ -115,7 +138,7 @@
         typedef typename category_of<T>::type category;
         const bool in = is_convertible<category, input>::value &&
                         !is_convertible<category, output>::value;
- if (in == ((which & BOOST_IOS::in) != 0)) {
+ if (in == (which == BOOST_IOS::in)) {
             non_blocking_adapter<Sink> nb(snk);
             t.close(nb);
         }
@@ -140,6 +163,45 @@
 
 #endif // #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) //-------------------------//
 
+namespace boost { namespace iostreams {
+
+namespace detail {
+
+template<typename T>
+void close_all(T& t)
+{
+ try {
+ boost::iostreams::close(t, BOOST_IOS::in);
+ } catch (...) {
+ try {
+ boost::iostreams::close(t, BOOST_IOS::out);
+ } catch (...) { }
+ throw;
+ }
+ boost::iostreams::close(t, BOOST_IOS::out);
+}
+
+template<typename T, typename Sink>
+void close_all(T& t, Sink& snk)
+{
+ try {
+ boost::iostreams::close(t, snk, BOOST_IOS::in);
+ } catch (...) {
+ try {
+ boost::iostreams::close(t, snk, BOOST_IOS::out);
+ } catch (...) { }
+ throw;
+ }
+ boost::iostreams::close(t, snk, BOOST_IOS::out);
+}
+
+} // End namespaces detail.
+
+template<typename T>
+void close(T& t) { detail::close_all(t); }
+
+} } // End iostreams, boost.
+
 #include <boost/iostreams/detail/config/enable_warnings.hpp>
 
 #endif // #ifndef BOOST_IOSTREAMS_CLOSE_HPP_INCLUDED

Modified: trunk/boost/iostreams/code_converter.hpp
==============================================================================
--- trunk/boost/iostreams/code_converter.hpp (original)
+++ trunk/boost/iostreams/code_converter.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -33,7 +33,9 @@
 #include <boost/iostreams/detail/codecvt_holder.hpp>
 #include <boost/iostreams/detail/codecvt_helper.hpp>
 #include <boost/iostreams/detail/double_object.hpp>
+#include <boost/iostreams/detail/execute.hpp>
 #include <boost/iostreams/detail/forward.hpp>
+#include <boost/iostreams/detail/functional.hpp>
 #include <boost/iostreams/detail/ios.hpp> // failure, openmode, int types.
 #include <boost/iostreams/detail/select.hpp>
 #include <boost/iostreams/traits.hpp>
@@ -146,7 +148,7 @@
     {
         try {
             if (flags_ & f_open) close();
- } catch (std::exception&) { /* */ }
+ } catch (...) { /* */ }
     }
 
     void open(const Device& dev, int buffer_size)
@@ -166,28 +168,32 @@
             buf_.second().set(0, 0);
         }
         dev_.reset(concept_adapter<policy_type>(dev));
- flags_ |= f_open;
+ flags_ = f_open;
     }
 
- void close(BOOST_IOS::openmode which = BOOST_IOS::in | BOOST_IOS::out)
+ void close()
     {
- if (which & BOOST_IOS::in) {
- iostreams::close(dev(), BOOST_IOS::in);
+ detail::execute_all(
+ detail::call_member_close(*this, BOOST_IOS::in),
+ detail::call_member_close(*this, BOOST_IOS::out)
+ );
+ }
+
+ void close(BOOST_IOS::openmode which)
+ {
+ if (which == BOOST_IOS::in && (flags_ & f_input_closed) == 0) {
             flags_ |= f_input_closed;
+ iostreams::close(dev(), BOOST_IOS::in);
         }
- if (which & BOOST_IOS::out) {
- buf_.second().flush(dev());
- iostreams::close(dev(), BOOST_IOS::out);
+ if (which == BOOST_IOS::out && (flags_ & f_output_closed) == 0) {
             flags_ |= f_output_closed;
- }
- if ( !is_double::value ||
- (flags_ & f_input_closed) != 0 &&
- (flags_ & f_output_closed) != 0 )
- {
- dev_.reset();
- buf_.first().reset();
- buf_.second().reset();
- flags_ = 0;
+ detail::execute_all(
+ detail::flush_buffer(buf_.second(), dev(), can_write::value),
+ detail::call_close(dev(), BOOST_IOS::out),
+ detail::call_reset(dev_),
+ detail::call_reset(buf_.first()),
+ detail::call_reset(buf_.second())
+ );
         }
     }
 

Modified: trunk/boost/iostreams/combine.hpp
==============================================================================
--- trunk/boost/iostreams/combine.hpp (original)
+++ trunk/boost/iostreams/combine.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -97,10 +97,10 @@
     template<typename Sink>
     void close(Sink& snk, BOOST_IOS::openmode which)
         {
- if (which & BOOST_IOS::in)
- iostreams::close(in_, snk, which);
- if (which & BOOST_IOS::out)
- iostreams::close(out_, snk, which);
+ if (which == BOOST_IOS::in)
+ detail::close_all(in_, snk);
+ if (which == BOOST_IOS::out)
+ detail::close_all(out_, snk);
         }
     #ifndef BOOST_NO_STD_LOCALE
         void imbue(const std::locale& loc);
@@ -193,10 +193,10 @@
 inline void
 combined_device<Source, Sink>::close(BOOST_IOS::openmode which)
 {
- if (which & BOOST_IOS::in)
- iostreams::close(src_, which);
- if (which & BOOST_IOS::out)
- iostreams::close(sink_, which);
+ if (which == BOOST_IOS::in)
+ detail::close_all(src_);
+ if (which == BOOST_IOS::out)
+ detail::close_all(sink_);
 }
 
 #ifndef BOOST_NO_STD_LOCALE

Modified: trunk/boost/iostreams/compose.hpp
==============================================================================
--- trunk/boost/iostreams/compose.hpp (original)
+++ trunk/boost/iostreams/compose.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -19,8 +19,9 @@
 #include <boost/iostreams/categories.hpp>
 #include <boost/iostreams/detail/adapter/direct_adapter.hpp>
 #include <boost/iostreams/detail/call_traits.hpp>
-#include <boost/iostreams/detail/closer.hpp>
 #include <boost/iostreams/detail/enable_if_stream.hpp>
+#include <boost/iostreams/detail/execute.hpp>
+#include <boost/iostreams/detail/functional.hpp>
 #include <boost/iostreams/operations.hpp>
 #include <boost/iostreams/traits.hpp> // mode_of, is_direct.
 #include <boost/mpl/if.hpp>
@@ -32,18 +33,20 @@
 
 namespace detail {
 
-template<typename Filter, typename Device>
-struct composite_mode {
- typedef typename mode_of<Filter>::type filter_mode;
- typedef typename mode_of<Device>::type device_mode;
- typedef is_convertible<filter_mode, dual_use> is_dual_use;
- typedef typename
- mpl::if_<
- is_convertible<device_mode, input>,
- input,
- output
- >::type type;
-};
+template< typename First,
+ typename Second,
+ typename FirstMode =
+ BOOST_DEDUCED_TYPENAME mode_of<First>::type,
+ typename SecondMode =
+ BOOST_DEDUCED_TYPENAME mode_of<Second>::type >
+struct composite_mode
+ : select<
+ is_convertible<SecondMode, FirstMode>, FirstMode,
+ is_convertible<FirstMode, SecondMode>, SecondMode,
+ is_convertible<SecondMode, input>, input,
+ else_, output
+ >
+ { };
 
 //
 // Template name: composite_device.
@@ -108,14 +111,17 @@
 // Filter - A model of Filter.
 // Device - An indirect model of Device.
 //
-template<typename Filter1, typename Filter2>
+template< typename Filter1,
+ typename Filter2,
+ typename Mode =
+ BOOST_DEDUCED_TYPENAME composite_mode<Filter1, Filter2>::type >
 class composite_filter {
 private:
      typedef reference_wrapper<Filter2> filter_ref;
 public:
     typedef typename char_type_of<Filter1>::type char_type;
     struct category
- : mode_of<Filter1>::type,
+ : Mode,
           filter_tag,
           multichar_tag,
           closable_tag,
@@ -151,12 +157,48 @@
     }
 
     template<typename Device>
- void close( Device& dev,
- BOOST_IOS::openmode which =
- BOOST_IOS::in | BOOST_IOS::out )
+ void close(Device& dev)
+ {
+ BOOST_STATIC_ASSERT((!is_convertible<category, two_sequence>::value));
+ BOOST_STATIC_ASSERT((!is_convertible<category, dual_use>::value));
+
+ // Create a new device by composing the second filter2_ with dev.
+ composite_device<filter_ref, Device> cmp(boost::ref(filter2_), dev);
+
+ // Close input sequences in reverse order and output sequences in
+ // forward order
+ detail::execute_all(
+ detail::call_close(filter2_, dev, BOOST_IOS::in),
+ detail::call_close(filter1_, cmp, BOOST_IOS::in),
+ detail::call_close(filter1_, cmp, BOOST_IOS::out),
+ detail::call_close(filter2_, dev, BOOST_IOS::out)
+ );
+ }
+
+ template<typename Device>
+ void close(Device& dev, BOOST_IOS::openmode which)
     {
+ BOOST_STATIC_ASSERT(
+ (is_convertible<category, two_sequence>::value) ||
+ (is_convertible<category, dual_use>::value)
+ );
+
+ // Create a new device by composing the second filter2_ with dev.
         composite_device<filter_ref, Device> cmp(boost::ref(filter2_), dev);
- iostreams::close(filter1_, cmp, which);
+
+ // Close input sequences in reverse order
+ if (which == BOOST_IOS::in)
+ detail::execute_all(
+ detail::call_close(filter2_, dev, BOOST_IOS::in),
+ detail::call_close(filter1_, cmp, BOOST_IOS::in)
+ );
+
+ // Close output sequences in forward order
+ if (which == BOOST_IOS::out)
+ detail::execute_all(
+ detail::call_close(filter1_, cmp, BOOST_IOS::out),
+ detail::call_close(filter2_, dev, BOOST_IOS::out)
+ );
     }
 
     template<typename Device>
@@ -332,25 +374,39 @@
 template<typename Filter, typename Device, typename Mode>
 void composite_device<Filter, Device, Mode>::close()
 {
- typedef typename mode_of<Device>::type device_mode;
- BOOST_IOS::openmode which =
- is_convertible<device_mode, input>() ?
- BOOST_IOS::in :
- BOOST_IOS::out;
- close(which);
+ BOOST_STATIC_ASSERT((!is_convertible<Mode, two_sequence>::value));
+
+ // Close input sequences in reverse order and output sequences
+ // in forward order
+ detail::execute_all( detail::call_close(device_, BOOST_IOS::in),
+ detail::call_close(filter_, device_, BOOST_IOS::in),
+ detail::call_close(filter_, device_, BOOST_IOS::out),
+ detail::call_close(device_, BOOST_IOS::out) );
 }
 
 template<typename Filter, typename Device, typename Mode>
 void composite_device<Filter, Device, Mode>::close(BOOST_IOS::openmode which)
 {
- bool nothrow = false;
- external_closer<value_type> close_device(device_, which, nothrow);
- external_closer<Filter, value_type> close_filter(filter_, device_, which, nothrow);
+ BOOST_STATIC_ASSERT((is_convertible<Mode, two_sequence>::value));
+
+ // Close input sequences in reverse order
+ if (which == BOOST_IOS::in)
+ detail::execute_all(
+ detail::call_close(device_, BOOST_IOS::in),
+ detail::call_close(filter_, device_, BOOST_IOS::in)
+ );
+
+ // Close output sequences in forward order
+ if (which == BOOST_IOS::out)
+ detail::execute_all(
+ detail::call_close(filter_, device_, BOOST_IOS::out),
+ detail::call_close(device_, BOOST_IOS::out)
+ );
 }
 
 template<typename Filter, typename Device, typename Mode>
 bool composite_device<Filter, Device, Mode>::flush()
-{ // To do: consider using RAII.
+{
     bool r1 = iostreams::flush(filter_, device_);
     bool r2 = iostreams::flush(device_);
     return r1 && r2;

Modified: trunk/boost/iostreams/copy.hpp
==============================================================================
--- trunk/boost/iostreams/copy.hpp (original)
+++ trunk/boost/iostreams/copy.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -20,13 +20,15 @@
 
 #include <algorithm> // copy.
 #include <utility> // pair.
+#include <boost/bind.hpp>
 #include <boost/detail/workaround.hpp>
 #include <boost/iostreams/chain.hpp>
 #include <boost/iostreams/constants.hpp>
 #include <boost/iostreams/detail/adapter/non_blocking_adapter.hpp>
-#include <boost/iostreams/detail/buffer.hpp>
-#include <boost/iostreams/detail/closer.hpp>
+#include <boost/iostreams/detail/buffer.hpp>
 #include <boost/iostreams/detail/enable_if_stream.hpp>
+#include <boost/iostreams/detail/execute.hpp>
+#include <boost/iostreams/detail/functional.hpp>
 #include <boost/iostreams/detail/ios.hpp> // failure, streamsize.
 #include <boost/iostreams/detail/resolve.hpp>
 #include <boost/iostreams/detail/wrap_unwrap.hpp>
@@ -39,11 +41,17 @@
 
 namespace detail {
 
+ // The following four overloads of copy_impl() optimize
+ // copying in the case that one or both of the two devices
+ // models Direct (see
+ // http://www.boost.org/libs/iostreams/doc/index.html?path=4.1.1.4)
+
+// Copy from a direct source to a direct sink
 template<typename Source, typename Sink>
 std::streamsize copy_impl( Source& src, Sink& snk,
                            std::streamsize /* buffer_size */,
                            mpl::true_, mpl::true_ )
-{ // Copy from a direct Source to a direct Sink.
+{
     using namespace std;
     typedef typename char_type_of<Source>::type char_type;
     typedef pair<char_type*, char_type*> pair_type;
@@ -57,11 +65,12 @@
     }
 }
 
+// Copy from a direct source to an indirect sink
 template<typename Source, typename Sink>
 std::streamsize copy_impl( Source& src, Sink& snk,
                            std::streamsize /* buffer_size */,
                            mpl::true_, mpl::false_ )
-{ // Copy from a direct Source to an indirect Sink.
+{
     using namespace std;
     typedef typename char_type_of<Source>::type char_type;
     typedef pair<char_type*, char_type*> pair_type;
@@ -77,11 +86,12 @@
     return size;
 }
 
+// Copy from an indirect source to a direct sink
 template<typename Source, typename Sink>
 std::streamsize copy_impl( Source& src, Sink& snk,
                            std::streamsize buffer_size,
                            mpl::false_, mpl::true_ )
-{ // Copy from an indirect Source to a direct Sink.
+{
     using namespace std;
     typedef typename char_type_of<Source>::type char_type;
     typedef pair<char_type*, char_type*> pair_type;
@@ -99,12 +109,12 @@
     return total;
 }
 
+// Copy from an indirect source to a direct sink
 template<typename Source, typename Sink>
 std::streamsize copy_impl( Source& src, Sink& snk,
                            std::streamsize buffer_size,
                            mpl::false_, mpl::false_ )
-{ // Copy from an indirect Source to a indirect Sink. This algorithm
- // can be improved by eliminating the non_blocking_adapter.
+{ // This algorithm can be improved by eliminating the non_blocking_adapter.
     typedef typename char_type_of<Source>::type char_type;
     detail::basic_buffer<char_type> buf(buffer_size);
     non_blocking_adapter<Sink> nb(snk);
@@ -121,6 +131,32 @@
     return total;
 }
 
+ // The following function object is used with
+ // boost::iostreams::detail::execute() in the primary
+ // overload of copy_impl(), below
+
+// Function object that delegates to one of the above four
+// overloads of compl_impl()
+template<typename Source, typename Sink>
+struct copy_operation {
+ typedef std::streamsize result_type;
+ copy_operation(Source& src, Sink& snk, std::streamsize buffer_size)
+ : src(src), snk(snk), buffer_size(buffer_size)
+ { }
+ std::streamsize operator()()
+ {
+ return copy_impl( src, snk, buffer_size,
+ is_direct<Source>(), is_direct<Sink>() );
+ }
+ Source& src;
+ Sink& snk;
+ std::streamsize buffer_size;
+};
+
+// Primary overload of copy_impl. Delegates to one of the above four
+// overloads of compl_impl(), depending on which of the two given
+// devices, if any, models Direct (see
+// http://www.boost.org/libs/iostreams/doc/index.html?path=4.1.1.4)
 template<typename Source, typename Sink>
 std::streamsize copy_impl(Source src, Sink snk, std::streamsize buffer_size)
 {
@@ -128,19 +164,19 @@
     typedef typename char_type_of<Source>::type src_char;
     typedef typename char_type_of<Sink>::type snk_char;
     BOOST_STATIC_ASSERT((is_same<src_char, snk_char>::value));
- bool nothrow = false;
- external_closer<Source> close_source(src, BOOST_IOS::in, nothrow);
- external_closer<Sink> close_sink(snk, BOOST_IOS::out, nothrow);
- streamsize result =
- copy_impl( src, snk, buffer_size,
- is_direct<Source>(), is_direct<Sink>() );
- return result;
+ return detail::execute_all(
+ copy_operation<Source, Sink>(src, snk, buffer_size),
+ detail::call_close_all(src),
+ detail::call_close_all(snk)
+ );
 }
 
 } // End namespace detail.
                     
 //------------------Definition of copy----------------------------------------//
 
+// Overload of copy() for the case where neither the source nor the sink is
+// a standard stream or stream buffer
 template<typename Source, typename Sink>
 std::streamsize
 copy( const Source& src, const Sink& snk,
@@ -156,6 +192,8 @@
 
 #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) //---------------------------------//
 
+// Overload of copy() for the case where the source, but not the sink, is
+// a standard stream or stream buffer
 template<typename Source, typename Sink>
 std::streamsize
 copy( Source& src, const Sink& snk,
@@ -169,6 +207,8 @@
                               buffer_size );
 }
 
+// Overload of copy() for the case where the sink, but not the source, is
+// a standard stream or stream buffer
 template<typename Source, typename Sink>
 std::streamsize
 copy( const Source& src, Sink& snk,
@@ -181,6 +221,8 @@
                               detail::wrap(snk), buffer_size);
 }
 
+// Overload of copy() for the case where neither the source nor the sink is
+// a standard stream or stream buffer
 template<typename Source, typename Sink>
 std::streamsize
 copy( Source& src, Sink& snk,

Deleted: trunk/boost/iostreams/detail/adapter/basic_adapter.hpp
==============================================================================
--- trunk/boost/iostreams/detail/adapter/basic_adapter.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
+++ (empty file)
@@ -1,69 +0,0 @@
-// (C) Copyright Jonathan Turkanis 2005.
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
-
-// See http://www.boost.org/libs/iostreams for documentation.
-
-#ifndef BOOST_IOSTREAMS_DETAIL_BASIC_ADAPTER_HPP_INCLUDED
-#define BOOST_IOSTREAMS_DETAIL_BASIC_ADAPTER_HPP_INCLUDED
-
-#include <boost/iostreams/categories.hpp>
-#include <boost/iostreams/detail/call_traits.hpp>
-#include <boost/iostreams/detail/ios.hpp>
-#include <boost/iostreams/operations.hpp>
-#include <boost/iostreams/traits.hpp>
-#include <boost/static_assert.hpp>
-
-namespace boost { namespace iostreams { namespace detail {
-
-template<typename T>
-class basic_adapter {
-private:
- typedef typename detail::value_type<T>::type value_type;
- typedef typename detail::param_type<T>::type param_type;
-public:
- explicit basic_adapter(param_type t) : t_(t) { }
- T& component() { return t_; }
-
- void close(BOOST_IOS::openmode which = BOOST_IOS::in | BOOST_IOS::out)
- {
- BOOST_STATIC_ASSERT(is_device<T>::value);
- iostreams::close(t_, which);
- }
-
- template<typename Device>
- void close( Device& dev,
- BOOST_IOS::openmode which =
- BOOST_IOS::in | BOOST_IOS::out )
- {
- BOOST_STATIC_ASSERT(is_filter<T>::value);
- iostreams::close(t_, dev, which);
- }
-
- bool flush()
- {
- BOOST_STATIC_ASSERT(is_device<T>::value);
- return iostreams::flush(t_);
- }
-
- template<typename Device>
- void flush(Device& dev)
- {
- BOOST_STATIC_ASSERT(is_filter<T>::value);
- return iostreams::flush(t_, dev);
- }
-
- template<typename Locale> // Avoid dependency on <locale>
- void imbue(const Locale& loc) { iostreams::imbue(t_, loc); }
-
- std::streamsize optimal_buffer_size() const
- { return iostreams::optimal_buffer_size(t_); }
-public:
- value_type t_;
-};
-
-//----------------------------------------------------------------------------//
-
-} } } // End namespaces detail, iostreams, boost.
-
-#endif // #ifndef BOOST_IOSTREAMS_DETAIL_BASIC_ADAPTER_HPP_INCLUDED

Added: trunk/boost/iostreams/detail/adapter/device_adapter.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/iostreams/detail/adapter/device_adapter.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -0,0 +1,66 @@
+/*
+ * Defines the class template boost::iostreams::detail::device_adapter,
+ * a convenience base class for device adapters.
+ *
+ * File: boost/iostreams/detail/adapter/filter_adapter.hpp
+ * Date: Mon Nov 26 14:35:48 MST 2007
+ *
+ * Copyright: 2007 CodeRage
+ * Author: Jonathan Turkanis
+ *
+ * Distributed under the Boost Software License, Version 1.0.(See accompanying
+ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
+ *
+ * See http://www.boost.org/libs/iostreams for documentation.
+ */
+
+#ifndef BOOST_IOSTREAMS_DETAIL_DEVICE_ADAPTER_HPP_INCLUDED
+#define BOOST_IOSTREAMS_DETAIL_DEVICE_ADAPTER_HPP_INCLUDED
+
+#include <boost/iostreams/categories.hpp>
+#include <boost/iostreams/detail/call_traits.hpp>
+#include <boost/iostreams/detail/ios.hpp>
+#include <boost/iostreams/operations.hpp>
+#include <boost/iostreams/traits.hpp>
+#include <boost/static_assert.hpp>
+
+namespace boost { namespace iostreams { namespace detail {
+
+template<typename T>
+class device_adapter {
+private:
+ typedef typename detail::value_type<T>::type value_type;
+ typedef typename detail::param_type<T>::type param_type;
+public:
+ explicit device_adapter(param_type t) : t_(t) { }
+ T& component() { return t_; }
+
+ void close()
+ {
+ detail::close_all(t_);
+ }
+
+ void close(BOOST_IOS::openmode which)
+ {
+ iostreams::close(t_, which);
+ }
+
+ bool flush()
+ {
+ return iostreams::flush(t_);
+ }
+
+ template<typename Locale> // Avoid dependency on <locale>
+ void imbue(const Locale& loc) { iostreams::imbue(t_, loc); }
+
+ std::streamsize optimal_buffer_size() const
+ { return iostreams::optimal_buffer_size(t_); }
+public:
+ value_type t_;
+};
+
+//----------------------------------------------------------------------------//
+
+} } } // End namespaces detail, iostreams, boost.
+
+#endif // #ifndef BOOST_IOSTREAMS_DETAIL_DEVICE_ADAPTER_HPP_INCLUDED

Modified: trunk/boost/iostreams/detail/adapter/direct_adapter.hpp
==============================================================================
--- trunk/boost/iostreams/detail/adapter/direct_adapter.hpp (original)
+++ trunk/boost/iostreams/detail/adapter/direct_adapter.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -255,7 +255,7 @@
 void direct_adapter<Direct>::close()
 {
     BOOST_STATIC_ASSERT((!is_convertible<category, two_sequence>::value));
- boost::iostreams::close(d_, BOOST_IOS::in | BOOST_IOS::out);
+ detail::close_all(d_);
 }
 
 template<typename Direct>

Added: trunk/boost/iostreams/detail/adapter/filter_adapter.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/iostreams/detail/adapter/filter_adapter.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -0,0 +1,68 @@
+/*
+ * Defines the class template boost::iostreams::detail::filter_adapter,
+ * a convenience base class for filter adapters.
+ *
+ * File: boost/iostreams/detail/adapter/filter_adapter.hpp
+ * Date: Mon Nov 26 14:35:48 MST 2007
+ * Copyright: 2007 CodeRage
+ * Author: Jonathan Turkanis
+ *
+ * Distributed under the Boost Software License, Version 1.0.(See accompanying
+ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
+ *
+ * See http://www.boost.org/libs/iostreams for documentation.
+ */
+
+#ifndef BOOST_IOSTREAMS_DETAIL_FILTER_ADAPTER_HPP_INCLUDED
+#define BOOST_IOSTREAMS_DETAIL_FILTER_ADAPTER_HPP_INCLUDED
+
+#include <boost/iostreams/categories.hpp>
+#include <boost/iostreams/detail/call_traits.hpp>
+#include <boost/iostreams/detail/ios.hpp>
+#include <boost/iostreams/operations.hpp>
+#include <boost/iostreams/traits.hpp>
+#include <boost/static_assert.hpp>
+
+namespace boost { namespace iostreams { namespace detail {
+
+template<typename T>
+class filter_adapter {
+private:
+ typedef typename detail::value_type<T>::type value_type;
+ typedef typename detail::param_type<T>::type param_type;
+public:
+ explicit filter_adapter(param_type t) : t_(t) { }
+ T& component() { return t_; }
+
+ template<typename Device>
+ void close(Device& dev)
+ {
+ detail::close_all(t_, dev);
+ }
+
+ template<typename Device>
+ void close(Device& dev, BOOST_IOS::openmode which)
+ {
+ iostreams::close(t_, dev, which);
+ }
+
+ template<typename Device>
+ void flush(Device& dev)
+ {
+ return iostreams::flush(t_, dev);
+ }
+
+ template<typename Locale> // Avoid dependency on <locale>
+ void imbue(const Locale& loc) { iostreams::imbue(t_, loc); }
+
+ std::streamsize optimal_buffer_size() const
+ { return iostreams::optimal_buffer_size(t_); }
+public:
+ value_type t_;
+};
+
+//----------------------------------------------------------------------------//
+
+} } } // End namespaces detail, iostreams, boost.
+
+#endif // #ifndef BOOST_IOSTREAMS_DETAIL_FILTER_ADAPTER_HPP_INCLUDED

Modified: trunk/boost/iostreams/detail/adapter/mode_adapter.hpp
==============================================================================
--- trunk/boost/iostreams/detail/adapter/mode_adapter.hpp (original)
+++ trunk/boost/iostreams/detail/adapter/mode_adapter.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -52,7 +52,8 @@
                          BOOST_IOS::openmode which =
                              BOOST_IOS::in | BOOST_IOS::out );
 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
- void close(BOOST_IOS::openmode which = BOOST_IOS::in | BOOST_IOS::out);
+ void close();
+ void close(BOOST_IOS::openmode which);
 #endif
 
         // Filter member functions.
@@ -76,7 +77,7 @@
 
     template<typename Device>
     void close(Device& dev)
- { iostreams::close(t_, dev); }
+ { detail::close_all(t_, dev); }
 
     template<typename Device>
     void close(Device& dev, BOOST_IOS::openmode which)
@@ -108,6 +109,10 @@
 
 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
     template<typename Mode, typename T>
+ void mode_adapter<Mode, T>::close()
+ { detail::close_all(t_); }
+
+ template<typename Mode, typename T>
     void mode_adapter<Mode, T>::close(BOOST_IOS::openmode which)
     { iostreams::close(t_, which); }
 #endif

Modified: trunk/boost/iostreams/detail/broken_overload_resolution/stream_buffer.hpp
==============================================================================
--- trunk/boost/iostreams/detail/broken_overload_resolution/stream_buffer.hpp (original)
+++ trunk/boost/iostreams/detail/broken_overload_resolution/stream_buffer.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -44,7 +44,7 @@
         try {
             if (this->is_open() && this->auto_close())
                 this->close();
- } catch (std::exception&) { }
+ } catch (...) { }
     }
     template<typename U0>
     stream_buffer(const U0& u0)

Deleted: trunk/boost/iostreams/detail/closer.hpp
==============================================================================
--- trunk/boost/iostreams/detail/closer.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
+++ (empty file)
@@ -1,122 +0,0 @@
-// (C) Copyright Jonathan Turkanis 2003.
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
-
-// See http://www.boost.org/libs/iostreams for documentation.
-
-#ifndef BOOST_IOSTREAMS_DETAIL_CLOSER_HPP_INCLUDED
-#define BOOST_IOSTREAMS_DETAIL_CLOSER_HPP_INCLUDED
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include <exception> // exception.
-#include <boost/iostreams/detail/ios.hpp> // openmode.
-#include <boost/iostreams/operations.hpp> // close
-#include <boost/iostreams/traits.hpp> // is_device.
-#include <boost/mpl/if.hpp>
-
-namespace boost { namespace iostreams { namespace detail {
-
-template<typename T>
-struct closer {
- closer(T& t) : t_(&t) { }
- ~closer() { try { t_->close(); } catch (std::exception&) { } }
- T* t_;
-};
-
-template<typename Device>
-struct external_device_closer {
- external_device_closer(Device& dev, BOOST_IOS::openmode which)
- : device_(&dev), which_(which),
- dummy_(true), nothrow_(dummy_)
- { }
- external_device_closer(Device& dev, BOOST_IOS::openmode which, bool& nothrow)
- : device_(&dev), which_(which),
- dummy_(true), nothrow_(nothrow)
- { }
- ~external_device_closer()
- {
- try {
- boost::iostreams::close(*device_, which_);
- } catch (...) {
- if (!nothrow_) {
- nothrow_ = true;
- throw;
- }
- }
- }
- Device* device_;
- BOOST_IOS::openmode which_;
- bool dummy_;
- bool& nothrow_;
-};
-
-template<typename Filter, typename Device>
-struct external_filter_closer {
- external_filter_closer(Filter& flt, Device& dev, BOOST_IOS::openmode which)
- : filter_(flt), device_(dev), which_(which),
- dummy_(true), nothrow_(dummy_)
- { }
- external_filter_closer( Filter& flt, Device& dev,
- BOOST_IOS::openmode which, bool& nothrow )
- : filter_(flt), device_(dev), which_(which),
- dummy_(true), nothrow_(nothrow)
- { }
- ~external_filter_closer()
- {
- try {
- boost::iostreams::close(filter_, device_, which_);
- } catch (...) {
- if (!nothrow_) {
- nothrow_ = true;
- throw;
- }
- }
- }
- Filter& filter_;
- Device& device_;
- BOOST_IOS::openmode which_;
- bool dummy_;
- bool& nothrow_;
-};
-
-template<typename FilterOrDevice, typename DeviceOrDummy = int>
-struct external_closer_traits {
- typedef typename
- mpl::if_<
- is_device<FilterOrDevice>,
- external_device_closer<FilterOrDevice>,
- external_filter_closer<FilterOrDevice, DeviceOrDummy>
- >::type type;
-};
-
-template<typename FilterOrDevice, typename DeviceOrDummy = int>
-struct external_closer
- : external_closer_traits<FilterOrDevice, DeviceOrDummy>::type
-{
- typedef typename
- external_closer_traits<
- FilterOrDevice, DeviceOrDummy
- >::type base_type;
- external_closer(FilterOrDevice& dev, BOOST_IOS::openmode which)
- : base_type(dev, which)
- { BOOST_STATIC_ASSERT(is_device<FilterOrDevice>::value); };
- external_closer( FilterOrDevice& dev, BOOST_IOS::openmode which,
- bool& nothrow )
- : base_type(dev, which, nothrow)
- { BOOST_STATIC_ASSERT(is_device<FilterOrDevice>::value); };
- external_closer( FilterOrDevice& flt, DeviceOrDummy& dev,
- BOOST_IOS::openmode which )
- : base_type(flt, dev, which)
- { BOOST_STATIC_ASSERT(is_filter<FilterOrDevice>::value); };
- external_closer( FilterOrDevice& flt, DeviceOrDummy& dev,
- BOOST_IOS::openmode which, bool& nothrow )
- : base_type(flt, dev, which, nothrow)
- { BOOST_STATIC_ASSERT(is_filter<FilterOrDevice>::value); };
-};
-
-} } } // End namespaces detail, iostreams, boost.
-
-#endif // #ifndef BOOST_IOSTREAMS_DETAIL_CLOSER_HPP_INCLUDED

Modified: trunk/boost/iostreams/detail/config/limits.hpp
==============================================================================
--- trunk/boost/iostreams/detail/config/limits.hpp (original)
+++ trunk/boost/iostreams/detail/config/limits.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -11,4 +11,8 @@
 # define BOOST_IOSTREAMS_MAX_FORWARDING_ARITY 3
 #endif
 
+#ifndef BOOST_IOSTREAMS_MAX_EXECUTE_ARITY
+# define BOOST_IOSTREAMS_MAX_EXECUTE_ARITY 5
+#endif
+
 #endif // #ifndef BOOST_IOSTREAMS_DETAIL_CONFIG_LIMITS_HPP_INCLUDED

Added: trunk/boost/iostreams/detail/execute.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/iostreams/detail/execute.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -0,0 +1,138 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.(See accompanying
+ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
+ *
+ * See http://www.boost.org/libs/iostreams for documentation.
+
+ * File: boost/iostreams/detail/execute.hpp
+ * Date: Thu Dec 06 13:21:54 MST 2007
+ * Copyright: 2007 CodeRage
+ * Author: Jonathan Turkanis
+
+ * Defines the overloaded function template
+ * boost::iostreams::detail::execute_all() and the function template
+ * boost::iostreams::detail::execute_foreach().
+ *
+ * execute_all() invokes a primary operation and performs a sequence of cleanup
+ * operations, returning the result of the primary operation if no exceptions
+ * are thrown. If one of the operations throws an exception, performs the
+ * remaining operations and rethrows the initial exception.
+ *
+ * In order to preserve support for old compilers, no attempt is made to deduce
+ * the return type of the primary operation, even though it could be easily
+ * deduced in all the intended use cases.
+ *
+ * execute_foreach() is a variant of std::foreach which invokes a function
+ * object for each item in a sequence, catching all execptions and rethrowing
+ * the first caucht exception after the function object has been invoked on each
+ * item.
+ */
+
+#ifndef BOOST_IOSTREAMS_DETAIL_EXECUTE_HPP_INCLUDED
+#define BOOST_IOSTREAMS_DETAIL_EXECUTE_HPP_INCLUDED
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+#include <boost/config.hpp> // BOOST_NO_RESULT_OF
+#include <boost/iostreams/detail/config/limits.hpp> // MAX_EXECUTE_ARITY
+#include <boost/preprocessor/arithmetic/dec.hpp>
+#include <boost/preprocessor/cat.hpp>
+#include <boost/preprocessor/iteration/local.hpp>
+#include <boost/preprocessor/repetition/enum_params.hpp>
+#include <boost/preprocessor/repetition/enum_binary_params.hpp>
+#include <boost/preprocessor/punctuation/comma_if.hpp>
+#ifndef BOOST_NO_RESULT_OF
+# include <boost/utility/result_of.hpp>
+#endif
+
+namespace boost { namespace iostreams { namespace detail {
+
+// Helper for class template execute_traits.
+template<typename Result>
+struct execute_traits_impl {
+ typedef Result result_type;
+ template<typename Op>
+ static Result execute(Op op) { return op(); }
+};
+
+// Specialization for void return. For simplicity, execute() returns int
+// for operations returning void. This could be avoided with additional work.
+template<>
+struct execute_traits_impl<void> {
+ typedef int result_type;
+ template<typename Op>
+ static int execute(Op op) { op(); return 0; }
+};
+
+// Deduces the result type of Op and allows uniform treatment of operations
+// returning void and non-void.
+template< typename Op,
+ typename Result = // VC6.5 workaround.
+ #ifndef BOOST_NO_RESULT_OF
+ typename boost::result_of<Op()>::type
+ #else
+ BOOST_DEDUCED_TYPENAME Op::result_type
+ #endif
+ >
+struct execute_traits
+ : execute_traits_impl<Result>
+ { };
+
+// Implementation with no cleanup operations.
+template<typename Op>
+typename execute_traits<Op>::result_type
+execute_all(Op op)
+{
+ return execute_traits<Op>::execute(op);
+}
+
+// Implementation with one or more cleanup operations
+#define BOOST_PP_LOCAL_MACRO(n) \
+ template<typename Op, BOOST_PP_ENUM_PARAMS(n, typename C)> \
+ typename execute_traits<Op>::result_type \
+ execute_all(Op op, BOOST_PP_ENUM_BINARY_PARAMS(n, C, c)) \
+ { \
+ typename execute_traits<Op>::result_type r; \
+ try { \
+ r = boost::iostreams::detail::execute_all( \
+ op BOOST_PP_COMMA_IF(BOOST_PP_DEC(n)) \
+ BOOST_PP_ENUM_PARAMS(BOOST_PP_DEC(n), c) \
+ ); \
+ } catch (...) { \
+ try { \
+ BOOST_PP_CAT(c, BOOST_PP_DEC(n))(); \
+ } catch (...) { } \
+ throw; \
+ } \
+ BOOST_PP_CAT(c, BOOST_PP_DEC(n))(); \
+ return r; \
+ } \
+ /**/
+
+#define BOOST_PP_LOCAL_LIMITS (1, BOOST_IOSTREAMS_MAX_EXECUTE_ARITY)
+#include BOOST_PP_LOCAL_ITERATE()
+#undef BOOST_PP_LOCAL_MACRO
+
+template<class InIt, class Op>
+Op execute_foreach(InIt first, InIt last, Op op)
+{
+ if (first == last)
+ return op;
+ try {
+ op(*first);
+ } catch (...) {
+ try {
+ ++first;
+ boost::iostreams::detail::execute_foreach(first, last, op);
+ } catch (...) { }
+ throw;
+ }
+ ++first;
+ return boost::iostreams::detail::execute_foreach(first, last, op);
+}
+
+} } } // End namespaces detail, iostreams, boost.
+
+#endif // #ifndef BOOST_IOSTREAMS_DETAIL_EXECUTE_HPP_INCLUDED

Added: trunk/boost/iostreams/detail/functional.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/iostreams/detail/functional.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -0,0 +1,164 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.(See accompanying
+ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
+ *
+ * See http://www.boost.org/libs/iostreams for documentation.
+
+ * File: boost/iostreams/detail/functional.hpp
+ * Date: Sun Dec 09 05:38:03 MST 2007
+ * Copyright: 2007 CodeRage
+ * Author: Jonathan Turkanis
+
+ * Defines several function objects and object generators for use with
+ * execute_all()
+ */
+
+#ifndef BOOST_IOSTREAMS_DETAIL_FUNCTIONAL_HPP_INCLUDED
+#define BOOST_IOSTREAMS_DETAIL_FUNCTIONAL_HPP_INCLUDED
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+#include <boost/iostreams/close.hpp>
+#include <boost/iostreams/detail/ios.hpp> // BOOST_IOS
+
+namespace boost { namespace iostreams { namespace detail {
+
+ // Function objects and object generators for invoking
+ // boost::iostreams::close
+
+template<typename T>
+struct device_close_operation {
+ typedef void result_type;
+ device_close_operation(T& t, BOOST_IOS::openmode which)
+ : t(t), which(which)
+ { }
+ void operator()() const { boost::iostreams::close(t, which); }
+ T& t;
+ BOOST_IOS::openmode which;
+};
+
+template<typename T, typename Sink>
+struct filter_close_operation {
+ typedef void result_type;
+ filter_close_operation(T& t, Sink& snk, BOOST_IOS::openmode which)
+ : t(t), snk(snk), which(which)
+ { }
+ void operator()() const { boost::iostreams::close(t, snk, which); }
+ T& t;
+ Sink& snk;
+ BOOST_IOS::openmode which;
+};
+
+template<typename T>
+device_close_operation<T>
+call_close(T& t, BOOST_IOS::openmode which)
+{ return device_close_operation<T>(t, which); }
+
+template<typename T, typename Sink>
+filter_close_operation<T, Sink>
+call_close(T& t, Sink& snk, BOOST_IOS::openmode which)
+{ return filter_close_operation<T, Sink>(t, snk, which); }
+
+ // Function objects and object generators for invoking
+ // boost::iostreams::detail::close_all
+
+template<typename T>
+struct device_close_all_operation {
+ typedef void result_type;
+ device_close_all_operation(T& t) : t(t) { }
+ void operator()() const { detail::close_all(t); }
+ T& t;
+};
+
+template<typename T, typename Sink>
+struct filter_close_all_operation {
+ typedef void result_type;
+ filter_close_all_operation(T& t, Sink& snk) : t(t), snk(snk) { }
+ void operator()() const { detail::close_all(t, snk); }
+ T& t;
+ Sink& snk;
+};
+
+template<typename T>
+device_close_all_operation<T> call_close_all(T& t)
+{ return device_close_all_operation<T>(t); }
+
+template<typename T, typename Sink>
+filter_close_all_operation<T, Sink>
+call_close_all(T& t, Sink& snk)
+{ return filter_close_all_operation<T, Sink>(t, snk); }
+
+ // Function object and object generator for invoking a
+ // member function void close(std::ios_base::openmode)
+
+template<typename T>
+struct member_close_operation {
+ typedef void result_type;
+ member_close_operation(T& t, BOOST_IOS::openmode which)
+ : t(t), which(which)
+ { }
+ void operator()() const { t.close(which); }
+ T& t;
+ BOOST_IOS::openmode which;
+};
+
+template<typename T>
+member_close_operation<T> call_member_close(T& t, BOOST_IOS::openmode which)
+{ return member_close_operation<T>(t, which); }
+
+ // Function object and object generator for invoking a
+ // member function void reset()
+
+template<typename T>
+struct reset_operation {
+ reset_operation(T& t) : t(t) { }
+ void operator()() const { t.reset(); }
+ T& t;
+};
+
+template<typename T>
+reset_operation<T> call_reset(T& t) { return reset_operation<T>(t); }
+
+ // Function object and object generator for clearing a flag
+
+template<typename T>
+struct clear_flags_operation {
+ typedef void result_type;
+ clear_flags_operation(T& t) : t(t) { }
+ void operator()() const { t = 0; }
+ T& t;
+};
+
+template<typename T>
+clear_flags_operation<T> clear_flags(T& t)
+{ return clear_flags_operation<T>(t); }
+
+ // Function object and generator for flushing a buffer
+
+// Function object for use with execute_all()
+template<typename Buffer, typename Device>
+struct flush_buffer_operation {
+ typedef void result_type;
+ flush_buffer_operation(Buffer& buf, Device& dev, bool flush)
+ : buf(buf), dev(dev), flush(flush)
+ { }
+ void operator()() const
+ {
+ if (flush)
+ buf.flush(dev);
+ }
+ Buffer& buf;
+ Device& dev;
+ bool flush;
+};
+
+template<typename Buffer, typename Device>
+flush_buffer_operation<Buffer, Device>
+flush_buffer(Buffer& buf, Device& dev, bool flush)
+{ return flush_buffer_operation<Buffer, Device>(buf, dev, flush); }
+
+} } } // End namespaces detail, iostreams, boost.
+
+#endif // #ifndef BOOST_IOSTREAMS_DETAIL_FUNCTIONAL_HPP_INCLUDED

Modified: trunk/boost/iostreams/detail/is_iterator_range.hpp
==============================================================================
--- trunk/boost/iostreams/detail/is_iterator_range.hpp (original)
+++ trunk/boost/iostreams/detail/is_iterator_range.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -11,6 +11,8 @@
 
 namespace boost {
 
+# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) //---------------------------------//
+
 // We avoid dependence on Boost.Range by using a forward declaration.
 template<typename Iterator>
 class iterator_range;
@@ -21,6 +23,19 @@
 
 } // End namespace iostreams.
 
+# else // # if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) //-----------------------//
+
+namespace iostreams {
+
+ template<typename T>
+ struct is_iterator_range {
+ BOOST_STATIC_CONSTANT(bool, value = false);
+ };
+
+} // End namespace iostreams.
+
+# endif // # if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) //----------------------//
+
 } // End namespace boost.
 
 #endif // #ifndef BOOST_IOSTREAMS_DETAIL_IS_ITERATOR_RANGE_HPP_INCLUDED

Modified: trunk/boost/iostreams/detail/resolve.hpp
==============================================================================
--- trunk/boost/iostreams/detail/resolve.hpp (original)
+++ trunk/boost/iostreams/detail/resolve.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -31,7 +31,9 @@
 #include <boost/mpl/and.hpp>
 #include <boost/mpl/bool.hpp> // true_.
 #include <boost/mpl/if.hpp>
-#include <boost/range/iterator_range.hpp>
+#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
+# include <boost/range/iterator_range.hpp>
+#endif // #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
 #include <boost/type_traits/is_array.hpp>
 
 // Must come last.
@@ -98,10 +100,12 @@
 array_adapter<Mode, Ch> resolve(Ch (&array)[N])
 { return array_adapter<Mode, Ch>(array); }
 
-template<typename Mode, typename Ch, typename Iter>
-range_adapter< Mode, boost::iterator_range<Iter> >
-resolve(const boost::iterator_range<Iter>& rng)
-{ return range_adapter< Mode, boost::iterator_range<Iter> >(rng); }
+# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
+ template<typename Mode, typename Ch, typename Iter>
+ range_adapter< Mode, boost::iterator_range<Iter> >
+ resolve(const boost::iterator_range<Iter>& rng)
+ { return range_adapter< Mode, boost::iterator_range<Iter> >(rng); }
+# endif // #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
 
 # else // # ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES //---------------------//
 

Modified: trunk/boost/iostreams/detail/streambuf/direct_streambuf.hpp
==============================================================================
--- trunk/boost/iostreams/detail/streambuf/direct_streambuf.hpp (original)
+++ trunk/boost/iostreams/detail/streambuf/direct_streambuf.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -14,15 +14,17 @@
 #include <cassert>
 #include <cstddef>
 #include <typeinfo>
-#include <utility> // pair.
-#include <boost/config.hpp> // BOOST_DEDUCED_TYPENAME.
-#include <boost/iostreams/detail/char_traits.hpp>
+#include <utility> // pair.
+#include <boost/config.hpp> // BOOST_DEDUCED_TYPENAME,
+#include <boost/iostreams/detail/char_traits.hpp> // member template friends.
 #include <boost/iostreams/detail/config/wide_streams.hpp>
+#include <boost/iostreams/detail/error.hpp>
+#include <boost/iostreams/detail/execute.hpp>
+#include <boost/iostreams/detail/functional.hpp>
 #include <boost/iostreams/detail/ios.hpp>
 #include <boost/iostreams/detail/optional.hpp>
 #include <boost/iostreams/detail/streambuf.hpp>
 #include <boost/iostreams/detail/streambuf/linked_streambuf.hpp>
-#include <boost/iostreams/detail/error.hpp>
 #include <boost/iostreams/operations.hpp>
 #include <boost/iostreams/positioning.hpp>
 #include <boost/iostreams/traits.hpp>
@@ -70,10 +72,9 @@
     //--------------Virtual functions-----------------------------------------//
 
     // Declared in linked_streambuf.
- void close(BOOST_IOS::openmode m);
+ void close_impl(BOOST_IOS::openmode m);
     const std::type_info& component_type() const { return typeid(T); }
     void* component_impl() { return component(); }
-
 #ifdef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES
     public:
 #endif
@@ -120,15 +121,15 @@
 
 template<typename T, typename Tr>
 bool direct_streambuf<T, Tr>::is_open() const
-{ return ibeg_ != 0 && !obeg_ != 0; }
+{ return ibeg_ != 0 || obeg_ != 0; }
 
 template<typename T, typename Tr>
 void direct_streambuf<T, Tr>::close()
 {
- using namespace std;
- try { close(BOOST_IOS::in); } catch (std::exception&) { }
- try { close(BOOST_IOS::out); } catch (std::exception&) { }
- storage_.reset();
+ base_type* self = this;
+ detail::execute_all( detail::call_member_close(*self, BOOST_IOS::in),
+ detail::call_member_close(*self, BOOST_IOS::out),
+ detail::call_reset(storage_) );
 }
 
 template<typename T, typename Tr>
@@ -193,7 +194,7 @@
 }
 
 template<typename T, typename Tr>
-void direct_streambuf<T, Tr>::close(BOOST_IOS::openmode which)
+void direct_streambuf<T, Tr>::close_impl(BOOST_IOS::openmode which)
 {
     if (which == BOOST_IOS::in && ibeg_ != 0) {
         setg(0, 0, 0);

Modified: trunk/boost/iostreams/detail/streambuf/indirect_streambuf.hpp
==============================================================================
--- trunk/boost/iostreams/detail/streambuf/indirect_streambuf.hpp (original)
+++ trunk/boost/iostreams/detail/streambuf/indirect_streambuf.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -21,6 +21,8 @@
 #include <boost/iostreams/detail/buffer.hpp>
 #include <boost/iostreams/detail/config/wide_streams.hpp>
 #include <boost/iostreams/detail/double_object.hpp>
+#include <boost/iostreams/detail/execute.hpp>
+#include <boost/iostreams/detail/functional.hpp>
 #include <boost/iostreams/detail/ios.hpp>
 #include <boost/iostreams/detail/optional.hpp>
 #include <boost/iostreams/detail/push.hpp>
@@ -89,7 +91,7 @@
 
     // Declared in linked_streambuf.
     void set_next(streambuf_type* next);
- void close(BOOST_IOS::openmode m);
+ void close_impl(BOOST_IOS::openmode m);
     const std::type_info& component_type() const { return typeid(T); }
     void* component_impl() { return component(); }
 private:
@@ -116,14 +118,11 @@
     pos_type seek_impl( stream_offset off, BOOST_IOS::seekdir way,
                         BOOST_IOS::openmode which );
     void sync_impl();
- void close_impl(BOOST_IOS::openmode);
 
     enum flag_type {
         f_open = 1,
- f_input_closed = f_open << 1,
- f_output_closed = f_input_closed << 1,
- f_output_buffered = f_output_closed << 1,
- f_auto_close = f_output_buffered << 1
+ f_output_buffered = f_open << 1,
+ f_auto_close = f_output_buffered << 1,
     };
 
     optional<wrapper> storage_;
@@ -196,10 +195,13 @@
 void indirect_streambuf<T, Tr, Alloc, Mode>::close()
 {
     using namespace std;
- try { close(BOOST_IOS::in); } catch (std::exception&) { }
- try { close(BOOST_IOS::out); } catch (std::exception&) { }
- storage_.reset();
- flags_ = 0;
+ base_type* self = this;
+ detail::execute_all(
+ detail::call_member_close(*self, BOOST_IOS::in),
+ detail::call_member_close(*self, BOOST_IOS::out),
+ detail::call_reset(storage_),
+ detail::clear_flags(flags_)
+ );
 }
 
 template<typename T, typename Tr, typename Alloc, typename Mode>
@@ -306,7 +308,7 @@
         sync_impl();
         obj().flush(next_);
         return 0;
- } catch (std::exception&) { return -1; }
+ } catch (...) { return -1; }
 }
 
 template<typename T, typename Tr, typename Alloc, typename Mode>
@@ -315,7 +317,7 @@
     try { // sync() is no-throw.
         sync_impl();
         return obj().flush(next_);
- } catch (std::exception&) { return false; }
+ } catch (...) { return false; }
 }
 
 template<typename T, typename Tr, typename Alloc, typename Mode>
@@ -353,30 +355,21 @@
 { next_ = next; }
 
 template<typename T, typename Tr, typename Alloc, typename Mode>
-inline void indirect_streambuf<T, Tr, Alloc, Mode>::close
- (BOOST_IOS::openmode which)
-{
- close_impl(which);
- try { obj().close(which, next_); } catch (std::exception&) { }
-}
-
-//----------State changing functions------------------------------------------//
-
-template<typename T, typename Tr, typename Alloc, typename Mode>
 inline void indirect_streambuf<T, Tr, Alloc, Mode>::close_impl
     (BOOST_IOS::openmode which)
 {
- if (which == BOOST_IOS::in && (flags_ & f_input_closed) == 0) {
+ if (which == BOOST_IOS::in && is_convertible<Mode, input>::value) {
         setg(0, 0, 0);
- flags_ |= f_input_closed;
     }
- if (which == BOOST_IOS::out && (flags_ & f_output_closed) == 0) {
+ if (which == BOOST_IOS::out && is_convertible<Mode, output>::value) {
         sync();
         setp(0, 0);
- flags_ |= f_output_closed;
     }
+ obj().close(which, next_);
 }
 
+//----------State changing functions------------------------------------------//
+
 template<typename T, typename Tr, typename Alloc, typename Mode>
 void indirect_streambuf<T, Tr, Alloc, Mode>::sync_impl()
 {

Modified: trunk/boost/iostreams/detail/streambuf/linked_streambuf.hpp
==============================================================================
--- trunk/boost/iostreams/detail/streambuf/linked_streambuf.hpp (original)
+++ trunk/boost/iostreams/detail/streambuf/linked_streambuf.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -40,13 +40,16 @@
 template<typename Ch, typename Tr = BOOST_IOSTREAMS_CHAR_TRAITS(Ch) >
 class linked_streambuf : public BOOST_IOSTREAMS_BASIC_STREAMBUF(Ch, Tr) {
 protected:
- linked_streambuf() : true_eof_(false) { }
- void set_true_eof(bool eof) { true_eof_ = eof; }
+ linked_streambuf() : flags_(0) { }
+ void set_true_eof(bool eof)
+ {
+ flags_ = (flags_ & ~f_true_eof) | (eof ? f_true_eof : 0);
+ }
 public:
 
     // Should be called only after receiving an ordinary EOF indication,
     // to confirm that it represents EOF rather than WOULD_BLOCK.
- bool true_eof() const { return true_eof_; }
+ bool true_eof() const { return (flags_ & f_true_eof) != 0; }
 protected:
 
     //----------grant friendship to chain_base and chainbuf-------------------//
@@ -57,20 +60,51 @@
     friend class chain_base;
     template<typename Chain, typename Mode, typename Access>
     friend class chainbuf;
+ template<typename U>
+ friend struct member_close_operation;
 #else
-public:
- typedef BOOST_IOSTREAMS_BASIC_STREAMBUF(Ch, Tr) base;
- BOOST_IOSTREAMS_USING_PROTECTED_STREAMBUF_MEMBERS(base)
+ public:
+ typedef BOOST_IOSTREAMS_BASIC_STREAMBUF(Ch, Tr) base;
+ BOOST_IOSTREAMS_USING_PROTECTED_STREAMBUF_MEMBERS(base)
 #endif
+ void close(BOOST_IOS::openmode which)
+ {
+ if ( which == BOOST_IOS::in &&
+ (flags_ & f_input_closed) == 0 )
+ {
+ flags_ |= f_input_closed;
+ close_impl(which);
+ }
+ if ( which == BOOST_IOS::out &&
+ (flags_ & f_output_closed) == 0 )
+ {
+ flags_ |= f_output_closed;
+ close_impl(which);
+ }
+ }
+ void set_needs_close()
+ {
+ flags_ &= ~(f_input_closed | f_output_closed);
+ }
     virtual void set_next(linked_streambuf<Ch, Tr>* /* next */) { }
- virtual void close(BOOST_IOS::openmode) = 0;
+ virtual void close_impl(BOOST_IOS::openmode) = 0;
     virtual bool auto_close() const = 0;
     virtual void set_auto_close(bool) = 0;
     virtual bool strict_sync() = 0;
     virtual const std::type_info& component_type() const = 0;
     virtual void* component_impl() = 0;
+#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
+ private:
+#else
+ public:
+#endif
 private:
- bool true_eof_;
+ enum flag_type {
+ f_true_eof = 1,
+ f_input_closed = f_true_eof << 1,
+ f_output_closed = f_input_closed << 1
+ };
+ int flags_;
 };
 
 } } } // End namespaces detail, iostreams, boost.

Modified: trunk/boost/iostreams/detail/vc6/close.hpp
==============================================================================
--- trunk/boost/iostreams/detail/vc6/close.hpp (original)
+++ trunk/boost/iostreams/detail/vc6/close.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -64,14 +64,14 @@
     struct inner {
         static void close(T& t, BOOST_IOS::openmode which)
         {
- if ((which & BOOST_IOS::out) != 0)
+ if (which == BOOST_IOS::out)
                 iostreams::flush(t);
         }
 
         template<typename Sink>
         static void close(T& t, Sink& snk, BOOST_IOS::openmode which)
         {
- if ((which & BOOST_IOS::out) != 0) {
+ if (which == BOOST_IOS::out) {
                 non_blocking_adapter<Sink> nb(snk);
                 iostreams::flush(t, nb);
             }
@@ -88,7 +88,7 @@
             typedef typename category_of<T>::type category;
             const bool in = is_convertible<category, input>::value &&
                             !is_convertible<category, output>::value;
- if (in == ((which & BOOST_IOS::in) != 0))
+ if (in == (which == BOOST_IOS::in))
                 t.close();
         }
         template<typename Sink>
@@ -97,7 +97,7 @@
             typedef typename category_of<T>::type category;
             const bool in = is_convertible<category, input>::value &&
                             !is_convertible<category, output>::value;
- if (in == ((which & BOOST_IOS::in) != 0)) {
+ if (in == (which == BOOST_IOS::in)) {
                 non_blocking_adapter<Sink> nb(snk);
                 t.close(nb);
             }

Modified: trunk/boost/iostreams/device/null.hpp
==============================================================================
--- trunk/boost/iostreams/device/null.hpp (original)
+++ trunk/boost/iostreams/device/null.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -34,7 +34,8 @@
                          BOOST_IOS::openmode =
                              BOOST_IOS::in | BOOST_IOS::out )
     { return -1; }
- void close(BOOST_IOS::openmode = BOOST_IOS::in | BOOST_IOS::out) { }
+ void close() { }
+ void close(BOOST_IOS::openmode) { }
 };
 
 template<typename Ch>

Modified: trunk/boost/iostreams/filter/aggregate.hpp
==============================================================================
--- trunk/boost/iostreams/filter/aggregate.hpp (original)
+++ trunk/boost/iostreams/filter/aggregate.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -17,7 +17,6 @@
 #include <vector>
 #include <boost/iostreams/categories.hpp>
 #include <boost/iostreams/detail/char_traits.hpp>
-#include <boost/iostreams/detail/closer.hpp>
 #include <boost/iostreams/detail/ios.hpp> // openmode, streamsize.
 #include <boost/iostreams/pipeline.hpp>
 #include <boost/mpl/bool.hpp>
@@ -76,25 +75,25 @@
         data_.insert(data_.end(), s, s + n);
         return n;
     }
-
- // Give detail::closer permission to call close().
- typedef aggregate_filter<Ch, Alloc> self;
- friend struct detail::closer<self>;
 
     template<typename Sink>
     void close(Sink& sink, BOOST_IOS::openmode which)
     {
- if ((state_ & f_read) && (which & BOOST_IOS::in))
- close();
-
- if ((state_ & f_write) && (which & BOOST_IOS::out)) {
- detail::closer<self> closer(*this);
- vector_type filtered;
- do_filter(data_, filtered);
- do_write(
- sink, &filtered[0],
- static_cast<std::streamsize>(filtered.size())
- );
+ if ((state_ & f_read) != 0 && which == BOOST_IOS::in)
+ close_impl();
+ if ((state_ & f_write) != 0 && which == BOOST_IOS::out) {
+ try {
+ vector_type filtered;
+ do_filter(data_, filtered);
+ do_write(
+ sink, &filtered[0],
+ static_cast<std::streamsize>(filtered.size())
+ );
+ } catch (...) {
+ close_impl();
+ throw;
+ }
+ close_impl();
         }
     }
 
@@ -137,7 +136,7 @@
     template<typename Sink>
     void do_write(Sink&, const char*, std::streamsize, mpl::false_) { }
 
- void close()
+ void close_impl()
     {
         data_.clear();
         ptr_ = 0;

Modified: trunk/boost/iostreams/filter/bzip2.hpp
==============================================================================
--- trunk/boost/iostreams/filter/bzip2.hpp (original)
+++ trunk/boost/iostreams/filter/bzip2.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -352,7 +352,16 @@
 }
 
 template<typename Alloc>
-void bzip2_decompressor_impl<Alloc>::close() { end(false); eof_ = false; }
+void bzip2_decompressor_impl<Alloc>::close()
+{
+ try {
+ end(false);
+ } catch (...) {
+ eof_ = false;
+ throw;
+ }
+ eof_ = false;
+}
 
 template<typename Alloc>
 inline void bzip2_decompressor_impl<Alloc>::init()

Modified: trunk/boost/iostreams/filter/gzip.hpp
==============================================================================
--- trunk/boost/iostreams/filter/gzip.hpp (original)
+++ trunk/boost/iostreams/filter/gzip.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -234,30 +234,25 @@
     template<typename Sink>
     void close(Sink& snk, BOOST_IOS::openmode m)
     {
- namespace io = boost::iostreams;
+ if (m == BOOST_IOS::out) {
+ try {
 
- if (m & BOOST_IOS::out) {
+ // Close zlib compressor.
+ base_type::close(snk, BOOST_IOS::out);
 
- // Close zlib compressor.
- base_type::close(snk, BOOST_IOS::out);
+ if (flags_ & f_header_done) {
 
- if (flags_ & f_header_done) {
+ // Write final fields of gzip file format.
+ write_long(this->crc(), snk);
+ write_long(this->total_in(), snk);
+ }
 
- // Write final fields of gzip file format.
- write_long(this->crc(), snk);
- write_long(this->total_in(), snk);
+ } catch (...) {
+ close_impl();
+ throw;
             }
-
+ close_impl();
         }
- #if BOOST_WORKAROUND(__GNUC__, == 2) && defined(__STL_CONFIG_H) || \
- BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1) \
- /**/
- footer_.erase(0, std::string::npos);
- #else
- footer_.clear();
- #endif
- offset_ = 0;
- flags_ = 0;
     }
 private:
     static gzip_params normalize_params(gzip_params p);
@@ -273,6 +268,19 @@
         boost::iostreams::put(next, static_cast<char>(0xFF & (n >> 24)));
     }
 
+ void close_impl()
+ {
+ #if BOOST_WORKAROUND(__GNUC__, == 2) && defined(__STL_CONFIG_H) || \
+ BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1) \
+ /**/
+ footer_.erase(0, std::string::npos);
+ #else
+ footer_.clear();
+ #endif
+ offset_ = 0;
+ flags_ = 0;
+ }
+
     enum flag_type {
         f_header_done = 1,
         f_body_done = f_header_done << 1,
@@ -342,10 +350,11 @@
     {
         try {
             base_type::close(src, BOOST_IOS::in);
- flags_ = 0;
         } catch (const zlib_error& e) {
+ flags_ = 0;
             throw gzip_error(e);
         }
+ flags_ = 0;
     }
 
     std::string file_name() const { return file_name_; }

Modified: trunk/boost/iostreams/filter/line.hpp
==============================================================================
--- trunk/boost/iostreams/filter/line.hpp (original)
+++ trunk/boost/iostreams/filter/line.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -17,7 +17,6 @@
 #include <string>
 #include <boost/config.hpp> // BOOST_STATIC_CONSTANT.
 #include <boost/iostreams/categories.hpp>
-#include <boost/iostreams/detail/closer.hpp>
 #include <boost/iostreams/detail/ios.hpp> // openmode, streamsize.
 #include <boost/iostreams/pipeline.hpp>
 
@@ -117,19 +116,23 @@
         }
     }
 
- typedef basic_line_filter<Ch, Alloc> self;
- friend struct detail::closer<self>;
-
     template<typename Sink>
     void close(Sink& snk, BOOST_IOS::openmode which)
     {
- if ((state_ & f_read) && (which & BOOST_IOS::in))
- close();
+ if ((state_ & f_read) && which == BOOST_IOS::in)
+ close_impl();
 
- if ((state_ & f_write) && (which & BOOST_IOS::out)) {
- detail::closer<self> closer(*this);
- if (!cur_line_.empty())
- write_line(snk);
+ if ((state_ & f_write) && which == BOOST_IOS::out) {
+ try {
+ if (!cur_line_.empty())
+ write_line(snk);
+ } catch (...) {
+ try {
+ close_impl();
+ } catch (...) { }
+ throw;
+ }
+ close_impl();
         }
     }
 private:
@@ -181,7 +184,7 @@
         return result;
     }
 
- void close()
+ void close_impl()
     {
         clear();
         state_ = 0;

Modified: trunk/boost/iostreams/filter/newline.hpp
==============================================================================
--- trunk/boost/iostreams/filter/newline.hpp (original)
+++ trunk/boost/iostreams/filter/newline.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -129,15 +129,18 @@
         using iostreams::newline::CR;
         using iostreams::newline::LF;
 
- if (flags_ & (has_LF | has_EOF)) {
- if (flags_ & has_LF)
+ assert((flags_ & f_write) == 0);
+ flags_ |= f_read;
+
+ if (flags_ & (f_has_LF | f_has_EOF)) {
+ if (flags_ & f_has_LF)
                 return newline();
             else
                 return EOF;
         }
 
         int c =
- (flags_ & has_CR) == 0 ?
+ (flags_ & f_has_CR) == 0 ?
                 iostreams::get(src) :
                 CR;
 
@@ -145,24 +148,24 @@
             return WOULD_BLOCK;
 
         if (c == CR) {
- flags_ |= has_CR;
+ flags_ |= f_has_CR;
 
             int d;
             if ((d = iostreams::get(src)) == WOULD_BLOCK)
                 return WOULD_BLOCK;
 
             if (d == LF) {
- flags_ &= ~has_CR;
+ flags_ &= ~f_has_CR;
                 return newline();
             }
 
             if (d == EOF) {
- flags_ |= has_EOF;
+ flags_ |= f_has_EOF;
             } else {
                 iostreams::putback(src, d);
             }
 
- flags_ &= ~has_CR;
+ flags_ &= ~f_has_CR;
             return newline();
         }
 
@@ -178,7 +181,10 @@
         using iostreams::newline::CR;
         using iostreams::newline::LF;
 
- if ((flags_ & has_LF) != 0)
+ assert((flags_ & f_read) == 0);
+ flags_ |= f_write;
+
+ if ((flags_ & f_has_LF) != 0)
             return c == LF ?
                 newline(dest) :
                 newline(dest) && this->put(dest, c);
@@ -186,13 +192,13 @@
         if (c == LF)
            return newline(dest);
 
- if ((flags_ & has_CR) != 0)
+ if ((flags_ & f_has_CR) != 0)
             return newline(dest) ?
                 this->put(dest, c) :
                 false;
 
         if (c == CR) {
- flags_ |= has_CR;
+ flags_ |= f_has_CR;
             return true;
         }
 
@@ -203,17 +209,12 @@
     void close(Sink& dest, BOOST_IOS::openmode which)
     {
         typedef typename iostreams::category_of<Sink>::type category;
- bool unfinished = (flags_ & has_CR) != 0;
- flags_ &= newline::platform_mask;
- if (which == BOOST_IOS::out && unfinished)
- close(dest, is_convertible<category, output>());
+ if ((flags_ & f_write) != 0 && (flags_ & f_has_CR) != 0)
+ newline_if_sink(dest);
+ if (which == BOOST_IOS::out)
+ flags_ &= newline::platform_mask;
     }
 private:
- template<typename Sink>
- void close(Sink& dest, mpl::true_) { newline(dest); }
-
- template<typename Sink>
- void close(Sink&, mpl::false_) { }
 
     // Returns the appropriate element of a newline sequence.
     int newline()
@@ -227,11 +228,11 @@
         case newline::mac:
             return CR;
         case newline::dos:
- if (flags_ & has_LF) {
- flags_ &= ~has_LF;
+ if (flags_ & f_has_LF) {
+ flags_ &= ~f_has_LF;
                 return LF;
             } else {
- flags_ |= has_LF;
+ flags_ |= f_has_LF;
                 return CR;
             }
         }
@@ -254,24 +255,41 @@
             success = boost::iostreams::put(dest, CR);
             break;
         case newline::dos:
- if ((flags_ & has_LF) != 0) {
+ if ((flags_ & f_has_LF) != 0) {
                 if ((success = boost::iostreams::put(dest, LF)))
- flags_ &= ~has_LF;
+ flags_ &= ~f_has_LF;
             } else if (boost::iostreams::put(dest, CR)) {
                 if (!(success = boost::iostreams::put(dest, LF)))
- flags_ |= has_LF;
+ flags_ |= f_has_LF;
             }
             break;
         }
         if (success)
- flags_ &= ~has_CR;
+ flags_ &= ~f_has_CR;
         return success;
     }
+
+ // Writes a newline sequence if the given device is a Sink.
+ template<typename Device>
+ void newline_if_sink(Device& dest)
+ {
+ typedef typename iostreams::category_of<Device>::type category;
+ newline_if_sink(dest, is_convertible<category, output>());
+ }
+
+ template<typename Sink>
+ void newline_if_sink(Sink& dest, mpl::true_) { newline(dest); }
+
+ template<typename Source>
+ void newline_if_sink(Source&, mpl::false_) { }
+
     enum flags {
- has_LF = 32768,
- has_CR = has_LF << 1,
- has_newline = has_CR << 1,
- has_EOF = has_newline << 1
+ f_has_LF = 32768,
+ f_has_CR = f_has_LF << 1,
+ f_has_newline = f_has_CR << 1,
+ f_has_EOF = f_has_newline << 1,
+ f_read = f_has_EOF << 1,
+ f_write = f_read << 1
     };
     int flags_;
 };
@@ -304,26 +322,26 @@
 
         // Update source flags.
         if (c != EOF)
- source() &= ~line_complete;
- if ((source() & has_CR) != 0) {
+ source() &= ~f_line_complete;
+ if ((source() & f_has_CR) != 0) {
             if (c == LF) {
                 source() |= newline::dos;
- source() |= line_complete;
+ source() |= f_line_complete;
             } else {
                 source() |= newline::mac;
                 if (c == EOF)
- source() |= line_complete;
+ source() |= f_line_complete;
             }
         } else if (c == LF) {
             source() |= newline::posix;
- source() |= line_complete;
+ source() |= f_line_complete;
         }
- source() = (source() & ~has_CR) | (c == CR ? has_CR : 0);
+ source() = (source() & ~f_has_CR) | (c == CR ? f_has_CR : 0);
 
         // Check for errors.
         if ( c == EOF &&
             (target_ & newline::final_newline) != 0 &&
- (source() & line_complete) == 0 )
+ (source() & f_line_complete) == 0 )
         {
             fail();
         }
@@ -351,19 +369,19 @@
             return false;
 
          // Update source flags.
- source() &= ~line_complete;
- if ((source() & has_CR) != 0) {
+ source() &= ~f_line_complete;
+ if ((source() & f_has_CR) != 0) {
             if (c == LF) {
                 source() |= newline::dos;
- source() |= line_complete;
+ source() |= f_line_complete;
             } else {
                 source() |= newline::mac;
             }
         } else if (c == LF) {
             source() |= newline::posix;
- source() |= line_complete;
+ source() |= f_line_complete;
         }
- source() = (source() & ~has_CR) | (c == CR ? has_CR : 0);
+ source() = (source() & ~f_has_CR) | (c == CR ? f_has_CR : 0);
 
         // Check for errors.
         if ( (target_ & newline::platform_mask) != 0 &&
@@ -380,22 +398,24 @@
     {
         using iostreams::newline::final_newline;
 
- // Update final_newline flag.
- if ( (source() & has_CR) != 0 ||
- (source() & line_complete) != 0 )
- {
- source() |= final_newline;
- }
+ if (which == BOOST_IOS::out) {
+
+ // Update final_newline flag.
+ if ( (source() & f_has_CR) != 0 ||
+ (source() & f_line_complete) != 0 )
+ {
+ source() |= final_newline;
+ }
 
- // Clear non-sticky flags.
- source() &= ~(has_CR | line_complete);
+ // Clear non-sticky flags.
+ source() &= ~(f_has_CR | f_line_complete);
 
- // Check for errors.
- if ( (which & BOOST_IOS::out) &&
- (target_ & final_newline) != 0 &&
- (source() & final_newline) == 0 )
- {
- fail();
+ // Check for errors.
+ if ( (target_ & final_newline) != 0 &&
+ (source() & final_newline) == 0 )
+ {
+ fail();
+ }
         }
     }
 private:
@@ -404,8 +424,8 @@
     int source() const { return flags_; }
 
     enum flags {
- has_CR = 32768,
- line_complete = has_CR << 1
+ f_has_CR = 32768,
+ f_line_complete = f_has_CR << 1
     };
 
     int target_; // Represents expected input.

Modified: trunk/boost/iostreams/filter/symmetric.hpp
==============================================================================
--- trunk/boost/iostreams/filter/symmetric.hpp (original)
+++ trunk/boost/iostreams/filter/symmetric.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -47,7 +47,6 @@
 #include <boost/iostreams/constants.hpp> // buffer size.
 #include <boost/iostreams/detail/buffer.hpp>
 #include <boost/iostreams/detail/char_traits.hpp>
-#include <boost/iostreams/detail/closer.hpp>
 #include <boost/iostreams/detail/config/limits.hpp>
 #include <boost/iostreams/detail/template_params.hpp>
 #include <boost/iostreams/traits.hpp>
@@ -149,29 +148,31 @@
         return static_cast<std::streamsize>(next_s - s);
     }
 
- // Give detail::closer<> permission to call close().
- typedef symmetric_filter<SymmetricFilter, Alloc> self;
- friend struct detail::closer<self>;
-
     template<typename Sink>
     void close(Sink& snk, BOOST_IOS::openmode which)
     {
         using namespace std;
- if ((state() & f_read) && (which & BOOST_IOS::in))
- close();
- if ((state() & f_write) && (which & BOOST_IOS::out)) {
+ if ((state() & f_write) == 0 && which == BOOST_IOS::in)
+ close_impl();
+ if ((state() & f_write) != 0 && which == BOOST_IOS::out) {
 
             // Repeatedly invoke filter() with no input.
- detail::closer<self> closer(*this);
- buffer_type& buf = pimpl_->buf_;
- char dummy;
- const char* end = &dummy;
- bool again = true;
- while (again) {
- if (buf.ptr() != buf.eptr())
- again = filter().filter(end, end, buf.ptr(), buf.eptr(), true);
- flush(snk);
+ try {
+ buffer_type& buf = pimpl_->buf_;
+ char dummy;
+ const char* end = &dummy;
+ bool again = true;
+ while (again) {
+ if (buf.ptr() != buf.eptr())
+ again = filter().filter( end, end, buf.ptr(),
+ buf.eptr(), true );
+ flush(snk);
+ }
+ } catch (...) {
+ try { close_impl(); } catch (...) { }
+ throw;
             }
+ close_impl();
         }
     }
     SymmetricFilter& filter() { return *pimpl_; }
@@ -229,7 +230,7 @@
     template<typename Sink>
     bool flush(Sink& snk, mpl::false_) { return true;}
 
- void close();
+ void close_impl();
 
     enum flag_type {
         f_read = 1,
@@ -281,7 +282,7 @@
 }
 
 template<typename SymmetricFilter, typename Alloc>
-void symmetric_filter<SymmetricFilter, Alloc>::close()
+void symmetric_filter<SymmetricFilter, Alloc>::close_impl()
 {
     state() = 0;
     buf().set(0, 0);

Modified: trunk/boost/iostreams/filter/test.hpp
==============================================================================
--- trunk/boost/iostreams/filter/test.hpp (original)
+++ trunk/boost/iostreams/filter/test.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -34,7 +34,6 @@
 #include <boost/iostreams/categories.hpp>
 #include <boost/iostreams/compose.hpp>
 #include <boost/iostreams/copy.hpp>
-#include <boost/iostreams/detail/adapter/basic_adapter.hpp>
 #include <boost/iostreams/detail/bool_trait_def.hpp>
 #include <boost/iostreams/detail/ios.hpp>
 #include <boost/iostreams/device/array.hpp>

Modified: trunk/boost/iostreams/invert.hpp
==============================================================================
--- trunk/boost/iostreams/invert.hpp (original)
+++ trunk/boost/iostreams/invert.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -21,6 +21,8 @@
 #include <boost/iostreams/device/array.hpp>
 #include <boost/iostreams/detail/buffer.hpp>
 #include <boost/iostreams/detail/counted_array.hpp>
+#include <boost/iostreams/detail/execute.hpp>
+#include <boost/iostreams/detail/functional.hpp> // clear_flags, call_reset
 #include <boost/mpl/if.hpp>
 #include <boost/ref.hpp>
 #include <boost/shared_ptr.hpp>
@@ -116,13 +118,13 @@
     }
 
     template<typename Device>
- void close( Device& dev,
- BOOST_IOS::openmode which =
- BOOST_IOS::in | BOOST_IOS::out )
+ void close(Device& dev)
     {
- if ((which & BOOST_IOS::out) != 0 && (flags() & f_write) != 0)
- buf().flush(dev);
- flags() = 0;
+ detail::execute_all(
+ detail::flush_buffer(buf(), dev, (flags() & f_write) != 0),
+ detail::call_close_all(pimpl_->filter_, dev),
+ detail::clear_flags(flags())
+ );
     }
 private:
     filter_ref filter() { return boost::ref(pimpl_->filter_); }

Modified: trunk/boost/iostreams/restrict.hpp
==============================================================================
--- trunk/boost/iostreams/restrict.hpp (original)
+++ trunk/boost/iostreams/restrict.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -17,7 +17,8 @@
 #include <boost/config.hpp> // DEDUCED_TYPENAME.
 #include <boost/iostreams/categories.hpp>
 #include <boost/iostreams/char_traits.hpp>
-#include <boost/iostreams/detail/adapter/basic_adapter.hpp>
+#include <boost/iostreams/detail/adapter/device_adapter.hpp>
+#include <boost/iostreams/detail/adapter/filter_adapter.hpp>
 #include <boost/iostreams/detail/call_traits.hpp>
 #include <boost/iostreams/detail/enable_if_stream.hpp>
 #include <boost/iostreams/detail/error.hpp>
@@ -44,7 +45,7 @@
 // SeekableDevice.
 //
 template<typename Device>
-class restricted_indirect_device : public basic_adapter<Device> {
+class restricted_indirect_device : public device_adapter<Device> {
 private:
     typedef typename detail::param_type<Device>::type param_type;
 public:
@@ -73,7 +74,7 @@
 // Device - A model of Direct and Device.
 //
 template<typename Device>
-class restricted_direct_device : public basic_adapter<Device> {
+class restricted_direct_device : public device_adapter<Device> {
 public:
     typedef typename char_type_of<Device>::type char_type;
     typedef std::pair<char_type*, char_type*> pair_type;
@@ -101,7 +102,7 @@
 // Filter - An indirect model of Filter.
 //
 template<typename Filter>
-class restricted_filter : public basic_adapter<Filter> {
+class restricted_filter : public filter_adapter<Filter> {
 public:
     typedef typename char_type_of<Filter>::type char_type;
     struct category
@@ -294,7 +295,7 @@
 template<typename Device>
 restricted_indirect_device<Device>::restricted_indirect_device
     (param_type dev, stream_offset off, stream_offset len)
- : basic_adapter<Device>(dev), beg_(off), pos_(off),
+ : device_adapter<Device>(dev), beg_(off), pos_(off),
       end_(len != -1 ? off + len : -1)
 {
     if (len < -1 || off < 0)
@@ -357,7 +358,7 @@
 template<typename Device>
 restricted_direct_device<Device>::restricted_direct_device
     (const Device& dev, stream_offset off, stream_offset len)
- : basic_adapter<Device>(dev), beg_(0), end_(0)
+ : device_adapter<Device>(dev), beg_(0), end_(0)
 {
     std::pair<char_type*, char_type*> seq =
         sequence(is_convertible<category, input>());
@@ -403,7 +404,7 @@
 template<typename Filter>
 restricted_filter<Filter>::restricted_filter
     (const Filter& flt, stream_offset off, stream_offset len)
- : basic_adapter<Filter>(flt), beg_(off),
+ : filter_adapter<Filter>(flt), beg_(off),
       pos_(off), end_(len != -1 ? off + len : -1), open_(false)
 {
     if (len < -1 || off < 0)

Modified: trunk/boost/iostreams/stream.hpp
==============================================================================
--- trunk/boost/iostreams/stream.hpp (original)
+++ trunk/boost/iostreams/stream.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -20,6 +20,7 @@
 #include <boost/iostreams/stream_buffer.hpp>
 #include <boost/mpl/and.hpp>
 #include <boost/type_traits/is_convertible.hpp>
+#include <boost/utility/base_from_member.hpp>
 
 namespace boost { namespace iostreams { namespace detail {
 

Modified: trunk/boost/iostreams/stream_buffer.hpp
==============================================================================
--- trunk/boost/iostreams/stream_buffer.hpp (original)
+++ trunk/boost/iostreams/stream_buffer.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -83,7 +83,7 @@
         try {
             if (this->is_open() && this->auto_close())
                 this->close();
- } catch (std::exception&) { }
+ } catch (...) { }
     }
     BOOST_IOSTREAMS_FORWARD( stream_buffer, open_impl, T,
                              BOOST_IOSTREAMS_PUSH_PARAMS,

Modified: trunk/boost/iostreams/tee.hpp
==============================================================================
--- trunk/boost/iostreams/tee.hpp (original)
+++ trunk/boost/iostreams/tee.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -14,9 +14,11 @@
 #include <cassert>
 #include <boost/config.hpp> // BOOST_DEDUCE_TYPENAME.
 #include <boost/iostreams/categories.hpp>
-#include <boost/iostreams/detail/adapter/basic_adapter.hpp>
+#include <boost/iostreams/detail/adapter/device_adapter.hpp>
+#include <boost/iostreams/detail/adapter/filter_adapter.hpp>
 #include <boost/iostreams/detail/call_traits.hpp>
-#include <boost/iostreams/detail/closer.hpp>
+#include <boost/iostreams/detail/execute.hpp>
+#include <boost/iostreams/detail/functional.hpp> // call_close_all
 #include <boost/iostreams/operations.hpp>
 #include <boost/iostreams/pipeline.hpp>
 #include <boost/iostreams/traits.hpp>
@@ -32,7 +34,7 @@
 // Device - A blocking Sink.
 //
 template<typename Device>
-class tee_filter : public detail::basic_adapter<Device> {
+class tee_filter : public detail::filter_adapter<Device> {
 public:
     typedef typename detail::param_type<Device>::type param_type;
     typedef typename char_type_of<Device>::type char_type;
@@ -51,7 +53,7 @@
     ));
 
     explicit tee_filter(param_type dev)
- : detail::basic_adapter<Device>(dev)
+ : detail::filter_adapter<Device>(dev)
         { }
 
     template<typename Sink>
@@ -65,10 +67,10 @@
     }
 
     template<typename Next>
- void close( Next&,
- BOOST_IOS::openmode which =
- BOOST_IOS::in | BOOST_IOS::out )
- { iostreams::close(this->component(), which); }
+ void close(Next&)
+ {
+ detail::close_all(this->component());
+ }
 
     template<typename Sink>
     bool flush(Sink& snk)
@@ -130,10 +132,10 @@
         assert(result1 == n && result2 == n);
         return n;
     }
- void close(BOOST_IOS::openmode which = BOOST_IOS::in | BOOST_IOS::out)
- {
- detail::external_closer<Sink2> close2(sink2_, which);
- detail::external_closer<Sink1> close1(sink1_, which);
+ void close()
+ {
+ detail::execute_all( detail::call_close_all(sink1_),
+ detail::call_close_all(sink2_) );
     }
     bool flush()
     {

Modified: trunk/boost/iostreams/traits.hpp
==============================================================================
--- trunk/boost/iostreams/traits.hpp (original)
+++ trunk/boost/iostreams/traits.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -32,9 +32,11 @@
 #include <boost/mpl/eval_if.hpp>
 #include <boost/mpl/identity.hpp>
 #include <boost/mpl/int.hpp>
-#include <boost/mpl/or.hpp>
-#include <boost/range/iterator_range.hpp>
-#include <boost/range/value_type.hpp>
+#include <boost/mpl/or.hpp>
+#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
+# include <boost/range/iterator_range.hpp>
+# include <boost/range/value_type.hpp>
+#endif // #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
 #include <boost/type_traits/is_convertible.hpp>
 
 namespace boost { namespace iostreams {
@@ -118,7 +120,9 @@
 struct char_type_of {
     template<typename U>
     struct get_value_type {
- typedef typename range_value<U>::type type;
+ #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
+ typedef typename range_value<U>::type type;
+ #endif // #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
     };
     typedef typename
             mpl::eval_if<

Modified: trunk/libs/iostreams/doc/classes/symmetric_filter.html
==============================================================================
--- trunk/libs/iostreams/doc/classes/symmetric_filter.html (original)
+++ trunk/libs/iostreams/doc/classes/symmetric_filter.html 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -64,7 +64,7 @@
 
     <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> T0, ..., <SPAN CLASS="keyword">typename</SPAN> TN&gt;
     symmetric_filter( <SPAN CLASS="keyword">int</SPAN> buffer_size, const T0& t0,
- <SPAN CLASS="keyword">const</SPAN> T1& t1, ..., <SPAN CLASS="keyword">const</SPAN> TN& tN );
+ <SPAN CLASS="keyword">const</SPAN> T1& t1, ..., <SPAN CLASS="keyword">const</SPAN> TN& tN );
 
     <SPAN CLASS="omitted">...</SPAN>
 <SPAN CLASS="keyword">protected</SPAN>:

Modified: trunk/libs/iostreams/doc/guide/concepts.html
==============================================================================
--- trunk/libs/iostreams/doc/guide/concepts.html (original)
+++ trunk/libs/iostreams/doc/guide/concepts.html 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -62,7 +62,7 @@
     <LI><A STYLE="font-weight:normal" HREF="../concepts/device.html">Device:</A> Base for all Device concepts, provides associated character type and category.
     <LI><A STYLE="font-weight:normal" HREF="../concepts/source.html">Source:</A> Provides read-only access to a sequence of characters.
     <LI><A STYLE="font-weight:normal" HREF="../concepts/sink.html">Sink:</A> Provides write-only access to a sequence of characters.
- <LI><A STYLE="font-weight:normal" HREF="../concepts/bidirectional_device.html">Bidirectionaldevice:</A> Provides access to two separate sequences of characters, one for reading and the other for writing.
+ <LI><A STYLE="font-weight:normal" HREF="../concepts/bidirectional_device.html">BidirectionalDevice:</A> Provides access to two separate sequences of characters, one for reading and the other for writing.
     <LI><A STYLE="font-weight:normal" HREF="../concepts/seekable_device.html">SeekableDevice:</A> Provides read-write access to a single sequence of characters, with a single repositionable read/write head.
 </UL>
 
@@ -73,10 +73,10 @@
 
 <UL>
     <LI><A STYLE="font-weight:normal" HREF="../concepts/filter.html">Filter:</A> Base for all Filter concepts, provides associated character type and category.
- <LI>InputFilter: Filters characters read from a stream buffer.
- <LI>OutputFilter: Filters characters written to a stream buffer.
- <LI>BidirectionalFilter: Filters two separate character sequences, one read from a stream buffer and the other written to a stream buffer.
- <LI>SeekableFilter: Filters a single characters sequence, controlled by a stream buffer,
+ <LI>InputFilter: Filters characters read from a Source.
+ <LI>OutputFilter: Filters characters written to a Sink
+ <LI>BidirectionalFilter: Filters two separate character sequences, one read from a Sink and the other written to a Sink.
+ <LI>SeekableFilter: Filters a single characters sequence, controlled by a SeekableDevice,
     providing filtered input, output and random access with a single repositionable read/write head
 </UL>
 

Modified: trunk/libs/iostreams/doc/guide/modes.html
==============================================================================
--- trunk/libs/iostreams/doc/guide/modes.html (original)
+++ trunk/libs/iostreams/doc/guide/modes.html 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -41,11 +41,11 @@
 <H2>Overview</H2>
 
 <P>
- In order for a sequence of Filters and Devices to work together they must have certain properties in common. The most basic requirement is that they have the same character type; a collection of additional properties which Filters and Devices must share to be used for a particular purpose is called an <SPAN CLASS="term">mode</SPAN>.
+ In order for a sequence of Filters and Devices to work together they must have certain properties in common. The most basic requirement is that they have the same character type; a collection of additional properties which Filters and Devices must share to be used for a particular purpose is called a <SPAN CLASS="term">mode</SPAN>.
 </P>
 
 <P>
- The templates stream_buffer and stream are each parameterized by an mode, represented by a mode tag.
+ The templates stream_buffer and stream are each parameterized by a mode, represented by a mode tag.
 </P>
 
 <P>

Modified: trunk/libs/iostreams/doc/tutorial/container_device.html
==============================================================================
--- trunk/libs/iostreams/doc/tutorial/container_device.html (original)
+++ trunk/libs/iostreams/doc/tutorial/container_device.html 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -131,7 +131,7 @@
         <SPAN CLASS="keyword">if</SPAN> (pos_ != container_.size()) {
             streamsize amt =
                 <SPAN CLASS="keyword">static_cast</SPAN>&lt;streamsize&gt;(container_.size() - pos_);
- streamsize result = (min)(n, amt);
+ result = (min)(n, amt);
             std::copy(s, s + result, container_.begin() + pos_);
             pos_ += result;
         }
@@ -200,7 +200,7 @@
     <SPAN CLASS="keyword">using</SPAN> <SPAN CLASS="keyword">namespace</SPAN> std;
     <SPAN CLASS="keyword">typedef</SPAN> ex::container_device&lt;string&gt; string_device;
 
- string one, two;
+ string one, two;
     io::stream&lt;string_device&gt; io(one);
     io &lt;&lt; <SPAN CLASS='literal'>"Hello World!"</SPAN>;
     io.flush();

Modified: trunk/libs/iostreams/doc/tutorial/container_sink.html
==============================================================================
--- trunk/libs/iostreams/doc/tutorial/container_sink.html (original)
+++ trunk/libs/iostreams/doc/tutorial/container_sink.html 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -100,8 +100,6 @@
 <LI>The implementation of <CODE>write()</CODE> simply appends the characters in the specified buffer to the underlying container using the container's <CODE>insert</CODE> funcion,
 </UL>
 
-<P>It's tempting to make <CODE>pos_</CODE> an iterator instead of an integral value. That would be fine here, but when you turn to Devices for <I>writing</I> to containers, a stored iterator could easily be invalidated if you're not careful. Since you're only dealing with RandomAccessIterators, maintaining the current reading position as an integral value is sufficient.</P>
-
 <P>You can write to a container_sink as follows</P>
 
 <PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS='literal'>&lt;cassert&gt;</SPAN>
@@ -117,7 +115,7 @@
     <SPAN CLASS='keyword'>using</SPAN> <SPAN CLASS='keyword'>namespace</SPAN> std;
     <SPAN CLASS='keyword'>typedef</SPAN> ex::container_sink&lt;string&gt; string_sink;
 
- string result;
+ string result;
     io::stream&lt;string_sink&gt; out(result);
     out &lt;&lt; <SPAN CLASS='literal'>"Hello World!"</SPAN>;
     out.flush();

Modified: trunk/libs/iostreams/doc/tutorial/container_source.html
==============================================================================
--- trunk/libs/iostreams/doc/tutorial/container_source.html (original)
+++ trunk/libs/iostreams/doc/tutorial/container_source.html 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -132,8 +132,8 @@
     <SPAN CLASS='keyword'>using</SPAN> <SPAN CLASS='keyword'>namespace</SPAN> std;
     <SPAN CLASS='keyword'>typedef</SPAN> ex::container_source&lt;string&gt; string_source;
 
- string input = <SPAN CLASS='literal'>"Hello World!"</SPAN>;
- string output;
+ string input = <SPAN CLASS='literal'>"Hello World!"</SPAN>;
+ string output;
     io::stream&lt;string_source&gt; in(input);
     getline(in, output);
     assert(input == output);

Modified: trunk/libs/iostreams/doc/tutorial/dictionary_filters.html
==============================================================================
--- trunk/libs/iostreams/doc/tutorial/dictionary_filters.html (original)
+++ trunk/libs/iostreams/doc/tutorial/dictionary_filters.html 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -222,7 +222,6 @@
     dictionary& dictionary_;
     std::string current_word_;
     std::string::size_type off_;
- <SPAN CLASS="keyword"><SPAN CLASS="keyword">bool</SPAN></SPAN> initialized_;
 };
 
 } } } <SPAN CLASS="comment">// End namespace boost::iostreams:example</SPAN></PRE>

Modified: trunk/libs/iostreams/doc/tutorial/multichar_filters.html
==============================================================================
--- trunk/libs/iostreams/doc/tutorial/multichar_filters.html (original)
+++ trunk/libs/iostreams/doc/tutorial/multichar_filters.html 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -29,7 +29,7 @@
 <H2>2.2.8. Multi-Character Filters</H2>
 
 <P>
- All the Filters you've seen so far &#8212; except for those that derive from <CODE>stdio_filter</CODE> &#8212; process characters one at a time. If you instead process several characters at once, you can often reduce the number of function calls it takes to filter a character sequence, resulting in more efficient code. This is what Multi-Character Filters allow us to do.
+ All the Filters you've seen so far &#8212; except for those that derive from <CODE>stdio_filter</CODE> &#8212; process characters one at a time. If you instead process several characters at once, you can often reduce the number of function calls it takes to filter a character sequence, resulting in more efficient code. This is what Multi-Character Filters allow you to do.
 </P>
 
 <A NAME="multichar_input_filters"></A>

Modified: trunk/libs/iostreams/doc/tutorial/shell_comments_filters.html
==============================================================================
--- trunk/libs/iostreams/doc/tutorial/shell_comments_filters.html (original)
+++ trunk/libs/iostreams/doc/tutorial/shell_comments_filters.html 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -165,7 +165,7 @@
     Here the member variable <CODE>skip_</CODE> plays the same role as the local variable <CODE>skip</CODE> <CODE>shell_comments_stdio_filter::do_filter</CODE>. The implementation of <CODE>get</CODE> is very similar to that of <CODE>shell_comments_stdio_filter::do_filter</CODE>: the <CODE>while</CODE> loop reads a character <CODE>c</CODE>, updates <CODE>skip_</CODE> and returns <CODE>c</CODE> unless <CODE>skip_</CODE> is <CODE>true</CODE>. The main difference is that you have to handle the special value <CODE>WOULD_BLOCK</CODE>, which indicates that no input is currently available.
 </P>
 <P>
- So you see that implementing an InputFilter from scratch is a bit more involved than deriving from stdio_filter. When writing an <CODE>InputFilter</CODE> you must be prepared to be interupted at any point in the middle of the algorithm; when this happens, you must record enough information about the current state of the algorithm to allow you to pick up later exactly where you left off. The same is true for OutputFilters. In fact, many Inputfilters and OutputFilters can be seen as finite state machines; I will formalize this idea later. <I>See</I> Finite State Filters.
+ So you see that implementing an InputFilter from scratch is a bit more involved than deriving from stdio_filter. When writing an <CODE>InputFilter</CODE> you must be prepared to be interrupted at any point in the middle of the algorithm; when this happens, you must record enough information about the current state of the algorithm to allow you to pick up later exactly where you left off. The same is true for OutputFilters. In fact, many Inputfilters and OutputFilters can be seen as finite state machines; I will formalize this idea later. <I>See</I> Finite State Filters.
 </P>
 <P>
     There's still one problem with <CODE>shell_comments_input_filter</CODE>: its instances can only be used once. That's because someone might close a stream while the <CODE>skip_</CODE> flag is set. If the stream were later reopened &#8212; with a fresh sequence of unfiltered data &#8212; the first line of text would be filtered out, regardless of whether it were commented.

Modified: trunk/libs/iostreams/example/container_device.hpp
==============================================================================
--- trunk/libs/iostreams/example/container_device.hpp (original)
+++ trunk/libs/iostreams/example/container_device.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -102,7 +102,7 @@
         if (pos_ != container_.size()) {
             streamsize amt =
                 static_cast<streamsize>(container_.size() - pos_);
- streamsize result = (min)(n, amt);
+ result = (min)(n, amt);
             std::copy(s, s + result, container_.begin() + pos_);
             pos_ += result;
         }

Modified: trunk/libs/iostreams/example/container_device_example.cpp
==============================================================================
--- trunk/libs/iostreams/example/container_device_example.cpp (original)
+++ trunk/libs/iostreams/example/container_device_example.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -6,7 +6,7 @@
 
 #include <cassert>
 #include <string>
-#include <boost/iostreams/stream_facade.hpp>
+#include <boost/iostreams/stream.hpp>
 #include <boost/iostreams/detail/ios.hpp> // ios_base::beg.
 #include <libs/iostreams/example/container_device.hpp>
 
@@ -18,8 +18,8 @@
     using namespace std;
     typedef ex::container_device<string> string_device;
 
- string one, two;
- io::stream_facade<string_device> io(one);
+ string one, two;
+ io::stream<string_device> io(one);
     io << "Hello World!";
     io.flush();
     io.seekg(0, BOOST_IOS::beg);

Modified: trunk/libs/iostreams/example/container_sink_example.cpp
==============================================================================
--- trunk/libs/iostreams/example/container_sink_example.cpp (original)
+++ trunk/libs/iostreams/example/container_sink_example.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -6,7 +6,7 @@
 
 #include <cassert>
 #include <string>
-#include <boost/iostreams/stream_facade.hpp>
+#include <boost/iostreams/stream.hpp>
 #include <libs/iostreams/example/container_device.hpp>
 
 namespace io = boost::iostreams;
@@ -17,8 +17,8 @@
     using namespace std;
     typedef ex::container_sink<string> string_sink;
 
- string result;
- io::stream_facade<string_sink> out(result);
+ string result;
+ io::stream<string_sink> out(result);
     out << "Hello World!";
     out.flush();
     assert(result == "Hello World!");

Modified: trunk/libs/iostreams/example/container_source_example.cpp
==============================================================================
--- trunk/libs/iostreams/example/container_source_example.cpp (original)
+++ trunk/libs/iostreams/example/container_source_example.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -6,7 +6,7 @@
 
 #include <cassert>
 #include <string>
-#include <boost/iostreams/stream_facade.hpp>
+#include <boost/iostreams/stream.hpp>
 #include <libs/iostreams/example/container_device.hpp>
 
 namespace io = boost::iostreams;
@@ -17,9 +17,9 @@
     using namespace std;
     typedef ex::container_source<string> string_source;
 
- string input = "Hello World!";
- string output;
- io::stream_facade<string_source> in(input);
+ string input = "Hello World!";
+ string output;
+ io::stream<string_source> in(input);
     getline(in, output);
     assert(input == output);
 }

Modified: trunk/libs/iostreams/example/dictionary_filter.hpp
==============================================================================
--- trunk/libs/iostreams/example/dictionary_filter.hpp (original)
+++ trunk/libs/iostreams/example/dictionary_filter.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -183,7 +183,6 @@
     dictionary& dictionary_;
     std::string current_word_;
     std::string::size_type off_;
- bool initialized_;
 };
 
 //------------------Implementation of dictionary------------------------------//

Modified: trunk/libs/iostreams/example/finite_state_filter.hpp
==============================================================================
--- trunk/libs/iostreams/example/finite_state_filter.hpp (original)
+++ trunk/libs/iostreams/example/finite_state_filter.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -342,11 +342,12 @@
     void close(Device& dev, BOOST_IOS::openmode which)
     {
         if (which == BOOST_IOS::out) {
- while (!this->empty())
- iostreams::put_if(dev, this->pop());
+ if (flags_ & f_write)
+ while (!this->empty())
+ iostreams::put_if(dev, this->pop());
+ this->reset();
+ flags_ = 0;
         }
- this->reset();
- flags_ = 0;
     }
 private:
     enum flags {

Modified: trunk/libs/iostreams/src/mapped_file.cpp
==============================================================================
--- trunk/libs/iostreams/src/mapped_file.cpp (original)
+++ trunk/libs/iostreams/src/mapped_file.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -39,7 +39,7 @@
 
 struct mapped_file_impl {
     mapped_file_impl() { clear(false); }
- ~mapped_file_impl() { try { close(); } catch (std::exception&) { } }
+ ~mapped_file_impl() { try { close(); } catch (...) { } }
     void clear(bool error)
     {
         data_ = 0;

Modified: trunk/libs/iostreams/test/Jamfile.v2
==============================================================================
--- trunk/libs/iostreams/test/Jamfile.v2 (original)
+++ trunk/libs/iostreams/test/Jamfile.v2 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -34,6 +34,7 @@
           [ test-iostreams array_test.cpp ]
           [ test-iostreams auto_close_test.cpp ]
           [ test-iostreams buffer_size_test.cpp ]
+ [ test-iostreams close_test.cpp ]
           [ test-iostreams
                 code_converter_test.cpp
                 detail/utf8_codecvt_facet.cpp ]
@@ -46,6 +47,7 @@
           [ test-iostreams counter_test.cpp ]
           [ test-iostreams direct_adapter_test.cpp ]
           [ test-iostreams example_test.cpp ]
+ [ test-iostreams execute_test.cpp ]
           [ test-iostreams file_test.cpp ]
           [ test-iostreams
                 file_descriptor_test.cpp
@@ -66,6 +68,7 @@
                 ../build//boost_iostreams : <link>static ]
           [ test-iostreams newline_test.cpp ]
           [ test-iostreams null_test.cpp ]
+ [ test-iostreams operation_sequence_test.cpp ]
           [ test-iostreams pipeline_test.cpp ]
           [ test-iostreams positioning_test.cpp ]
           [ test-iostreams
@@ -74,6 +77,7 @@
           [ test-iostreams restrict_test.cpp ]
           [ test-iostreams seekable_file_test.cpp ]
           [ test-iostreams seekable_filter_test.cpp ]
+ [ test-iostreams sequence_test.cpp ]
           [ test-iostreams stdio_filter_test.cpp ]
           [ test-iostreams symmetric_filter_test.cpp ]
           [ test-iostreams tee_test.cpp ]

Added: trunk/libs/iostreams/test/close_test.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/iostreams/test/close_test.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -0,0 +1,1482 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.(See accompanying
+ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
+ *
+ * See http://www.boost.org/libs/iostreams for documentation.
+ *
+ * Verifies that the close() member functions of filters and devices
+ * are called with the correct arguments in the correct order when
+ * they are combined using chains or adapters.
+ *
+ * File: libs/iostreams/test/close_test.cpp
+ * Date: Sun Dec 09 16:12:23 MST 2007
+ * Copyright: 2007 CodeRage
+ * Author: Jonathan Turkanis
+ */
+
+#include <boost/iostreams/chain.hpp>
+#include <boost/iostreams/combine.hpp>
+#include <boost/iostreams/compose.hpp>
+#include <boost/iostreams/filter/symmetric.hpp>
+#include <boost/iostreams/invert.hpp>
+#include <boost/iostreams/restrict.hpp>
+#include <boost/iostreams/stream.hpp>
+#include <boost/iostreams/tee.hpp>
+#include <boost/test/test_tools.hpp>
+#include <boost/test/unit_test.hpp>
+#include "./detail/closable.hpp"
+#include "./detail/operation_sequence.hpp"
+
+using namespace std;
+using namespace boost;
+using namespace boost::iostreams;
+using namespace boost::iostreams::test;
+using boost::unit_test::test_suite;
+namespace io = boost::iostreams;
+
+void input_chain_test()
+{
+ // Test input filter and device
+ {
+ operation_sequence seq;
+ chain<input> ch;
+
+ // Test chain::pop()
+ ch.push(closable_filter<input>(seq.new_operation(2)));
+ ch.push(closable_device<input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(closable_device<input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test bidirectional filter and device
+ {
+ operation_sequence seq;
+ chain<input> ch;
+
+
+ // Test chain::pop()
+ ch.push(
+ closable_filter<bidirectional>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ )
+ );
+ ch.push(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test seekable filter and device
+ {
+ operation_sequence seq;
+ chain<input> ch;
+
+ // Test chain::pop()
+ ch.push(closable_filter<seekable>(seq.new_operation(1)));
+ ch.push(closable_device<seekable>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(closable_device<seekable>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test dual-user filter
+ {
+ operation_sequence seq;
+ chain<input> ch;
+
+ // Test chain::pop()
+ ch.push(
+ closable_filter<dual_use>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ )
+ );
+ ch.push(closable_device<input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(closable_device<input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test direct source
+ {
+ operation_sequence seq;
+ chain<input> ch;
+
+ // Test chain::pop()
+ ch.push(closable_filter<input>(seq.new_operation(2)));
+ ch.push(closable_device<direct_input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(closable_device<direct_input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test direct bidirectional device
+ {
+ operation_sequence seq;
+ chain<input> ch;
+
+ // Test chain::pop()
+ ch.push(closable_filter<input>(seq.new_operation(2)));
+ ch.push(
+ closable_device<direct_bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(3)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(
+ closable_device<direct_bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(3)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test direct seekable device
+ {
+ operation_sequence seq;
+ chain<input> ch;
+
+ // Test chain::pop()
+ ch.push(closable_filter<input>(seq.new_operation(1)));
+ ch.push(closable_device<direct_seekable>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(closable_device<direct_seekable>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+}
+
+void output_chain_test()
+{
+ // Test output filter and device
+ {
+ operation_sequence seq;
+ chain<output> ch;
+
+ // Test chain::pop()
+ ch.push(closable_filter<output>(seq.new_operation(1)));
+ ch.push(closable_device<output>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(closable_device<output>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test bidirectional filter and device
+ {
+ operation_sequence seq;
+ chain<output> ch;
+
+
+ // Test chain::pop()
+ ch.push(
+ closable_filter<bidirectional>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ )
+ );
+ ch.push(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test seekable filter and device
+ {
+ operation_sequence seq;
+ chain<output> ch;
+
+ // Test chain::pop()
+ ch.push(closable_filter<seekable>(seq.new_operation(1)));
+ ch.push(closable_device<seekable>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(closable_device<seekable>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test dual-user filter
+ {
+ operation_sequence seq;
+ chain<output> ch;
+
+ // Test chain::pop()
+ ch.push(
+ closable_filter<dual_use>(
+ seq.new_operation(1),
+ seq.new_operation(2)
+ )
+ );
+ ch.push(closable_device<output>(seq.new_operation(3)));
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(closable_device<output>(seq.new_operation(3)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test direct sink
+ {
+ operation_sequence seq;
+ chain<output> ch;
+
+ // Test chain::pop()
+ ch.push(closable_filter<output>(seq.new_operation(1)));
+ ch.push(closable_device<direct_output>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(closable_device<direct_output>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test direct bidirectional device
+ {
+ operation_sequence seq;
+ chain<output> ch;
+
+ // Test chain::pop()
+ ch.push(closable_filter<output>(seq.new_operation(2)));
+ ch.push(
+ closable_device<direct_bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(3)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(
+ closable_device<direct_bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(3)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test direct seekable device
+ {
+ operation_sequence seq;
+ chain<output> ch;
+
+ // Test chain::pop()
+ ch.push(closable_filter<output>(seq.new_operation(1)));
+ ch.push(closable_device<direct_seekable>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(closable_device<direct_seekable>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+}
+
+void bidirectional_chain_test()
+{
+ // Test bidirectional filter and device
+ {
+ operation_sequence seq;
+ chain<bidirectional> ch;
+
+ // Test chain::pop()
+ ch.push(
+ closable_filter<bidirectional>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ )
+ );
+ ch.push(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test direct bidirectional device
+ {
+ operation_sequence seq;
+ chain<bidirectional> ch;
+
+ // Test chain::pop()
+ ch.push(
+ closable_filter<bidirectional>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ )
+ );
+ ch.push(
+ closable_device<direct_bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(
+ closable_device<direct_bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+}
+
+void seekable_chain_test()
+{
+ // Test seekable filter and device
+ {
+ operation_sequence seq;
+ chain<seekable> ch;
+
+ // Test chain::pop()
+ ch.push(closable_filter<seekable>(seq.new_operation(1)));
+ ch.push(closable_device<seekable>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(closable_device<seekable>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test direct seekable device
+ {
+ operation_sequence seq;
+ chain<output> ch;
+
+ // Test chain::pop()
+ ch.push(closable_filter<output>(seq.new_operation(1)));
+ ch.push(closable_device<direct_seekable>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.pop());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+
+ // Test filter reuse and chain::reset()
+ seq.reset();
+ ch.push(closable_device<direct_seekable>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+}
+
+void stream_test()
+{
+ // Test source
+ {
+ operation_sequence seq;
+ stream< closable_device<input> > str;
+ str.open(closable_device<input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(str.close());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test sink
+ {
+ operation_sequence seq;
+ stream< closable_device<output> > str;
+ str.open(closable_device<output>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(str.close());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test bidirectional device
+ {
+ operation_sequence seq;
+ stream< closable_device<bidirectional> > str;
+ str.open(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(2)
+ )
+ );
+ BOOST_CHECK_NO_THROW(str.close());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test seekable device
+ {
+ operation_sequence seq;
+ stream< closable_device<seekable> > str;
+ str.open(closable_device<seekable>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(str.close());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+}
+
+void combine_test()
+{
+ // Combine a source and a sink
+ {
+ operation_sequence seq;
+ chain<bidirectional> ch;
+ ch.push(
+ io::combine(
+ closable_device<input>(seq.new_operation(1)),
+ closable_device<output>(seq.new_operation(2))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Combine two bidirectional devices
+ {
+ operation_sequence seq;
+ chain<bidirectional> ch;
+ ch.push(
+ io::combine(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(2)
+ ),
+ closable_device<bidirectional>(
+ seq.new_operation(3),
+ seq.new_operation(4)
+ )
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Combine two seekable devices
+ {
+ operation_sequence seq;
+ chain<bidirectional> ch;
+ ch.push(
+ io::combine(
+ closable_device<seekable>(seq.new_operation(1)),
+ closable_device<seekable>(seq.new_operation(2))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Combine an input filter and an output filter
+ {
+ operation_sequence seq;
+ chain<bidirectional> ch;
+ ch.push(
+ io::combine(
+ closable_filter<input>(seq.new_operation(2)),
+ closable_filter<output>(seq.new_operation(3))
+ )
+ );
+ ch.push(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Combine two bidirectional filters
+ {
+ operation_sequence seq;
+ chain<bidirectional> ch;
+ ch.push(
+ io::combine(
+ closable_filter<bidirectional>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ ),
+ closable_filter<bidirectional>(
+ seq.new_operation(4),
+ seq.new_operation(5)
+ )
+ )
+ );
+ ch.push(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(6)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Combine two seekable filters
+ {
+ operation_sequence seq;
+ chain<bidirectional> ch;
+ ch.push(
+ io::combine(
+ closable_filter<seekable>(seq.new_operation(2)),
+ closable_filter<seekable>(seq.new_operation(3))
+ )
+ );
+ ch.push(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Combine two dual-use filters
+ {
+ operation_sequence seq;
+ chain<bidirectional> ch;
+ ch.push(
+ io::combine(
+ closable_filter<dual_use>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ ),
+ closable_filter<dual_use>(
+ seq.new_operation(4),
+ seq.new_operation(5)
+ )
+ )
+ );
+ ch.push(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(6)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+}
+
+void composite_device_test()
+{
+ // Compose an input filter with a source
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(
+ io::compose(
+ closable_filter<input>(seq.new_operation(2)),
+ closable_device<input>(seq.new_operation(1))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose a bidirectional filter with a source
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(
+ io::compose(
+ closable_filter<bidirectional>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ ),
+ closable_device<input>(seq.new_operation(1))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose a seekable filter with a source
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(
+ io::compose(
+ closable_filter<seekable>(seq.new_operation(2)),
+ closable_device<input>(seq.new_operation(1))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose a dual-use filter with a source
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(
+ io::compose(
+ closable_filter<dual_use>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ ),
+ closable_device<input>(seq.new_operation(1))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose an output filter with a sink
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::compose(
+ closable_filter<output>(seq.new_operation(1)),
+ closable_device<output>(seq.new_operation(2))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose a bidirectional filter with a sink
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::compose(
+ closable_filter<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(2)
+ ),
+ closable_device<output>(seq.new_operation(3))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose a seekable filter with a sink
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::compose(
+ closable_filter<seekable>(seq.new_operation(1)),
+ closable_device<output>(seq.new_operation(2))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose a dual-use filter with a sink
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::compose(
+ closable_filter<dual_use>(
+ seq.new_operation(1),
+ seq.new_operation(2)
+ ),
+ closable_device<output>(seq.new_operation(3))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose a bidirectional filter with a bidirectional device
+ {
+ operation_sequence seq;
+ chain<bidirectional> ch;
+ ch.push(
+ io::compose(
+ closable_filter<bidirectional>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ ),
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose a seekable filter with a seekable device
+ {
+ operation_sequence seq;
+ chain<seekable> ch;
+ ch.push(
+ io::compose(
+ closable_filter<seekable>(seq.new_operation(1)),
+ closable_device<seekable>(seq.new_operation(2))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+}
+
+void composite_filter_test()
+{
+ // Compose two input filters
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(
+ io::compose(
+ closable_filter<input>(seq.new_operation(3)),
+ closable_filter<input>(seq.new_operation(2))
+ )
+ );
+ ch.push(closable_device<input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose a bidirectional filter with an input filter
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(
+ io::compose(
+ closable_filter<bidirectional>(
+ seq.new_operation(3),
+ seq.new_operation(4)
+ ),
+ closable_filter<input>(seq.new_operation(2))
+ )
+ );
+ ch.push(closable_device<input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_MESSAGE(seq.is_success(), seq.message());
+ }
+
+ // Compose a seekable filter with an input filter
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(
+ io::compose(
+ closable_filter<seekable>(seq.new_operation(3)),
+ closable_filter<input>(seq.new_operation(2))
+ )
+ );
+ ch.push(closable_device<input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose a dual-use filter with an input filter
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(
+ io::compose(
+ closable_filter<dual_use>(
+ seq.new_operation(3),
+ seq.new_operation(4)
+ ),
+ closable_filter<input>(seq.new_operation(2))
+ )
+ );
+ ch.push(closable_device<input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose two output filters
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::compose(
+ closable_filter<output>(seq.new_operation(1)),
+ closable_filter<output>(seq.new_operation(2))
+ )
+ );
+ ch.push(closable_device<output>(seq.new_operation(3)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose a bidirectional filter with an output filter
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::compose(
+ closable_filter<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(2)
+ ),
+ closable_filter<output>(seq.new_operation(3))
+ )
+ );
+ ch.push(closable_device<output>(seq.new_operation(4)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose a seekable filter with an output filter
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::compose(
+ closable_filter<seekable>(seq.new_operation(1)),
+ closable_filter<output>(seq.new_operation(2))
+ )
+ );
+ ch.push(closable_device<output>(seq.new_operation(3)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose a dual-use filter with an output filter
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::compose(
+ closable_filter<dual_use>(
+ seq.new_operation(1),
+ seq.new_operation(2)
+ ),
+ closable_filter<output>(seq.new_operation(3))
+ )
+ );
+ ch.push(closable_device<output>(seq.new_operation(4)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose two bidirectional filters
+ {
+ operation_sequence seq;
+ chain<bidirectional> ch;
+ ch.push(
+ io::compose(
+ closable_filter<bidirectional>(
+ seq.new_operation(3),
+ seq.new_operation(4)
+ ),
+ closable_filter<bidirectional>(
+ seq.new_operation(2),
+ seq.new_operation(5)
+ )
+ )
+ );
+ ch.push(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(6)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose two seekable filters
+ {
+ operation_sequence seq;
+ chain<seekable> ch;
+ ch.push(
+ io::compose(
+ closable_filter<seekable>(seq.new_operation(1)),
+ closable_filter<seekable>(seq.new_operation(2))
+ )
+ );
+ ch.push(closable_device<seekable>(seq.new_operation(3)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose two dual-use filters for input
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(
+ io::compose(
+ closable_filter<dual_use>(
+ seq.new_operation(3),
+ seq.new_operation(4)
+ ),
+ closable_filter<dual_use>(
+ seq.new_operation(2),
+ seq.new_operation(5)
+ )
+ )
+ );
+ ch.push(closable_device<input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Compose two dual-use filters for output
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::compose(
+ closable_filter<dual_use>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ ),
+ closable_filter<dual_use>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ )
+ );
+ ch.push(closable_device<output>(seq.new_operation(5)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+}
+
+void invert_test()
+{
+ // Invert an output filter
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(io::invert(closable_filter<output>(seq.new_operation(2))));
+ ch.push(closable_device<input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Invert an input filter
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(io::invert(closable_filter<input>(seq.new_operation(1))));
+ ch.push(closable_device<output>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+}
+
+void restrict_test()
+{
+ // Restrict a source
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(io::restrict(closable_device<input>(seq.new_operation(1)), 0));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Restrict a bidirectional device
+ {
+ operation_sequence seq;
+ chain<bidirectional> ch;
+ ch.push(
+ io::restrict(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(2)
+ ),
+ 0
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Restrict a seekable device
+ {
+ operation_sequence seq;
+ chain<seekable> ch;
+ ch.push(
+ io::restrict(closable_device<seekable>(seq.new_operation(1)), 0)
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Restrict a direct source
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(
+ io::restrict(closable_device<direct_input>(seq.new_operation(1)), 0)
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Restrict a direct bidirectional device
+ {
+ operation_sequence seq;
+ chain<bidirectional> ch;
+ ch.push(
+ io::restrict(
+ closable_device<direct_bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(2)
+ ),
+ 0
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Restrict a direct seekable device
+ {
+ operation_sequence seq;
+ chain<seekable> ch;
+ ch.push(
+ io::restrict(
+ closable_device<direct_seekable>(seq.new_operation(1)),
+ 0
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Restrict an input filter
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(io::restrict(closable_filter<input>(seq.new_operation(2)), 0));
+ ch.push(closable_device<input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Restrict a bidirectional filter
+ {
+ operation_sequence seq;
+ chain<bidirectional> ch;
+ ch.push(
+ io::restrict(
+ closable_filter<bidirectional>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ ),
+ 0
+ )
+ );
+ ch.push(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Restrict a seekable filter
+ {
+ operation_sequence seq;
+ chain<seekable> ch;
+ ch.push(
+ io::restrict(closable_filter<seekable>(seq.new_operation(1)), 0)
+ );
+ ch.push(closable_device<seekable>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Restrict a dual_use filter for input
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(
+ io::restrict(
+ closable_filter<dual_use>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ ),
+ 0
+ )
+ );
+ ch.push(closable_device<input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Restrict a dual_use filter for output
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::restrict(
+ closable_filter<dual_use>(
+ seq.new_operation(1),
+ seq.new_operation(2)
+ ),
+ 0
+ )
+ );
+ ch.push(closable_device<output>(seq.new_operation(3)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+}
+
+void symmetric_filter_test()
+{
+ // Test input
+ {
+ operation_sequence seq;
+ chain<input> ch;
+ ch.push(
+ io::symmetric_filter<closable_symmetric_filter>
+ (0, seq.new_operation(2))
+ );
+ ch.push(closable_device<input>(seq.new_operation(1)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test output
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::symmetric_filter<closable_symmetric_filter>
+ (0, seq.new_operation(1))
+ );
+ ch.push(closable_device<output>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+}
+
+void tee_test()
+{
+ // Note: The implementation of tee_device closes the first
+ // sink before the second
+
+ // Tee two sinks (Borland <= 5.8.2 needs a little help compiling this case,
+ // but it executes the closing algorithm correctly)
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::tee(
+ closable_device<output>(seq.new_operation(1)),
+ closable_device<
+ #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
+ borland_output
+ #else
+ output
+ #endif
+ >(seq.new_operation(2))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Tee two bidirectional devices
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::tee(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(2)
+ ),
+ closable_device<bidirectional>(
+ seq.new_operation(3),
+ seq.new_operation(4)
+ )
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Tee two seekable devices
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::tee(
+ closable_device<seekable>(seq.new_operation(1)),
+ closable_device<seekable>(seq.new_operation(2))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Tee a sink
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(io::tee(closable_device<output>(seq.new_operation(1))));
+ ch.push(closable_device<output>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Tee a bidirectional device
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::tee(
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(2)
+ )
+ )
+ );
+ ch.push(closable_device<output>(seq.new_operation(3)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Tee a seekable device
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(io::tee(closable_device<seekable>(seq.new_operation(1))));
+ ch.push(closable_device<seekable>(seq.new_operation(2)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+}
+
+void tee_composite_test()
+{
+ // This test is probably redundant, but it verifies that
+ // ticket #1002 is fixed
+
+ // Tee a composite sink with a sink
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::tee(
+ io::compose(
+ closable_filter<output>(seq.new_operation(1)),
+ closable_device<output>(seq.new_operation(2))
+ ),
+ closable_device<output>(seq.new_operation(3))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Tee a composite bidirectional device with a sink
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::tee(
+ io::compose(
+ closable_filter<bidirectional>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ ),
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ ),
+ closable_device<output>(seq.new_operation(5))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Tee a composite composite seekable device with a sink
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::tee(
+ io::compose(
+ closable_filter<seekable>(seq.new_operation(1)),
+ closable_device<seekable>(seq.new_operation(2))
+ ),
+ closable_device<output>(seq.new_operation(3))
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+
+ // Tee a composite sink
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::tee(
+ io::compose(
+ closable_filter<output>(seq.new_operation(1)),
+ closable_device<output>(seq.new_operation(2))
+ )
+ )
+ );
+ ch.push(closable_device<output>(seq.new_operation(3)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Tee a composite bidirectional device with a sink
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::tee(
+ io::compose(
+ closable_filter<bidirectional>(
+ seq.new_operation(2),
+ seq.new_operation(3)
+ ),
+ closable_device<bidirectional>(
+ seq.new_operation(1),
+ seq.new_operation(4)
+ )
+ )
+ )
+ );
+ ch.push(closable_device<output>(seq.new_operation(5)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Tee a composite composite seekable device with a sink
+ {
+ operation_sequence seq;
+ chain<output> ch;
+ ch.push(
+ io::tee(
+ io::compose(
+ closable_filter<seekable>(seq.new_operation(1)),
+ closable_device<seekable>(seq.new_operation(2))
+ )
+ )
+ );
+ ch.push(closable_device<output>(seq.new_operation(3)));
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+}
+
+test_suite* init_unit_test_suite(int, char* [])
+{
+ test_suite* test = BOOST_TEST_SUITE("execute test");
+ test->add(BOOST_TEST_CASE(&input_chain_test));
+ test->add(BOOST_TEST_CASE(&output_chain_test));
+ test->add(BOOST_TEST_CASE(&bidirectional_chain_test));
+ test->add(BOOST_TEST_CASE(&seekable_chain_test));
+ test->add(BOOST_TEST_CASE(&stream_test));
+ test->add(BOOST_TEST_CASE(&combine_test));
+ test->add(BOOST_TEST_CASE(&composite_device_test));
+ test->add(BOOST_TEST_CASE(&composite_filter_test));
+ test->add(BOOST_TEST_CASE(&invert_test));
+ test->add(BOOST_TEST_CASE(&restrict_test));
+ test->add(BOOST_TEST_CASE(&symmetric_filter_test));
+ test->add(BOOST_TEST_CASE(&tee_test));
+ test->add(BOOST_TEST_CASE(&tee_composite_test));
+ return test;
+}

Modified: trunk/libs/iostreams/test/code_converter_test.cpp
==============================================================================
--- trunk/libs/iostreams/test/code_converter_test.cpp (original)
+++ trunk/libs/iostreams/test/code_converter_test.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -29,6 +29,8 @@
 #include <boost/iostreams/stream.hpp>
 #include <boost/test/test_tools.hpp>
 #include <boost/test/unit_test.hpp>
+#include "detail/closable.hpp"
+#include "detail/operation_sequence.hpp"
 #include "detail/temp_file.hpp"
 
     // Include codevct facets
@@ -200,14 +202,14 @@
     typedef code_converter<classic_file_sink, Codecvt> wide_file_sink;
 
     BOOST_CHECK(Codecvt().max_length() <= max_length);
- temp_file temp;
- string_type test = test_string<Codecvt>();
+ temp_file temp;
+ string_type test = test_string<Codecvt>();
     stream<wide_file_sink> out(temp.name());
     out.write(test.data(), static_cast<streamsize>(test.size()));
     out.close();
 
     stream<wide_file_source> in(temp.name());
- string_type test2;
+ string_type test2;
     io::copy(in, io::back_inserter(test2));
 
     return test == test2;
@@ -227,14 +229,14 @@
     locale loc = add_facet(locale(), new Codecvt);
     locale::global(loc);
 
- temp_file temp;
- string_type test = test_string<Codecvt>();
+ temp_file temp;
+ string_type test = test_string<Codecvt>();
     stream<wide_file_sink> out(temp.name());
     out.write(test.data(), static_cast<streamsize>(test.size()));
     out.close();
 
     stream<wide_file_source> in(temp.name());
- string_type test2;
+ string_type test2;
     io::copy(in, io::back_inserter(test2));
 
     return test == test2;
@@ -329,9 +331,56 @@
 #endif
 }
 
+/* Defer pending further testing
+void close_test()
+{
+ typedef utf8_codecvt_facet<wchar_t, char> codecvt_type;
+
+ // Test code converter based on a source
+ {
+ operation_sequence seq;
+ io::wchain<input> ch;
+ ch.push(
+ code_converter<closable_device<input>, codecvt_type>(
+ seq.new_operation(1)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test code converter based on a sink
+ {
+ operation_sequence seq;
+ io::wchain<output> ch;
+ ch.push(
+ code_converter<closable_device<output>, codecvt_type>(
+ seq.new_operation(1)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+
+ // Test code converter based on a bidirectional device
+ {
+ operation_sequence seq;
+ io::wchain<bidirectional> ch;
+ ch.push(
+ code_converter<closable_device<bidirectional>, codecvt_type>(
+ seq.new_operation(1),
+ seq.new_operation(2)
+ )
+ );
+ BOOST_CHECK_NO_THROW(ch.reset());
+ BOOST_CHECK_OPERATION_SEQUENCE(seq);
+ }
+}*/
+
 test_suite* init_unit_test_suite(int, char* [])
 {
     test_suite* test = BOOST_TEST_SUITE("code_converter test");
     test->add(BOOST_TEST_CASE(&code_converter_test));
+ //test->add(BOOST_TEST_CASE(&close_test));
     return test;
 }
\ No newline at end of file

Modified: trunk/libs/iostreams/test/compose_test.cpp
==============================================================================
--- trunk/libs/iostreams/test/compose_test.cpp (original)
+++ trunk/libs/iostreams/test/compose_test.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -27,6 +27,7 @@
     test_file src1, src2;
     filtering_istream first, second;
 
+ // Test composite device
     first.push(toupper_filter());
     first.push(padding_filter('a'));
     first.push(file_source(src1.name(), in_mode));
@@ -38,6 +39,7 @@
         "failed reading from a stdio_filter"
     );
 
+ // Test composite filter
     first.reset();
     second.reset();
     first.push(toupper_filter());
@@ -60,6 +62,7 @@
     temp_file dest1, dest2;
     filtering_ostream out1, out2;
 
+ // Test composite device
     out1.push(tolower_filter());
     out1.push(padding_filter('a'));
     out1.push(file_sink(dest1.name(), in_mode));
@@ -80,6 +83,7 @@
         );
     }
 
+ // Test composite filter
     out1.push(tolower_filter());
     out1.push(padding_filter('a'));
     out1.push(file_sink(dest1.name(), in_mode));

Added: trunk/libs/iostreams/test/detail/closable.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/iostreams/test/detail/closable.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -0,0 +1,342 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.(See accompanying
+ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
+ *
+ * See http://www.boost.org/libs/iostreams for documentation.
+ *
+ * Defines a large collection of closable filters and devices that
+ * execute instances of boost::iostreams::test::operation upon
+ * closre(). Used to verify that filters and devices are closed
+ * correctly by the iostreams library
+ *
+ * File: libs/iostreams/test/detail/closable.hpp
+ * Date: Sun Dec 09 16:12:23 MST 2007
+ * Copyright: 2007 CodeRage
+ * Author: Jonathan Turkanis
+ */
+
+#ifndef BOOST_IOSTREAMS_TEST_CLOSABLE_HPP_INCLUDED
+#define BOOST_IOSTREAMS_TEST_CLOSABLE_HPP_INCLUDED
+
+#include <boost/iostreams/categories.hpp>
+#include <boost/iostreams/char_traits.hpp> // EOF
+#include <boost/iostreams/concepts.hpp>
+#include <boost/iostreams/detail/ios.hpp>
+#include "./operation_sequence.hpp"
+
+namespace boost { namespace iostreams { namespace test {
+
+template<typename Category>
+class closable_device { };
+
+// Source
+template<>
+class closable_device<input> : public source {
+public:
+ closable_device(operation close) : close_(close) { }
+ std::streamsize read(char*, std::streamsize) { return -1; }
+ void close() { close_.execute(); }
+private:
+ operation close_;
+};
+
+// Sink
+template<>
+class closable_device<output> : public sink {
+public:
+ closable_device(operation close) : close_(close) { }
+ std::streamsize write(const char*, std::streamsize n) { return 0; }
+ void close() { close_.execute(); }
+private:
+ operation close_;
+};
+
+struct borland_output { };
+
+// Copy of closable_device<output>, for Borland <= 5.8.2
+template<>
+class closable_device<borland_output> : public sink {
+public:
+ closable_device(operation close) : close_(close) { }
+ std::streamsize write(const char*, std::streamsize n) { return 0; }
+ void close() { close_.execute(); }
+private:
+ operation close_;
+};
+
+// Bidirectional device
+template<>
+class closable_device<bidirectional> : public device<bidirectional> {
+public:
+ closable_device(operation close_input, operation close_output)
+ : close_input_(close_input), close_output_(close_output)
+ { }
+ std::streamsize read(char*, std::streamsize) { return -1; }
+ std::streamsize write(const char*, std::streamsize n) { return 0; }
+ void close(BOOST_IOS::openmode which)
+ {
+ switch (which) {
+ case BOOST_IOS::in:
+ close_input_.execute();
+ break;
+ case BOOST_IOS::out:
+ close_output_.execute();
+ break;
+ default:
+ break;
+ }
+ }
+private:
+ operation close_input_;
+ operation close_output_;
+};
+
+// Seekable device
+template<>
+class closable_device<seekable> : public device<seekable> {
+public:
+ closable_device(operation close) : close_(close) { }
+ std::streamsize read(char*, std::streamsize) { return -1; }
+ std::streamsize write(const char*, std::streamsize n) { return 0; }
+ stream_offset seek(stream_offset, BOOST_IOS::seekdir) { return 0; }
+ void close() { close_.execute(); }
+private:
+ operation close_;
+};
+
+struct direct_input
+ : input, device_tag, closable_tag, direct_tag
+ { };
+struct direct_output
+ : output, device_tag, closable_tag, direct_tag
+ { };
+struct direct_bidirectional
+ : bidirectional, device_tag, closable_tag, direct_tag
+ { };
+struct direct_seekable
+ : seekable, device_tag, closable_tag, direct_tag
+ { };
+
+// Direct source
+template<>
+class closable_device<direct_input> {
+public:
+ typedef char char_type;
+ typedef direct_input category;
+ closable_device(operation close) : close_(close) { }
+ std::pair<char*, char*> input_sequence()
+ { return std::pair<char*, char*>(0, 0); }
+ void close() { close_.execute(); }
+private:
+ operation close_;
+};
+
+// Direct sink
+template<>
+class closable_device<direct_output> {
+public:
+ typedef char char_type;
+ typedef direct_output category;
+ closable_device(operation close) : close_(close) { }
+ std::pair<char*, char*> output_sequence()
+ { return std::pair<char*, char*>(0, 0); }
+ void close() { close_.execute(); }
+private:
+ operation close_;
+};
+
+// Direct bidirectional device
+template<>
+class closable_device<direct_bidirectional> {
+public:
+ typedef char char_type;
+ typedef direct_bidirectional category;
+ closable_device(operation close_input, operation close_output)
+ : close_input_(close_input), close_output_(close_output)
+ { }
+ std::pair<char*, char*> input_sequence()
+ { return std::pair<char*, char*>(0, 0); }
+ std::pair<char*, char*> output_sequence()
+ { return std::pair<char*, char*>(0, 0); }
+ void close(BOOST_IOS::openmode which)
+ {
+ switch (which) {
+ case BOOST_IOS::in:
+ close_input_.execute();
+ break;
+ case BOOST_IOS::out:
+ close_output_.execute();
+ break;
+ default:
+ break;
+ }
+ }
+private:
+ operation close_input_;
+ operation close_output_;
+};
+
+// Direct seekable device
+template<>
+class closable_device<direct_seekable> {
+public:
+ typedef char char_type;
+ typedef direct_seekable category;
+ closable_device(operation close) : close_(close) { }
+ std::pair<char*, char*> input_sequence()
+ { return std::pair<char*, char*>(0, 0); }
+ std::pair<char*, char*> output_sequence()
+ { return std::pair<char*, char*>(0, 0); }
+ void close() { close_.execute(); }
+private:
+ operation close_;
+};
+
+template<typename Mode>
+class closable_filter { };
+
+// Input filter
+template<>
+class closable_filter<input> : public input_filter {
+public:
+ closable_filter(operation close) : close_(close) { }
+
+ template<typename Source>
+ int get(Source&) { return EOF; }
+
+ template<typename Source>
+ void close(Source&) { close_.execute(); }
+private:
+ operation close_;
+};
+
+// Output filter
+template<>
+class closable_filter<output> : public output_filter {
+public:
+ closable_filter(operation close) : close_(close) { }
+
+ template<typename Sink>
+ bool put(Sink&, char) { return true; }
+
+ template<typename Sink>
+ void close(Sink&) { close_.execute(); }
+private:
+ operation close_;
+};
+
+// Bidirectional filter
+template<>
+class closable_filter<bidirectional> : public filter<bidirectional> {
+public:
+ closable_filter(operation close_input, operation close_output)
+ : close_input_(close_input), close_output_(close_output)
+ { }
+
+ template<typename Source>
+ int get(Source&) { return EOF; }
+
+ template<typename Sink>
+ bool put(Sink&, char) { return true; }
+
+ template<typename Device>
+ void close(Device&, BOOST_IOS::openmode which)
+ {
+ switch (which) {
+ case BOOST_IOS::in:
+ close_input_.execute();
+ break;
+ case BOOST_IOS::out:
+ close_output_.execute();
+ break;
+ default:
+ break;
+ }
+ }
+private:
+ operation close_input_;
+ operation close_output_;
+};
+
+// Seekable filter
+template<>
+class closable_filter<seekable> : public filter<seekable> {
+public:
+ closable_filter(operation close) : close_(close) { }
+ std::streamsize read(char*, std::streamsize) { return -1; }
+
+ template<typename Source>
+ int get(Source&) { return EOF; }
+
+ template<typename Sink>
+ bool put(Sink&, char) { return true; }
+
+ template<typename Device>
+ stream_offset seek(Device&, stream_offset, BOOST_IOS::seekdir)
+ {
+ return 0;
+ }
+
+ template<typename Device>
+ void close(Device&) { close_.execute(); }
+private:
+ operation close_;
+};
+
+// Dual-use filter
+template<>
+class closable_filter<dual_use> {
+public:
+ typedef char char_type;
+ struct category
+ : filter_tag,
+ dual_use,
+ closable_tag
+ { };
+ closable_filter(operation close_input, operation close_output)
+ : close_input_(close_input), close_output_(close_output)
+ { }
+
+ template<typename Source>
+ int get(Source&) { return EOF; }
+
+ template<typename Sink>
+ bool put(Sink&, char) { return true; }
+
+ template<typename Device>
+ void close(Device&, BOOST_IOS::openmode which)
+ {
+ switch (which) {
+ case BOOST_IOS::in:
+ close_input_.execute();
+ break;
+ case BOOST_IOS::out:
+ close_output_.execute();
+ break;
+ default:
+ break;
+ }
+ }
+private:
+ operation close_input_;
+ operation close_output_;
+};
+
+// Symmetric filter
+class closable_symmetric_filter {
+public:
+ typedef char char_type;
+ closable_symmetric_filter(operation close) : close_(close) { }
+ bool filter( const char*&, const char*,
+ char*&, char*, bool )
+ {
+ return false;
+ }
+ void close() { close_.execute(); }
+private:
+ operation close_;
+};
+
+} } } // End namespaces test, iostreams, boost.
+
+#endif // #ifndef BOOST_IOSTREAMS_TEST_CLOSABLE_HPP_INCLUDED

Added: trunk/libs/iostreams/test/detail/operation_sequence.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/iostreams/test/detail/operation_sequence.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -0,0 +1,222 @@
+/*
+ *
+ * Distributed under the Boost Software License, Version 1.0.(See accompanying
+ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
+ *
+ * See http://www.boost.org/libs/iostreams for documentation.
+ *
+ * Defines the classes operation_sequence and operation, in the namespace
+ * boost::iostreams::test, for verifying that all elements of a sequence of
+ * operations are executed, and that they are executed in the correct order.
+ *
+ * File: libs/iostreams/test/detail/operation_sequence.hpp
+ * Date: Mon Dec 10 18:58:19 MST 2007
+ * Copyright: 2007 CodeRage
+ * Author: Jonathan Turkanis
+ */
+
+#ifndef BOOST_IOSTREAMS_TEST_OPERATION_SEQUENCE_HPP_INCLUDED
+#define BOOST_IOSTREAMS_TEST_OPERATION_SEQUENCE_HPP_INCLUDED
+
+#include <boost/config.hpp> // make sure size_t is in namespace std
+#include <cstddef>
+#include <climits>
+#include <map>
+#include <stdexcept>
+#include <string>
+#include <utility> // pair
+#include <vector>
+#include <boost/lexical_cast.hpp>
+#include <boost/preprocessor/iteration/local.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/test/test_tools.hpp>
+#include <boost/weak_ptr.hpp>
+
+#ifndef BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR
+# define BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR 20
+#endif
+
+#define BOOST_CHECK_OPERATION_SEQUENCE(seq) \
+ BOOST_CHECK_MESSAGE(seq.is_success(), seq.message()) \
+ /**/
+
+namespace boost { namespace iostreams { namespace test {
+
+// Simple exception class with error code built in to type
+template<int Code>
+struct operation_error { };
+
+class operation_sequence;
+
+// Represent an operation in a sequence of operations to be executed
+class operation {
+public:
+ friend class operation_sequence;
+ operation() : pimpl_() { }
+ void execute();
+private:
+ static void remove_operation(operation_sequence& seq, int id);
+
+ struct impl {
+ impl(operation_sequence& seq, int id, int error_code = -1)
+ : seq(seq), id(id), error_code(error_code)
+ { }
+ ~impl() { remove_operation(seq, id); }
+ operation_sequence& seq;
+ int id;
+ int error_code;
+ };
+ friend struct impl;
+
+ operation(operation_sequence& seq, int id, int error_code = -1)
+ : pimpl_(new impl(seq, id, error_code))
+ { }
+
+ shared_ptr<impl> pimpl_;
+};
+
+// Represents a sequence of operations to be executed in a particular order
+class operation_sequence {
+public:
+ friend class operation;
+ operation_sequence() { reset(); }
+
+ //
+ // Returns a new operation.
+ // Parameters:
+ //
+ // id - The operation id, determining the position
+ // of the new operation in the operation sequence
+ // error_code - If supplied, indicates that the new
+ // operation will throw operation_error<error_code>
+ // when executed. Must be an integer between 0 and
+ // BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR,
+ // inclusive.
+ //
+ operation new_operation(int id, int error_code = INT_MAX);
+
+ bool is_success() const { return success_; }
+ bool is_failure() const { return failed_; }
+ std::string message() const;
+ void reset();
+private:
+ void execute(int id);
+ void remove_operation(int id);
+ operation_sequence(const operation_sequence&);
+ operation_sequence& operator=(const operation_sequence&);
+
+ typedef weak_ptr<operation::impl> ptr_type;
+ typedef std::map<int, ptr_type> map_type;
+
+ map_type operations_;
+ std::vector<int> log_;
+ std::size_t total_executed_;
+ int last_executed_;
+ bool success_;
+ bool failed_;
+};
+
+//--------------Implementation of operation-----------------------------------//
+
+void operation::execute()
+{
+ pimpl_->seq.execute(pimpl_->id);
+ switch (pimpl_->error_code) {
+
+ // Implementation with one or more cleanup operations
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ case n: throw operation_error<n>(); \
+ /**/
+
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR)
+ #include BOOST_PP_LOCAL_ITERATE()
+ #undef BOOST_PP_LOCAL_MACRO
+
+ default:
+ break;
+ }
+}
+
+inline void operation::remove_operation(operation_sequence& seq, int id)
+{
+ seq.remove_operation(id);
+}
+
+//--------------Implementation of operation_sequence--------------------------//
+
+inline operation operation_sequence::new_operation(int id, int error_code)
+{
+ using namespace std;
+ if ( error_code < 0 ||
+ error_code > BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR &&
+ error_code != INT_MAX )
+ {
+ throw runtime_error( string("The error code ") +
+ lexical_cast<string>(error_code) +
+ " is out of range" );
+ }
+ if (last_executed_ != INT_MIN)
+ throw runtime_error( "Operations in progress; call reset() "
+ "before creating more operations" );
+ map_type::const_iterator it = operations_.find(id);
+ if (it != operations_.end())
+ throw runtime_error( string("The operation ") +
+ lexical_cast<string>(id) +
+ " already exists" );
+ operation op(*this, id, error_code);
+ operations_.insert(make_pair(id, ptr_type(op.pimpl_)));
+ return op;
+}
+
+inline std::string operation_sequence::message() const
+{
+ using namespace std;
+ if (success_)
+ return "success";
+ std::string msg = failed_ ?
+ "operations occurred out of order: " :
+ "operation sequence is incomplete: ";
+ typedef vector<int>::size_type size_type;
+ for (size_type z = 0, n = log_.size(); z < n; ++z) {
+ msg += lexical_cast<string>(log_[z]);
+ if (z < n - 1)
+ msg += ',';
+ }
+ return msg;
+}
+
+inline void operation_sequence::reset()
+{
+ log_.clear();
+ total_executed_ = 0;
+ last_executed_ = INT_MIN;
+ success_ = false;
+ failed_ = false;
+}
+
+inline void operation_sequence::execute(int id)
+{
+ log_.push_back(id);
+ if (!failed_ && last_executed_ < id) {
+ if (++total_executed_ == operations_.size())
+ success_ = true;
+ last_executed_ = id;
+ } else {
+ success_ = false;
+ failed_ = true;
+ }
+}
+
+inline void operation_sequence::remove_operation(int id)
+{
+ using namespace std;
+ map_type::iterator it = operations_.find(id);
+ if (it == operations_.end())
+ throw runtime_error( string("No such operation: ") +
+ lexical_cast<string>(id) );
+ operations_.erase(it);
+}
+
+} } } // End namespace boost::iostreams::test.
+
+#endif // #ifndef BOOST_IOSTREAMS_TEST_OPERATION_SEQUENCE_HPP_INCLUDED

Modified: trunk/libs/iostreams/test/example_test.cpp
==============================================================================
--- trunk/libs/iostreams/test/example_test.cpp (original)
+++ trunk/libs/iostreams/test/example_test.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -39,23 +39,23 @@
     typedef ex::container_device<vector_type> vector_device;
 
     {
- test_sequence<> seq;
- test_file file;
+ test_sequence<> seq;
+ test_file file;
         io::stream<vector_source> first(seq);
         io::stream<io::file_source> second(file.name(), in_mode);
         BOOST_CHECK(compare_streams_in_chunks(first, second));
     }
 
     {
- std::vector<char> first;
- test_sequence<> second;
- io::stream<vector_sink> out(first);
+ std::vector<char> first;
+ test_sequence<> second;
+ io::stream<vector_sink> out(first);
         write_data_in_chunks(out);
         BOOST_CHECK(first == second);
     }
 
     {
- vector<char> v;
+ vector<char> v;
         io::stream<vector_device> io(v);
         BOOST_CHECK(test_seekable_in_chunks(io));
     }

Added: trunk/libs/iostreams/test/execute_test.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/iostreams/test/execute_test.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -0,0 +1,645 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.(See accompanying
+ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
+ *
+ * See http://www.boost.org/libs/iostreams for documentation.
+ *
+ * Tests the function templates boost::iostreams::detail::execute_all and
+ * boost::iostreams::detail::execute_foreach
+ *
+ * File: libs/iostreams/test/execute_test.cpp
+ * Date: Thu Dec 06 13:21:54 MST 2007
+ * Copyright: 2007 CodeRage
+ * Author: Jonathan Turkanis
+ */
+
+#include <boost/iostreams/detail/execute.hpp>
+#include <boost/test/test_tools.hpp>
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace boost;
+using namespace boost::iostreams;
+using namespace boost::iostreams::detail;
+using boost::unit_test::test_suite;
+
+// Function object that sets a boolean flag and returns a value
+// specified at construction
+template<typename Result>
+struct operation {
+ typedef Result result_type;
+ operation(Result r, bool& executed) : r(r), executed(executed) { }
+ Result operator()() const
+ {
+ executed = true;
+ return r;
+ }
+ Result r;
+ bool& executed;
+};
+
+// Specialization for void return
+template<>
+struct operation<void> {
+ typedef void result_type;
+ operation(bool& executed) : executed(executed) { }
+ void operator()() const { executed = true; }
+ bool& executed;
+};
+
+// Simple exception class with error code built in to type
+template<int Code>
+struct error { };
+
+// Function object that sets a boolean flag and throws an exception
+template<int Code>
+struct thrower {
+ typedef void result_type;
+ thrower(bool& executed) : executed(executed) { }
+ void operator()() const
+ {
+ executed = true;
+ throw error<Code>();
+ }
+ bool& executed;
+};
+
+// Function object for use by foreach_test
+struct foreach_func {
+ typedef void result_type;
+ foreach_func(int& count) : count(count) { }
+ void operator()(int x) const
+ {
+ ++count;
+ switch (x) {
+ case 0: throw error<0>();
+ case 1: throw error<1>();
+ case 2: throw error<2>();
+ case 3: throw error<3>();
+ case 4: throw error<4>();
+ case 5: throw error<5>();
+ case 6: throw error<6>();
+ case 7: throw error<7>();
+ case 8: throw error<8>();
+ case 9: throw error<9>();
+ default:
+ break;
+ }
+ }
+ int& count; // Number of times operator() has been called
+};
+
+void success_test()
+{
+ // Test returning an int
+ {
+ bool executed = false;
+ BOOST_CHECK(execute_all(operation<int>(9, executed)) == 9);
+ BOOST_CHECK(executed);
+ }
+
+ // Test returning void
+ {
+ bool executed = false;
+ execute_all(operation<void>(executed));
+ BOOST_CHECK(executed);
+ }
+
+ // Test returning an int with one cleanup operation
+ {
+ bool executed = false, cleaned_up = false;
+ BOOST_CHECK(
+ execute_all(
+ operation<int>(9, executed),
+ operation<void>(cleaned_up)
+ ) == 9
+ );
+ BOOST_CHECK(executed && cleaned_up);
+ }
+
+ // Test returning void with one cleanup operation
+ {
+ bool executed = false, cleaned_up = false;
+ execute_all(
+ operation<void>(executed),
+ operation<void>(cleaned_up)
+ );
+ BOOST_CHECK(executed && cleaned_up);
+ }
+
+ // Test returning an int with two cleanup operations
+ {
+ bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
+ BOOST_CHECK(
+ execute_all(
+ operation<int>(9, executed),
+ operation<void>(cleaned_up1),
+ operation<void>(cleaned_up2)
+ ) == 9
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
+ }
+
+ // Test returning void with two cleanup operations
+ {
+ bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
+ execute_all(
+ operation<void>(executed),
+ operation<void>(cleaned_up1),
+ operation<void>(cleaned_up2)
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
+ }
+
+ // Test returning an int with three cleanup operations
+ {
+ bool executed = false, cleaned_up1 = false,
+ cleaned_up2 = false, cleaned_up3 = false;
+ BOOST_CHECK(
+ execute_all(
+ operation<int>(9, executed),
+ operation<void>(cleaned_up1),
+ operation<void>(cleaned_up2),
+ operation<void>(cleaned_up3)
+ ) == 9
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
+ }
+
+ // Test returning void with three cleanup operations
+ {
+ bool executed = false, cleaned_up1 = false,
+ cleaned_up2 = false, cleaned_up3 = false;
+ execute_all(
+ operation<void>(executed),
+ operation<void>(cleaned_up1),
+ operation<void>(cleaned_up2),
+ operation<void>(cleaned_up3)
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
+ }
+}
+
+void operation_throws_test()
+{
+ // Test primary operation throwing with no cleanup operations
+ {
+ bool executed = false;
+ BOOST_CHECK_THROW(
+ execute_all(thrower<0>(executed)),
+ error<0>
+ );
+ BOOST_CHECK(executed);
+ }
+
+ // Test primary operation throwing with one cleanup operation
+ {
+ bool executed = false, cleaned_up = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ thrower<0>(executed),
+ operation<void>(cleaned_up)
+ ),
+ error<0>
+ );
+ BOOST_CHECK(executed && cleaned_up);
+ }
+
+ // Test primary operation throwing with two cleanup operations
+ {
+ bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ thrower<0>(executed),
+ operation<void>(cleaned_up1),
+ operation<void>(cleaned_up2)
+ ),
+ error<0>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
+ }
+
+ // Test primary operation throwing with three cleanup operations
+ {
+ bool executed = false, cleaned_up1 = false,
+ cleaned_up2 = false, cleaned_up3 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ thrower<0>(executed),
+ operation<void>(cleaned_up1),
+ operation<void>(cleaned_up2),
+ operation<void>(cleaned_up3)
+ ),
+ error<0>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
+ }
+}
+
+void cleanup_throws_test()
+{
+ // Test single cleanup operation that throws
+ {
+ bool executed = false, cleaned_up = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ operation<void>(executed),
+ thrower<1>(cleaned_up)
+ ),
+ error<1>
+ );
+ BOOST_CHECK(executed && cleaned_up);
+ }
+
+ // Test fist of two cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ operation<void>(executed),
+ thrower<1>(cleaned_up1),
+ operation<void>(cleaned_up2)
+ ),
+ error<1>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
+ }
+
+ // Test second of two cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ operation<void>(executed),
+ operation<void>(cleaned_up1),
+ thrower<2>(cleaned_up2)
+ ),
+ error<2>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
+ }
+
+ // Test first of three cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false,
+ cleaned_up2 = false, cleaned_up3 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ operation<void>(executed),
+ thrower<1>(cleaned_up1),
+ operation<void>(cleaned_up2),
+ operation<void>(cleaned_up3)
+ ),
+ error<1>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
+ }
+
+ // Test second of three cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false,
+ cleaned_up2 = false, cleaned_up3 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ operation<void>(executed),
+ operation<void>(cleaned_up1),
+ thrower<2>(cleaned_up2),
+ operation<void>(cleaned_up3)
+ ),
+ error<2>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
+ }
+
+ // Test third of three cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false,
+ cleaned_up2 = false, cleaned_up3 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ operation<void>(executed),
+ operation<void>(cleaned_up1),
+ operation<void>(cleaned_up2),
+ thrower<3>(cleaned_up3)
+ ),
+ error<3>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
+ }
+}
+
+void multiple_exceptions_test()
+{
+ // Test primary operation and cleanup operation throwing
+ {
+ bool executed = false, cleaned_up = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ thrower<0>(executed),
+ thrower<1>(cleaned_up)
+ ),
+ error<0>
+ );
+ BOOST_CHECK(executed && cleaned_up);
+ }
+
+ // Test primary operation and first of two cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ thrower<0>(executed),
+ thrower<1>(cleaned_up1),
+ operation<void>(cleaned_up2)
+ ),
+ error<0>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
+ }
+
+ // Test primary operation and second of two cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ thrower<0>(executed),
+ operation<void>(cleaned_up1),
+ thrower<2>(cleaned_up2)
+ ),
+ error<0>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
+ }
+
+ // Test two cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ operation<void>(executed),
+ thrower<1>(cleaned_up1),
+ thrower<2>(cleaned_up2)
+ ),
+ error<1>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
+ }
+
+ // Test primary operation and first of three cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false,
+ cleaned_up2 = false, cleaned_up3 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ thrower<0>(executed),
+ thrower<1>(cleaned_up1),
+ operation<void>(cleaned_up2),
+ operation<void>(cleaned_up3)
+ ),
+ error<0>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
+ }
+
+ // Test primary operation and second of three cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false,
+ cleaned_up2 = false, cleaned_up3 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ thrower<0>(executed),
+ operation<void>(cleaned_up1),
+ thrower<2>(cleaned_up2),
+ operation<void>(cleaned_up3)
+ ),
+ error<0>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
+ }
+
+ // Test primary operation and third of three cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false,
+ cleaned_up2 = false, cleaned_up3 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ thrower<0>(executed),
+ operation<void>(cleaned_up1),
+ operation<void>(cleaned_up2),
+ thrower<3>(cleaned_up3)
+ ),
+ error<0>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
+ }
+
+ // Test first and second of three cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false,
+ cleaned_up2 = false, cleaned_up3 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ operation<void>(executed),
+ thrower<1>(cleaned_up1),
+ thrower<2>(cleaned_up2),
+ operation<void>(cleaned_up3)
+ ),
+ error<1>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
+ }
+
+ // Test first and third of three cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false,
+ cleaned_up2 = false, cleaned_up3 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ operation<void>(executed),
+ thrower<1>(cleaned_up1),
+ operation<void>(cleaned_up2),
+ thrower<3>(cleaned_up3)
+ ),
+ error<1>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
+ }
+
+ // Test second and third of three cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false,
+ cleaned_up2 = false, cleaned_up3 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ operation<void>(executed),
+ operation<void>(cleaned_up1),
+ thrower<2>(cleaned_up2),
+ thrower<3>(cleaned_up3)
+ ),
+ error<2>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
+ }
+
+ // Test three cleanup operations throwing
+ {
+ bool executed = false, cleaned_up1 = false,
+ cleaned_up2 = false, cleaned_up3 = false;
+ BOOST_CHECK_THROW(
+ execute_all(
+ operation<void>(executed),
+ thrower<1>(cleaned_up1),
+ thrower<2>(cleaned_up2),
+ thrower<3>(cleaned_up3)
+ ),
+ error<1>
+ );
+ BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
+ }
+}
+
+#define ARRAY_SIZE(ar) (sizeof(ar) / sizeof(ar[0]))
+
+void foreach_test()
+{
+ // Test case where neither of two operations throws
+ {
+ int count = 0;
+ int seq[] = {-1, -1};
+ BOOST_CHECK_NO_THROW(
+ execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count))
+ );
+ BOOST_CHECK(count == ARRAY_SIZE(seq));
+ }
+
+ // Test case where first of two operations throws
+ {
+ int count = 0;
+ int seq[] = {0, -1};
+ BOOST_CHECK_THROW(
+ execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
+ error<0>
+ );
+ BOOST_CHECK(count == ARRAY_SIZE(seq));
+ }
+
+ // Test case where second of two operations throws
+ {
+ int count = 0;
+ int seq[] = {-1, 1};
+ BOOST_CHECK_THROW(
+ execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
+ error<1>
+ );
+ BOOST_CHECK(count == ARRAY_SIZE(seq));
+ }
+
+ // Test case where both of two operations throw
+ {
+ int count = 0;
+ int seq[] = {0, 1};
+ BOOST_CHECK_THROW(
+ execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
+ error<0>
+ );
+ BOOST_CHECK(count == ARRAY_SIZE(seq));
+ }
+
+ // Test case where none of three operations throws
+ {
+ int count = 0;
+ int seq[] = {-1, -1, -1};
+ BOOST_CHECK_NO_THROW(
+ execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count))
+ );
+ BOOST_CHECK(count == ARRAY_SIZE(seq));
+ }
+
+ // Test case where first of three operations throw
+ {
+ int count = 0;
+ int seq[] = {0, -1, -1};
+ BOOST_CHECK_THROW(
+ execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
+ error<0>
+ );
+ BOOST_CHECK(count == ARRAY_SIZE(seq));
+ }
+
+ // Test case where second of three operations throw
+ {
+ int count = 0;
+ int seq[] = {-1, 1, -1};
+ BOOST_CHECK_THROW(
+ execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
+ error<1>
+ );
+ BOOST_CHECK(count == ARRAY_SIZE(seq));
+ }
+
+ // Test case where third of three operations throw
+ {
+ int count = 0;
+ int seq[] = {-1, -1, 2};
+ BOOST_CHECK_THROW(
+ execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
+ error<2>
+ );
+ BOOST_CHECK(count == ARRAY_SIZE(seq));
+ }
+
+ // Test case where first and second of three operations throw
+ {
+ int count = 0;
+ int seq[] = {0, 1, -1};
+ BOOST_CHECK_THROW(
+ execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
+ error<0>
+ );
+ BOOST_CHECK(count == ARRAY_SIZE(seq));
+ }
+
+ // Test case where first and third of three operations throw
+ {
+ int count = 0;
+ int seq[] = {0, -1, 2};
+ BOOST_CHECK_THROW(
+ execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
+ error<0>
+ );
+ BOOST_CHECK(count == ARRAY_SIZE(seq));
+ }
+
+ // Test case where second and third of three operations throw
+ {
+ int count = 0;
+ int seq[] = {-1, 1, 2};
+ BOOST_CHECK_THROW(
+ execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
+ error<1>
+ );
+ BOOST_CHECK(count == ARRAY_SIZE(seq));
+ }
+
+ // Test case where three of three operations throw
+ {
+ int count = 0;
+ int seq[] = {0, 1, 2};
+ BOOST_CHECK_THROW(
+ execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
+ error<0>
+ );
+ BOOST_CHECK(count == ARRAY_SIZE(seq));
+ }
+}
+
+test_suite* init_unit_test_suite(int, char* [])
+{
+ test_suite* test = BOOST_TEST_SUITE("execute test");
+ test->add(BOOST_TEST_CASE(&success_test));
+ test->add(BOOST_TEST_CASE(&operation_throws_test));
+ test->add(BOOST_TEST_CASE(&cleanup_throws_test));
+ test->add(BOOST_TEST_CASE(&multiple_exceptions_test));
+ test->add(BOOST_TEST_CASE(&foreach_test));
+ return test;
+}

Modified: trunk/libs/iostreams/test/filtering_stream_test.cpp
==============================================================================
--- trunk/libs/iostreams/test/filtering_stream_test.cpp (original)
+++ trunk/libs/iostreams/test/filtering_stream_test.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -8,17 +8,13 @@
 #include "read_input_test.hpp"
 #include "read_bidir_test.hpp"
 #include "read_seekable_test.hpp"
-#include "read_input_seq_test.hpp"
 #include "read_bidir_streambuf_test.hpp"
-#include "read_seekable_seq_test.hpp"
 #include "read_input_istream_test.hpp"
 #include "write_output_test.hpp"
 #include "write_bidir_test.hpp"
 #include "write_seekable_test.hpp"
 #include "write_output_iterator_test.hpp"
-#include "write_output_seq_test.hpp"
 #include "write_bidir_streambuf_test.hpp"
-#include "write_seekable_seq_test.hpp"
 #include "write_output_ostream_test.hpp"
 #include "read_input_filter_test.hpp"
 #include "read_bidir_filter_test.hpp"
@@ -31,21 +27,17 @@
 
 test_suite* init_unit_test_suite(int, char* [])
 {
- test_suite* test = BOOST_TEST_SUITE("filtering_streambuf test");
+ test_suite* test = BOOST_TEST_SUITE("filtering_stream test");
     test->add(BOOST_TEST_CASE(&read_input_test));
     test->add(BOOST_TEST_CASE(&read_bidirectional_test));
     test->add(BOOST_TEST_CASE(&read_seekable_test));
- test->add(BOOST_TEST_CASE(&read_input_sequence_test));
     test->add(BOOST_TEST_CASE(&read_bidirectional_streambuf_test));
- test->add(BOOST_TEST_CASE(&read_seekable_sequence_test));
     test->add(BOOST_TEST_CASE(&read_input_istream_test));
     test->add(BOOST_TEST_CASE(&write_output_test));
     test->add(BOOST_TEST_CASE(&write_bidirectional_test));
     test->add(BOOST_TEST_CASE(&write_seekable_test));
     test->add(BOOST_TEST_CASE(&write_output_iterator_test));
- test->add(BOOST_TEST_CASE(&write_output_sequence_test));
     test->add(BOOST_TEST_CASE(&write_bidirectional_streambuf_test));
- test->add(BOOST_TEST_CASE(&write_seekable_sequence_test));
     test->add(BOOST_TEST_CASE(&write_output_ostream_test));
     test->add(BOOST_TEST_CASE(&read_input_filter_test));
     test->add(BOOST_TEST_CASE(&read_bidirectional_filter_test));

Modified: trunk/libs/iostreams/test/offset_test.cpp
==============================================================================
--- trunk/libs/iostreams/test/offset_test.cpp (original)
+++ trunk/libs/iostreams/test/offset_test.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -15,7 +15,6 @@
 #include <boost/iostreams/device/null.hpp>
 #include <boost/iostreams/filtering_stream.hpp>
 #include <boost/iostreams/offset.hpp>
-#include <boost/range/iterator_range.hpp>
 #include <boost/test/test_tools.hpp>
 #include <boost/test/unit_test.hpp>
 #include "detail/constants.hpp"

Added: trunk/libs/iostreams/test/operation_sequence_test.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/iostreams/test/operation_sequence_test.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -0,0 +1,268 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.(See accompanying
+ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
+ *
+ * See http://www.boost.org/libs/iostreams for documentation.
+ *
+ * Verifies that the close() member functions of filters and devices
+ * are called with the correct arguments in the correct order when
+ * they are combined using chains or adapters.
+ *
+ * File: libs/iostreams/test/operation_sequence_test.cpp
+ * Date: Mon Dec 10 18:58:19 MST 2007
+ * Copyright: 2007 CodeRage
+ * Author: Jonathan Turkanis
+ */
+
+#include <stdexcept>
+#include <boost/test/test_tools.hpp>
+#include <boost/test/unit_test.hpp>
+#include "./detail/operation_sequence.hpp"
+
+using namespace std;
+using namespace boost;
+using namespace boost::iostreams::test;
+using boost::unit_test::test_suite;
+
+ // Infrastructure for checking that operations are
+ // executed in the correct order
+
+void operation_sequence_test()
+{
+ // Test creating a duplicate operation
+ {
+ operation_sequence seq;
+ operation op = seq.new_operation(1);
+ BOOST_CHECK_THROW(seq.new_operation(1), runtime_error);
+ }
+
+ // Test reusing an operation id after first operation is destroyed
+ {
+ operation_sequence seq;
+ seq.new_operation(1);
+ BOOST_CHECK_NO_THROW(seq.new_operation(1));
+ }
+
+ // Test creating operations with illegal error codes
+ {
+ operation_sequence seq;
+ BOOST_CHECK_THROW(seq.new_operation(1, -100), runtime_error);
+ BOOST_CHECK_THROW(
+ seq.new_operation(1, BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR + 1),
+ runtime_error
+ );
+ }
+
+ // Test two successful operations executed out of order
+ {
+ operation_sequence seq;
+ operation op1 = seq.new_operation(1);
+ operation op2 = seq.new_operation(2);
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_NO_THROW(op2.execute());
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_NO_THROW(op1.execute());
+ BOOST_CHECK(seq.is_failure());
+ }
+
+ // Test executing an operation twice without resetting the sequence
+ {
+ operation_sequence seq;
+ operation op = seq.new_operation(1);
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_NO_THROW(op.execute());
+ BOOST_CHECK(seq.is_success());
+ BOOST_CHECK_NO_THROW(op.execute());
+ BOOST_CHECK(seq.is_failure());
+ }
+
+ // Test creating an operation after operation execution has commenced
+ {
+ operation_sequence seq;
+ operation op1 = seq.new_operation(1);
+ operation op2 = seq.new_operation(2);
+ operation op3;
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_NO_THROW(op1.execute());
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_THROW(op3 = seq.new_operation(3), runtime_error);
+ BOOST_CHECK_NO_THROW(op2.execute());
+ BOOST_CHECK(seq.is_success());
+ }
+
+ // Test three successful operations with consecutive ids, executed in order
+ {
+ operation_sequence seq;
+ operation op1 = seq.new_operation(1);
+ operation op2 = seq.new_operation(2);
+ operation op3 = seq.new_operation(3);
+
+ // First pass
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op1.execute();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op2.execute();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op3.execute();
+ BOOST_CHECK(seq.is_success());
+
+ // Second pass
+ seq.reset();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op1.execute();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op2.execute();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op3.execute();
+ BOOST_CHECK(seq.is_success());
+ }
+
+ // Test three successful operations with non-consecutive ids,
+ // executed in order
+ {
+ operation_sequence seq;
+ operation op2 = seq.new_operation(2);
+ operation op3 = seq.new_operation(101);
+ operation op1 = seq.new_operation(-43);
+
+ // First pass
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op1.execute();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op2.execute();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op3.execute();
+ BOOST_CHECK(seq.is_success());
+
+ // Second pass
+ seq.reset();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op1.execute();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op2.execute();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op3.execute();
+ BOOST_CHECK(seq.is_success());
+ }
+
+ // Test checking for success after one of three operations
+ // has been destroyed
+ {
+ operation_sequence seq;
+ operation op1 = seq.new_operation(1);
+ operation op3 = seq.new_operation(3);
+
+ {
+ operation op2 = seq.new_operation(2);
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op1.execute();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op2.execute();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op3.execute();
+ }
+ BOOST_CHECK(seq.is_success());
+ }
+
+ // Test executing an operation sequence twice, with one of the
+ // operations replaced with a new operation with the same id
+ // in the second pass
+ {
+ operation_sequence seq;
+ operation op1 = seq.new_operation(1);
+ operation op3 = seq.new_operation(3);
+
+ // First pass
+ {
+ operation op2 = seq.new_operation(2);
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op1.execute();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op2.execute();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op3.execute();
+ BOOST_CHECK(seq.is_success());
+ }
+
+ // Second pass
+ seq.reset();
+ {
+ operation op2 = seq.new_operation(2);
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op1.execute();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op2.execute();
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ op3.execute();
+ BOOST_CHECK(seq.is_success());
+ }
+ }
+
+ // Test three operations executed in order, the first of which throws
+ {
+ operation_sequence seq;
+ operation op1 = seq.new_operation(1, 1);
+ operation op2 = seq.new_operation(2);
+ operation op3 = seq.new_operation(3);
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_THROW(op1.execute(), operation_error<1>);
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_NO_THROW(op2.execute());
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_NO_THROW(op3.execute());
+ BOOST_CHECK(seq.is_success());
+ }
+
+ // Test three operations executed in order, the second of which throws
+ {
+ operation_sequence seq;
+ operation op1 = seq.new_operation(1);
+ operation op2 = seq.new_operation(2, 2);
+ operation op3 = seq.new_operation(3);
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_NO_THROW(op1.execute());
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_THROW(op2.execute(), operation_error<2>);
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_NO_THROW(op3.execute());
+ BOOST_CHECK(seq.is_success());
+ }
+
+ // Test three operations executed in order, the third of which throws
+ {
+ operation_sequence seq;
+ operation op1 = seq.new_operation(1);
+ operation op2 = seq.new_operation(2);
+ operation op3 = seq.new_operation(3, 3);
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_NO_THROW(op1.execute());
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_NO_THROW(op2.execute());
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_THROW(op3.execute(), operation_error<3>);
+ BOOST_CHECK(seq.is_success());
+ }
+
+ // Test three operations executed in order, the first and
+ // third of which throw
+ {
+ operation_sequence seq;
+ operation op1 = seq.new_operation(1, 1);
+ operation op2 = seq.new_operation(2);
+ operation op3 = seq.new_operation(3, 3);
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_THROW(op1.execute(), operation_error<1>);
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_NO_THROW(op2.execute());
+ BOOST_CHECK(!seq.is_failure() && !seq.is_success());
+ BOOST_CHECK_THROW(op3.execute(), operation_error<3>);
+ BOOST_CHECK(seq.is_success());
+ }
+}
+
+test_suite* init_unit_test_suite(int, char* [])
+{
+ test_suite* test = BOOST_TEST_SUITE("execute test");
+ test->add(BOOST_TEST_CASE(&operation_sequence_test));
+ return test;
+}

Modified: trunk/libs/iostreams/test/seek_test.hpp
==============================================================================
--- trunk/libs/iostreams/test/seek_test.hpp (original)
+++ trunk/libs/iostreams/test/seek_test.hpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -7,22 +7,29 @@
 #ifndef BOOST_IOSTREAMS_TEST_SEEK_HPP_INCLUDED
 #define BOOST_IOSTREAMS_TEST_SEEK_HPP_INCLUDED
 
+
+#include <boost/config.hpp> // BOOST_MSVC, make sure size_t is in std.
+#include <cstddef> // std::size_t.
 #include <string>
+#include <boost/iostreams/device/array.hpp>
 #include <boost/iostreams/filtering_stream.hpp>
-#include <boost/range/iterator_range.hpp>
 #include <boost/test/test_tools.hpp>
-#include "detail/verification.hpp"
+#include "../example/container_device.hpp" // We use container_device instead
+#include "detail/verification.hpp" // of make_iterator_range to
+ // reduce dependence on Boost.Range
 
 void seek_test()
 {
     using namespace std;
     using namespace boost;
     using namespace boost::iostreams;
+ using namespace boost::iostreams::example;
     using namespace boost::iostreams::test;
 
     {
         string test(data_reps * data_length(), '\0');
- filtering_stream<seekable> io(make_iterator_range(test));
+ filtering_stream<seekable> io;
+ io.push(container_device<string>(test));
         BOOST_CHECK_MESSAGE(
             test_seekable_in_chars(io),
             "failed seeking within a filtering_stream<seekable>, in chars"
@@ -31,7 +38,8 @@
 
     {
         string test(data_reps * data_length(), '\0');
- filtering_stream<seekable> io(make_iterator_range(test));
+ filtering_stream<seekable> io;
+ io.push(container_device<string>(test));
         BOOST_CHECK_MESSAGE(
             test_seekable_in_chunks(io),
             "failed seeking within a filtering_stream<seekable>, in chunks"

Modified: trunk/libs/iostreams/test/seekable_filter_test.cpp
==============================================================================
--- trunk/libs/iostreams/test/seekable_filter_test.cpp (original)
+++ trunk/libs/iostreams/test/seekable_filter_test.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -10,16 +10,18 @@
 #include <boost/iostreams/device/array.hpp>
 #include <boost/iostreams/device/array.hpp>
 #include <boost/iostreams/filtering_stream.hpp>
-#include <boost/range/iterator_range.hpp>
 #include <boost/test/test_tools.hpp>
 #include <boost/test/unit_test.hpp>
-#include "detail/filters.hpp"
-#include "detail/temp_file.hpp"
-#include "detail/verification.hpp"
+#include "../example/container_device.hpp" // We use container_device instead
+#include "detail/filters.hpp" // of make_iterator_range to
+#include "detail/temp_file.hpp" // reduce dependence on Boost.Range
+#include "detail/verification.hpp"
+
 
 using namespace std;
 using namespace boost;
 using namespace boost::iostreams;
+using namespace boost::iostreams::example;
 using namespace boost::iostreams::test;
 using boost::unit_test::test_suite;
 
@@ -35,7 +37,7 @@
         vector<char> test(data_reps * data_length(), '0');
         filtering_stream<seekable> io;
         io.push(identity_seekable_filter());
- io.push(make_iterator_range(test));
+ io.push(container_device< vector<char> >(test));
         io.exceptions(BOOST_IOS::failbit | BOOST_IOS::badbit);
         BOOST_CHECK_MESSAGE(
             test_seekable_in_chars(io),
@@ -47,7 +49,7 @@
         vector<char> test(data_reps * data_length(), '0');
         filtering_stream<seekable> io;
         io.push(identity_seekable_filter());
- io.push(make_iterator_range(test));
+ io.push(container_device< vector<char> >(test));
         io.exceptions(BOOST_IOS::failbit | BOOST_IOS::badbit);
         BOOST_CHECK_MESSAGE(
             test_seekable_in_chunks(io),
@@ -59,7 +61,7 @@
         vector<char> test(data_reps * data_length(), '0');
         filtering_stream<seekable> io;
         io.push(identity_seekable_multichar_filter());
- io.push(make_iterator_range(test));
+ io.push(container_device< vector<char> >(test));
         io.exceptions(BOOST_IOS::failbit | BOOST_IOS::badbit);
         BOOST_CHECK_MESSAGE(
             test_seekable_in_chars(io),
@@ -71,7 +73,7 @@
         vector<char> test(data_reps * data_length(), '0');
         filtering_stream<seekable> io;
         io.push(identity_seekable_multichar_filter());
- io.push(make_iterator_range(test));
+ io.push(container_device< vector<char> >(test));
         io.exceptions(BOOST_IOS::failbit | BOOST_IOS::badbit);
         BOOST_CHECK_MESSAGE(
             test_seekable_in_chunks(io),

Added: trunk/libs/iostreams/test/sequence_test.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/iostreams/test/sequence_test.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -0,0 +1,23 @@
+// (C) Copyright Jonathan Turkanis 2007
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
+
+// See http://www.boost.org/libs/iostreams for documentation.
+
+#include <boost/test/unit_test.hpp>
+#include "read_input_seq_test.hpp"
+#include "read_seekable_seq_test.hpp"
+#include "write_output_seq_test.hpp"
+#include "write_seekable_seq_test.hpp"
+
+using boost::unit_test::test_suite;
+
+test_suite* init_unit_test_suite(int, char* [])
+{
+ test_suite* test = BOOST_TEST_SUITE("sequence test");
+ test->add(BOOST_TEST_CASE(&read_input_sequence_test));
+ test->add(BOOST_TEST_CASE(&read_seekable_sequence_test));
+ test->add(BOOST_TEST_CASE(&write_output_sequence_test));
+ test->add(BOOST_TEST_CASE(&write_seekable_sequence_test));
+ return test;
+}

Modified: trunk/libs/iostreams/test/wide_stream_test.cpp
==============================================================================
--- trunk/libs/iostreams/test/wide_stream_test.cpp (original)
+++ trunk/libs/iostreams/test/wide_stream_test.cpp 2007-12-14 14:30:07 EST (Fri, 14 Dec 2007)
@@ -13,11 +13,11 @@
 #include <vector>
 #include <boost/iostreams/device/back_inserter.hpp>
 #include <boost/iostreams/filtering_stream.hpp>
-#include <boost/range/iterator_range.hpp>
-#include "detail/filters.hpp"
 #include <boost/test/test_tools.hpp>
 #include <boost/test/unit_test.hpp>
-#include "detail/sequence.hpp"
+#include "../example/container_device.hpp" // We use container_device instead
+#include "detail/filters.hpp" // of make_iterator_range to
+#include "detail/sequence.hpp" // reduce dependence on Boost.Range
 #include "detail/temp_file.hpp"
 #include "detail/verification.hpp"
 
@@ -28,12 +28,14 @@
     using namespace std;
     using namespace boost;
     using namespace boost::iostreams;
+ using namespace boost::iostreams::example;
     using namespace boost::iostreams::test;
 
- test_sequence<wchar_t> seq;
+ test_sequence<wchar_t> seq;
+ container_device< test_sequence<wchar_t> > source(seq);
 
     {
- filtering_wistream first(make_iterator_range(seq), 0);
+ filtering_wistream first(source, 0);
         basic_istringstream<wchar_t> second(
             basic_string<wchar_t>(seq.begin(), seq.end())
         );
@@ -44,7 +46,7 @@
     }
 
     {
- filtering_wistream first(make_iterator_range(seq), 0);
+ filtering_wistream first(source, 0);
         basic_istringstream<wchar_t> second(
             basic_string<wchar_t>(seq.begin(), seq.end())
         );
@@ -55,7 +57,7 @@
     }
 
     {
- filtering_wistream first(make_iterator_range(seq));
+ filtering_wistream first(source);
         basic_istringstream<wchar_t> second(
             basic_string<wchar_t>(seq.begin(), seq.end())
         );
@@ -66,7 +68,7 @@
     }
 
     {
- filtering_wistream first(make_iterator_range(seq));
+ filtering_wistream first(source);
         basic_istringstream<wchar_t> second(
             basic_string<wchar_t>(seq.begin(), seq.end())
         );


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