Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/iostreams/chain.hpp @ 47

Last change on this file since 47 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 20.2 KB
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    //----------Direct component access---------------------------------------//
166
167    const std::type_info& component_type(int n) const
168    {
169        if (static_cast<size_type>(n) >= size())
170            throw std::out_of_range("bad chain offset");
171        return (*boost::next(list().begin(), n))->component_type();
172    }
173
174#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310)
175    // Deprecated.
176    template<int N>
177    const std::type_info& component_type() const { return component_type(N); }
178
179    template<typename T>
180    T* component(int n) const { return component(n, boost::type<T>()); }
181
182    // Deprecated.
183    template<int N, typename T> 
184    T* component() const { return component<T>(N); }
185#endif
186
187#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310)
188    private:
189#endif
190    template<typename T>
191    T* component(int n, boost::type<T>) const
192    {
193        if (static_cast<size_type>(n) >= size())
194            throw std::out_of_range("bad chain offset");
195        streambuf_type* link = *boost::next(list().begin(), n);
196        if (BOOST_IOSTREAMS_COMPARE_TYPE_ID(link->component_type(), typeid(T)))
197            return static_cast<T*>(link->component_impl());
198        else
199            return 0;
200    }
201public:
202
203    //----------Container-like interface--------------------------------------//
204
205    typedef typename list_type::size_type size_type;
206    streambuf_type& front() { return *list().front(); }
207    BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
208    void pop();
209    bool empty() const { return list().empty(); }
210    size_type size() const { return list().size(); }
211    void reset();
212
213    //----------Additional i/o functions--------------------------------------//
214
215    // Returns true if this chain is non-empty and its final link
216    // is a source or sink, i.e., if it is ready to perform i/o.
217    bool is_complete() const;
218    bool auto_close() const;
219    void set_auto_close(bool close);
220    bool sync() { return front().BOOST_IOSTREAMS_PUBSYNC() != -1; }
221    bool strict_sync();
222private:
223    template<typename T>
224    void push_impl(const T& t, int buffer_size = -1, int pback_size = -1)
225    {
226        typedef typename iostreams::category_of<T>::type  category;
227        typedef typename unwrap_ios<T>::type              policy_type;
228        typedef stream_buffer<
229                    policy_type,
230                    BOOST_IOSTREAMS_CHAR_TRAITS(char_type),
231                    Alloc, Mode
232                >                                         facade_type;
233        BOOST_STATIC_ASSERT((is_convertible<category, Mode>::value));
234        if (is_complete())
235            throw 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        std::auto_ptr<facade_type>
246            buf(new facade_type(t, buffer_size, pback_size));
247        list().push_back(buf.get());
248        buf.release();
249        if (is_device<policy_type>::value)
250            pimpl_->flags_ |= f_complete | f_open;
251        if (prev) prev->set_next(list().back());
252        notify();
253    }
254
255    list_type& list() { return pimpl_->links_; }
256    const list_type& list() const { return pimpl_->links_; }
257    void register_client(client_type* client) { pimpl_->client_ = client; }
258    void notify() { if (pimpl_->client_) pimpl_->client_->notify(); }
259
260    //----------Nested classes------------------------------------------------//
261
262    static void close(streambuf_type* b, BOOST_IOS::openmode m)
263    {
264        if (m & BOOST_IOS::out)
265            b->BOOST_IOSTREAMS_PUBSYNC();
266        b->close(m);
267    }
268
269    static void set_next(streambuf_type* b, streambuf_type* next)
270    { b->set_next(next); }
271
272    static void set_auto_close(streambuf_type* b, bool close)
273    { b->set_auto_close(close); }
274
275    struct closer  : public std::unary_function<streambuf_type*, void>  {
276        closer(BOOST_IOS::openmode m) : mode_(m) { }
277        void operator() (streambuf_type* b)
278        {
279            close(b, mode_);
280        }
281        BOOST_IOS::openmode mode_;
282    };
283    friend struct closer;
284
285    enum flags {
286        f_complete = 1,
287        f_open = 2,
288        f_auto_close = 4
289    };
290
291    struct chain_impl {
292        chain_impl()
293            : client_(0), device_buffer_size_(default_device_buffer_size),
294              filter_buffer_size_(default_filter_buffer_size),
295              pback_size_(default_pback_buffer_size),
296              flags_(f_auto_close)
297            { }
298        ~chain_impl() { try { close(); reset(); } catch (std::exception&) { } }
299        void close()
300            {
301                if ((flags_ & f_open) != 0) {
302                    stream_buffer< basic_null_device<Ch, Mode> > null;
303                    if ((flags_ & f_complete) == 0) {
304                        null.open(basic_null_device<Ch, Mode>());
305                        set_next(links_.back(), &null);
306                    }
307                    links_.front()->BOOST_IOSTREAMS_PUBSYNC();
308                    if (is_convertible<Mode, input>::value)
309                        std::for_each( links_.rbegin(), links_.rend(),
310                                       closer(BOOST_IOS::in) );
311                    if (is_convertible<Mode, output>::value)
312                        std::for_each( links_.begin(), links_.end(),
313                                       closer(BOOST_IOS::out) );
314                    flags_ &= ~f_open;
315                }
316            }
317        void reset()
318            {
319                typedef typename list_type::iterator iterator;
320                for ( iterator first = links_.begin(),
321                               last = links_.end();
322                      first != last;
323                      ++first )
324                {
325                    if ( (flags_ & f_complete) == 0 ||
326                         (flags_ & f_auto_close) == 0 )
327                    {
328                        set_auto_close(*first, false);
329                    }
330                    streambuf_type* buf = 0;
331                    std::swap(buf, *first);
332                    delete buf;
333                }
334                links_.clear();
335                flags_ &= ~f_complete;
336                flags_ &= ~f_open;
337            }
338        list_type     links_;
339        client_type*  client_;
340        int           device_buffer_size_,
341                      filter_buffer_size_,
342                      pback_size_;
343        int           flags_;
344    };
345    friend struct chain_impl;
346
347    //----------Member data---------------------------------------------------//
348
349private:
350    shared_ptr<chain_impl> pimpl_;
351};
352
353} // End namespace detail.
354
355//
356// Macro: BOOST_IOSTREAMS_DECL_CHAIN(name, category)
357// Description: Defines a template derived from chain_base appropriate for a
358//      particular i/o category. The template has the following parameters:
359//      Ch - The character type.
360//      Tr - The character traits type.
361//      Alloc - The allocator type.
362// Macro parameters:
363//      name_ - The name of the template to be defined.
364//      category_ - The i/o category of the template to be defined.
365//
366#define BOOST_IOSTREAMS_DECL_CHAIN(name_, default_char_) \
367    template< typename Mode, typename Ch = default_char_, \
368              typename Tr = BOOST_IOSTREAMS_CHAR_TRAITS(Ch), \
369              typename Alloc = std::allocator<Ch> > \
370    class name_ : public boost::iostreams::detail::chain_base< \
371                            name_<Mode, Ch, Tr, Alloc>, \
372                            Ch, Tr, Alloc, Mode \
373                         > \
374    { \
375    public: \
376        struct category : device_tag, Mode { }; \
377        typedef Mode                                   mode; \
378    private: \
379        typedef boost::iostreams::detail::chain_base< \
380                    name_<Mode, Ch, Tr, Alloc>, \
381                    Ch, Tr, Alloc, Mode \
382                >                                      base_type; \
383    public: \
384        typedef Ch                                     char_type; \
385        typedef Tr                                     traits_type; \
386        typedef typename traits_type::int_type         int_type; \
387        typedef typename traits_type::off_type         off_type; \
388        name_() { } \
389        name_(const name_& rhs) { *this = rhs; } \
390        name_& operator=(const name_& rhs) \
391        { base_type::operator=(rhs); return *this; } \
392    }; \
393    /**/
394BOOST_IOSTREAMS_DECL_CHAIN(chain, char)
395BOOST_IOSTREAMS_DECL_CHAIN(wchain, wchar_t)
396#undef BOOST_IOSTREAMS_DECL_CHAIN
397
398//--------------Definition of chain_client------------------------------------//
399
400namespace detail {
401
402//
403// Template name: chain_client
404// Description: Class whose instances provide access to an underlying chain
405//      using an interface similar to the chains.
406// Subclasses: the various stream and stream buffer templates.
407//
408template<typename Chain>
409class chain_client {
410public:
411    typedef Chain                             chain_type;
412    typedef typename chain_type::char_type    char_type;
413    typedef typename chain_type::traits_type  traits_type;
414    typedef typename chain_type::size_type    size_type;
415    typedef typename chain_type::mode         mode;
416
417    chain_client(chain_type* chn = 0) : chain_(chn ) { }
418    chain_client(chain_client* client) : chain_(client->chain_) { }
419    virtual ~chain_client() { }
420
421    const std::type_info& component_type(int n) const
422    { return chain_->component_type(n); }
423
424#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310)
425    // Deprecated.
426    template<int N>
427    const std::type_info& component_type() const
428    { return chain_->BOOST_NESTED_TEMPLATE component_type<N>(); }
429
430    template<typename T>
431    T* component(int n) const
432    { return chain_->BOOST_NESTED_TEMPLATE component<T>(n); }
433
434    // Deprecated.
435    template<int N, typename T>
436    T* component() const
437    { return chain_->BOOST_NESTED_TEMPLATE component<N, T>(); }
438#else
439    template<typename T>
440    T* component(int n, boost::type<T> t) const
441    { return chain_->component(n, t); }
442#endif
443
444    bool is_complete() const { return chain_->is_complete(); }
445    bool auto_close() const { return chain_->auto_close(); }
446    void set_auto_close(bool close) { chain_->set_auto_close(close); }
447    bool strict_sync() { return chain_->strict_sync(); }
448    void set_device_buffer_size(std::streamsize n)
449        { chain_->set_device_buffer_size(n); }
450    void set_filter_buffer_size(std::streamsize n)
451        { chain_->set_filter_buffer_size(n); }
452    void set_pback_size(std::streamsize n) { chain_->set_pback_size(n); }
453    BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
454    void pop() { chain_->pop(); }
455    bool empty() const { return chain_->empty(); }
456    size_type size() { return chain_->size(); }
457    void reset() { chain_->reset(); }
458
459    // Returns a copy of the underlying chain.
460    chain_type filters() { return *chain_; }
461    chain_type filters() const { return *chain_; }
462protected:
463    template<typename T>
464    void push_impl(const T& t BOOST_IOSTREAMS_PUSH_PARAMS())
465    { chain_->push(t BOOST_IOSTREAMS_PUSH_ARGS()); }
466    chain_type& ref() { return *chain_; }
467    void set_chain(chain_type* c)
468    { chain_ = c; chain_->register_client(this); }
469#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) && \
470    (!BOOST_WORKAROUND(__BORLANDC__, < 0x600))
471    template<typename S, typename C, typename T, typename A, typename M>
472    friend class chain_base;
473#else
474    public:
475#endif
476    virtual void notify() { }
477private:
478    chain_type* chain_;
479};
480
481//--------------Implementation of chain_base----------------------------------//
482
483template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
484inline std::streamsize chain_base<Self, Ch, Tr, Alloc, Mode>::read
485    (char_type* s, std::streamsize n)
486{ return iostreams::read(*list().front(), s, n); }
487
488template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
489inline std::streamsize chain_base<Self, Ch, Tr, Alloc, Mode>::write
490    (const char_type* s, std::streamsize n)
491{ return iostreams::write(*list().front(), s, n); }
492
493template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
494inline std::streampos chain_base<Self, Ch, Tr, Alloc, Mode>::seek
495    (stream_offset off, BOOST_IOS::seekdir way)
496{ return iostreams::seek(*list().front(), off, way); }
497
498template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
499void chain_base<Self, Ch, Tr, Alloc, Mode>::reset()
500{
501    using namespace std;
502    pimpl_->close();
503    pimpl_->reset();
504}
505
506template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
507bool chain_base<Self, Ch, Tr, Alloc, Mode>::is_complete() const
508{
509    return (pimpl_->flags_ & f_complete) != 0;
510}
511
512template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
513bool chain_base<Self, Ch, Tr, Alloc, Mode>::auto_close() const
514{
515    return (pimpl_->flags_ & f_auto_close) != 0;
516}
517
518template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
519void chain_base<Self, Ch, Tr, Alloc, Mode>::set_auto_close(bool close)
520{
521    pimpl_->flags_ =
522        (pimpl_->flags_ & ~f_auto_close) |
523        (close ? f_auto_close : 0);
524}
525
526template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
527bool chain_base<Self, Ch, Tr, Alloc, Mode>::strict_sync()
528{
529    typedef typename list_type::iterator iterator;
530    bool result = true;
531    for ( iterator first = list().begin(),
532                   last = list().end();
533          first != last;
534          ++first )
535    {
536        bool s = (*first)->strict_sync();
537        result = result && s;
538    }
539    return result;
540}
541
542template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
543void chain_base<Self, Ch, Tr, Alloc, Mode>::pop()
544{
545    assert(!empty());
546    if (auto_close())
547        pimpl_->close();
548    streambuf_type* buf = 0;
549    std::swap(buf, list().back());
550    buf->set_auto_close(false);
551    buf->set_next(0);
552    delete buf;
553    list().pop_back();
554    pimpl_->flags_ &= ~f_complete;
555    if (auto_close() || list().empty())
556        pimpl_->flags_ &= ~f_open;
557}
558
559} // End namespace detail.
560
561} } // End namespaces iostreams, boost.
562
563#endif // #ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
Note: See TracBrowser for help on using the repository browser.