File indexing completed on 2025-01-30 09:44:32
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
0009 #define BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
0010
0011 #if defined(_MSC_VER)
0012 # pragma once
0013 #endif
0014
0015 #include <boost/assert.hpp>
0016 #include <exception>
0017 #include <iterator> // advance.
0018 #include <list>
0019 #include <memory> // allocator, auto_ptr or unique_ptr.
0020 #include <stdexcept> // logic_error, out_of_range.
0021 #include <boost/checked_delete.hpp>
0022 #include <boost/config.hpp> // BOOST_MSVC, template friends,
0023 #include <boost/detail/workaround.hpp> // BOOST_NESTED_TEMPLATE
0024 #include <boost/core/typeinfo.hpp>
0025 #include <boost/iostreams/constants.hpp>
0026 #include <boost/iostreams/detail/access_control.hpp>
0027 #include <boost/iostreams/detail/char_traits.hpp>
0028 #include <boost/iostreams/detail/push.hpp>
0029 #include <boost/iostreams/detail/streambuf.hpp> // pubsync.
0030 #include <boost/iostreams/detail/wrap_unwrap.hpp>
0031 #include <boost/iostreams/device/null.hpp>
0032 #include <boost/iostreams/positioning.hpp>
0033 #include <boost/iostreams/traits.hpp> // is_filter.
0034 #include <boost/iostreams/stream_buffer.hpp>
0035 #include <boost/next_prior.hpp>
0036 #include <boost/shared_ptr.hpp>
0037 #include <boost/static_assert.hpp>
0038 #include <boost/throw_exception.hpp>
0039 #include <boost/type_traits/is_convertible.hpp>
0040 #include <boost/type.hpp>
0041 #include <boost/iostreams/detail/execute.hpp>
0042
0043
0044
0045 #if defined(__GNUC__) || \
0046 defined(_AIX) || \
0047 (defined(__sgi) && defined(__host_mips)) || \
0048 (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC)) \
0049
0050 # include <cstring>
0051 # define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) \
0052 (std::strcmp((X).name(),(Y).name()) == 0)
0053 #else
0054 # define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
0055 #endif
0056
0057
0058 #define BOOST_IOSTREAMS_COMPONENT_TYPE(chain, index) \
0059 chain.component_type( index ) \
0060
0061
0062
0063 #define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \
0064 chain.component< target >( index ) \
0065
0066
0067 namespace boost { namespace iostreams {
0068
0069
0070
0071 namespace detail {
0072
0073 template<typename Chain> class chain_client;
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0114 class chain_base {
0115 public:
0116 typedef Ch char_type;
0117 BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr)
0118 typedef Alloc allocator_type;
0119 typedef Mode mode;
0120 struct category
0121 : Mode,
0122 device_tag
0123 { };
0124 typedef chain_client<Self> client_type;
0125 friend class chain_client<Self>;
0126 private:
0127 typedef linked_streambuf<Ch> streambuf_type;
0128 typedef std::list<streambuf_type*> list_type;
0129 typedef chain_base<Self, Ch, Tr, Alloc, Mode> my_type;
0130 protected:
0131 chain_base() : pimpl_(new chain_impl) { }
0132 chain_base(const chain_base& rhs): pimpl_(rhs.pimpl_) { }
0133 public:
0134
0135
0136
0137 BOOST_STATIC_ASSERT((!is_convertible<mode, dual_use>::value));
0138
0139
0140
0141
0142
0143
0144 void set_device_buffer_size(std::streamsize n)
0145 { pimpl_->device_buffer_size_ = n; }
0146
0147
0148
0149
0150 void set_filter_buffer_size(std::streamsize n)
0151 { pimpl_->filter_buffer_size_ = n; }
0152
0153
0154
0155
0156 void set_pback_size(std::streamsize n)
0157 { pimpl_->pback_size_ = n; }
0158
0159
0160
0161 std::streamsize read(char_type* s, std::streamsize n);
0162 std::streamsize write(const char_type* s, std::streamsize n);
0163 std::streampos seek(stream_offset off, BOOST_IOS::seekdir way);
0164
0165
0166
0167 const boost::core::typeinfo& component_type(int n) const
0168 {
0169 if (static_cast<size_type>(n) >= size())
0170 boost::throw_exception(std::out_of_range("bad chain offset"));
0171 return (*boost::next(list().begin(), n))->component_type();
0172 }
0173
0174
0175 template<int N>
0176 const boost::core::typeinfo& component_type() const { return component_type(N); }
0177
0178 template<typename T>
0179 T* component(int n) const { return component(n, boost::type<T>()); }
0180
0181
0182 template<int N, typename T>
0183 T* component() const { return component<T>(N); }
0184
0185 #if !BOOST_WORKAROUND(BOOST_MSVC, == 1310)
0186 private:
0187 #endif
0188 template<typename T>
0189 T* component(int n, boost::type<T>) const
0190 {
0191 if (static_cast<size_type>(n) >= size())
0192 boost::throw_exception(std::out_of_range("bad chain offset"));
0193 streambuf_type* link = *boost::next(list().begin(), n);
0194 if (BOOST_IOSTREAMS_COMPARE_TYPE_ID(link->component_type(), BOOST_CORE_TYPEID(T)))
0195 return static_cast<T*>(link->component_impl());
0196 else
0197 return 0;
0198 }
0199 public:
0200
0201
0202
0203 typedef typename list_type::size_type size_type;
0204 streambuf_type& front() { return *list().front(); }
0205 BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
0206 void pop();
0207 bool empty() const { return list().empty(); }
0208 size_type size() const { return list().size(); }
0209 void reset();
0210
0211
0212
0213
0214
0215 bool is_complete() const;
0216 bool auto_close() const;
0217 void set_auto_close(bool close);
0218 bool sync() { return front().BOOST_IOSTREAMS_PUBSYNC() != -1; }
0219 bool strict_sync();
0220 private:
0221 template<typename T>
0222 void push_impl(const T& t, std::streamsize buffer_size = -1,
0223 std::streamsize pback_size = -1)
0224 {
0225 typedef typename iostreams::category_of<T>::type category;
0226 typedef typename unwrap_ios<T>::type component_type;
0227 typedef stream_buffer<
0228 component_type,
0229 BOOST_IOSTREAMS_CHAR_TRAITS(char_type),
0230 Alloc, Mode
0231 > streambuf_t;
0232 typedef typename list_type::iterator iterator;
0233 BOOST_STATIC_ASSERT((is_convertible<category, Mode>::value));
0234 if (is_complete())
0235 boost::throw_exception(std::logic_error("chain complete"));
0236 streambuf_type* prev = !empty() ? list().back() : 0;
0237 buffer_size =
0238 buffer_size != -1 ?
0239 buffer_size :
0240 iostreams::optimal_buffer_size(t);
0241 pback_size =
0242 pback_size != -1 ?
0243 pback_size :
0244 pimpl_->pback_size_;
0245
0246 #if defined(BOOST_NO_CXX11_SMART_PTR)
0247
0248 std::auto_ptr<streambuf_t>
0249 buf(new streambuf_t(t, buffer_size, pback_size));
0250
0251 #else
0252
0253 std::unique_ptr<streambuf_t>
0254 buf(new streambuf_t(t, buffer_size, pback_size));
0255
0256 #endif
0257
0258 list().push_back(buf.get());
0259 buf.release();
0260 if (is_device<component_type>::value) {
0261 pimpl_->flags_ |= f_complete | f_open;
0262 for ( iterator first = list().begin(),
0263 last = list().end();
0264 first != last;
0265 ++first )
0266 {
0267 (*first)->set_needs_close();
0268 }
0269 }
0270 if (prev) prev->set_next(list().back());
0271 notify();
0272 }
0273
0274 list_type& list() { return pimpl_->links_; }
0275 const list_type& list() const { return pimpl_->links_; }
0276 void register_client(client_type* client) { pimpl_->client_ = client; }
0277 void notify() { if (pimpl_->client_) pimpl_->client_->notify(); }
0278
0279
0280
0281 static void close(streambuf_type* b, BOOST_IOS::openmode m)
0282 {
0283 if (m == BOOST_IOS::out && is_convertible<Mode, output>::value)
0284 b->BOOST_IOSTREAMS_PUBSYNC();
0285 b->close(m);
0286 }
0287
0288 static void set_next(streambuf_type* b, streambuf_type* next)
0289 { b->set_next(next); }
0290
0291 static void set_auto_close(streambuf_type* b, bool close)
0292 { b->set_auto_close(close); }
0293
0294 struct closer {
0295 typedef streambuf_type* argument_type;
0296 typedef void result_type;
0297 closer(BOOST_IOS::openmode m) : mode_(m) { }
0298 void operator() (streambuf_type* b)
0299 {
0300 close(b, mode_);
0301 }
0302 BOOST_IOS::openmode mode_;
0303 };
0304 friend struct closer;
0305
0306 enum flags {
0307 f_complete = 1,
0308 f_open = 2,
0309 f_auto_close = 4
0310 };
0311
0312 struct chain_impl {
0313 chain_impl()
0314 : client_(0), device_buffer_size_(default_device_buffer_size),
0315 filter_buffer_size_(default_filter_buffer_size),
0316 pback_size_(default_pback_buffer_size),
0317 flags_(f_auto_close)
0318 { }
0319 ~chain_impl()
0320 {
0321 try { close(); } catch (...) { }
0322 try { reset(); } catch (...) { }
0323 }
0324 void close()
0325 {
0326 if ((flags_ & f_open) != 0) {
0327 flags_ &= ~f_open;
0328 stream_buffer< basic_null_device<Ch, Mode> > null;
0329 if ((flags_ & f_complete) == 0) {
0330 null.open(basic_null_device<Ch, Mode>());
0331 set_next(links_.back(), &null);
0332 }
0333 links_.front()->BOOST_IOSTREAMS_PUBSYNC();
0334 try {
0335 boost::iostreams::detail::execute_foreach(
0336 links_.rbegin(), links_.rend(),
0337 closer(BOOST_IOS::in)
0338 );
0339 } catch (...) {
0340 try {
0341 boost::iostreams::detail::execute_foreach(
0342 links_.begin(), links_.end(),
0343 closer(BOOST_IOS::out)
0344 );
0345 } catch (...) { }
0346 throw;
0347 }
0348 boost::iostreams::detail::execute_foreach(
0349 links_.begin(), links_.end(),
0350 closer(BOOST_IOS::out)
0351 );
0352 }
0353 }
0354 void reset()
0355 {
0356 typedef typename list_type::iterator iterator;
0357 for ( iterator first = links_.begin(),
0358 last = links_.end();
0359 first != last;
0360 ++first )
0361 {
0362 if ( (flags_ & f_complete) == 0 ||
0363 (flags_ & f_auto_close) == 0 )
0364 {
0365 set_auto_close(*first, false);
0366 }
0367 streambuf_type* buf = 0;
0368 std::swap(buf, *first);
0369 delete buf;
0370 }
0371 links_.clear();
0372 flags_ &= ~f_complete;
0373 flags_ &= ~f_open;
0374 }
0375 list_type links_;
0376 client_type* client_;
0377 std::streamsize device_buffer_size_,
0378 filter_buffer_size_,
0379 pback_size_;
0380 int flags_;
0381 };
0382 friend struct chain_impl;
0383
0384
0385
0386 private:
0387 shared_ptr<chain_impl> pimpl_;
0388 };
0389
0390 }
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403 #define BOOST_IOSTREAMS_DECL_CHAIN(name_, default_char_) \
0404 template< typename Mode, typename Ch = default_char_, \
0405 typename Tr = BOOST_IOSTREAMS_CHAR_TRAITS(Ch), \
0406 typename Alloc = std::allocator<Ch> > \
0407 class name_ : public boost::iostreams::detail::chain_base< \
0408 name_<Mode, Ch, Tr, Alloc>, \
0409 Ch, Tr, Alloc, Mode \
0410 > \
0411 { \
0412 public: \
0413 struct category : device_tag, Mode { }; \
0414 typedef Mode mode; \
0415 private: \
0416 typedef boost::iostreams::detail::chain_base< \
0417 name_<Mode, Ch, Tr, Alloc>, \
0418 Ch, Tr, Alloc, Mode \
0419 > base_type; \
0420 public: \
0421 typedef Ch char_type; \
0422 typedef Tr traits_type; \
0423 typedef typename traits_type::int_type int_type; \
0424 typedef typename traits_type::off_type off_type; \
0425 name_() { } \
0426 name_(const name_& rhs) : base_type(rhs) { } \
0427 name_& operator=(const name_& rhs) \
0428 { base_type::operator=(rhs); return *this; } \
0429 }; \
0430
0431 BOOST_IOSTREAMS_DECL_CHAIN(chain, char)
0432 BOOST_IOSTREAMS_DECL_CHAIN(wchain, wchar_t)
0433 #undef BOOST_IOSTREAMS_DECL_CHAIN
0434
0435
0436
0437 namespace detail {
0438
0439
0440
0441
0442
0443
0444
0445 template<typename Chain>
0446 class chain_client {
0447 public:
0448 typedef Chain chain_type;
0449 typedef typename chain_type::char_type char_type;
0450 typedef typename chain_type::traits_type traits_type;
0451 typedef typename chain_type::size_type size_type;
0452 typedef typename chain_type::mode mode;
0453
0454 chain_client(chain_type* chn = 0) : chain_(chn ) { }
0455 chain_client(chain_client* client) : chain_(client->chain_) { }
0456 virtual ~chain_client() { }
0457
0458 const boost::core::typeinfo& component_type(int n) const
0459 { return chain_->component_type(n); }
0460
0461
0462 template<int N>
0463 const boost::core::typeinfo& component_type() const
0464 { return chain_->BOOST_NESTED_TEMPLATE component_type<N>(); }
0465
0466 template<typename T>
0467 T* component(int n) const
0468 { return chain_->BOOST_NESTED_TEMPLATE component<T>(n); }
0469
0470
0471 template<int N, typename T>
0472 T* component() const
0473 { return chain_->BOOST_NESTED_TEMPLATE component<N, T>(); }
0474
0475 bool is_complete() const { return chain_->is_complete(); }
0476 bool auto_close() const { return chain_->auto_close(); }
0477 void set_auto_close(bool close) { chain_->set_auto_close(close); }
0478 bool strict_sync() { return chain_->strict_sync(); }
0479 void set_device_buffer_size(std::streamsize n)
0480 { chain_->set_device_buffer_size(n); }
0481 void set_filter_buffer_size(std::streamsize n)
0482 { chain_->set_filter_buffer_size(n); }
0483 void set_pback_size(std::streamsize n) { chain_->set_pback_size(n); }
0484 BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
0485 void pop() { chain_->pop(); }
0486 bool empty() const { return chain_->empty(); }
0487 size_type size() const { return chain_->size(); }
0488 void reset() { chain_->reset(); }
0489
0490
0491 chain_type filters() { return *chain_; }
0492 chain_type filters() const { return *chain_; }
0493 protected:
0494 template<typename T>
0495 void push_impl(const T& t BOOST_IOSTREAMS_PUSH_PARAMS())
0496 { chain_->push(t BOOST_IOSTREAMS_PUSH_ARGS()); }
0497 chain_type& ref() { return *chain_; }
0498 void set_chain(chain_type* c)
0499 { chain_ = c; chain_->register_client(this); }
0500 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) && \
0501 (!BOOST_WORKAROUND(BOOST_BORLANDC, < 0x600))
0502 template<typename S, typename C, typename T, typename A, typename M>
0503 friend class chain_base;
0504 #else
0505 public:
0506 #endif
0507 virtual void notify() { }
0508 private:
0509 chain_type* chain_;
0510 };
0511
0512
0513
0514 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0515 inline std::streamsize chain_base<Self, Ch, Tr, Alloc, Mode>::read
0516 (char_type* s, std::streamsize n)
0517 { return iostreams::read(*list().front(), s, n); }
0518
0519 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0520 inline std::streamsize chain_base<Self, Ch, Tr, Alloc, Mode>::write
0521 (const char_type* s, std::streamsize n)
0522 { return iostreams::write(*list().front(), s, n); }
0523
0524 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0525 inline std::streampos chain_base<Self, Ch, Tr, Alloc, Mode>::seek
0526 (stream_offset off, BOOST_IOS::seekdir way)
0527 { return iostreams::seek(*list().front(), off, way); }
0528
0529 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0530 void chain_base<Self, Ch, Tr, Alloc, Mode>::reset()
0531 {
0532 using namespace std;
0533 pimpl_->close();
0534 pimpl_->reset();
0535 }
0536
0537 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0538 bool chain_base<Self, Ch, Tr, Alloc, Mode>::is_complete() const
0539 {
0540 return (pimpl_->flags_ & f_complete) != 0;
0541 }
0542
0543 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0544 bool chain_base<Self, Ch, Tr, Alloc, Mode>::auto_close() const
0545 {
0546 return (pimpl_->flags_ & f_auto_close) != 0;
0547 }
0548
0549 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0550 void chain_base<Self, Ch, Tr, Alloc, Mode>::set_auto_close(bool close)
0551 {
0552 pimpl_->flags_ =
0553 (pimpl_->flags_ & ~f_auto_close) |
0554 (close ? f_auto_close : 0);
0555 }
0556
0557 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0558 bool chain_base<Self, Ch, Tr, Alloc, Mode>::strict_sync()
0559 {
0560 typedef typename list_type::iterator iterator;
0561 bool result = true;
0562 for ( iterator first = list().begin(),
0563 last = list().end();
0564 first != last;
0565 ++first )
0566 {
0567 bool s = (*first)->strict_sync();
0568 result = result && s;
0569 }
0570 return result;
0571 }
0572
0573 template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
0574 void chain_base<Self, Ch, Tr, Alloc, Mode>::pop()
0575 {
0576 BOOST_ASSERT(!empty());
0577 if (auto_close())
0578 pimpl_->close();
0579 streambuf_type* buf = 0;
0580 std::swap(buf, list().back());
0581 buf->set_auto_close(false);
0582 buf->set_next(0);
0583 delete buf;
0584 list().pop_back();
0585 pimpl_->flags_ &= ~f_complete;
0586 if (auto_close() || list().empty())
0587 pimpl_->flags_ &= ~f_open;
0588 }
0589
0590 }
0591
0592 } }
0593
0594 #endif