Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:44:32

0001 // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
0002 // (C) Copyright 2003-2007 Jonathan Turkanis
0003 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0004 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
0005 
0006 // See http://www.boost.org/libs/iostreams for documentation.
0007 
0008 #ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
0009 #define BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
0010 
0011 #if defined(_MSC_VER)
0012 # pragma once
0013 #endif
0014 
0015 #include <boost/assert.hpp>
0016 #include <exception>
0017 #include <iterator>                             // advance.
0018 #include <list>
0019 #include <memory>                               // allocator, auto_ptr or unique_ptr.
0020 #include <stdexcept>                            // logic_error, out_of_range.
0021 #include <boost/checked_delete.hpp>
0022 #include <boost/config.hpp>                     // BOOST_MSVC, template friends,
0023 #include <boost/detail/workaround.hpp>          // BOOST_NESTED_TEMPLATE 
0024 #include <boost/core/typeinfo.hpp>
0025 #include <boost/iostreams/constants.hpp>
0026 #include <boost/iostreams/detail/access_control.hpp>
0027 #include <boost/iostreams/detail/char_traits.hpp>
0028 #include <boost/iostreams/detail/push.hpp>
0029 #include <boost/iostreams/detail/streambuf.hpp> // pubsync.
0030 #include <boost/iostreams/detail/wrap_unwrap.hpp>
0031 #include <boost/iostreams/device/null.hpp>
0032 #include <boost/iostreams/positioning.hpp>
0033 #include <boost/iostreams/traits.hpp>           // is_filter.
0034 #include <boost/iostreams/stream_buffer.hpp>
0035 #include <boost/next_prior.hpp>
0036 #include <boost/shared_ptr.hpp>
0037 #include <boost/static_assert.hpp>
0038 #include <boost/throw_exception.hpp>
0039 #include <boost/type_traits/is_convertible.hpp>
0040 #include <boost/type.hpp>
0041 #include <boost/iostreams/detail/execute.hpp>
0042 
0043 // Sometimes type_info objects must be compared by name. Borrowed from
0044 // Boost.Python and Boost.Function.
0045 #if defined(__GNUC__) || \
0046      defined(_AIX) || \
0047     (defined(__sgi) && defined(__host_mips)) || \
0048     (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC)) \
0049     /**/
0050 # include <cstring>
0051 # define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) \
0052      (std::strcmp((X).name(),(Y).name()) == 0)
0053 #else
0054 # define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
0055 #endif
0056 
0057 // Deprecated. Unused.
0058 #define BOOST_IOSTREAMS_COMPONENT_TYPE(chain, index) \
0059     chain.component_type( index ) \
0060     /**/
0061 
0062 // Deprecated. Unused.
0063 #define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \
0064     chain.component< target >( index ) \
0065     /**/
0066 
0067 namespace boost { namespace iostreams {
0068 
0069 //--------------Definition of chain and wchain--------------------------------//
0070 
0071 namespace detail {
0072 
0073 template<typename Chain> class chain_client;
0074 
0075 //
0076 // Concept name: Chain.
0077 // Description: Represents a chain of stream buffers which provides access
0078 //     to the first buffer in the chain and sends notifications when the
0079 //     streambufs are added to or removed from chain.
0080 // Refines: Closable device with mode equal to typename Chain::mode.
0081 // Models: chain, converting_chain.
0082 // Example:
0083 //
0084 //    class chain {
0085 //    public:
0086 //        typedef xxx chain_type;
0087 //        typedef xxx client_type;
0088 //        typedef xxx mode;
0089 //        bool is_complete() const;                  // Ready for i/o.
0090 //        template<typename T>
0091 //        void push( const T& t,                     // Adds a stream buffer to
0092 //                   streamsize,                     // chain, based on t, with
0093 //                   streamsize );                   // given buffer and putback
0094 //                                                   // buffer sizes. Pass -1 to
0095 //                                                   // request default size.
0096 //    protected:
0097 //        void register_client(client_type* client); // Associate client.
0098 //        void notify();                             // Notify client.
0099 //    };
0100 //
0101 
0102 //
0103 // Description: Represents a chain of filters with an optional device at the
0104 //      end.
0105 // Template parameters:
0106 //      Self - A class deriving from the current instantiation of this template.
0107 //          This is an example of the Curiously Recurring Template Pattern.
0108 //      Ch - The character type.
0109 //      Tr - The character traits type.
0110 //      Alloc - The allocator type.
0111 //      Mode - A mode tag.
0112 //
0113 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0114 class chain_base {
0115 public:
0116     typedef Ch                                     char_type;
0117     BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr)
0118     typedef Alloc                                  allocator_type;
0119     typedef Mode                                   mode;
0120     struct category
0121         : Mode,
0122           device_tag
0123         { };
0124     typedef chain_client<Self>                     client_type;
0125     friend class chain_client<Self>;
0126 private:
0127     typedef linked_streambuf<Ch>                   streambuf_type;
0128     typedef std::list<streambuf_type*>             list_type;
0129     typedef chain_base<Self, Ch, Tr, Alloc, Mode>  my_type;
0130 protected:
0131     chain_base() : pimpl_(new chain_impl) { }
0132     chain_base(const chain_base& rhs): pimpl_(rhs.pimpl_) { }
0133 public:
0134 
0135     // dual_use is a pseudo-mode to facilitate filter writing, 
0136     // not a genuine mode.
0137     BOOST_STATIC_ASSERT((!is_convertible<mode, dual_use>::value));
0138 
0139     //----------Buffer sizing-------------------------------------------------//
0140 
0141     // Sets the size of the buffer created for the devices to be added to this
0142     // chain. Does not affect the size of the buffer for devices already
0143     // added.
0144     void set_device_buffer_size(std::streamsize n) 
0145         { pimpl_->device_buffer_size_ = n; }
0146 
0147     // Sets the size of the buffer created for the filters to be added
0148     // to this chain. Does not affect the size of the buffer for filters already
0149     // added.
0150     void set_filter_buffer_size(std::streamsize n) 
0151         { pimpl_->filter_buffer_size_ = n; }
0152 
0153     // Sets the size of the putback buffer for filters and devices to be added
0154     // to this chain. Does not affect the size of the buffer for filters or
0155     // devices already added.
0156     void set_pback_size(std::streamsize n) 
0157         { pimpl_->pback_size_ = n; }
0158 
0159     //----------Device interface----------------------------------------------//
0160 
0161     std::streamsize read(char_type* s, std::streamsize n);
0162     std::streamsize write(const char_type* s, std::streamsize n);
0163     std::streampos seek(stream_offset off, BOOST_IOS::seekdir way);
0164 
0165     //----------Direct component access---------------------------------------//
0166 
0167     const boost::core::typeinfo& component_type(int n) const
0168     {
0169         if (static_cast<size_type>(n) >= size())
0170             boost::throw_exception(std::out_of_range("bad chain offset"));
0171         return (*boost::next(list().begin(), n))->component_type();
0172     }
0173 
0174     // Deprecated.
0175     template<int N>
0176     const boost::core::typeinfo& component_type() const { return component_type(N); }
0177 
0178     template<typename T>
0179     T* component(int n) const { return component(n, boost::type<T>()); }
0180 
0181     // Deprecated.
0182     template<int N, typename T> 
0183     T* component() const { return component<T>(N); }
0184 
0185 #if !BOOST_WORKAROUND(BOOST_MSVC, == 1310)
0186     private:
0187 #endif
0188     template<typename T>
0189     T* component(int n, boost::type<T>) const
0190     {
0191         if (static_cast<size_type>(n) >= size())
0192             boost::throw_exception(std::out_of_range("bad chain offset"));
0193         streambuf_type* link = *boost::next(list().begin(), n);
0194         if (BOOST_IOSTREAMS_COMPARE_TYPE_ID(link->component_type(), BOOST_CORE_TYPEID(T)))
0195             return static_cast<T*>(link->component_impl());
0196         else
0197             return 0;
0198     }
0199 public:
0200 
0201     //----------Container-like interface--------------------------------------//
0202 
0203     typedef typename list_type::size_type size_type;
0204     streambuf_type& front() { return *list().front(); }
0205     BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
0206     void pop();
0207     bool empty() const { return list().empty(); }
0208     size_type size() const { return list().size(); }
0209     void reset();
0210 
0211     //----------Additional i/o functions--------------------------------------//
0212 
0213     // Returns true if this chain is non-empty and its final link
0214     // is a source or sink, i.e., if it is ready to perform i/o.
0215     bool is_complete() const;
0216     bool auto_close() const;
0217     void set_auto_close(bool close);
0218     bool sync() { return front().BOOST_IOSTREAMS_PUBSYNC() != -1; }
0219     bool strict_sync();
0220 private:
0221     template<typename T>
0222     void push_impl(const T& t, std::streamsize buffer_size = -1, 
0223                    std::streamsize pback_size = -1)
0224     {
0225         typedef typename iostreams::category_of<T>::type  category;
0226         typedef typename unwrap_ios<T>::type              component_type;
0227         typedef stream_buffer<
0228                     component_type,
0229                     BOOST_IOSTREAMS_CHAR_TRAITS(char_type),
0230                     Alloc, Mode
0231                 >                                         streambuf_t;
0232         typedef typename list_type::iterator              iterator;
0233         BOOST_STATIC_ASSERT((is_convertible<category, Mode>::value));
0234         if (is_complete())
0235             boost::throw_exception(std::logic_error("chain complete"));
0236         streambuf_type* prev = !empty() ? list().back() : 0;
0237         buffer_size =
0238             buffer_size != -1 ?
0239                 buffer_size :
0240                 iostreams::optimal_buffer_size(t);
0241         pback_size =
0242             pback_size != -1 ?
0243                 pback_size :
0244                 pimpl_->pback_size_;
0245                 
0246 #if defined(BOOST_NO_CXX11_SMART_PTR)
0247 
0248         std::auto_ptr<streambuf_t>
0249             buf(new streambuf_t(t, buffer_size, pback_size));
0250             
0251 #else
0252 
0253         std::unique_ptr<streambuf_t>
0254             buf(new streambuf_t(t, buffer_size, pback_size));
0255             
0256 #endif
0257             
0258         list().push_back(buf.get());
0259         buf.release();
0260         if (is_device<component_type>::value) {
0261             pimpl_->flags_ |= f_complete | f_open;
0262             for ( iterator first = list().begin(),
0263                            last = list().end();
0264                   first != last;
0265                   ++first )
0266             {
0267                 (*first)->set_needs_close();
0268             }
0269         }
0270         if (prev) prev->set_next(list().back());
0271         notify();
0272     }
0273 
0274     list_type& list() { return pimpl_->links_; }
0275     const list_type& list() const { return pimpl_->links_; }
0276     void register_client(client_type* client) { pimpl_->client_ = client; }
0277     void notify() { if (pimpl_->client_) pimpl_->client_->notify(); }
0278 
0279     //----------Nested classes------------------------------------------------//
0280 
0281     static void close(streambuf_type* b, BOOST_IOS::openmode m)
0282     {
0283         if (m == BOOST_IOS::out && is_convertible<Mode, output>::value)
0284             b->BOOST_IOSTREAMS_PUBSYNC();
0285         b->close(m);
0286     }
0287 
0288     static void set_next(streambuf_type* b, streambuf_type* next)
0289     { b->set_next(next); }
0290 
0291     static void set_auto_close(streambuf_type* b, bool close)
0292     { b->set_auto_close(close); }
0293 
0294     struct closer {
0295         typedef streambuf_type* argument_type;
0296         typedef void result_type;
0297         closer(BOOST_IOS::openmode m) : mode_(m) { }
0298         void operator() (streambuf_type* b)
0299         {
0300             close(b, mode_);
0301         }
0302         BOOST_IOS::openmode mode_;
0303     };
0304     friend struct closer;
0305 
0306     enum flags {
0307         f_complete = 1,
0308         f_open = 2,
0309         f_auto_close = 4
0310     };
0311 
0312     struct chain_impl {
0313         chain_impl()
0314             : client_(0), device_buffer_size_(default_device_buffer_size),
0315               filter_buffer_size_(default_filter_buffer_size),
0316               pback_size_(default_pback_buffer_size),
0317               flags_(f_auto_close)
0318             { }
0319         ~chain_impl()
0320             {
0321                 try { close(); } catch (...) { }
0322                 try { reset(); } catch (...) { }
0323             }
0324         void close()
0325             {
0326                 if ((flags_ & f_open) != 0) {
0327                     flags_ &= ~f_open;
0328                     stream_buffer< basic_null_device<Ch, Mode> > null;
0329                     if ((flags_ & f_complete) == 0) {
0330                         null.open(basic_null_device<Ch, Mode>());
0331                         set_next(links_.back(), &null);
0332                     }
0333                     links_.front()->BOOST_IOSTREAMS_PUBSYNC();
0334                     try {
0335                         boost::iostreams::detail::execute_foreach(
0336                             links_.rbegin(), links_.rend(), 
0337                             closer(BOOST_IOS::in)
0338                         );
0339                     } catch (...) {
0340                         try {
0341                             boost::iostreams::detail::execute_foreach(
0342                                 links_.begin(), links_.end(), 
0343                                 closer(BOOST_IOS::out)
0344                             );
0345                         } catch (...) { }
0346                         throw;
0347                     }
0348                     boost::iostreams::detail::execute_foreach(
0349                         links_.begin(), links_.end(), 
0350                         closer(BOOST_IOS::out)
0351                     );
0352                 }
0353             }
0354         void reset()
0355             {
0356                 typedef typename list_type::iterator iterator;
0357                 for ( iterator first = links_.begin(),
0358                                last = links_.end();
0359                       first != last;
0360                       ++first )
0361                 {
0362                     if ( (flags_ & f_complete) == 0 ||
0363                          (flags_ & f_auto_close) == 0 )
0364                     {
0365                         set_auto_close(*first, false);
0366                     }
0367                     streambuf_type* buf = 0;
0368                     std::swap(buf, *first);
0369                     delete buf;
0370                 }
0371                 links_.clear();
0372                 flags_ &= ~f_complete;
0373                 flags_ &= ~f_open;
0374             }
0375         list_type        links_;
0376         client_type*     client_;
0377         std::streamsize  device_buffer_size_,
0378                          filter_buffer_size_,
0379                          pback_size_;
0380         int              flags_;
0381     };
0382     friend struct chain_impl;
0383 
0384     //----------Member data---------------------------------------------------//
0385 
0386 private:
0387     shared_ptr<chain_impl> pimpl_;
0388 };
0389 
0390 } // End namespace detail.
0391 
0392 //
0393 // Macro: BOOST_IOSTREAMS_DECL_CHAIN(name, category)
0394 // Description: Defines a template derived from chain_base appropriate for a
0395 //      particular i/o category. The template has the following parameters:
0396 //      Ch - The character type.
0397 //      Tr - The character traits type.
0398 //      Alloc - The allocator type.
0399 // Macro parameters:
0400 //      name_ - The name of the template to be defined.
0401 //      category_ - The i/o category of the template to be defined.
0402 //
0403 #define BOOST_IOSTREAMS_DECL_CHAIN(name_, default_char_) \
0404     template< typename Mode, typename Ch = default_char_, \
0405               typename Tr = BOOST_IOSTREAMS_CHAR_TRAITS(Ch), \
0406               typename Alloc = std::allocator<Ch> > \
0407     class name_ : public boost::iostreams::detail::chain_base< \
0408                             name_<Mode, Ch, Tr, Alloc>, \
0409                             Ch, Tr, Alloc, Mode \
0410                          > \
0411     { \
0412     public: \
0413         struct category : device_tag, Mode { }; \
0414         typedef Mode                                   mode; \
0415     private: \
0416         typedef boost::iostreams::detail::chain_base< \
0417                     name_<Mode, Ch, Tr, Alloc>, \
0418                     Ch, Tr, Alloc, Mode \
0419                 >                                      base_type; \
0420     public: \
0421         typedef Ch                                     char_type; \
0422         typedef Tr                                     traits_type; \
0423         typedef typename traits_type::int_type         int_type; \
0424         typedef typename traits_type::off_type         off_type; \
0425         name_() { } \
0426         name_(const name_& rhs) : base_type(rhs) { } \
0427         name_& operator=(const name_& rhs) \
0428         { base_type::operator=(rhs); return *this; } \
0429     }; \
0430     /**/
0431 BOOST_IOSTREAMS_DECL_CHAIN(chain, char)
0432 BOOST_IOSTREAMS_DECL_CHAIN(wchain, wchar_t)
0433 #undef BOOST_IOSTREAMS_DECL_CHAIN
0434 
0435 //--------------Definition of chain_client------------------------------------//
0436 
0437 namespace detail {
0438 
0439 //
0440 // Template name: chain_client
0441 // Description: Class whose instances provide access to an underlying chain
0442 //      using an interface similar to the chains.
0443 // Subclasses: the various stream and stream buffer templates.
0444 //
0445 template<typename Chain>
0446 class chain_client {
0447 public:
0448     typedef Chain                             chain_type;
0449     typedef typename chain_type::char_type    char_type;
0450     typedef typename chain_type::traits_type  traits_type;
0451     typedef typename chain_type::size_type    size_type;
0452     typedef typename chain_type::mode         mode;
0453 
0454     chain_client(chain_type* chn = 0) : chain_(chn ) { }
0455     chain_client(chain_client* client) : chain_(client->chain_) { }
0456     virtual ~chain_client() { }
0457 
0458     const boost::core::typeinfo& component_type(int n) const
0459     { return chain_->component_type(n); }
0460 
0461     // Deprecated.
0462     template<int N>
0463     const boost::core::typeinfo& component_type() const
0464     { return chain_->BOOST_NESTED_TEMPLATE component_type<N>(); }
0465 
0466     template<typename T>
0467     T* component(int n) const
0468     { return chain_->BOOST_NESTED_TEMPLATE component<T>(n); }
0469 
0470     // Deprecated.
0471     template<int N, typename T>
0472     T* component() const
0473     { return chain_->BOOST_NESTED_TEMPLATE component<N, T>(); }
0474 
0475     bool is_complete() const { return chain_->is_complete(); }
0476     bool auto_close() const { return chain_->auto_close(); }
0477     void set_auto_close(bool close) { chain_->set_auto_close(close); }
0478     bool strict_sync() { return chain_->strict_sync(); }
0479     void set_device_buffer_size(std::streamsize n)
0480         { chain_->set_device_buffer_size(n); }
0481     void set_filter_buffer_size(std::streamsize n)
0482         { chain_->set_filter_buffer_size(n); }
0483     void set_pback_size(std::streamsize n) { chain_->set_pback_size(n); }
0484     BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
0485     void pop() { chain_->pop(); }
0486     bool empty() const { return chain_->empty(); }
0487     size_type size() const { return chain_->size(); }
0488     void reset() { chain_->reset(); }
0489 
0490     // Returns a copy of the underlying chain.
0491     chain_type filters() { return *chain_; }
0492     chain_type filters() const { return *chain_; }
0493 protected:
0494     template<typename T>
0495     void push_impl(const T& t BOOST_IOSTREAMS_PUSH_PARAMS())
0496     { chain_->push(t BOOST_IOSTREAMS_PUSH_ARGS()); }
0497     chain_type& ref() { return *chain_; }
0498     void set_chain(chain_type* c)
0499     { chain_ = c; chain_->register_client(this); }
0500 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) && \
0501     (!BOOST_WORKAROUND(BOOST_BORLANDC, < 0x600))
0502     template<typename S, typename C, typename T, typename A, typename M>
0503     friend class chain_base;
0504 #else
0505     public:
0506 #endif
0507     virtual void notify() { }
0508 private:
0509     chain_type* chain_;
0510 };
0511 
0512 //--------------Implementation of chain_base----------------------------------//
0513 
0514 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0515 inline std::streamsize chain_base<Self, Ch, Tr, Alloc, Mode>::read
0516     (char_type* s, std::streamsize n)
0517 { return iostreams::read(*list().front(), s, n); }
0518 
0519 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0520 inline std::streamsize chain_base<Self, Ch, Tr, Alloc, Mode>::write
0521     (const char_type* s, std::streamsize n)
0522 { return iostreams::write(*list().front(), s, n); }
0523 
0524 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0525 inline std::streampos chain_base<Self, Ch, Tr, Alloc, Mode>::seek
0526     (stream_offset off, BOOST_IOS::seekdir way)
0527 { return iostreams::seek(*list().front(), off, way); }
0528 
0529 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0530 void chain_base<Self, Ch, Tr, Alloc, Mode>::reset()
0531 {
0532     using namespace std;
0533     pimpl_->close();
0534     pimpl_->reset();
0535 }
0536 
0537 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0538 bool chain_base<Self, Ch, Tr, Alloc, Mode>::is_complete() const
0539 {
0540     return (pimpl_->flags_ & f_complete) != 0;
0541 }
0542 
0543 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0544 bool chain_base<Self, Ch, Tr, Alloc, Mode>::auto_close() const
0545 {
0546     return (pimpl_->flags_ & f_auto_close) != 0;
0547 }
0548 
0549 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0550 void chain_base<Self, Ch, Tr, Alloc, Mode>::set_auto_close(bool close)
0551 {
0552     pimpl_->flags_ =
0553         (pimpl_->flags_ & ~f_auto_close) |
0554         (close ? f_auto_close : 0);
0555 }
0556 
0557 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0558 bool chain_base<Self, Ch, Tr, Alloc, Mode>::strict_sync()
0559 {
0560     typedef typename list_type::iterator iterator;
0561     bool result = true;
0562     for ( iterator first = list().begin(),
0563                    last = list().end();
0564           first != last;
0565           ++first )
0566     {
0567         bool s = (*first)->strict_sync();
0568         result = result && s;
0569     }
0570     return result;
0571 }
0572 
0573 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0574 void chain_base<Self, Ch, Tr, Alloc, Mode>::pop()
0575 {
0576     BOOST_ASSERT(!empty());
0577     if (auto_close())
0578         pimpl_->close();
0579     streambuf_type* buf = 0;
0580     std::swap(buf, list().back());
0581     buf->set_auto_close(false);
0582     buf->set_next(0);
0583     delete buf;
0584     list().pop_back();
0585     pimpl_->flags_ &= ~f_complete;
0586     if (auto_close() || list().empty())
0587         pimpl_->flags_ &= ~f_open;
0588 }
0589 
0590 } // End namespace detail.
0591 
0592 } } // End namespaces iostreams, boost.
0593 
0594 #endif // #ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED