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