source: NonGTP/Boost/boost/iostreams/chain.hpp @ 857

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