]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | { }; | |
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> | |
b32b8144 | 76 | std::streamsize read(Source& src, char_type* s, std::streamsize n) |
7c673cae FG |
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> | |
b32b8144 | 104 | std::streamsize write(Sink& dest, const char_type* s, std::streamsize n) |
7c673cae FG |
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 |