123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594 |
- // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
- // (C) Copyright 2003-2007 Jonathan Turkanis
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
- // See http://www.boost.org/libs/iostreams for documentation.
- #ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
- #define BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
- #if defined(_MSC_VER)
- # pragma once
- #endif
- #include <boost/assert.hpp>
- #include <exception>
- #include <iterator> // advance.
- #include <list>
- #include <memory> // allocator, auto_ptr or unique_ptr.
- #include <stdexcept> // logic_error, out_of_range.
- #include <boost/checked_delete.hpp>
- #include <boost/config.hpp> // BOOST_MSVC, template friends,
- #include <boost/detail/workaround.hpp> // BOOST_NESTED_TEMPLATE
- #include <boost/core/typeinfo.hpp>
- #include <boost/iostreams/constants.hpp>
- #include <boost/iostreams/detail/access_control.hpp>
- #include <boost/iostreams/detail/char_traits.hpp>
- #include <boost/iostreams/detail/push.hpp>
- #include <boost/iostreams/detail/streambuf.hpp> // pubsync.
- #include <boost/iostreams/detail/wrap_unwrap.hpp>
- #include <boost/iostreams/device/null.hpp>
- #include <boost/iostreams/positioning.hpp>
- #include <boost/iostreams/traits.hpp> // is_filter.
- #include <boost/iostreams/stream_buffer.hpp>
- #include <boost/next_prior.hpp>
- #include <boost/shared_ptr.hpp>
- #include <boost/static_assert.hpp>
- #include <boost/throw_exception.hpp>
- #include <boost/type_traits/is_convertible.hpp>
- #include <boost/type.hpp>
- #include <boost/iostreams/detail/execute.hpp>
- // Sometimes type_info objects must be compared by name. Borrowed from
- // Boost.Python and Boost.Function.
- #if defined(__GNUC__) || \
- defined(_AIX) || \
- (defined(__sgi) && defined(__host_mips)) || \
- (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC)) \
- /**/
- # include <cstring>
- # define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) \
- (std::strcmp((X).name(),(Y).name()) == 0)
- #else
- # define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
- #endif
- // Deprecated. Unused.
- #define BOOST_IOSTREAMS_COMPONENT_TYPE(chain, index) \
- chain.component_type( index ) \
- /**/
- // Deprecated. Unused.
- #define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \
- chain.component< target >( index ) \
- /**/
- namespace boost { namespace iostreams {
- //--------------Definition of chain and wchain--------------------------------//
- namespace detail {
- template<typename Chain> class chain_client;
- //
- // Concept name: Chain.
- // Description: Represents a chain of stream buffers which provides access
- // to the first buffer in the chain and sends notifications when the
- // streambufs are added to or removed from chain.
- // Refines: Closable device with mode equal to typename Chain::mode.
- // Models: chain, converting_chain.
- // Example:
- //
- // class chain {
- // public:
- // typedef xxx chain_type;
- // typedef xxx client_type;
- // typedef xxx mode;
- // bool is_complete() const; // Ready for i/o.
- // template<typename T>
- // void push( const T& t, // Adds a stream buffer to
- // streamsize, // chain, based on t, with
- // streamsize ); // given buffer and putback
- // // buffer sizes. Pass -1 to
- // // request default size.
- // protected:
- // void register_client(client_type* client); // Associate client.
- // void notify(); // Notify client.
- // };
- //
- //
- // Description: Represents a chain of filters with an optional device at the
- // end.
- // Template parameters:
- // Self - A class deriving from the current instantiation of this template.
- // This is an example of the Curiously Recurring Template Pattern.
- // Ch - The character type.
- // Tr - The character traits type.
- // Alloc - The allocator type.
- // Mode - A mode tag.
- //
- template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
- class chain_base {
- public:
- typedef Ch char_type;
- BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr)
- typedef Alloc allocator_type;
- typedef Mode mode;
- struct category
- : Mode,
- device_tag
- { };
- typedef chain_client<Self> client_type;
- friend class chain_client<Self>;
- private:
- typedef linked_streambuf<Ch> streambuf_type;
- typedef std::list<streambuf_type*> list_type;
- typedef chain_base<Self, Ch, Tr, Alloc, Mode> my_type;
- protected:
- chain_base() : pimpl_(new chain_impl) { }
- chain_base(const chain_base& rhs): pimpl_(rhs.pimpl_) { }
- public:
- // dual_use is a pseudo-mode to facilitate filter writing,
- // not a genuine mode.
- BOOST_STATIC_ASSERT((!is_convertible<mode, dual_use>::value));
- //----------Buffer sizing-------------------------------------------------//
- // Sets the size of the buffer created for the devices to be added to this
- // chain. Does not affect the size of the buffer for devices already
- // added.
- void set_device_buffer_size(std::streamsize n)
- { pimpl_->device_buffer_size_ = n; }
- // Sets the size of the buffer created for the filters to be added
- // to this chain. Does not affect the size of the buffer for filters already
- // added.
- void set_filter_buffer_size(std::streamsize n)
- { pimpl_->filter_buffer_size_ = n; }
- // Sets the size of the putback buffer for filters and devices to be added
- // to this chain. Does not affect the size of the buffer for filters or
- // devices already added.
- void set_pback_size(std::streamsize n)
- { pimpl_->pback_size_ = n; }
- //----------Device interface----------------------------------------------//
- std::streamsize read(char_type* s, std::streamsize n);
- std::streamsize write(const char_type* s, std::streamsize n);
- std::streampos seek(stream_offset off, BOOST_IOS::seekdir way);
- //----------Direct component access---------------------------------------//
- const boost::core::typeinfo& component_type(int n) const
- {
- if (static_cast<size_type>(n) >= size())
- boost::throw_exception(std::out_of_range("bad chain offset"));
- return (*boost::next(list().begin(), n))->component_type();
- }
- // Deprecated.
- template<int N>
- const boost::core::typeinfo& component_type() const { return component_type(N); }
- template<typename T>
- T* component(int n) const { return component(n, boost::type<T>()); }
- // Deprecated.
- template<int N, typename T>
- T* component() const { return component<T>(N); }
- #if !BOOST_WORKAROUND(BOOST_MSVC, == 1310)
- private:
- #endif
- template<typename T>
- T* component(int n, boost::type<T>) const
- {
- if (static_cast<size_type>(n) >= size())
- boost::throw_exception(std::out_of_range("bad chain offset"));
- streambuf_type* link = *boost::next(list().begin(), n);
- if (BOOST_IOSTREAMS_COMPARE_TYPE_ID(link->component_type(), BOOST_CORE_TYPEID(T)))
- return static_cast<T*>(link->component_impl());
- else
- return 0;
- }
- public:
- //----------Container-like interface--------------------------------------//
- typedef typename list_type::size_type size_type;
- streambuf_type& front() { return *list().front(); }
- BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
- void pop();
- bool empty() const { return list().empty(); }
- size_type size() const { return list().size(); }
- void reset();
- //----------Additional i/o functions--------------------------------------//
- // Returns true if this chain is non-empty and its final link
- // is a source or sink, i.e., if it is ready to perform i/o.
- bool is_complete() const;
- bool auto_close() const;
- void set_auto_close(bool close);
- bool sync() { return front().BOOST_IOSTREAMS_PUBSYNC() != -1; }
- bool strict_sync();
- private:
- template<typename T>
- void push_impl(const T& t, std::streamsize buffer_size = -1,
- std::streamsize pback_size = -1)
- {
- typedef typename iostreams::category_of<T>::type category;
- typedef typename unwrap_ios<T>::type component_type;
- typedef stream_buffer<
- component_type,
- BOOST_IOSTREAMS_CHAR_TRAITS(char_type),
- Alloc, Mode
- > streambuf_t;
- typedef typename list_type::iterator iterator;
- BOOST_STATIC_ASSERT((is_convertible<category, Mode>::value));
- if (is_complete())
- boost::throw_exception(std::logic_error("chain complete"));
- streambuf_type* prev = !empty() ? list().back() : 0;
- buffer_size =
- buffer_size != -1 ?
- buffer_size :
- iostreams::optimal_buffer_size(t);
- pback_size =
- pback_size != -1 ?
- pback_size :
- pimpl_->pback_size_;
-
- #if defined(BOOST_NO_CXX11_SMART_PTR)
- std::auto_ptr<streambuf_t>
- buf(new streambuf_t(t, buffer_size, pback_size));
-
- #else
- std::unique_ptr<streambuf_t>
- buf(new streambuf_t(t, buffer_size, pback_size));
-
- #endif
-
- list().push_back(buf.get());
- buf.release();
- if (is_device<component_type>::value) {
- pimpl_->flags_ |= f_complete | f_open;
- for ( iterator first = list().begin(),
- last = list().end();
- first != last;
- ++first )
- {
- (*first)->set_needs_close();
- }
- }
- if (prev) prev->set_next(list().back());
- notify();
- }
- list_type& list() { return pimpl_->links_; }
- const list_type& list() const { return pimpl_->links_; }
- void register_client(client_type* client) { pimpl_->client_ = client; }
- void notify() { if (pimpl_->client_) pimpl_->client_->notify(); }
- //----------Nested classes------------------------------------------------//
- static void close(streambuf_type* b, BOOST_IOS::openmode m)
- {
- if (m == BOOST_IOS::out && is_convertible<Mode, output>::value)
- b->BOOST_IOSTREAMS_PUBSYNC();
- 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 {
- typedef streambuf_type* argument_type;
- typedef void result_type;
- closer(BOOST_IOS::openmode m) : mode_(m) { }
- void operator() (streambuf_type* b)
- {
- close(b, mode_);
- }
- BOOST_IOS::openmode mode_;
- };
- friend struct closer;
- enum flags {
- f_complete = 1,
- f_open = 2,
- f_auto_close = 4
- };
- struct chain_impl {
- chain_impl()
- : client_(0), device_buffer_size_(default_device_buffer_size),
- filter_buffer_size_(default_filter_buffer_size),
- pback_size_(default_pback_buffer_size),
- flags_(f_auto_close)
- { }
- ~chain_impl()
- {
- try { close(); } catch (...) { }
- try { reset(); } catch (...) { }
- }
- void close()
- {
- if ((flags_ & f_open) != 0) {
- flags_ &= ~f_open;
- stream_buffer< basic_null_device<Ch, Mode> > null;
- if ((flags_ & f_complete) == 0) {
- null.open(basic_null_device<Ch, Mode>());
- set_next(links_.back(), &null);
- }
- links_.front()->BOOST_IOSTREAMS_PUBSYNC();
- try {
- boost::iostreams::detail::execute_foreach(
- links_.rbegin(), links_.rend(),
- closer(BOOST_IOS::in)
- );
- } catch (...) {
- try {
- boost::iostreams::detail::execute_foreach(
- links_.begin(), links_.end(),
- closer(BOOST_IOS::out)
- );
- } catch (...) { }
- throw;
- }
- boost::iostreams::detail::execute_foreach(
- links_.begin(), links_.end(),
- closer(BOOST_IOS::out)
- );
- }
- }
- 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_;
- std::streamsize device_buffer_size_,
- filter_buffer_size_,
- pback_size_;
- int flags_;
- };
- friend struct chain_impl;
- //----------Member data---------------------------------------------------//
- private:
- shared_ptr<chain_impl> pimpl_;
- };
- } // End namespace detail.
- //
- // Macro: BOOST_IOSTREAMS_DECL_CHAIN(name, category)
- // Description: Defines a template derived from chain_base appropriate for a
- // particular i/o category. The template has the following parameters:
- // Ch - The character type.
- // Tr - The character traits type.
- // Alloc - The allocator type.
- // Macro parameters:
- // name_ - The name of the template to be defined.
- // category_ - The i/o category of the template to be defined.
- //
- #define BOOST_IOSTREAMS_DECL_CHAIN(name_, default_char_) \
- template< typename Mode, typename Ch = default_char_, \
- typename Tr = BOOST_IOSTREAMS_CHAR_TRAITS(Ch), \
- typename Alloc = std::allocator<Ch> > \
- class name_ : public boost::iostreams::detail::chain_base< \
- name_<Mode, Ch, Tr, Alloc>, \
- Ch, Tr, Alloc, Mode \
- > \
- { \
- public: \
- struct category : device_tag, Mode { }; \
- typedef Mode mode; \
- private: \
- typedef boost::iostreams::detail::chain_base< \
- name_<Mode, Ch, Tr, Alloc>, \
- Ch, Tr, Alloc, Mode \
- > base_type; \
- public: \
- typedef Ch char_type; \
- typedef Tr traits_type; \
- typedef typename traits_type::int_type int_type; \
- typedef typename traits_type::off_type off_type; \
- name_() { } \
- name_(const name_& rhs) : base_type(rhs) { } \
- name_& operator=(const name_& rhs) \
- { base_type::operator=(rhs); return *this; } \
- }; \
- /**/
- BOOST_IOSTREAMS_DECL_CHAIN(chain, char)
- BOOST_IOSTREAMS_DECL_CHAIN(wchain, wchar_t)
- #undef BOOST_IOSTREAMS_DECL_CHAIN
- //--------------Definition of chain_client------------------------------------//
- namespace detail {
- //
- // Template name: chain_client
- // Description: Class whose instances provide access to an underlying chain
- // using an interface similar to the chains.
- // Subclasses: the various stream and stream buffer templates.
- //
- template<typename Chain>
- class chain_client {
- public:
- typedef Chain chain_type;
- typedef typename chain_type::char_type char_type;
- typedef typename chain_type::traits_type traits_type;
- typedef typename chain_type::size_type size_type;
- typedef typename chain_type::mode mode;
- chain_client(chain_type* chn = 0) : chain_(chn ) { }
- chain_client(chain_client* client) : chain_(client->chain_) { }
- virtual ~chain_client() { }
- const boost::core::typeinfo& component_type(int n) const
- { return chain_->component_type(n); }
- // Deprecated.
- template<int N>
- const boost::core::typeinfo& component_type() const
- { return chain_->BOOST_NESTED_TEMPLATE component_type<N>(); }
- template<typename T>
- T* component(int n) const
- { return chain_->BOOST_NESTED_TEMPLATE component<T>(n); }
- // Deprecated.
- template<int N, typename T>
- T* component() const
- { return chain_->BOOST_NESTED_TEMPLATE component<N, T>(); }
- 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)
- { chain_->set_filter_buffer_size(n); }
- void set_pback_size(std::streamsize n) { chain_->set_pback_size(n); }
- BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl)
- void pop() { chain_->pop(); }
- bool empty() const { return chain_->empty(); }
- size_type size() const { return chain_->size(); }
- void reset() { chain_->reset(); }
- // Returns a copy of the underlying chain.
- chain_type filters() { return *chain_; }
- chain_type filters() const { return *chain_; }
- protected:
- template<typename T>
- void push_impl(const T& t BOOST_IOSTREAMS_PUSH_PARAMS())
- { chain_->push(t BOOST_IOSTREAMS_PUSH_ARGS()); }
- chain_type& ref() { return *chain_; }
- void set_chain(chain_type* c)
- { chain_ = c; chain_->register_client(this); }
- #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) && \
- (!BOOST_WORKAROUND(BOOST_BORLANDC, < 0x600))
- template<typename S, typename C, typename T, typename A, typename M>
- friend class chain_base;
- #else
- public:
- #endif
- virtual void notify() { }
- private:
- chain_type* chain_;
- };
- //--------------Implementation of chain_base----------------------------------//
- template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
- inline std::streamsize chain_base<Self, Ch, Tr, Alloc, Mode>::read
- (char_type* s, std::streamsize n)
- { return iostreams::read(*list().front(), s, n); }
- template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
- inline std::streamsize chain_base<Self, Ch, Tr, Alloc, Mode>::write
- (const char_type* s, std::streamsize n)
- { return iostreams::write(*list().front(), s, n); }
- template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
- inline std::streampos chain_base<Self, Ch, Tr, Alloc, Mode>::seek
- (stream_offset off, BOOST_IOS::seekdir way)
- { return iostreams::seek(*list().front(), off, way); }
- template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
- void chain_base<Self, Ch, Tr, Alloc, Mode>::reset()
- {
- using namespace std;
- pimpl_->close();
- pimpl_->reset();
- }
- template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
- bool chain_base<Self, Ch, Tr, Alloc, Mode>::is_complete() const
- {
- return (pimpl_->flags_ & f_complete) != 0;
- }
- template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
- bool chain_base<Self, Ch, Tr, Alloc, Mode>::auto_close() const
- {
- return (pimpl_->flags_ & f_auto_close) != 0;
- }
- template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
- void chain_base<Self, Ch, Tr, Alloc, Mode>::set_auto_close(bool close)
- {
- pimpl_->flags_ =
- (pimpl_->flags_ & ~f_auto_close) |
- (close ? f_auto_close : 0);
- }
- template<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
- bool chain_base<Self, Ch, Tr, Alloc, Mode>::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<typename Self, typename Ch, typename Tr, typename Alloc, typename Mode>
- void chain_base<Self, Ch, Tr, Alloc, Mode>::pop()
- {
- BOOST_ASSERT(!empty());
- if (auto_close())
- pimpl_->close();
- streambuf_type* buf = 0;
- std::swap(buf, list().back());
- buf->set_auto_close(false);
- buf->set_next(0);
- delete buf;
- list().pop_back();
- pimpl_->flags_ &= ~f_complete;
- if (auto_close() || list().empty())
- pimpl_->flags_ &= ~f_open;
- }
- } // End namespace detail.
- } } // End namespaces iostreams, boost.
- #endif // #ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED
|