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