]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/iostreams/include/boost/iostreams/chain.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / iostreams / include / 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)
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>
43
44 // Sometimes type_info objects must be compared by name. Borrowed from
45 // Boost.Python and Boost.Function.
46 #if defined(__GNUC__) || \
47 defined(_AIX) || \
48 (defined(__sgi) && defined(__host_mips)) || \
49 (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC)) \
50 /**/
51 # include <cstring>
52 # define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) \
53 (std::strcmp((X).name(),(Y).name()) == 0)
54 #else
55 # define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
56 #endif
57
58 // Deprecated. Unused.
59 #define BOOST_IOSTREAMS_COMPONENT_TYPE(chain, index) \
60 chain.component_type( index ) \
61 /**/
62
63 // Deprecated. Unused.
64 #define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \
65 chain.component< target >( index ) \
66 /**/
67
68 namespace boost { namespace iostreams {
69
70 //--------------Definition of chain and wchain--------------------------------//
71
72 namespace detail {
73
74 template<typename Chain> class chain_client;
75
76 //
77 // Concept name: Chain.
78 // Description: Represents a chain of stream buffers which provides access
79 // to the first buffer in the chain and sends notifications when the
80 // streambufs are added to or removed from chain.
81 // Refines: Closable device with mode equal to typename Chain::mode.
82 // Models: chain, converting_chain.
83 // Example:
84 //
85 // class chain {
86 // public:
87 // typedef xxx chain_type;
88 // typedef xxx client_type;
89 // typedef xxx mode;
90 // bool is_complete() const; // Ready for i/o.
91 // template<typename T>
92 // void push( const T& t, // Adds a stream buffer to
93 // streamsize, // chain, based on t, with
94 // streamsize ); // given buffer and putback
95 // // buffer sizes. Pass -1 to
96 // // request default size.
97 // protected:
98 // void register_client(client_type* client); // Associate client.
99 // void notify(); // Notify client.
100 // };
101 //
102
103 //
104 // Description: Represents a chain of filters with an optional device at the
105 // end.
106 // Template parameters:
107 // Self - A class deriving from the current instantiation of this template.
108 // This is an example of the Curiously Recurring Template Pattern.
109 // Ch - The character type.
110 // Tr - The character traits type.
111 // Alloc - The allocator type.
112 // Mode - A mode tag.
113 //
114 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
115 class chain_base {
116 public:
117 typedef Ch char_type;
118 BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr)
119 typedef Alloc allocator_type;
120 typedef Mode mode;
121 struct category
122 : Mode,
123 device_tag
124 { };
125 typedef chain_client<Self> client_type;
126 friend class chain_client<Self>;
127 private:
128 typedef linked_streambuf<Ch> streambuf_type;
129 typedef std::list<streambuf_type*> list_type;
130 typedef chain_base<Self, Ch, Tr, Alloc, Mode> my_type;
131 protected:
132 chain_base() : pimpl_(new chain_impl) { }
133 chain_base(const chain_base& rhs): pimpl_(rhs.pimpl_) { }
134 public:
135
136 // dual_use is a pseudo-mode to facilitate filter writing,
137 // not a genuine mode.
138 BOOST_STATIC_ASSERT((!is_convertible<mode, dual_use>::value));
139
140 //----------Buffer sizing-------------------------------------------------//
141
142 // Sets the size of the buffer created for the devices to be added to this
143 // chain. Does not affect the size of the buffer for devices already
144 // added.
145 void set_device_buffer_size(std::streamsize n)
146 { pimpl_->device_buffer_size_ = n; }
147
148 // Sets the size of the buffer created for the filters to be added
149 // to this chain. Does not affect the size of the buffer for filters already
150 // added.
151 void set_filter_buffer_size(std::streamsize n)
152 { 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(std::streamsize n)
158 { pimpl_->pback_size_ = n; }
159
160 //----------Device interface----------------------------------------------//
161
162 std::streamsize read(char_type* s, std::streamsize n);
163 std::streamsize write(const char_type* s, std::streamsize n);
164 std::streampos seek(stream_offset off, BOOST_IOS::seekdir way);
165
166 //----------Direct component access---------------------------------------//
167
168 const std::type_info& component_type(int n) const
169 {
170 if (static_cast<size_type>(n) >= size())
171 boost::throw_exception(std::out_of_range("bad chain offset"));
172 return (*boost::next(list().begin(), n))->component_type();
173 }
174
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
186 #if !BOOST_WORKAROUND(BOOST_MSVC, == 1310)
187 private:
188 #endif
189 template<typename T>
190 T* component(int n, boost::type<T>) const
191 {
192 if (static_cast<size_type>(n) >= size())
193 boost::throw_exception(std::out_of_range("bad chain offset"));
194 streambuf_type* link = *boost::next(list().begin(), n);
195 if (BOOST_IOSTREAMS_COMPARE_TYPE_ID(link->component_type(), typeid(T)))
196 return static_cast<T*>(link->component_impl());
197 else
198 return 0;
199 }
200 public:
201
202 //----------Container-like interface--------------------------------------//
203
204 typedef typename list_type::size_type size_type;
205 streambuf_type& front() { return *list().front(); }
206 BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
207 void pop();
208 bool empty() const { return list().empty(); }
209 size_type size() const { return list().size(); }
210 void reset();
211
212 //----------Additional i/o functions--------------------------------------//
213
214 // Returns true if this chain is non-empty and its final link
215 // is a source or sink, i.e., if it is ready to perform i/o.
216 bool is_complete() const;
217 bool auto_close() const;
218 void set_auto_close(bool close);
219 bool sync() { return front().BOOST_IOSTREAMS_PUBSYNC() != -1; }
220 bool strict_sync();
221 private:
222 template<typename T>
223 void push_impl(const T& t, std::streamsize buffer_size = -1,
224 std::streamsize pback_size = -1)
225 {
226 typedef typename iostreams::category_of<T>::type category;
227 typedef typename unwrap_ios<T>::type component_type;
228 typedef stream_buffer<
229 component_type,
230 BOOST_IOSTREAMS_CHAR_TRAITS(char_type),
231 Alloc, Mode
232 > streambuf_t;
233 typedef typename list_type::iterator iterator;
234 BOOST_STATIC_ASSERT((is_convertible<category, Mode>::value));
235 if (is_complete())
236 boost::throw_exception(std::logic_error("chain complete"));
237 streambuf_type* prev = !empty() ? list().back() : 0;
238 buffer_size =
239 buffer_size != -1 ?
240 buffer_size :
241 iostreams::optimal_buffer_size(t);
242 pback_size =
243 pback_size != -1 ?
244 pback_size :
245 pimpl_->pback_size_;
246 std::auto_ptr<streambuf_t>
247 buf(new streambuf_t(t, buffer_size, pback_size));
248 list().push_back(buf.get());
249 buf.release();
250 if (is_device<component_type>::value) {
251 pimpl_->flags_ |= f_complete | f_open;
252 for ( iterator first = list().begin(),
253 last = list().end();
254 first != last;
255 ++first )
256 {
257 (*first)->set_needs_close();
258 }
259 }
260 if (prev) prev->set_next(list().back());
261 notify();
262 }
263
264 list_type& list() { return pimpl_->links_; }
265 const list_type& list() const { return pimpl_->links_; }
266 void register_client(client_type* client) { pimpl_->client_ = client; }
267 void notify() { if (pimpl_->client_) pimpl_->client_->notify(); }
268
269 //----------Nested classes------------------------------------------------//
270
271 static void close(streambuf_type* b, BOOST_IOS::openmode m)
272 {
273 if (m == BOOST_IOS::out && is_convertible<Mode, output>::value)
274 b->BOOST_IOSTREAMS_PUBSYNC();
275 b->close(m);
276 }
277
278 static void set_next(streambuf_type* b, streambuf_type* next)
279 { b->set_next(next); }
280
281 static void set_auto_close(streambuf_type* b, bool close)
282 { b->set_auto_close(close); }
283
284 struct closer : public std::unary_function<streambuf_type*, void> {
285 closer(BOOST_IOS::openmode m) : mode_(m) { }
286 void operator() (streambuf_type* b)
287 {
288 close(b, mode_);
289 }
290 BOOST_IOS::openmode mode_;
291 };
292 friend struct closer;
293
294 enum flags {
295 f_complete = 1,
296 f_open = 2,
297 f_auto_close = 4
298 };
299
300 struct chain_impl {
301 chain_impl()
302 : client_(0), device_buffer_size_(default_device_buffer_size),
303 filter_buffer_size_(default_filter_buffer_size),
304 pback_size_(default_pback_buffer_size),
305 flags_(f_auto_close)
306 { }
307 ~chain_impl()
308 {
309 try { close(); } catch (...) { }
310 try { reset(); } catch (...) { }
311 }
312 void close()
313 {
314 if ((flags_ & f_open) != 0) {
315 flags_ &= ~f_open;
316 stream_buffer< basic_null_device<Ch, Mode> > null;
317 if ((flags_ & f_complete) == 0) {
318 null.open(basic_null_device<Ch, Mode>());
319 set_next(links_.back(), &null);
320 }
321 links_.front()->BOOST_IOSTREAMS_PUBSYNC();
322 try {
323 boost::iostreams::detail::execute_foreach(
324 links_.rbegin(), links_.rend(),
325 closer(BOOST_IOS::in)
326 );
327 } catch (...) {
328 try {
329 boost::iostreams::detail::execute_foreach(
330 links_.begin(), links_.end(),
331 closer(BOOST_IOS::out)
332 );
333 } catch (...) { }
334 throw;
335 }
336 boost::iostreams::detail::execute_foreach(
337 links_.begin(), links_.end(),
338 closer(BOOST_IOS::out)
339 );
340 }
341 }
342 void reset()
343 {
344 typedef typename list_type::iterator iterator;
345 for ( iterator first = links_.begin(),
346 last = links_.end();
347 first != last;
348 ++first )
349 {
350 if ( (flags_ & f_complete) == 0 ||
351 (flags_ & f_auto_close) == 0 )
352 {
353 set_auto_close(*first, false);
354 }
355 streambuf_type* buf = 0;
356 std::swap(buf, *first);
357 delete buf;
358 }
359 links_.clear();
360 flags_ &= ~f_complete;
361 flags_ &= ~f_open;
362 }
363 list_type links_;
364 client_type* client_;
365 std::streamsize device_buffer_size_,
366 filter_buffer_size_,
367 pback_size_;
368 int flags_;
369 };
370 friend struct chain_impl;
371
372 //----------Member data---------------------------------------------------//
373
374 private:
375 shared_ptr<chain_impl> pimpl_;
376 };
377
378 } // End namespace detail.
379
380 //
381 // Macro: BOOST_IOSTREAMS_DECL_CHAIN(name, category)
382 // Description: Defines a template derived from chain_base appropriate for a
383 // particular i/o category. The template has the following parameters:
384 // Ch - The character type.
385 // Tr - The character traits type.
386 // Alloc - The allocator type.
387 // Macro parameters:
388 // name_ - The name of the template to be defined.
389 // category_ - The i/o category of the template to be defined.
390 //
391 #define BOOST_IOSTREAMS_DECL_CHAIN(name_, default_char_) \
392 template< typename Mode, typename Ch = default_char_, \
393 typename Tr = BOOST_IOSTREAMS_CHAR_TRAITS(Ch), \
394 typename Alloc = std::allocator<Ch> > \
395 class name_ : public boost::iostreams::detail::chain_base< \
396 name_<Mode, Ch, Tr, Alloc>, \
397 Ch, Tr, Alloc, Mode \
398 > \
399 { \
400 public: \
401 struct category : device_tag, Mode { }; \
402 typedef Mode mode; \
403 private: \
404 typedef boost::iostreams::detail::chain_base< \
405 name_<Mode, Ch, Tr, Alloc>, \
406 Ch, Tr, Alloc, Mode \
407 > base_type; \
408 public: \
409 typedef Ch char_type; \
410 typedef Tr traits_type; \
411 typedef typename traits_type::int_type int_type; \
412 typedef typename traits_type::off_type off_type; \
413 name_() { } \
414 name_(const name_& rhs) : base_type(rhs) { } \
415 name_& operator=(const name_& rhs) \
416 { base_type::operator=(rhs); return *this; } \
417 }; \
418 /**/
419 BOOST_IOSTREAMS_DECL_CHAIN(chain, char)
420 BOOST_IOSTREAMS_DECL_CHAIN(wchain, wchar_t)
421 #undef BOOST_IOSTREAMS_DECL_CHAIN
422
423 //--------------Definition of chain_client------------------------------------//
424
425 namespace detail {
426
427 //
428 // Template name: chain_client
429 // Description: Class whose instances provide access to an underlying chain
430 // using an interface similar to the chains.
431 // Subclasses: the various stream and stream buffer templates.
432 //
433 template<typename Chain>
434 class chain_client {
435 public:
436 typedef Chain chain_type;
437 typedef typename chain_type::char_type char_type;
438 typedef typename chain_type::traits_type traits_type;
439 typedef typename chain_type::size_type size_type;
440 typedef typename chain_type::mode mode;
441
442 chain_client(chain_type* chn = 0) : chain_(chn ) { }
443 chain_client(chain_client* client) : chain_(client->chain_) { }
444 virtual ~chain_client() { }
445
446 const std::type_info& component_type(int n) const
447 { return chain_->component_type(n); }
448
449 // Deprecated.
450 template<int N>
451 const std::type_info& component_type() const
452 { return chain_->BOOST_NESTED_TEMPLATE component_type<N>(); }
453
454 template<typename T>
455 T* component(int n) const
456 { return chain_->BOOST_NESTED_TEMPLATE component<T>(n); }
457
458 // Deprecated.
459 template<int N, typename T>
460 T* component() const
461 { return chain_->BOOST_NESTED_TEMPLATE component<N, T>(); }
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 BOOST_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