// (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_INVERT_HPP_INCLUDED | |
#define BOOST_IOSTREAMS_INVERT_HPP_INCLUDED | |
#if defined(_MSC_VER) && (_MSC_VER >= 1020) | |
# pragma once | |
#endif | |
#include <algorithm> // copy, min. | |
#include <boost/assert.hpp> | |
#include <boost/config.hpp> // BOOST_DEDUCED_TYPENAME. | |
#include <boost/detail/workaround.hpp> // default_filter_buffer_size. | |
#include <boost/iostreams/char_traits.hpp> | |
#include <boost/iostreams/compose.hpp> | |
#include <boost/iostreams/constants.hpp> | |
#include <boost/iostreams/device/array.hpp> | |
#include <boost/iostreams/detail/buffer.hpp> | |
#include <boost/iostreams/detail/counted_array.hpp> | |
#include <boost/iostreams/detail/execute.hpp> | |
#include <boost/iostreams/detail/functional.hpp> // clear_flags, call_reset | |
#include <boost/mpl/if.hpp> | |
#include <boost/ref.hpp> | |
#include <boost/shared_ptr.hpp> | |
#include <boost/type_traits/is_convertible.hpp> | |
// Must come last. | |
#include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC. | |
namespace boost { namespace iostreams { | |
// | |
// Template name: inverse. | |
// Template paramters: | |
// Filter - A model of InputFilter or OutputFilter. | |
// Description: Generates an InputFilter from an OutputFilter or | |
// vice versa. | |
// | |
template<typename Filter> | |
class inverse { | |
private: | |
BOOST_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; | |
BOOST_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; | |
BOOST_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 boost::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 paramters: | |
// 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 <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC. | |
#endif // #ifndef BOOST_IOSTREAMS_INVERT_HPP_INCLUDED |