1    	// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2    	// (C) Copyright 2003-2007 Jonathan Turkanis
3    	// Distributed under the Boost Software License, Version 1.0. (See accompanying
4    	// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
5    	
6    	// See http://www.boost.org/libs/iostreams for documentation.
7    	
8    	#ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
9    	#define BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
10   	
11   	#if defined(_MSC_VER)
12   	# pragma once
13   	#endif
14   	
15   	#include <boost/assert.hpp>
16   	#include <exception>
17   	#include <iterator>                             // advance.
18   	#include <list>
19   	#include <memory>                               // allocator, auto_ptr or unique_ptr.
20   	#include <typeinfo>
21   	#include <stdexcept>                            // logic_error, out_of_range.
22   	#include <boost/checked_delete.hpp>
23   	#include <boost/config.hpp>                     // BOOST_MSVC, template friends,
24   	#include <boost/detail/workaround.hpp>          // BOOST_NESTED_TEMPLATE 
25   	#include <boost/iostreams/constants.hpp>
26   	#include <boost/iostreams/detail/access_control.hpp>
27   	#include <boost/iostreams/detail/char_traits.hpp>
28   	#include <boost/iostreams/detail/push.hpp>
29   	#include <boost/iostreams/detail/streambuf.hpp> // pubsync.
30   	#include <boost/iostreams/detail/wrap_unwrap.hpp>
31   	#include <boost/iostreams/device/null.hpp>
32   	#include <boost/iostreams/positioning.hpp>
33   	#include <boost/iostreams/traits.hpp>           // is_filter.
34   	#include <boost/iostreams/stream_buffer.hpp>
35   	#include <boost/next_prior.hpp>
36   	#include <boost/shared_ptr.hpp>
37   	#include <boost/static_assert.hpp>
38   	#include <boost/throw_exception.hpp>
39   	#include <boost/type_traits/is_convertible.hpp>
40   	#include <boost/type.hpp>
41   	#include <boost/iostreams/detail/execute.hpp>
42   	
43   	// Sometimes type_info objects must be compared by name. Borrowed from
44   	// Boost.Python and Boost.Function.
45   	#if defined(__GNUC__) || \
46   	     defined(_AIX) || \
47   	    (defined(__sgi) && defined(__host_mips)) || \
48   	    (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC)) \
49   	    /**/
50   	# include <cstring>
51   	# define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) \
52   	     (std::strcmp((X).name(),(Y).name()) == 0)
53   	#else
54   	# define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
55   	#endif
56   	
57   	// Deprecated. Unused.
58   	#define BOOST_IOSTREAMS_COMPONENT_TYPE(chain, index) \
59   	    chain.component_type( index ) \
60   	    /**/
61   	
62   	// Deprecated. Unused.
63   	#define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \
64   	    chain.component< target >( index ) \
65   	    /**/
66   	
67   	namespace boost { namespace iostreams {
68   	
69   	//--------------Definition of chain and wchain--------------------------------//
70   	
71   	namespace detail {
72   	
73   	template<typename Chain> class chain_client;
74   	
75   	//
76   	// Concept name: Chain.
77   	// Description: Represents a chain of stream buffers which provides access
78   	//     to the first buffer in the chain and sends notifications when the
79   	//     streambufs are added to or removed from chain.
80   	// Refines: Closable device with mode equal to typename Chain::mode.
81   	// Models: chain, converting_chain.
82   	// Example:
83   	//
84   	//    class chain {
85   	//    public:
86   	//        typedef xxx chain_type;
87   	//        typedef xxx client_type;
88   	//        typedef xxx mode;
89   	//        bool is_complete() const;                  // Ready for i/o.
90   	//        template<typename T>
91   	//        void push( const T& t,                     // Adds a stream buffer to
92   	//                   streamsize,                     // chain, based on t, with
93   	//                   streamsize );                   // given buffer and putback
94   	//                                                   // buffer sizes. Pass -1 to
95   	//                                                   // request default size.
96   	//    protected:
97   	//        void register_client(client_type* client); // Associate client.
98   	//        void notify();                             // Notify client.
99   	//    };
100  	//
101  	
102  	//
103  	// Description: Represents a chain of filters with an optional device at the
104  	//      end.
105  	// Template parameters:
106  	//      Self - A class deriving from the current instantiation of this template.
107  	//          This is an example of the Curiously Recurring Template Pattern.
108  	//      Ch - The character type.
109  	//      Tr - The character traits type.
110  	//      Alloc - The allocator type.
111  	//      Mode - A mode tag.
112  	//
113  	template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
114  	class chain_base {
115  	public:
116  	    typedef Ch                                     char_type;
117  	    BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr)
118  	    typedef Alloc                                  allocator_type;
119  	    typedef Mode                                   mode;
120  	    struct category
121  	        : Mode,
122  	          device_tag
123  	        { };
124  	    typedef chain_client<Self>                     client_type;
125  	    friend class chain_client<Self>;
126  	private:
127  	    typedef linked_streambuf<Ch>                   streambuf_type;
128  	    typedef std::list<streambuf_type*>             list_type;
129  	    typedef chain_base<Self, Ch, Tr, Alloc, Mode>  my_type;
130  	protected:
131  	    chain_base() : pimpl_(new chain_impl) { }
132  	    chain_base(const chain_base& rhs): pimpl_(rhs.pimpl_) { }
133  	public:
134  	
135  	    // dual_use is a pseudo-mode to facilitate filter writing, 
136  	    // not a genuine mode.
137  	    BOOST_STATIC_ASSERT((!is_convertible<mode, dual_use>::value));
138  	
139  	    //----------Buffer sizing-------------------------------------------------//
140  	
141  	    // Sets the size of the buffer created for the devices to be added to this
142  	    // chain. Does not affect the size of the buffer for devices already
143  	    // added.
144  	    void set_device_buffer_size(std::streamsize n) 
145  	        { pimpl_->device_buffer_size_ = n; }
146  	
147  	    // Sets the size of the buffer created for the filters to be added
148  	    // to this chain. Does not affect the size of the buffer for filters already
149  	    // added.
150  	    void set_filter_buffer_size(std::streamsize n) 
151  	        { pimpl_->filter_buffer_size_ = n; }
152  	
153  	    // Sets the size of the putback buffer for filters and devices to be added
154  	    // to this chain. Does not affect the size of the buffer for filters or
155  	    // devices already added.
156  	    void set_pback_size(std::streamsize n) 
157  	        { pimpl_->pback_size_ = n; }
158  	
159  	    //----------Device interface----------------------------------------------//
160  	
161  	    std::streamsize read(char_type* s, std::streamsize n);
162  	    std::streamsize write(const char_type* s, std::streamsize n);
163  	    std::streampos seek(stream_offset off, BOOST_IOS::seekdir way);
164  	
165  	    //----------Direct component access---------------------------------------//
166  	
167  	    const std::type_info& component_type(int n) const
168  	    {
169  	        if (static_cast<size_type>(n) >= size())
170  	            boost::throw_exception(std::out_of_range("bad chain offset"));
171  	        return (*boost::next(list().begin(), n))->component_type();
172  	    }
173  	
174  	    // Deprecated.
175  	    template<int N>
176  	    const std::type_info& component_type() const { return component_type(N); }
177  	
178  	    template<typename T>
179  	    T* component(int n) const { return component(n, boost::type<T>()); }
180  	
181  	    // Deprecated.
182  	    template<int N, typename T> 
183  	    T* component() const { return component<T>(N); }
184  	
185  	#if !BOOST_WORKAROUND(BOOST_MSVC, == 1310)
186  	    private:
187  	#endif
188  	    template<typename T>
189  	    T* component(int n, boost::type<T>) const
190  	    {
191  	        if (static_cast<size_type>(n) >= size())
192  	            boost::throw_exception(std::out_of_range("bad chain offset"));
193  	        streambuf_type* link = *boost::next(list().begin(), n);
194  	        if (BOOST_IOSTREAMS_COMPARE_TYPE_ID(link->component_type(), typeid(T)))
195  	            return static_cast<T*>(link->component_impl());
196  	        else
197  	            return 0;
198  	    }
199  	public:
200  	
201  	    //----------Container-like interface--------------------------------------//
202  	
203  	    typedef typename list_type::size_type size_type;
204  	    streambuf_type& front() { return *list().front(); }
205  	    BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
206  	    void pop();
207  	    bool empty() const { return list().empty(); }
208  	    size_type size() const { return list().size(); }
209  	    void reset();
210  	
211  	    //----------Additional i/o functions--------------------------------------//
212  	
213  	    // Returns true if this chain is non-empty and its final link
214  	    // is a source or sink, i.e., if it is ready to perform i/o.
215  	    bool is_complete() const;
216  	    bool auto_close() const;
217  	    void set_auto_close(bool close);
218  	    bool sync() { return front().BOOST_IOSTREAMS_PUBSYNC() != -1; }
219  	    bool strict_sync();
220  	private:
221  	    template<typename T>
222  	    void push_impl(const T& t, std::streamsize buffer_size = -1, 
223  	                   std::streamsize pback_size = -1)
224  	    {
225  	        typedef typename iostreams::category_of<T>::type  category;
226  	        typedef typename unwrap_ios<T>::type              component_type;
227  	        typedef stream_buffer<
228  	                    component_type,
229  	                    BOOST_IOSTREAMS_CHAR_TRAITS(char_type),
230  	                    Alloc, Mode
231  	                >                                         streambuf_t;
232  	        typedef typename list_type::iterator              iterator;
233  	        BOOST_STATIC_ASSERT((is_convertible<category, Mode>::value));
234  	        if (is_complete())
235  	            boost::throw_exception(std::logic_error("chain complete"));
236  	        streambuf_type* prev = !empty() ? list().back() : 0;
237  	        buffer_size =
238  	            buffer_size != -1 ?
239  	                buffer_size :
240  	                iostreams::optimal_buffer_size(t);
241  	        pback_size =
242  	            pback_size != -1 ?
243  	                pback_size :
244  	                pimpl_->pback_size_;
245  	                
246  	#if defined(BOOST_NO_CXX11_SMART_PTR)
247  	
248  	        std::auto_ptr<streambuf_t>
249  	            buf(new streambuf_t(t, buffer_size, pback_size));
250  	            
251  	#else
252  	
253  	        std::unique_ptr<streambuf_t>
254  	            buf(new streambuf_t(t, buffer_size, pback_size));
255  	            
256  	#endif
257  	            
258  	        list().push_back(buf.get());
259  	        buf.release();
260  	        if (is_device<component_type>::value) {
261  	            pimpl_->flags_ |= f_complete | f_open;
262  	            for ( iterator first = list().begin(),
263  	                           last = list().end();
264  	                  first != last;
265  	                  ++first )
266  	            {
267  	                (*first)->set_needs_close();
268  	            }
269  	        }
270  	        if (prev) prev->set_next(list().back());
271  	        notify();
272  	    }
273  	
274  	    list_type& list() { return pimpl_->links_; }
275  	    const list_type& list() const { return pimpl_->links_; }
276  	    void register_client(client_type* client) { pimpl_->client_ = client; }
277  	    void notify() { if (pimpl_->client_) pimpl_->client_->notify(); }
278  	
279  	    //----------Nested classes------------------------------------------------//
280  	
281  	    static void close(streambuf_type* b, BOOST_IOS::openmode m)
282  	    {
283  	        if (m == BOOST_IOS::out && is_convertible<Mode, output>::value)
284  	            b->BOOST_IOSTREAMS_PUBSYNC();
285  	        b->close(m);
286  	    }
287  	
288  	    static void set_next(streambuf_type* b, streambuf_type* next)
289  	    { b->set_next(next); }
290  	
291  	    static void set_auto_close(streambuf_type* b, bool close)
292  	    { b->set_auto_close(close); }
293  	
294  	    struct closer {
295  	        typedef streambuf_type* argument_type;
296  	        typedef void result_type;
297  	        closer(BOOST_IOS::openmode m) : mode_(m) { }
298  	        void operator() (streambuf_type* b)
299  	        {
300  	            close(b, mode_);
301  	        }
302  	        BOOST_IOS::openmode mode_;
303  	    };
304  	    friend struct closer;
305  	
306  	    enum flags {
307  	        f_complete = 1,
308  	        f_open = 2,
309  	        f_auto_close = 4
310  	    };
311  	
312  	    struct chain_impl {
313  	        chain_impl()
314  	            : client_(0), device_buffer_size_(default_device_buffer_size),
315  	              filter_buffer_size_(default_filter_buffer_size),
316  	              pback_size_(default_pback_buffer_size),
317  	              flags_(f_auto_close)
318  	            { }
319  	        ~chain_impl()
320  	            {
321  	                try { close(); } catch (...) { }
322  	                try { reset(); } catch (...) { }
323  	            }
324  	        void close()
325  	            {
326  	                if ((flags_ & f_open) != 0) {
327  	                    flags_ &= ~f_open;
328  	                    stream_buffer< basic_null_device<Ch, Mode> > null;
329  	                    if ((flags_ & f_complete) == 0) {
(1) Event fun_call_w_exception: Called function throws an exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE". [details]
330  	                        null.open(basic_null_device<Ch, Mode>());
331  	                        set_next(links_.back(), &null);
332  	                    }
333  	                    links_.front()->BOOST_IOSTREAMS_PUBSYNC();
334  	                    try {
335  	                        boost::iostreams::detail::execute_foreach(
336  	                            links_.rbegin(), links_.rend(), 
337  	                            closer(BOOST_IOS::in)
338  	                        );
339  	                    } catch (...) {
340  	                        try {
341  	                            boost::iostreams::detail::execute_foreach(
342  	                                links_.begin(), links_.end(), 
343  	                                closer(BOOST_IOS::out)
344  	                            );
345  	                        } catch (...) { }
346  	                        throw;
347  	                    }
348  	                    boost::iostreams::detail::execute_foreach(
349  	                        links_.begin(), links_.end(), 
350  	                        closer(BOOST_IOS::out)
351  	                    );
352  	                }
353  	            }
354  	        void reset()
355  	            {
356  	                typedef typename list_type::iterator iterator;
357  	                for ( iterator first = links_.begin(),
358  	                               last = links_.end();
359  	                      first != last;
360  	                      ++first )
361  	                {
362  	                    if ( (flags_ & f_complete) == 0 ||
363  	                         (flags_ & f_auto_close) == 0 )
364  	                    {
365  	                        set_auto_close(*first, false);
366  	                    }
367  	                    streambuf_type* buf = 0;
368  	                    std::swap(buf, *first);
369  	                    delete buf;
370  	                }
371  	                links_.clear();
372  	                flags_ &= ~f_complete;
373  	                flags_ &= ~f_open;
374  	            }
375  	        list_type        links_;
376  	        client_type*     client_;
377  	        std::streamsize  device_buffer_size_,
378  	                         filter_buffer_size_,
379  	                         pback_size_;
380  	        int              flags_;
381  	    };
382  	    friend struct chain_impl;
383  	
384  	    //----------Member data---------------------------------------------------//
385  	
386  	private:
387  	    shared_ptr<chain_impl> pimpl_;
388  	};
389  	
390  	} // End namespace detail.
391  	
392  	//
393  	// Macro: BOOST_IOSTREAMS_DECL_CHAIN(name, category)
394  	// Description: Defines a template derived from chain_base appropriate for a
395  	//      particular i/o category. The template has the following parameters:
396  	//      Ch - The character type.
397  	//      Tr - The character traits type.
398  	//      Alloc - The allocator type.
399  	// Macro parameters:
400  	//      name_ - The name of the template to be defined.
401  	//      category_ - The i/o category of the template to be defined.
402  	//
403  	#define BOOST_IOSTREAMS_DECL_CHAIN(name_, default_char_) \
404  	    template< typename Mode, typename Ch = default_char_, \
405  	              typename Tr = BOOST_IOSTREAMS_CHAR_TRAITS(Ch), \
406  	              typename Alloc = std::allocator<Ch> > \
407  	    class name_ : public boost::iostreams::detail::chain_base< \
408  	                            name_<Mode, Ch, Tr, Alloc>, \
409  	                            Ch, Tr, Alloc, Mode \
410  	                         > \
411  	    { \
412  	    public: \
413  	        struct category : device_tag, Mode { }; \
414  	        typedef Mode                                   mode; \
415  	    private: \
416  	        typedef boost::iostreams::detail::chain_base< \
417  	                    name_<Mode, Ch, Tr, Alloc>, \
418  	                    Ch, Tr, Alloc, Mode \
419  	                >                                      base_type; \
420  	    public: \
421  	        typedef Ch                                     char_type; \
422  	        typedef Tr                                     traits_type; \
423  	        typedef typename traits_type::int_type         int_type; \
424  	        typedef typename traits_type::off_type         off_type; \
425  	        name_() { } \
426  	        name_(const name_& rhs) : base_type(rhs) { } \
427  	        name_& operator=(const name_& rhs) \
428  	        { base_type::operator=(rhs); return *this; } \
429  	    }; \
430  	    /**/
431  	BOOST_IOSTREAMS_DECL_CHAIN(chain, char)
432  	BOOST_IOSTREAMS_DECL_CHAIN(wchain, wchar_t)
433  	#undef BOOST_IOSTREAMS_DECL_CHAIN
434  	
435  	//--------------Definition of chain_client------------------------------------//
436  	
437  	namespace detail {
438  	
439  	//
440  	// Template name: chain_client
441  	// Description: Class whose instances provide access to an underlying chain
442  	//      using an interface similar to the chains.
443  	// Subclasses: the various stream and stream buffer templates.
444  	//
445  	template<typename Chain>
446  	class chain_client {
447  	public:
448  	    typedef Chain                             chain_type;
449  	    typedef typename chain_type::char_type    char_type;
450  	    typedef typename chain_type::traits_type  traits_type;
451  	    typedef typename chain_type::size_type    size_type;
452  	    typedef typename chain_type::mode         mode;
453  	
454  	    chain_client(chain_type* chn = 0) : chain_(chn ) { }
455  	    chain_client(chain_client* client) : chain_(client->chain_) { }
456  	    virtual ~chain_client() { }
457  	
458  	    const std::type_info& component_type(int n) const
459  	    { return chain_->component_type(n); }
460  	
461  	    // Deprecated.
462  	    template<int N>
463  	    const std::type_info& component_type() const
464  	    { return chain_->BOOST_NESTED_TEMPLATE component_type<N>(); }
465  	
466  	    template<typename T>
467  	    T* component(int n) const
468  	    { return chain_->BOOST_NESTED_TEMPLATE component<T>(n); }
469  	
470  	    // Deprecated.
471  	    template<int N, typename T>
472  	    T* component() const
473  	    { return chain_->BOOST_NESTED_TEMPLATE component<N, T>(); }
474  	
475  	    bool is_complete() const { return chain_->is_complete(); }
476  	    bool auto_close() const { return chain_->auto_close(); }
477  	    void set_auto_close(bool close) { chain_->set_auto_close(close); }
478  	    bool strict_sync() { return chain_->strict_sync(); }
479  	    void set_device_buffer_size(std::streamsize n)
480  	        { chain_->set_device_buffer_size(n); }
481  	    void set_filter_buffer_size(std::streamsize n)
482  	        { chain_->set_filter_buffer_size(n); }
483  	    void set_pback_size(std::streamsize n) { chain_->set_pback_size(n); }
484  	    BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
485  	    void pop() { chain_->pop(); }
486  	    bool empty() const { return chain_->empty(); }
487  	    size_type size() const { return chain_->size(); }
(1) Event fun_call_w_exception: Called function throws an exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE". [details]
488  	    void reset() { chain_->reset(); }
489  	
490  	    // Returns a copy of the underlying chain.
491  	    chain_type filters() { return *chain_; }
492  	    chain_type filters() const { return *chain_; }
493  	protected:
494  	    template<typename T>
495  	    void push_impl(const T& t BOOST_IOSTREAMS_PUSH_PARAMS())
496  	    { chain_->push(t BOOST_IOSTREAMS_PUSH_ARGS()); }
497  	    chain_type& ref() { return *chain_; }
498  	    void set_chain(chain_type* c)
499  	    { chain_ = c; chain_->register_client(this); }
500  	#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) && \
501  	    (!BOOST_WORKAROUND(__BORLANDC__, < 0x600))
502  	    template<typename S, typename C, typename T, typename A, typename M>
503  	    friend class chain_base;
504  	#else
505  	    public:
506  	#endif
507  	    virtual void notify() { }
508  	private:
509  	    chain_type* chain_;
510  	};
511  	
512  	//--------------Implementation of chain_base----------------------------------//
513  	
514  	template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
515  	inline std::streamsize chain_base<Self, Ch, Tr, Alloc, Mode>::read
516  	    (char_type* s, std::streamsize n)
517  	{ return iostreams::read(*list().front(), s, n); }
518  	
519  	template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
520  	inline std::streamsize chain_base<Self, Ch, Tr, Alloc, Mode>::write
521  	    (const char_type* s, std::streamsize n)
522  	{ return iostreams::write(*list().front(), s, n); }
523  	
524  	template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
525  	inline std::streampos chain_base<Self, Ch, Tr, Alloc, Mode>::seek
526  	    (stream_offset off, BOOST_IOS::seekdir way)
527  	{ return iostreams::seek(*list().front(), off, way); }
528  	
529  	template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
530  	void chain_base<Self, Ch, Tr, Alloc, Mode>::reset()
531  	{
532  	    using namespace std;
(1) Event fun_call_w_exception: Called function throws an exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE". [details]
533  	    pimpl_->close();
534  	    pimpl_->reset();
535  	}
536  	
537  	template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
538  	bool chain_base<Self, Ch, Tr, Alloc, Mode>::is_complete() const
539  	{
540  	    return (pimpl_->flags_ & f_complete) != 0;
541  	}
542  	
543  	template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
544  	bool chain_base<Self, Ch, Tr, Alloc, Mode>::auto_close() const
545  	{
546  	    return (pimpl_->flags_ & f_auto_close) != 0;
547  	}
548  	
549  	template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
550  	void chain_base<Self, Ch, Tr, Alloc, Mode>::set_auto_close(bool close)
551  	{
552  	    pimpl_->flags_ =
553  	        (pimpl_->flags_ & ~f_auto_close) |
554  	        (close ? f_auto_close : 0);
555  	}
556  	
557  	template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
558  	bool chain_base<Self, Ch, Tr, Alloc, Mode>::strict_sync()
559  	{
560  	    typedef typename list_type::iterator iterator;
561  	    bool result = true;
562  	    for ( iterator first = list().begin(),
563  	                   last = list().end();
564  	          first != last;
565  	          ++first )
566  	    {
567  	        bool s = (*first)->strict_sync();
568  	        result = result && s;
569  	    }
570  	    return result;
571  	}
572  	
573  	template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
574  	void chain_base<Self, Ch, Tr, Alloc, Mode>::pop()
575  	{
576  	    BOOST_ASSERT(!empty());
577  	    if (auto_close())
578  	        pimpl_->close();
579  	    streambuf_type* buf = 0;
580  	    std::swap(buf, list().back());
581  	    buf->set_auto_close(false);
582  	    buf->set_next(0);
583  	    delete buf;
584  	    list().pop_back();
585  	    pimpl_->flags_ &= ~f_complete;
586  	    if (auto_close() || list().empty())
587  	        pimpl_->flags_ &= ~f_open;
588  	}
589  	
590  	} // End namespace detail.
591  	
592  	} } // End namespaces iostreams, boost.
593  	
594  	#endif // #ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
595