File indexing completed on 2025-01-30 09:44:31
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 #ifndef BOOST_IOSTREAMS_SYMMETRIC_FILTER_HPP_INCLUDED
0038 #define BOOST_IOSTREAMS_SYMMETRIC_FILTER_HPP_INCLUDED
0039
0040 #if defined(_MSC_VER)
0041 # pragma once
0042 #endif
0043
0044 #include <boost/assert.hpp>
0045 #include <memory> // allocator.
0046 #include <boost/config.hpp> // BOOST_DEDUCED_TYPENAME.
0047 #include <boost/iostreams/char_traits.hpp>
0048 #include <boost/iostreams/constants.hpp> // buffer size.
0049 #include <boost/iostreams/detail/buffer.hpp>
0050 #include <boost/iostreams/detail/char_traits.hpp>
0051 #include <boost/iostreams/detail/config/limits.hpp>
0052 #include <boost/iostreams/detail/ios.hpp> // streamsize.
0053 #include <boost/iostreams/detail/template_params.hpp>
0054 #include <boost/iostreams/traits.hpp>
0055 #include <boost/iostreams/operations.hpp> // read, write.
0056 #include <boost/iostreams/pipeline.hpp>
0057 #include <boost/preprocessor/iteration/local.hpp>
0058 #include <boost/preprocessor/punctuation/comma_if.hpp>
0059 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
0060 #include <boost/preprocessor/repetition/enum_params.hpp>
0061 #include <boost/shared_ptr.hpp>
0062
0063
0064 #include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC.
0065
0066 namespace boost { namespace iostreams {
0067
0068 template< typename SymmetricFilter,
0069 typename Alloc =
0070 std::allocator<
0071 BOOST_DEDUCED_TYPENAME char_type_of<SymmetricFilter>::type
0072 > >
0073 class symmetric_filter {
0074 public:
0075 typedef typename char_type_of<SymmetricFilter>::type char_type;
0076 typedef BOOST_IOSTREAMS_CHAR_TRAITS(char_type) traits_type;
0077 typedef std::basic_string<char_type, traits_type, Alloc> string_type;
0078 struct category
0079 : dual_use,
0080 filter_tag,
0081 multichar_tag,
0082 closable_tag
0083 { };
0084
0085
0086 #define BOOST_PP_LOCAL_MACRO(n) \
0087 BOOST_IOSTREAMS_TEMPLATE_PARAMS(n, T) \
0088 explicit symmetric_filter( \
0089 std::streamsize buffer_size BOOST_PP_COMMA_IF(n) \
0090 BOOST_PP_ENUM_BINARY_PARAMS(n, const T, &t) ) \
0091 : pimpl_(new impl(buffer_size BOOST_PP_COMMA_IF(n) \
0092 BOOST_PP_ENUM_PARAMS(n, t))) \
0093 { BOOST_ASSERT(buffer_size > 0); } \
0094
0095 #define BOOST_PP_LOCAL_LIMITS (0, BOOST_IOSTREAMS_MAX_FORWARDING_ARITY)
0096 #include BOOST_PP_LOCAL_ITERATE()
0097 #undef BOOST_PP_LOCAL_MACRO
0098
0099 template<typename Source>
0100 std::streamsize read(Source& src, char_type* s, std::streamsize n)
0101 {
0102 using namespace std;
0103 if (!(state() & f_read))
0104 begin_read();
0105
0106 buffer_type& buf = pimpl_->buf_;
0107 int status = (state() & f_eof) != 0 ? f_eof : f_good;
0108 char_type *next_s = s,
0109 *end_s = s + n;
0110 while (true)
0111 {
0112
0113
0114 bool flush = status == f_eof;
0115 if (buf.ptr() != buf.eptr() || flush) {
0116 const char_type* next = buf.ptr();
0117 bool done =
0118 !filter().filter(next, buf.eptr(), next_s, end_s, flush);
0119 buf.ptr() = buf.data() + (next - buf.data());
0120 if (done)
0121 return detail::check_eof(
0122 static_cast<std::streamsize>(next_s - s)
0123 );
0124 }
0125
0126
0127
0128 if ( (status == f_would_block && buf.ptr() == buf.eptr()) ||
0129 next_s == end_s )
0130 {
0131 return static_cast<std::streamsize>(next_s - s);
0132 }
0133
0134
0135 if (status == f_good)
0136 status = fill(src);
0137 }
0138 }
0139
0140 template<typename Sink>
0141 std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
0142 {
0143 if (!(state() & f_write))
0144 begin_write();
0145
0146 buffer_type& buf = pimpl_->buf_;
0147 const char_type *next_s, *end_s;
0148 for (next_s = s, end_s = s + n; next_s != end_s; ) {
0149 if (buf.ptr() == buf.eptr() && !flush(snk))
0150 break;
0151 if(!filter().filter(next_s, end_s, buf.ptr(), buf.eptr(), false)) {
0152 flush(snk);
0153 break;
0154 }
0155 }
0156 return static_cast<std::streamsize>(next_s - s);
0157 }
0158
0159 template<typename Sink>
0160 void close(Sink& snk, BOOST_IOS::openmode mode)
0161 {
0162 if (mode == BOOST_IOS::out) {
0163
0164 if (!(state() & f_write))
0165 begin_write();
0166
0167
0168 try {
0169 buffer_type& buf = pimpl_->buf_;
0170 char_type dummy;
0171 const char_type* end = &dummy;
0172 bool again = true;
0173 while (again) {
0174 if (buf.ptr() != buf.eptr())
0175 again = filter().filter( end, end, buf.ptr(),
0176 buf.eptr(), true );
0177 flush(snk);
0178 }
0179 } catch (...) {
0180 try { close_impl(); } catch (...) { }
0181 throw;
0182 }
0183 close_impl();
0184 } else {
0185 close_impl();
0186 }
0187 }
0188 SymmetricFilter& filter() { return *pimpl_; }
0189 string_type unconsumed_input() const;
0190
0191
0192 #if !BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042))
0193 private:
0194 #endif
0195 typedef detail::buffer<char_type, Alloc> buffer_type;
0196 private:
0197 buffer_type& buf() { return pimpl_->buf_; }
0198 const buffer_type& buf() const { return pimpl_->buf_; }
0199 int& state() { return pimpl_->state_; }
0200 void begin_read();
0201 void begin_write();
0202
0203 template<typename Source>
0204 int fill(Source& src)
0205 {
0206 std::streamsize amt = iostreams::read(src, buf().data(), buf().size());
0207 if (amt == -1) {
0208 state() |= f_eof;
0209 return f_eof;
0210 }
0211 buf().set(0, amt);
0212 return amt != 0 ? f_good : f_would_block;
0213 }
0214
0215
0216
0217 template<typename Sink>
0218 bool flush(Sink& snk)
0219 {
0220 typedef typename iostreams::category_of<Sink>::type category;
0221 typedef is_convertible<category, output> can_write;
0222 return flush(snk, can_write());
0223 }
0224
0225 template<typename Sink>
0226 bool flush(Sink& snk, mpl::true_)
0227 {
0228 std::streamsize amt =
0229 static_cast<std::streamsize>(buf().ptr() - buf().data());
0230 std::streamsize result =
0231 boost::iostreams::write(snk, buf().data(), amt);
0232 if (result < amt && result > 0)
0233 traits_type::move(buf().data(), buf().data() + result, amt - result);
0234 buf().set(amt - result, buf().size());
0235 return result != 0;
0236 }
0237
0238 template<typename Sink>
0239 bool flush(Sink&, mpl::false_) { return true;}
0240
0241 void close_impl();
0242
0243 enum flag_type {
0244 f_read = 1,
0245 f_write = f_read << 1,
0246 f_eof = f_write << 1,
0247 f_good,
0248 f_would_block
0249 };
0250
0251 struct impl : SymmetricFilter {
0252
0253
0254 #define BOOST_PP_LOCAL_MACRO(n) \
0255 BOOST_IOSTREAMS_TEMPLATE_PARAMS(n, T) \
0256 impl( std::streamsize buffer_size BOOST_PP_COMMA_IF(n) \
0257 BOOST_PP_ENUM_BINARY_PARAMS(n, const T, &t) ) \
0258 : SymmetricFilter(BOOST_PP_ENUM_PARAMS(n, t)), \
0259 buf_(buffer_size), state_(0) \
0260 { } \
0261
0262 #define BOOST_PP_LOCAL_LIMITS (0, BOOST_IOSTREAMS_MAX_FORWARDING_ARITY)
0263 #include BOOST_PP_LOCAL_ITERATE()
0264 #undef BOOST_PP_LOCAL_MACRO
0265
0266 buffer_type buf_;
0267 int state_;
0268 };
0269
0270 shared_ptr<impl> pimpl_;
0271 };
0272 BOOST_IOSTREAMS_PIPABLE(symmetric_filter, 2)
0273
0274
0275
0276 template<typename SymmetricFilter, typename Alloc>
0277 void symmetric_filter<SymmetricFilter, Alloc>::begin_read()
0278 {
0279 BOOST_ASSERT(!(state() & f_write));
0280 state() |= f_read;
0281 buf().set(0, 0);
0282 }
0283
0284 template<typename SymmetricFilter, typename Alloc>
0285 void symmetric_filter<SymmetricFilter, Alloc>::begin_write()
0286 {
0287 BOOST_ASSERT(!(state() & f_read));
0288 state() |= f_write;
0289 buf().set(0, buf().size());
0290 }
0291
0292 template<typename SymmetricFilter, typename Alloc>
0293 void symmetric_filter<SymmetricFilter, Alloc>::close_impl()
0294 {
0295 state() = 0;
0296 buf().set(0, 0);
0297 filter().close();
0298 }
0299
0300 template<typename SymmetricFilter, typename Alloc>
0301 typename symmetric_filter<SymmetricFilter, Alloc>::string_type
0302 symmetric_filter<SymmetricFilter, Alloc>::unconsumed_input() const
0303 { return string_type(buf().ptr(), buf().eptr()); }
0304
0305
0306
0307 } }
0308
0309 #include <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC.
0310
0311 #endif