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) && (_MSC_VER >= 1020) |
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 | { }; |
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> |
76 | std::streamsize read(Source& src, char* 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> |
104 | std::streamsize write(Sink& dest, const char* 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> |
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: |
133 | filter_ref filter() { return boost::ref(pimpl_->filter_); } |
134 | detail::buffer<char_type>& buf() { return pimpl_->buf_; } |
135 | int& flags() { return pimpl_->flags_; } |
136 | |
137 | enum flags_ { |
138 | f_read = 1, f_write = 2 |
139 | }; |
140 | |
141 | struct impl { |
142 | 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> |
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 | |