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