sl@0: // (C) Copyright Jonathan Turkanis 2003.
sl@0: // Distributed under the Boost Software License, Version 1.0. (See accompanying
sl@0: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
sl@0: 
sl@0: // See http://www.boost.org/libs/iostreams for documentation.
sl@0: 
sl@0: #ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
sl@0: #define BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
sl@0: 
sl@0: #if defined(_MSC_VER) && (_MSC_VER >= 1020)
sl@0: # pragma once
sl@0: #endif
sl@0: 
sl@0: #include <algorithm>                            // for_each.
sl@0: #include <cassert>
sl@0: #include <exception>
sl@0: #include <functional>                           // unary_function.
sl@0: #include <iterator>                             // advance.
sl@0: #include <list>
sl@0: #include <memory>                               // allocator, auto_ptr.
sl@0: #include <typeinfo>
sl@0: #include <stdexcept>                            // logic_error, out_of_range.
sl@0: #include <boost/checked_delete.hpp>
sl@0: #include <boost/config.hpp>                     // BOOST_MSVC, template friends,
sl@0: #include <boost/detail/workaround.hpp>          // BOOST_NESTED_TEMPLATE 
sl@0: #include <boost/iostreams/constants.hpp>
sl@0: #include <boost/iostreams/detail/access_control.hpp>
sl@0: #include <boost/iostreams/detail/char_traits.hpp>
sl@0: #include <boost/iostreams/detail/push.hpp>
sl@0: #include <boost/iostreams/detail/streambuf.hpp> // pubsync.
sl@0: #include <boost/iostreams/detail/wrap_unwrap.hpp>
sl@0: #include <boost/iostreams/device/null.hpp>
sl@0: #include <boost/iostreams/positioning.hpp>
sl@0: #include <boost/iostreams/traits.hpp>           // is_filter.
sl@0: #include <boost/iostreams/stream_buffer.hpp>
sl@0: #include <boost/next_prior.hpp>
sl@0: #include <boost/shared_ptr.hpp>
sl@0: #include <boost/static_assert.hpp>
sl@0: #include <boost/type_traits/is_convertible.hpp>
sl@0: #include <boost/type.hpp>
sl@0: #if BOOST_WORKAROUND(BOOST_MSVC, < 1310)
sl@0: # include <boost/mpl/int.hpp>
sl@0: #endif
sl@0: 
sl@0: // Sometimes type_info objects must be compared by name. Borrowed from
sl@0: // Boost.Python and Boost.Function.
sl@0: #if (defined(__GNUC__) && __GNUC__ >= 3) || \
sl@0:      defined(_AIX) || \
sl@0:     (defined(__sgi) && defined(__host_mips)) || \
sl@0:     (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC)) \
sl@0:     /**/
sl@0: # include <cstring>
sl@0: # define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) \
sl@0:      (std::strcmp((X).name(),(Y).name()) == 0)
sl@0: #else
sl@0: # define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
sl@0: #endif
sl@0: 
sl@0: // Deprecated
sl@0: #define BOOST_IOSTREAMS_COMPONENT_TYPE(chain, index) \
sl@0:     chain.component_type( index ) \
sl@0:     /**/
sl@0: 
sl@0: #if !BOOST_WORKAROUND(BOOST_MSVC, < 1310)
sl@0: # define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \
sl@0:     chain.component< target >( index ) \
sl@0:     /**/
sl@0: #else
sl@0: # define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \
sl@0:     chain.component( index, ::boost::type< target >() ) \
sl@0:     /**/
sl@0: #endif
sl@0: 
sl@0: namespace boost { namespace iostreams {
sl@0: 
sl@0: //--------------Definition of chain and wchain--------------------------------//
sl@0: 
sl@0: namespace detail {
sl@0: 
sl@0: template<typename Chain> class chain_client;
sl@0: 
sl@0: //
sl@0: // Concept name: Chain.
sl@0: // Description: Represents a chain of stream buffers which provides access
sl@0: //     to the first buffer in the chain and send notifications when the
sl@0: //     streambufs are added to or removed from chain.
sl@0: // Refines: Closable device with mode equal to typename Chain::mode.
sl@0: // Models: chain, converting_chain.
sl@0: // Example:
sl@0: //
sl@0: //    class chain {
sl@0: //    public:
sl@0: //        typedef xxx chain_type;
sl@0: //        typedef xxx client_type;
sl@0: //        typedef xxx mode;
sl@0: //        bool is_complete() const;                  // Ready for i/o.
sl@0: //        template<typename T>
sl@0: //        void push( const T& t,                     // Adds a stream buffer to
sl@0: //                   streamsize,                     // chain, based on t, with
sl@0: //                   streamsize );                   // given buffer and putback
sl@0: //                                                   // buffer sizes. Pass -1 to
sl@0: //                                                   // request default size.
sl@0: //    protected:
sl@0: //        void register_client(client_type* client); // Associate client.
sl@0: //        void notify();                             // Notify client.
sl@0: //    };
sl@0: //
sl@0: 
sl@0: //
sl@0: // Description: Represents a chain of filters with an optional device at the
sl@0: //      end.
sl@0: // Template parameters:
sl@0: //      Self - A class deriving from the current instantiation of this template.
sl@0: //          This is an example of the Curiously Recurring Template Pattern.
sl@0: //      Ch - The character type.
sl@0: //      Tr - The character traits type.
sl@0: //      Alloc - The allocator type.
sl@0: //      Mode - A mode tag.
sl@0: //
sl@0: template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
sl@0: class chain_base {
sl@0: public:
sl@0:     typedef Ch                                     char_type;
sl@0:     BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr)
sl@0:     typedef Alloc                                  allocator_type;
sl@0:     typedef Mode                                   mode;
sl@0:     struct category
sl@0:         : Mode,
sl@0:           device_tag
sl@0:         { };
sl@0:     typedef chain_client<Self>                     client_type;
sl@0:     friend class chain_client<Self>;
sl@0: private:
sl@0:     typedef linked_streambuf<Ch>                   streambuf_type;
sl@0:     typedef std::list<streambuf_type*>             list_type;
sl@0:     typedef chain_base<Self, Ch, Tr, Alloc, Mode>  my_type;
sl@0: protected:
sl@0:     chain_base() : pimpl_(new chain_impl) { }
sl@0:     chain_base(const chain_base& rhs): pimpl_(rhs.pimpl_) { }
sl@0: public:
sl@0: 
sl@0:     //----------Buffer sizing-------------------------------------------------//
sl@0: 
sl@0:     // Sets the size of the buffer created for the devices to be added to this
sl@0:     // chain. Does not affect the size of the buffer for devices already
sl@0:     // added.
sl@0:     void set_device_buffer_size(int n) { pimpl_->device_buffer_size_ = n; }
sl@0: 
sl@0:     // Sets the size of the buffer created for the filters to be added
sl@0:     // to this chain. Does not affect the size of the buffer for filters already
sl@0:     // added.
sl@0:     void set_filter_buffer_size(int n) { pimpl_->filter_buffer_size_ = n; }
sl@0: 
sl@0:     // Sets the size of the putback buffer for filters and devices to be added
sl@0:     // to this chain. Does not affect the size of the buffer for filters or
sl@0:     // devices already added.
sl@0:     void set_pback_size(int n) { pimpl_->pback_size_ = n; }
sl@0: 
sl@0:     //----------Device interface----------------------------------------------//
sl@0: 
sl@0:     std::streamsize read(char_type* s, std::streamsize n);
sl@0:     std::streamsize write(const char_type* s, std::streamsize n);
sl@0:     std::streampos seek(stream_offset off, BOOST_IOS::seekdir way);
sl@0: 
sl@0:     //----------Direct component access---------------------------------------//
sl@0: 
sl@0:     const std::type_info& component_type(int n) const
sl@0:     {
sl@0:         if (static_cast<size_type>(n) >= size())
sl@0:             throw std::out_of_range("bad chain offset");
sl@0:         return (*boost::next(list().begin(), n))->component_type();
sl@0:     }
sl@0: 
sl@0: #if !BOOST_WORKAROUND(BOOST_MSVC, < 1310)
sl@0:     // Deprecated.
sl@0:     template<int N>
sl@0:     const std::type_info& component_type() const { return component_type(N); }
sl@0: 
sl@0:     template<typename T>
sl@0:     T* component(int n) const { return component(n, boost::type<T>()); }
sl@0: 
sl@0:     // Deprecated.
sl@0:     template<int N, typename T> 
sl@0:     T* component() const { return component<T>(N); }
sl@0: #endif
sl@0: 
sl@0: #if !BOOST_WORKAROUND(BOOST_MSVC, < 1310)
sl@0:     private:
sl@0: #endif
sl@0:     template<typename T>
sl@0:     T* component(int n, boost::type<T>) const
sl@0:     {
sl@0:         if (static_cast<size_type>(n) >= size())
sl@0:             throw std::out_of_range("bad chain offset");
sl@0:         streambuf_type* link = *boost::next(list().begin(), n);
sl@0:         if (BOOST_IOSTREAMS_COMPARE_TYPE_ID(link->component_type(), typeid(T)))
sl@0:             return static_cast<T*>(link->component_impl());
sl@0:         else
sl@0:             return 0;
sl@0:     }
sl@0: public:
sl@0: 
sl@0:     //----------Container-like interface--------------------------------------//
sl@0: 
sl@0:     typedef typename list_type::size_type size_type;
sl@0:     streambuf_type& front() { return *list().front(); }
sl@0:     BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
sl@0:     void pop();
sl@0:     bool empty() const { return list().empty(); }
sl@0:     size_type size() const { return list().size(); }
sl@0:     void reset();
sl@0: 
sl@0:     //----------Additional i/o functions--------------------------------------//
sl@0: 
sl@0:     // Returns true if this chain is non-empty and its final link
sl@0:     // is a source or sink, i.e., if it is ready to perform i/o.
sl@0:     bool is_complete() const;
sl@0:     bool auto_close() const;
sl@0:     void set_auto_close(bool close);
sl@0:     bool sync() { return front().BOOST_IOSTREAMS_PUBSYNC() != -1; }
sl@0:     bool strict_sync();
sl@0: private:
sl@0:     template<typename T>
sl@0:     void push_impl(const T& t, int buffer_size = -1, int pback_size = -1)
sl@0:     {
sl@0:         typedef typename iostreams::category_of<T>::type  category;
sl@0:         typedef typename unwrap_ios<T>::type              policy_type;
sl@0:         typedef stream_buffer<
sl@0:                     policy_type,
sl@0:                     BOOST_IOSTREAMS_CHAR_TRAITS(char_type),
sl@0:                     Alloc, Mode
sl@0:                 >                                         facade_type;
sl@0:         BOOST_STATIC_ASSERT((is_convertible<category, Mode>::value));
sl@0:         if (is_complete())
sl@0:             throw std::logic_error("chain complete");
sl@0:         streambuf_type* prev = !empty() ? list().back() : 0;
sl@0:         buffer_size =
sl@0:             buffer_size != -1 ?
sl@0:                 buffer_size :
sl@0:                 iostreams::optimal_buffer_size(t);
sl@0:         pback_size =
sl@0:             pback_size != -1 ?
sl@0:                 pback_size :
sl@0:                 pimpl_->pback_size_;
sl@0:         std::auto_ptr<facade_type>
sl@0:             buf(new facade_type(t, buffer_size, pback_size));
sl@0:         list().push_back(buf.get());
sl@0:         buf.release();
sl@0:         if (is_device<policy_type>::value)
sl@0:             pimpl_->flags_ |= f_complete | f_open;
sl@0:         if (prev) prev->set_next(list().back());
sl@0:         notify();
sl@0:     }
sl@0: 
sl@0:     list_type& list() { return pimpl_->links_; }
sl@0:     const list_type& list() const { return pimpl_->links_; }
sl@0:     void register_client(client_type* client) { pimpl_->client_ = client; }
sl@0:     void notify() { if (pimpl_->client_) pimpl_->client_->notify(); }
sl@0: 
sl@0:     //----------Nested classes------------------------------------------------//
sl@0: 
sl@0:     static void close(streambuf_type* b, BOOST_IOS::openmode m)
sl@0:     {
sl@0:         if (m & BOOST_IOS::out)
sl@0:             b->BOOST_IOSTREAMS_PUBSYNC();
sl@0:         b->close(m);
sl@0:     }
sl@0: 
sl@0:     static void set_next(streambuf_type* b, streambuf_type* next)
sl@0:     { b->set_next(next); }
sl@0: 
sl@0:     static void set_auto_close(streambuf_type* b, bool close)
sl@0:     { b->set_auto_close(close); }
sl@0: 
sl@0:     struct closer  : public std::unary_function<streambuf_type*, void>  {
sl@0:         closer(BOOST_IOS::openmode m) : mode_(m) { }
sl@0:         void operator() (streambuf_type* b)
sl@0:         {
sl@0:             close(b, mode_);
sl@0:         }
sl@0:         BOOST_IOS::openmode mode_;
sl@0:     };
sl@0:     friend struct closer;
sl@0: 
sl@0:     enum flags {
sl@0:         f_complete = 1,
sl@0:         f_open = 2,
sl@0:         f_auto_close = 4
sl@0:     };
sl@0: 
sl@0:     struct chain_impl {
sl@0:         chain_impl()
sl@0:             : client_(0), device_buffer_size_(default_device_buffer_size),
sl@0:               filter_buffer_size_(default_filter_buffer_size),
sl@0:               pback_size_(default_pback_buffer_size),
sl@0:               flags_(f_auto_close)
sl@0:             { }
sl@0:         ~chain_impl() { try { close(); reset(); } catch (std::exception&) { } }
sl@0:         void close()
sl@0:             {
sl@0:                 if ((flags_ & f_open) != 0) {
sl@0:                     stream_buffer< basic_null_device<Ch, Mode> > null;
sl@0:                     if ((flags_ & f_complete) == 0) {
sl@0:                         null.open(basic_null_device<Ch, Mode>());
sl@0:                         set_next(links_.back(), &null);
sl@0:                     }
sl@0:                     links_.front()->BOOST_IOSTREAMS_PUBSYNC();
sl@0:                     if (is_convertible<Mode, input>::value)
sl@0:                         std::for_each( links_.rbegin(), links_.rend(),
sl@0:                                        closer(BOOST_IOS::in) );
sl@0:                     if (is_convertible<Mode, output>::value)
sl@0:                         std::for_each( links_.begin(), links_.end(),
sl@0:                                        closer(BOOST_IOS::out) );
sl@0:                     flags_ &= ~f_open;
sl@0:                 }
sl@0:             }
sl@0:         void reset()
sl@0:             {
sl@0:                 typedef typename list_type::iterator iterator;
sl@0:                 for ( iterator first = links_.begin(),
sl@0:                                last = links_.end();
sl@0:                       first != last;
sl@0:                       ++first )
sl@0:                 {
sl@0:                     if ( (flags_ & f_complete) == 0 ||
sl@0:                          (flags_ & f_auto_close) == 0 )
sl@0:                     {
sl@0:                         set_auto_close(*first, false);
sl@0:                     }
sl@0:                     streambuf_type* buf = 0;
sl@0:                     std::swap(buf, *first);
sl@0:                     delete buf;
sl@0:                 }
sl@0:                 links_.clear();
sl@0:                 flags_ &= ~f_complete;
sl@0:                 flags_ &= ~f_open;
sl@0:             }
sl@0:         list_type     links_;
sl@0:         client_type*  client_;
sl@0:         int           device_buffer_size_,
sl@0:                       filter_buffer_size_,
sl@0:                       pback_size_;
sl@0:         int           flags_;
sl@0:     };
sl@0:     friend struct chain_impl;
sl@0: 
sl@0:     //----------Member data---------------------------------------------------//
sl@0: 
sl@0: private:
sl@0:     shared_ptr<chain_impl> pimpl_;
sl@0: };
sl@0: 
sl@0: } // End namespace detail.
sl@0: 
sl@0: //
sl@0: // Macro: BOOST_IOSTREAMS_DECL_CHAIN(name, category)
sl@0: // Description: Defines a template derived from chain_base appropriate for a
sl@0: //      particular i/o category. The template has the following parameters:
sl@0: //      Ch - The character type.
sl@0: //      Tr - The character traits type.
sl@0: //      Alloc - The allocator type.
sl@0: // Macro parameters:
sl@0: //      name_ - The name of the template to be defined.
sl@0: //      category_ - The i/o category of the template to be defined.
sl@0: //
sl@0: #define BOOST_IOSTREAMS_DECL_CHAIN(name_, default_char_) \
sl@0:     template< typename Mode, typename Ch = default_char_, \
sl@0:               typename Tr = BOOST_IOSTREAMS_CHAR_TRAITS(Ch), \
sl@0:               typename Alloc = std::allocator<Ch> > \
sl@0:     class name_ : public boost::iostreams::detail::chain_base< \
sl@0:                             name_<Mode, Ch, Tr, Alloc>, \
sl@0:                             Ch, Tr, Alloc, Mode \
sl@0:                          > \
sl@0:     { \
sl@0:     public: \
sl@0:         struct category : device_tag, Mode { }; \
sl@0:         typedef Mode                                   mode; \
sl@0:     private: \
sl@0:         typedef boost::iostreams::detail::chain_base< \
sl@0:                     name_<Mode, Ch, Tr, Alloc>, \
sl@0:                     Ch, Tr, Alloc, Mode \
sl@0:                 >                                      base_type; \
sl@0:     public: \
sl@0:         typedef Ch                                     char_type; \
sl@0:         typedef Tr                                     traits_type; \
sl@0:         typedef typename traits_type::int_type         int_type; \
sl@0:         typedef typename traits_type::off_type         off_type; \
sl@0:         name_() { } \
sl@0:         name_(const name_& rhs) { *this = rhs; } \
sl@0:         name_& operator=(const name_& rhs) \
sl@0:         { base_type::operator=(rhs); return *this; } \
sl@0:     }; \
sl@0:     /**/
sl@0: BOOST_IOSTREAMS_DECL_CHAIN(chain, char)
sl@0: BOOST_IOSTREAMS_DECL_CHAIN(wchain, wchar_t)
sl@0: #undef BOOST_IOSTREAMS_DECL_CHAIN
sl@0: 
sl@0: //--------------Definition of chain_client------------------------------------//
sl@0: 
sl@0: namespace detail {
sl@0: 
sl@0: //
sl@0: // Template name: chain_client
sl@0: // Description: Class whose instances provide access to an underlying chain
sl@0: //      using an interface similar to the chains.
sl@0: // Subclasses: the various stream and stream buffer templates.
sl@0: //
sl@0: template<typename Chain>
sl@0: class chain_client {
sl@0: public:
sl@0:     typedef Chain                             chain_type;
sl@0:     typedef typename chain_type::char_type    char_type;
sl@0:     typedef typename chain_type::traits_type  traits_type;
sl@0:     typedef typename chain_type::size_type    size_type;
sl@0:     typedef typename chain_type::mode         mode;
sl@0: 
sl@0:     chain_client(chain_type* chn = 0) : chain_(chn ) { }
sl@0:     chain_client(chain_client* client) : chain_(client->chain_) { }
sl@0:     virtual ~chain_client() { }
sl@0: 
sl@0:     const std::type_info& component_type(int n) const
sl@0:     { return chain_->component_type(n); }
sl@0: 
sl@0: #if !BOOST_WORKAROUND(BOOST_MSVC, < 1310)
sl@0:     // Deprecated.
sl@0:     template<int N>
sl@0:     const std::type_info& component_type() const
sl@0:     { return chain_->BOOST_NESTED_TEMPLATE component_type<N>(); }
sl@0: 
sl@0:     template<typename T>
sl@0:     T* component(int n) const
sl@0:     { return chain_->BOOST_NESTED_TEMPLATE component<T>(n); }
sl@0: 
sl@0:     // Deprecated.
sl@0:     template<int N, typename T>
sl@0:     T* component() const
sl@0:     { return chain_->BOOST_NESTED_TEMPLATE component<N, T>(); }
sl@0: #else
sl@0:     template<typename T>
sl@0:     T* component(int n, boost::type<T> t) const
sl@0:     { return chain_->component(n, t); }
sl@0: #endif
sl@0: 
sl@0:     bool is_complete() const { return chain_->is_complete(); }
sl@0:     bool auto_close() const { return chain_->auto_close(); }
sl@0:     void set_auto_close(bool close) { chain_->set_auto_close(close); }
sl@0:     bool strict_sync() { return chain_->strict_sync(); }
sl@0:     void set_device_buffer_size(std::streamsize n)
sl@0:         { chain_->set_device_buffer_size(n); }
sl@0:     void set_filter_buffer_size(std::streamsize n)
sl@0:         { chain_->set_filter_buffer_size(n); }
sl@0:     void set_pback_size(std::streamsize n) { chain_->set_pback_size(n); }
sl@0:     BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
sl@0:     void pop() { chain_->pop(); }
sl@0:     bool empty() const { return chain_->empty(); }
sl@0:     size_type size() { return chain_->size(); }
sl@0:     void reset() { chain_->reset(); }
sl@0: 
sl@0:     // Returns a copy of the underlying chain.
sl@0:     chain_type filters() { return *chain_; }
sl@0:     chain_type filters() const { return *chain_; }
sl@0: protected:
sl@0:     template<typename T>
sl@0:     void push_impl(const T& t BOOST_IOSTREAMS_PUSH_PARAMS())
sl@0:     { chain_->push(t BOOST_IOSTREAMS_PUSH_ARGS()); }
sl@0:     chain_type& ref() { return *chain_; }
sl@0:     void set_chain(chain_type* c)
sl@0:     { chain_ = c; chain_->register_client(this); }
sl@0: #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) && \
sl@0:     (!BOOST_WORKAROUND(__BORLANDC__, < 0x600))
sl@0:     template<typename S, typename C, typename T, typename A, typename M>
sl@0:     friend class chain_base;
sl@0: #else
sl@0:     public:
sl@0: #endif
sl@0:     virtual void notify() { }
sl@0: private:
sl@0:     chain_type* chain_;
sl@0: };
sl@0: 
sl@0: //--------------Implementation of chain_base----------------------------------//
sl@0: 
sl@0: template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
sl@0: inline std::streamsize chain_base<Self, Ch, Tr, Alloc, Mode>::read
sl@0:     (char_type* s, std::streamsize n)
sl@0: { return iostreams::read(*list().front(), s, n); }
sl@0: 
sl@0: template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
sl@0: inline std::streamsize chain_base<Self, Ch, Tr, Alloc, Mode>::write
sl@0:     (const char_type* s, std::streamsize n)
sl@0: { return iostreams::write(*list().front(), s, n); }
sl@0: 
sl@0: template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
sl@0: inline std::streampos chain_base<Self, Ch, Tr, Alloc, Mode>::seek
sl@0:     (stream_offset off, BOOST_IOS::seekdir way)
sl@0: { return iostreams::seek(*list().front(), off, way); }
sl@0: 
sl@0: template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
sl@0: void chain_base<Self, Ch, Tr, Alloc, Mode>::reset()
sl@0: {
sl@0:     using namespace std;
sl@0:     pimpl_->close();
sl@0:     pimpl_->reset();
sl@0: }
sl@0: 
sl@0: template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
sl@0: bool chain_base<Self, Ch, Tr, Alloc, Mode>::is_complete() const
sl@0: {
sl@0:     return (pimpl_->flags_ & f_complete) != 0;
sl@0: }
sl@0: 
sl@0: template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
sl@0: bool chain_base<Self, Ch, Tr, Alloc, Mode>::auto_close() const
sl@0: {
sl@0:     return (pimpl_->flags_ & f_auto_close) != 0;
sl@0: }
sl@0: 
sl@0: template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
sl@0: void chain_base<Self, Ch, Tr, Alloc, Mode>::set_auto_close(bool close)
sl@0: {
sl@0:     pimpl_->flags_ =
sl@0:         (pimpl_->flags_ & ~f_auto_close) |
sl@0:         (close ? f_auto_close : 0);
sl@0: }
sl@0: 
sl@0: template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
sl@0: bool chain_base<Self, Ch, Tr, Alloc, Mode>::strict_sync()
sl@0: {
sl@0:     typedef typename list_type::iterator iterator;
sl@0:     bool result = true;
sl@0:     for ( iterator first = list().begin(),
sl@0:                    last = list().end();
sl@0:           first != last;
sl@0:           ++first )
sl@0:     {
sl@0:         bool s = (*first)->strict_sync();
sl@0:         result = result && s;
sl@0:     }
sl@0:     return result;
sl@0: }
sl@0: 
sl@0: template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
sl@0: void chain_base<Self, Ch, Tr, Alloc, Mode>::pop()
sl@0: {
sl@0:     assert(!empty());
sl@0:     if (auto_close())
sl@0:         pimpl_->close();
sl@0:     streambuf_type* buf = 0;
sl@0:     std::swap(buf, list().back());
sl@0:     buf->set_auto_close(false);
sl@0:     buf->set_next(0);
sl@0:     delete buf;
sl@0:     list().pop_back();
sl@0:     pimpl_->flags_ &= ~f_complete;
sl@0:     if (auto_close() || list().empty())
sl@0:         pimpl_->flags_ &= ~f_open;
sl@0: }
sl@0: 
sl@0: } // End namespace detail.
sl@0: 
sl@0: } } // End namespaces iostreams, boost.
sl@0: 
sl@0: #endif // #ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED