invert.hpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
  2. // (C) Copyright 2003-2007 Jonathan Turkanis
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
  5. // See http://www.boost.org/libs/iostreams for documentation.
  6. #ifndef BOOST_IOSTREAMS_INVERT_HPP_INCLUDED
  7. #define BOOST_IOSTREAMS_INVERT_HPP_INCLUDED
  8. #if defined(_MSC_VER)
  9. # pragma once
  10. #endif
  11. #include <algorithm> // copy, min.
  12. #include <boost/assert.hpp>
  13. #include <boost/config.hpp> // BOOST_DEDUCED_TYPENAME.
  14. #include <boost/detail/workaround.hpp> // default_filter_buffer_size.
  15. #include <boost/iostreams/char_traits.hpp>
  16. #include <boost/iostreams/compose.hpp>
  17. #include <boost/iostreams/constants.hpp>
  18. #include <boost/iostreams/device/array.hpp>
  19. #include <boost/iostreams/detail/buffer.hpp>
  20. #include <boost/iostreams/detail/counted_array.hpp>
  21. #include <boost/iostreams/detail/execute.hpp>
  22. #include <boost/iostreams/detail/functional.hpp> // clear_flags, call_reset
  23. #include <boost/mpl/if.hpp>
  24. #include <boost/ref.hpp>
  25. #include <boost/shared_ptr.hpp>
  26. #include <boost/type_traits/is_convertible.hpp>
  27. // Must come last.
  28. #include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC.
  29. namespace boost { namespace iostreams {
  30. //
  31. // Template name: inverse.
  32. // Template parameters:
  33. // Filter - A model of InputFilter or OutputFilter.
  34. // Description: Generates an InputFilter from an OutputFilter or
  35. // vice versa.
  36. //
  37. template<typename Filter>
  38. class inverse {
  39. private:
  40. BOOST_STATIC_ASSERT(is_filter<Filter>::value);
  41. typedef typename category_of<Filter>::type base_category;
  42. typedef reference_wrapper<Filter> filter_ref;
  43. public:
  44. typedef typename char_type_of<Filter>::type char_type;
  45. typedef typename int_type_of<Filter>::type int_type;
  46. typedef char_traits<char_type> traits_type;
  47. typedef typename
  48. mpl::if_<
  49. is_convertible<
  50. base_category,
  51. input
  52. >,
  53. output,
  54. input
  55. >::type mode;
  56. struct category
  57. : mode,
  58. filter_tag,
  59. multichar_tag,
  60. closable_tag
  61. { };
  62. explicit inverse( const Filter& filter,
  63. std::streamsize buffer_size =
  64. default_filter_buffer_size)
  65. : pimpl_(new impl(filter, buffer_size))
  66. { }
  67. template<typename Source>
  68. std::streamsize read(Source& src, char_type* s, std::streamsize n)
  69. {
  70. typedef detail::counted_array_sink<char_type> array_sink;
  71. typedef composite<filter_ref, array_sink> filtered_array_sink;
  72. BOOST_ASSERT((flags() & f_write) == 0);
  73. if (flags() == 0) {
  74. flags() = f_read;
  75. buf().set(0, 0);
  76. }
  77. filtered_array_sink snk(filter(), array_sink(s, n));
  78. int_type status;
  79. for ( status = traits_type::good();
  80. snk.second().count() < n && status == traits_type::good(); )
  81. {
  82. status = buf().fill(src);
  83. buf().flush(snk);
  84. }
  85. return snk.second().count() == 0 &&
  86. status == traits_type::eof()
  87. ?
  88. -1
  89. :
  90. snk.second().count();
  91. }
  92. template<typename Sink>
  93. std::streamsize write(Sink& dest, const char_type* s, std::streamsize n)
  94. {
  95. typedef detail::counted_array_source<char_type> array_source;
  96. typedef composite<filter_ref, array_source> filtered_array_source;
  97. BOOST_ASSERT((flags() & f_read) == 0);
  98. if (flags() == 0) {
  99. flags() = f_write;
  100. buf().set(0, 0);
  101. }
  102. filtered_array_source src(filter(), array_source(s, n));
  103. for (bool good = true; src.second().count() < n && good; ) {
  104. buf().fill(src);
  105. good = buf().flush(dest);
  106. }
  107. return src.second().count();
  108. }
  109. template<typename Device>
  110. void close(Device& dev)
  111. {
  112. detail::execute_all(
  113. detail::flush_buffer(buf(), dev, (flags() & f_write) != 0),
  114. detail::call_close_all(pimpl_->filter_, dev),
  115. detail::clear_flags(flags())
  116. );
  117. }
  118. private:
  119. filter_ref filter() { return boost::ref(pimpl_->filter_); }
  120. detail::buffer<char_type>& buf() { return pimpl_->buf_; }
  121. int& flags() { return pimpl_->flags_; }
  122. enum flags_ {
  123. f_read = 1, f_write = 2
  124. };
  125. struct impl {
  126. impl(const Filter& filter, std::streamsize n)
  127. : filter_(filter), buf_(n), flags_(0)
  128. { buf_.set(0, 0); }
  129. Filter filter_;
  130. detail::buffer<char_type> buf_;
  131. int flags_;
  132. };
  133. shared_ptr<impl> pimpl_;
  134. };
  135. //
  136. // Template name: invert.
  137. // Template parameters:
  138. // Filter - A model of InputFilter or OutputFilter.
  139. // Description: Returns an instance of an appropriate specialization of inverse.
  140. //
  141. template<typename Filter>
  142. inverse<Filter> invert(const Filter& f) { return inverse<Filter>(f); }
  143. //----------------------------------------------------------------------------//
  144. } } // End namespaces iostreams, boost.
  145. #include <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC.
  146. #endif // #ifndef BOOST_IOSTREAMS_INVERT_HPP_INCLUDED