]> git.lyx.org Git - lyx.git/blob - boost/boost/iostreams/chain.hpp
Replace gzstream by boost::iostreams::gzip_(de)compressor: by Bo Peng (ben.bob@gmail...
[lyx.git] / boost / boost / iostreams / chain.hpp
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