123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- // (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.
- // Contains the definitions of the class templates symmetric_filter,
- // which models DualUseFilter based on a model of the Symmetric Filter.
- //
- // Roughly, a Symmetric Filter is a class type with the following interface:
- //
- // struct symmetric_filter {
- // typedef xxx char_type;
- //
- // bool filter( const char*& begin_in, const char* end_in,
- // char*& begin_out, char* end_out, bool flush )
- // {
- // // Consume as many characters as possible from the interval
- // // [begin_in, end_in), without exhausting the output range
- // // [begin_out, end_out). If flush is true, write as mush output
- // // as possible.
- // // A return value of true indicates that filter should be called
- // // again. More precisely, if flush is false, a return value of
- // // false indicates that the natural end of stream has been reached
- // // and that all filtered data has been forwarded; if flush is
- // // true, a return value of false indicates that all filtered data
- // // has been forwarded.
- // }
- // void close() { /* Reset filter's state. */ }
- // };
- //
- // Symmetric Filter filters need not be CopyConstructable.
- //
- #ifndef BOOST_IOSTREAMS_SYMMETRIC_FILTER_HPP_INCLUDED
- #define BOOST_IOSTREAMS_SYMMETRIC_FILTER_HPP_INCLUDED
- #if defined(_MSC_VER)
- # pragma once
- #endif
- #include <boost/assert.hpp>
- #include <memory> // allocator.
- #include <boost/config.hpp> // BOOST_DEDUCED_TYPENAME.
- #include <boost/iostreams/char_traits.hpp>
- #include <boost/iostreams/constants.hpp> // buffer size.
- #include <boost/iostreams/detail/buffer.hpp>
- #include <boost/iostreams/detail/char_traits.hpp>
- #include <boost/iostreams/detail/config/limits.hpp>
- #include <boost/iostreams/detail/ios.hpp> // streamsize.
- #include <boost/iostreams/detail/template_params.hpp>
- #include <boost/iostreams/traits.hpp>
- #include <boost/iostreams/operations.hpp> // read, write.
- #include <boost/iostreams/pipeline.hpp>
- #include <boost/preprocessor/iteration/local.hpp>
- #include <boost/preprocessor/punctuation/comma_if.hpp>
- #include <boost/preprocessor/repetition/enum_binary_params.hpp>
- #include <boost/preprocessor/repetition/enum_params.hpp>
- #include <boost/shared_ptr.hpp>
- // Must come last.
- #include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC.
- namespace boost { namespace iostreams {
- template< typename SymmetricFilter,
- typename Alloc =
- std::allocator<
- BOOST_DEDUCED_TYPENAME char_type_of<SymmetricFilter>::type
- > >
- class symmetric_filter {
- public:
- typedef typename char_type_of<SymmetricFilter>::type char_type;
- typedef BOOST_IOSTREAMS_CHAR_TRAITS(char_type) traits_type;
- typedef std::basic_string<char_type, traits_type, Alloc> string_type;
- struct category
- : dual_use,
- filter_tag,
- multichar_tag,
- closable_tag
- { };
- // Expands to a sequence of ctors which forward to impl.
- #define BOOST_PP_LOCAL_MACRO(n) \
- BOOST_IOSTREAMS_TEMPLATE_PARAMS(n, T) \
- explicit symmetric_filter( \
- std::streamsize buffer_size BOOST_PP_COMMA_IF(n) \
- BOOST_PP_ENUM_BINARY_PARAMS(n, const T, &t) ) \
- : pimpl_(new impl(buffer_size BOOST_PP_COMMA_IF(n) \
- BOOST_PP_ENUM_PARAMS(n, t))) \
- { BOOST_ASSERT(buffer_size > 0); } \
- /**/
- #define BOOST_PP_LOCAL_LIMITS (0, BOOST_IOSTREAMS_MAX_FORWARDING_ARITY)
- #include BOOST_PP_LOCAL_ITERATE()
- #undef BOOST_PP_LOCAL_MACRO
- template<typename Source>
- std::streamsize read(Source& src, char_type* s, std::streamsize n)
- {
- using namespace std;
- if (!(state() & f_read))
- begin_read();
- buffer_type& buf = pimpl_->buf_;
- int status = (state() & f_eof) != 0 ? f_eof : f_good;
- char_type *next_s = s,
- *end_s = s + n;
- while (true)
- {
- // Invoke filter if there are unconsumed characters in buffer or if
- // filter must be flushed.
- bool flush = status == f_eof;
- if (buf.ptr() != buf.eptr() || flush) {
- const char_type* next = buf.ptr();
- bool done =
- !filter().filter(next, buf.eptr(), next_s, end_s, flush);
- buf.ptr() = buf.data() + (next - buf.data());
- if (done)
- return detail::check_eof(
- static_cast<std::streamsize>(next_s - s)
- );
- }
- // If no more characters are available without blocking, or
- // if read request has been satisfied, return.
- if ( (status == f_would_block && buf.ptr() == buf.eptr()) ||
- next_s == end_s )
- {
- return static_cast<std::streamsize>(next_s - s);
- }
- // Fill buffer.
- if (status == f_good)
- status = fill(src);
- }
- }
- template<typename Sink>
- std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
- {
- if (!(state() & f_write))
- begin_write();
- buffer_type& buf = pimpl_->buf_;
- const char_type *next_s, *end_s;
- for (next_s = s, end_s = s + n; next_s != end_s; ) {
- if (buf.ptr() == buf.eptr() && !flush(snk))
- break;
- if(!filter().filter(next_s, end_s, buf.ptr(), buf.eptr(), false)) {
- flush(snk);
- break;
- }
- }
- return static_cast<std::streamsize>(next_s - s);
- }
- template<typename Sink>
- void close(Sink& snk, BOOST_IOS::openmode mode)
- {
- if (mode == BOOST_IOS::out) {
- if (!(state() & f_write))
- begin_write();
- // Repeatedly invoke filter() with no input.
- try {
- buffer_type& buf = pimpl_->buf_;
- char_type dummy;
- const char_type* end = &dummy;
- bool again = true;
- while (again) {
- if (buf.ptr() != buf.eptr())
- again = filter().filter( end, end, buf.ptr(),
- buf.eptr(), true );
- flush(snk);
- }
- } catch (...) {
- try { close_impl(); } catch (...) { }
- throw;
- }
- close_impl();
- } else {
- close_impl();
- }
- }
- SymmetricFilter& filter() { return *pimpl_; }
- string_type unconsumed_input() const;
- // Give impl access to buffer_type on Tru64
- #if !BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042))
- private:
- #endif
- typedef detail::buffer<char_type, Alloc> buffer_type;
- private:
- buffer_type& buf() { return pimpl_->buf_; }
- const buffer_type& buf() const { return pimpl_->buf_; }
- int& state() { return pimpl_->state_; }
- void begin_read();
- void begin_write();
- template<typename Source>
- int fill(Source& src)
- {
- std::streamsize amt = iostreams::read(src, buf().data(), buf().size());
- if (amt == -1) {
- state() |= f_eof;
- return f_eof;
- }
- buf().set(0, amt);
- return amt != 0 ? f_good : f_would_block;
- }
- // Attempts to write the contents of the buffer the given Sink.
- // Returns true if at least on character was written.
- template<typename Sink>
- bool flush(Sink& snk)
- {
- typedef typename iostreams::category_of<Sink>::type category;
- typedef is_convertible<category, output> can_write;
- return flush(snk, can_write());
- }
- template<typename Sink>
- bool flush(Sink& snk, mpl::true_)
- {
- std::streamsize amt =
- static_cast<std::streamsize>(buf().ptr() - buf().data());
- std::streamsize result =
- boost::iostreams::write(snk, buf().data(), amt);
- if (result < amt && result > 0)
- traits_type::move(buf().data(), buf().data() + result, amt - result);
- buf().set(amt - result, buf().size());
- return result != 0;
- }
- template<typename Sink>
- bool flush(Sink&, mpl::false_) { return true;}
- void close_impl();
- enum flag_type {
- f_read = 1,
- f_write = f_read << 1,
- f_eof = f_write << 1,
- f_good,
- f_would_block
- };
- struct impl : SymmetricFilter {
- // Expands to a sequence of ctors which forward to SymmetricFilter.
- #define BOOST_PP_LOCAL_MACRO(n) \
- BOOST_IOSTREAMS_TEMPLATE_PARAMS(n, T) \
- impl( std::streamsize buffer_size BOOST_PP_COMMA_IF(n) \
- BOOST_PP_ENUM_BINARY_PARAMS(n, const T, &t) ) \
- : SymmetricFilter(BOOST_PP_ENUM_PARAMS(n, t)), \
- buf_(buffer_size), state_(0) \
- { } \
- /**/
- #define BOOST_PP_LOCAL_LIMITS (0, BOOST_IOSTREAMS_MAX_FORWARDING_ARITY)
- #include BOOST_PP_LOCAL_ITERATE()
- #undef BOOST_PP_LOCAL_MACRO
- buffer_type buf_;
- int state_;
- };
- shared_ptr<impl> pimpl_;
- };
- BOOST_IOSTREAMS_PIPABLE(symmetric_filter, 2)
- //------------------Implementation of symmetric_filter----------------//
- template<typename SymmetricFilter, typename Alloc>
- void symmetric_filter<SymmetricFilter, Alloc>::begin_read()
- {
- BOOST_ASSERT(!(state() & f_write));
- state() |= f_read;
- buf().set(0, 0);
- }
- template<typename SymmetricFilter, typename Alloc>
- void symmetric_filter<SymmetricFilter, Alloc>::begin_write()
- {
- BOOST_ASSERT(!(state() & f_read));
- state() |= f_write;
- buf().set(0, buf().size());
- }
- template<typename SymmetricFilter, typename Alloc>
- void symmetric_filter<SymmetricFilter, Alloc>::close_impl()
- {
- state() = 0;
- buf().set(0, 0);
- filter().close();
- }
- template<typename SymmetricFilter, typename Alloc>
- typename symmetric_filter<SymmetricFilter, Alloc>::string_type
- symmetric_filter<SymmetricFilter, Alloc>::unconsumed_input() const
- { return string_type(buf().ptr(), buf().eptr()); }
- //----------------------------------------------------------------------------//
- } } // End namespaces iostreams, boost.
- #include <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC.
- #endif // #ifndef BOOST_IOSTREAMS_SYMMETRIC_FILTER_HPP_INCLUDED
|