| [12] | 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 |  | 
|---|
 | 74 | namespace boost { namespace iostreams { | 
|---|
 | 75 |  | 
|---|
 | 76 | //--------------Definition of chain and wchain--------------------------------// | 
|---|
 | 77 |  | 
|---|
 | 78 | namespace detail { | 
|---|
 | 79 |  | 
|---|
 | 80 | template<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 | // | 
|---|
 | 120 | template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode> | 
|---|
 | 121 | class chain_base { | 
|---|
 | 122 | public: | 
|---|
 | 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>; | 
|---|
 | 133 | private: | 
|---|
 | 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; | 
|---|
 | 137 | protected: | 
|---|
 | 138 |     chain_base() : pimpl_(new chain_impl) { } | 
|---|
 | 139 |     chain_base(const chain_base& rhs): pimpl_(rhs.pimpl_) { } | 
|---|
 | 140 | public: | 
|---|
 | 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 |     } | 
|---|
 | 221 | private: | 
|---|
 | 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 |  | 
|---|
 | 348 | private: | 
|---|
 | 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 |     /**/ | 
|---|
 | 393 | BOOST_IOSTREAMS_DECL_CHAIN(chain, char) | 
|---|
 | 394 | BOOST_IOSTREAMS_DECL_CHAIN(wchain, wchar_t) | 
|---|
 | 395 | #undef BOOST_IOSTREAMS_DECL_CHAIN | 
|---|
 | 396 |  | 
|---|
 | 397 | //--------------Definition of chain_client------------------------------------// | 
|---|
 | 398 |  | 
|---|
 | 399 | namespace 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 | // | 
|---|
 | 407 | template<typename Chain> | 
|---|
 | 408 | class chain_client { | 
|---|
 | 409 | public: | 
|---|
 | 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_; } | 
|---|
 | 481 | protected: | 
|---|
 | 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() { } | 
|---|
 | 496 | private: | 
|---|
 | 497 |     chain_type* chain_; | 
|---|
 | 498 | }; | 
|---|
 | 499 |  | 
|---|
 | 500 | //--------------Implementation of chain_base----------------------------------// | 
|---|
 | 501 |  | 
|---|
 | 502 | template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode> | 
|---|
 | 503 | inline 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 |  | 
|---|
 | 507 | template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode> | 
|---|
 | 508 | inline 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 |  | 
|---|
 | 512 | template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode> | 
|---|
 | 513 | inline 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 |  | 
|---|
 | 517 | template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode> | 
|---|
 | 518 | void chain_base<Self, Ch, Tr, Alloc, Mode>::reset() | 
|---|
 | 519 | { | 
|---|
 | 520 |     using namespace std; | 
|---|
 | 521 |     pimpl_->close(); | 
|---|
 | 522 |     pimpl_->reset(); | 
|---|
 | 523 | } | 
|---|
 | 524 |  | 
|---|
 | 525 | template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode> | 
|---|
 | 526 | bool chain_base<Self, Ch, Tr, Alloc, Mode>::is_complete() const | 
|---|
 | 527 | { | 
|---|
 | 528 |     return (pimpl_->flags_ & f_complete) != 0; | 
|---|
 | 529 | } | 
|---|
 | 530 |  | 
|---|
 | 531 | template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode> | 
|---|
 | 532 | bool chain_base<Self, Ch, Tr, Alloc, Mode>::auto_close() const | 
|---|
 | 533 | { | 
|---|
 | 534 |     return (pimpl_->flags_ & f_auto_close) != 0; | 
|---|
 | 535 | } | 
|---|
 | 536 |  | 
|---|
 | 537 | template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode> | 
|---|
 | 538 | void 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 |  | 
|---|
 | 545 | template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode> | 
|---|
 | 546 | bool 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 |  | 
|---|
 | 561 | template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode> | 
|---|
 | 562 | void 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 | 
|---|