From 6bcce095979898aaef5ba71940d94c1cb0e07c83 Mon Sep 17 00:00:00 2001 From: Jonathan Turkanis Date: Wed, 13 Apr 2005 03:42:06 +0000 Subject: [PATCH] fixed auto_close; added component_type compatibility macros [SVN r28188] --- include/boost/iostreams/chain.hpp | 156 ++++++++++++++++++++++++------ 1 file changed, 126 insertions(+), 30 deletions(-) diff --git a/include/boost/iostreams/chain.hpp b/include/boost/iostreams/chain.hpp index 05ae983..cba300a 100755 --- a/include/boost/iostreams/chain.hpp +++ b/include/boost/iostreams/chain.hpp @@ -30,12 +30,17 @@ #include #include // pubsync. #include +#include #include // is_filter. #include #include #include #include #include +#if BOOST_WORKAROUND(BOOST_MSVC, < 1310) +# include +# include +#endif // Sometimes type_info objects must be compared by name. Borrowed from // Boost.Python and Boost.Function. @@ -51,6 +56,22 @@ # define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) ((X)==(Y)) #endif +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310) +# define BOOST_IOSTREAMS_COMPONENT_TYPE(chain, index) \ + chain.component_type< index >() \ + /**/ +# define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \ + chain.component< index, target >() \ + /**/ +#else +# define BOOST_IOSTREAMS_COMPONENT_TYPE(chain, index) \ + chain.component_type( ::boost::mpl::int_< index >() ) \ + /**/ +# define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \ + chain.component( ::boost::mpl::int_< index >(), ::boost::type< target >() ) \ + /**/ +#endif + namespace boost { namespace iostreams { //--------------Definition of chain and wchain--------------------------------// @@ -145,6 +166,7 @@ public: //----------Direct component access---------------------------------------// +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310) template const std::type_info& component_type() const { @@ -164,6 +186,27 @@ public: else return 0; } +#else + template + const std::type_info& component_type(mpl::int_) const + { + if (N >= size()) + throw std::out_of_range("bad chain offset"); + return (*boost::next(list().begin(), N))->component_type(); + } + + template + T* component(mpl::int_, boost::type) const + { + if (N >= size()) + throw std::out_of_range("bad chain offset"); + streambuf_type* link = *boost::next(list().begin(), N); + if (BOOST_IOSTREAMS_COMPARE_TYPE_ID(link->component_type(), typeid(T))) + return static_cast(link->component_impl()); + else + return 0; + } +#endif //----------Container-like interface--------------------------------------// @@ -180,6 +223,7 @@ public: bool is_complete() const; bool auto_close() const; void set_auto_close(bool close); + bool strict_sync(); private: template void push_impl(const T& t, int buffer_size = -1, int pback_size = -1) @@ -208,7 +252,7 @@ private: list().push_back(buf.get()); buf.release(); if (is_device::value) - pimpl_->flags_ |= f_complete; + pimpl_->flags_ |= f_complete | f_open; if (prev) prev->set_next(list().back()); notify(); } @@ -220,10 +264,6 @@ private: //----------Nested classes------------------------------------------------// - // The static member close and the structs closer are used by - // chain_impl::close. A more elegant solution using boost::bind failed on - // VC6 and Borland. - static void close(streambuf_type* b, BOOST_IOS::openmode m) { if (m & BOOST_IOS::out) @@ -231,6 +271,12 @@ private: b->close(m); } + static void set_next(streambuf_type* b, streambuf_type* next) + { b->set_next(next); } + + static void set_auto_close(streambuf_type* b, bool close) + { b->set_auto_close(close); } + struct closer : public std::unary_function { closer(BOOST_IOS::openmode m) : mode_(m) { } void operator() (streambuf_type* b) { close(b, mode_); } @@ -240,7 +286,8 @@ private: enum { f_complete = 1, - f_auto_close = 2 + f_open = 2, + f_auto_close = 4 }; struct chain_impl { @@ -250,26 +297,45 @@ private: pback_size_(default_pback_buffer_size), flags_(f_auto_close) { } - ~chain_impl() - { - try { - if ((flags_ & f_auto_close) != 0) - close(); - } catch (std::exception&) { } - std::for_each( links_.begin(), links_.end(), - checked_deleter() ); - } + ~chain_impl() { try { close(); reset(); } catch (std::exception&) { } } void close() { - if ((flags_ & f_complete) == 0) - return; - links_.front()->BOOST_IOSTREAMS_PUBSYNC(); - if (is_convertible::value) - std::for_each( links_.rbegin(), links_.rend(), - closer(BOOST_IOS::in) ); - if (is_convertible::value) - std::for_each( links_.begin(), links_.end(), - closer(BOOST_IOS::out) ); + if ((flags_ & f_open) != 0) { + streambuf_facade< basic_null_device > null; + if ((flags_ & f_complete) == 0) { + null.open(basic_null_device()); + set_next(links_.back(), &null); + } + links_.front()->BOOST_IOSTREAMS_PUBSYNC(); + if (is_convertible::value) + std::for_each( links_.rbegin(), links_.rend(), + closer(BOOST_IOS::in) ); + if (is_convertible::value) + std::for_each( links_.begin(), links_.end(), + closer(BOOST_IOS::out) ); + flags_ &= ~f_open; + } + } + void reset() + { + typedef typename list_type::iterator iterator; + for ( iterator first = links_.begin(), + last = links_.end(); + first != last; + ++first ) + { + if ( (flags_ & f_complete) == 0 || + (flags_ & f_auto_close) == 0 ) + { + set_auto_close(*first, false); + } + streambuf_type* buf = 0; + std::swap(buf, *first); + delete buf; + } + links_.clear(); + flags_ &= ~f_complete; + flags_ &= ~f_open; } list_type links_; client_type* client_; @@ -354,6 +420,7 @@ public: chain_client(chain_client* client) : chain_(client->chain_) { } virtual ~chain_client() { } +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310) template const std::type_info& component_type() const { return chain_->component_type(); } @@ -361,10 +428,20 @@ public: template T* component() const { return chain_->component(); } +#else + template + const std::type_info& component_type(mpl::int_ i) const + { return chain_->component_type(i); } + + template + T* component(mpl::int_ i, boost::type t) const + { return chain_->component(i, t); } +#endif bool is_complete() const { return chain_->is_complete(); } bool auto_close() const { return chain_->auto_close(); } void set_auto_close(bool close) { chain_->set_auto_close(close); } + bool strict_sync() { return chain_->strict_sync(); } void set_device_buffer_size(std::streamsize n) { chain_->set_device_buffer_size(n); } void set_filter_buffer_size(std::streamsize n) @@ -420,10 +497,7 @@ void chain_base::reset() { using namespace std; pimpl_->close(); - std::for_each( list().begin(), list().end(), - checked_deleter() ); - list().clear(); - pimpl_->flags_ &= ~f_complete; + pimpl_->reset(); } template @@ -446,14 +520,36 @@ void chain_base::set_auto_close(bool close) (close ? f_auto_close : 0); } +template +bool chain_base::strict_sync() +{ + typedef typename list_type::iterator iterator; + bool result = true; + for ( iterator first = list().begin(), + last = list().end(); + first != last; + ++first ) + { + bool s = (*first)->strict_sync(); + result = result && s; + } + return result; +} + template void chain_base::pop() { assert(!empty()); - pimpl_->close(); - delete list().back(); + if (auto_close()) + pimpl_->close(); + streambuf_type* buf = 0; + std::swap(buf, list().back()); + buf->set_auto_close(auto_close()); + delete buf; list().pop_back(); pimpl_->flags_ &= ~f_complete; + if (auto_close() || list().empty()) + pimpl_->flags_ &= ~f_open; } } // End namespace detail.