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