]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/iostreams/filter/symmetric.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / iostreams / filter / symmetric.hpp
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 // Contains the definitions of the class templates symmetric_filter,
9 // which models DualUseFilter based on a model of the Symmetric Filter.
10
11 //
12 // Roughly, a Symmetric Filter is a class type with the following interface:
13 //
14 // struct symmetric_filter {
15 // typedef xxx char_type;
16 //
17 // bool filter( const char*& begin_in, const char* end_in,
18 // char*& begin_out, char* end_out, bool flush )
19 // {
20 // // Consume as many characters as possible from the interval
21 // // [begin_in, end_in), without exhausting the output range
22 // // [begin_out, end_out). If flush is true, write as mush output
23 // // as possible.
24 // // A return value of true indicates that filter should be called
25 // // again. More precisely, if flush is false, a return value of
26 // // false indicates that the natural end of stream has been reached
27 // // and that all filtered data has been forwarded; if flush is
28 // // true, a return value of false indicates that all filtered data
29 // // has been forwarded.
30 // }
31 // void close() { /* Reset filter's state. */ }
32 // };
33 //
34 // Symmetric Filter filters need not be CopyConstructable.
35 //
36
37 #ifndef BOOST_IOSTREAMS_SYMMETRIC_FILTER_HPP_INCLUDED
38 #define BOOST_IOSTREAMS_SYMMETRIC_FILTER_HPP_INCLUDED
39
40 #if defined(_MSC_VER)
41 # pragma once
42 #endif
43
44 #include <boost/assert.hpp>
45 #include <memory> // allocator.
46 #include <boost/config.hpp> // BOOST_DEDUCED_TYPENAME.
47 #include <boost/iostreams/char_traits.hpp>
48 #include <boost/iostreams/constants.hpp> // buffer size.
49 #include <boost/iostreams/detail/buffer.hpp>
50 #include <boost/iostreams/detail/char_traits.hpp>
51 #include <boost/iostreams/detail/config/limits.hpp>
52 #include <boost/iostreams/detail/ios.hpp> // streamsize.
53 #include <boost/iostreams/detail/template_params.hpp>
54 #include <boost/iostreams/traits.hpp>
55 #include <boost/iostreams/operations.hpp> // read, write.
56 #include <boost/iostreams/pipeline.hpp>
57 #include <boost/preprocessor/iteration/local.hpp>
58 #include <boost/preprocessor/punctuation/comma_if.hpp>
59 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
60 #include <boost/preprocessor/repetition/enum_params.hpp>
61 #include <boost/shared_ptr.hpp>
62
63 // Must come last.
64 #include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC.
65
66 namespace boost { namespace iostreams {
67
68 template< typename SymmetricFilter,
69 typename Alloc =
70 std::allocator<
71 BOOST_DEDUCED_TYPENAME char_type_of<SymmetricFilter>::type
72 > >
73 class symmetric_filter {
74 public:
75 typedef typename char_type_of<SymmetricFilter>::type char_type;
76 typedef BOOST_IOSTREAMS_CHAR_TRAITS(char_type) traits_type;
77 typedef std::basic_string<char_type, traits_type, Alloc> string_type;
78 struct category
79 : dual_use,
80 filter_tag,
81 multichar_tag,
82 closable_tag
83 { };
84
85 // Expands to a sequence of ctors which forward to impl.
86 #define BOOST_PP_LOCAL_MACRO(n) \
87 BOOST_IOSTREAMS_TEMPLATE_PARAMS(n, T) \
88 explicit symmetric_filter( \
89 std::streamsize buffer_size BOOST_PP_COMMA_IF(n) \
90 BOOST_PP_ENUM_BINARY_PARAMS(n, const T, &t) ) \
91 : pimpl_(new impl(buffer_size BOOST_PP_COMMA_IF(n) \
92 BOOST_PP_ENUM_PARAMS(n, t))) \
93 { BOOST_ASSERT(buffer_size > 0); } \
94 /**/
95 #define BOOST_PP_LOCAL_LIMITS (0, BOOST_IOSTREAMS_MAX_FORWARDING_ARITY)
96 #include BOOST_PP_LOCAL_ITERATE()
97 #undef BOOST_PP_LOCAL_MACRO
98
99 template<typename Source>
100 std::streamsize read(Source& src, char_type* s, std::streamsize n)
101 {
102 using namespace std;
103 if (!(state() & f_read))
104 begin_read();
105
106 buffer_type& buf = pimpl_->buf_;
107 int status = (state() & f_eof) != 0 ? f_eof : f_good;
108 char_type *next_s = s,
109 *end_s = s + n;
110 while (true)
111 {
112 // Invoke filter if there are unconsumed characters in buffer or if
113 // filter must be flushed.
114 bool flush = status == f_eof;
115 if (buf.ptr() != buf.eptr() || flush) {
116 const char_type* next = buf.ptr();
117 bool done =
118 !filter().filter(next, buf.eptr(), next_s, end_s, flush);
119 buf.ptr() = buf.data() + (next - buf.data());
120 if (done)
121 return detail::check_eof(
122 static_cast<std::streamsize>(next_s - s)
123 );
124 }
125
126 // If no more characters are available without blocking, or
127 // if read request has been satisfied, return.
128 if ( (status == f_would_block && buf.ptr() == buf.eptr()) ||
129 next_s == end_s )
130 {
131 return static_cast<std::streamsize>(next_s - s);
132 }
133
134 // Fill buffer.
135 if (status == f_good)
136 status = fill(src);
137 }
138 }
139
140 template<typename Sink>
141 std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
142 {
143 if (!(state() & f_write))
144 begin_write();
145
146 buffer_type& buf = pimpl_->buf_;
147 const char_type *next_s, *end_s;
148 for (next_s = s, end_s = s + n; next_s != end_s; ) {
149 if (buf.ptr() == buf.eptr() && !flush(snk))
150 break;
151 if(!filter().filter(next_s, end_s, buf.ptr(), buf.eptr(), false)) {
152 flush(snk);
153 break;
154 }
155 }
156 return static_cast<std::streamsize>(next_s - s);
157 }
158
159 template<typename Sink>
160 void close(Sink& snk, BOOST_IOS::openmode mode)
161 {
162 if (mode == BOOST_IOS::out) {
163
164 if (!(state() & f_write))
165 begin_write();
166
167 // Repeatedly invoke filter() with no input.
168 try {
169 buffer_type& buf = pimpl_->buf_;
170 char_type dummy;
171 const char_type* end = &dummy;
172 bool again = true;
173 while (again) {
174 if (buf.ptr() != buf.eptr())
175 again = filter().filter( end, end, buf.ptr(),
176 buf.eptr(), true );
177 flush(snk);
178 }
179 } catch (...) {
180 try { close_impl(); } catch (...) { }
181 throw;
182 }
183 close_impl();
184 } else {
185 close_impl();
186 }
187 }
188 SymmetricFilter& filter() { return *pimpl_; }
189 string_type unconsumed_input() const;
190
191 // Give impl access to buffer_type on Tru64
192 #if !BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042))
193 private:
194 #endif
195 typedef detail::buffer<char_type, Alloc> buffer_type;
196 private:
197 buffer_type& buf() { return pimpl_->buf_; }
198 const buffer_type& buf() const { return pimpl_->buf_; }
199 int& state() { return pimpl_->state_; }
200 void begin_read();
201 void begin_write();
202
203 template<typename Source>
204 int fill(Source& src)
205 {
206 std::streamsize amt = iostreams::read(src, buf().data(), buf().size());
207 if (amt == -1) {
208 state() |= f_eof;
209 return f_eof;
210 }
211 buf().set(0, amt);
212 return amt != 0 ? f_good : f_would_block;
213 }
214
215 // Attempts to write the contents of the buffer the given Sink.
216 // Returns true if at least on character was written.
217 template<typename Sink>
218 bool flush(Sink& snk)
219 {
220 typedef typename iostreams::category_of<Sink>::type category;
221 typedef is_convertible<category, output> can_write;
222 return flush(snk, can_write());
223 }
224
225 template<typename Sink>
226 bool flush(Sink& snk, mpl::true_)
227 {
228 std::streamsize amt =
229 static_cast<std::streamsize>(buf().ptr() - buf().data());
230 std::streamsize result =
231 boost::iostreams::write(snk, buf().data(), amt);
232 if (result < amt && result > 0)
233 traits_type::move(buf().data(), buf().data() + result, amt - result);
234 buf().set(amt - result, buf().size());
235 return result != 0;
236 }
237
238 template<typename Sink>
239 bool flush(Sink&, mpl::false_) { return true;}
240
241 void close_impl();
242
243 enum flag_type {
244 f_read = 1,
245 f_write = f_read << 1,
246 f_eof = f_write << 1,
247 f_good,
248 f_would_block
249 };
250
251 struct impl : SymmetricFilter {
252
253 // Expands to a sequence of ctors which forward to SymmetricFilter.
254 #define BOOST_PP_LOCAL_MACRO(n) \
255 BOOST_IOSTREAMS_TEMPLATE_PARAMS(n, T) \
256 impl( std::streamsize buffer_size BOOST_PP_COMMA_IF(n) \
257 BOOST_PP_ENUM_BINARY_PARAMS(n, const T, &t) ) \
258 : SymmetricFilter(BOOST_PP_ENUM_PARAMS(n, t)), \
259 buf_(buffer_size), state_(0) \
260 { } \
261 /**/
262 #define BOOST_PP_LOCAL_LIMITS (0, BOOST_IOSTREAMS_MAX_FORWARDING_ARITY)
263 #include BOOST_PP_LOCAL_ITERATE()
264 #undef BOOST_PP_LOCAL_MACRO
265
266 buffer_type buf_;
267 int state_;
268 };
269
270 shared_ptr<impl> pimpl_;
271 };
272 BOOST_IOSTREAMS_PIPABLE(symmetric_filter, 2)
273
274 //------------------Implementation of symmetric_filter----------------//
275
276 template<typename SymmetricFilter, typename Alloc>
277 void symmetric_filter<SymmetricFilter, Alloc>::begin_read()
278 {
279 BOOST_ASSERT(!(state() & f_write));
280 state() |= f_read;
281 buf().set(0, 0);
282 }
283
284 template<typename SymmetricFilter, typename Alloc>
285 void symmetric_filter<SymmetricFilter, Alloc>::begin_write()
286 {
287 BOOST_ASSERT(!(state() & f_read));
288 state() |= f_write;
289 buf().set(0, buf().size());
290 }
291
292 template<typename SymmetricFilter, typename Alloc>
293 void symmetric_filter<SymmetricFilter, Alloc>::close_impl()
294 {
295 state() = 0;
296 buf().set(0, 0);
297 filter().close();
298 }
299
300 template<typename SymmetricFilter, typename Alloc>
301 typename symmetric_filter<SymmetricFilter, Alloc>::string_type
302 symmetric_filter<SymmetricFilter, Alloc>::unconsumed_input() const
303 { return string_type(buf().ptr(), buf().eptr()); }
304
305 //----------------------------------------------------------------------------//
306
307 } } // End namespaces iostreams, boost.
308
309 #include <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC.
310
311 #endif // #ifndef BOOST_IOSTREAMS_SYMMETRIC_FILTER_HPP_INCLUDED