| // (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 NDNBOOST_IOSTREAMS_INVERT_HPP_INCLUDED |
| #define NDNBOOST_IOSTREAMS_INVERT_HPP_INCLUDED |
| |
| #if defined(_MSC_VER) && (_MSC_VER >= 1020) |
| # pragma once |
| #endif |
| |
| #include <algorithm> // copy, min. |
| #include <ndnboost/assert.hpp> |
| #include <ndnboost/config.hpp> // NDNBOOST_DEDUCED_TYPENAME. |
| #include <ndnboost/detail/workaround.hpp> // default_filter_buffer_size. |
| #include <ndnboost/iostreams/char_traits.hpp> |
| #include <ndnboost/iostreams/compose.hpp> |
| #include <ndnboost/iostreams/constants.hpp> |
| #include <ndnboost/iostreams/device/array.hpp> |
| #include <ndnboost/iostreams/detail/buffer.hpp> |
| #include <ndnboost/iostreams/detail/counted_array.hpp> |
| #include <ndnboost/iostreams/detail/execute.hpp> |
| #include <ndnboost/iostreams/detail/functional.hpp> // clear_flags, call_reset |
| #include <ndnboost/mpl/if.hpp> |
| #include <ndnboost/ref.hpp> |
| #include <ndnboost/shared_ptr.hpp> |
| #include <ndnboost/type_traits/is_convertible.hpp> |
| |
| // Must come last. |
| #include <ndnboost/iostreams/detail/config/disable_warnings.hpp> // MSVC. |
| |
| namespace ndnboost { namespace iostreams { |
| |
| // |
| // Template name: inverse. |
| // Template parameters: |
| // Filter - A model of InputFilter or OutputFilter. |
| // Description: Generates an InputFilter from an OutputFilter or |
| // vice versa. |
| // |
| template<typename Filter> |
| class inverse { |
| private: |
| NDNBOOST_STATIC_ASSERT(is_filter<Filter>::value); |
| typedef typename category_of<Filter>::type base_category; |
| typedef reference_wrapper<Filter> filter_ref; |
| public: |
| typedef typename char_type_of<Filter>::type char_type; |
| typedef typename int_type_of<Filter>::type int_type; |
| typedef char_traits<char_type> traits_type; |
| typedef typename |
| mpl::if_< |
| is_convertible< |
| base_category, |
| input |
| >, |
| output, |
| input |
| >::type mode; |
| struct category |
| : mode, |
| filter_tag, |
| multichar_tag, |
| closable_tag |
| { }; |
| explicit inverse( const Filter& filter, |
| std::streamsize buffer_size = |
| default_filter_buffer_size) |
| : pimpl_(new impl(filter, buffer_size)) |
| { } |
| |
| template<typename Source> |
| std::streamsize read(Source& src, char* s, std::streamsize n) |
| { |
| typedef detail::counted_array_sink<char_type> array_sink; |
| typedef composite<filter_ref, array_sink> filtered_array_sink; |
| |
| NDNBOOST_ASSERT((flags() & f_write) == 0); |
| if (flags() == 0) { |
| flags() = f_read; |
| buf().set(0, 0); |
| } |
| |
| filtered_array_sink snk(filter(), array_sink(s, n)); |
| int_type status; |
| for ( status = traits_type::good(); |
| snk.second().count() < n && status == traits_type::good(); ) |
| { |
| status = buf().fill(src); |
| buf().flush(snk); |
| } |
| return snk.second().count() == 0 && |
| status == traits_type::eof() |
| ? |
| -1 |
| : |
| snk.second().count(); |
| } |
| |
| template<typename Sink> |
| std::streamsize write(Sink& dest, const char* s, std::streamsize n) |
| { |
| typedef detail::counted_array_source<char_type> array_source; |
| typedef composite<filter_ref, array_source> filtered_array_source; |
| |
| NDNBOOST_ASSERT((flags() & f_read) == 0); |
| if (flags() == 0) { |
| flags() = f_write; |
| buf().set(0, 0); |
| } |
| |
| filtered_array_source src(filter(), array_source(s, n)); |
| for (bool good = true; src.second().count() < n && good; ) { |
| buf().fill(src); |
| good = buf().flush(dest); |
| } |
| return src.second().count(); |
| } |
| |
| template<typename Device> |
| void close(Device& dev) |
| { |
| detail::execute_all( |
| detail::flush_buffer(buf(), dev, (flags() & f_write) != 0), |
| detail::call_close_all(pimpl_->filter_, dev), |
| detail::clear_flags(flags()) |
| ); |
| } |
| private: |
| filter_ref filter() { return ndnboost::ref(pimpl_->filter_); } |
| detail::buffer<char_type>& buf() { return pimpl_->buf_; } |
| int& flags() { return pimpl_->flags_; } |
| |
| enum flags_ { |
| f_read = 1, f_write = 2 |
| }; |
| |
| struct impl { |
| impl(const Filter& filter, std::streamsize n) |
| : filter_(filter), buf_(n), flags_(0) |
| { buf_.set(0, 0); } |
| Filter filter_; |
| detail::buffer<char_type> buf_; |
| int flags_; |
| }; |
| shared_ptr<impl> pimpl_; |
| }; |
| |
| // |
| // Template name: invert. |
| // Template parameters: |
| // Filter - A model of InputFilter or OutputFilter. |
| // Description: Returns an instance of an appropriate specialization of inverse. |
| // |
| template<typename Filter> |
| inverse<Filter> invert(const Filter& f) { return inverse<Filter>(f); } |
| |
| //----------------------------------------------------------------------------// |
| |
| } } // End namespaces iostreams, boost. |
| |
| #include <ndnboost/iostreams/detail/config/enable_warnings.hpp> // MSVC. |
| |
| #endif // #ifndef NDNBOOST_IOSTREAMS_INVERT_HPP_INCLUDED |