1 // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2 // (C) Copyright 2005-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.)
6 // See http://www.boost.org/libs/iostreams for documentation.
8 #ifndef BOOST_IOSTREAMS_FILTER_TEST_HPP_INCLUDED
14 #include <boost/config.hpp> // BOOST_MSVC,put size_t in std.
15 #include <boost/detail/workaround.hpp>
16 #include <algorithm> // min.
17 #include <cstddef> // size_t.
18 #if BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x564)) || \
19 BOOST_WORKAROUND(__MWERKS__, <= 0x3003) \
21 # include <cstdlib> // rand.
23 #include <cstring> // memcpy, strlen.
27 #if !BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x564)) && \
28 !BOOST_WORKAROUND(__MWERKS__, <= 0x3003) \
30 # include <boost/random/linear_congruential.hpp>
31 # include <boost/random/uniform_smallint.hpp>
33 #include <boost/iostreams/categories.hpp>
34 #include <boost/iostreams/compose.hpp>
35 #include <boost/iostreams/copy.hpp>
36 #include <boost/iostreams/detail/bool_trait_def.hpp>
37 #include <boost/iostreams/detail/ios.hpp>
38 #include <boost/iostreams/device/array.hpp>
39 #include <boost/iostreams/device/back_inserter.hpp>
40 #include <boost/iostreams/operations.hpp>
41 #include <boost/mpl/bool.hpp>
42 #include <boost/type_traits/is_array.hpp>
43 #include <boost/type_traits/is_same.hpp>
49 #if defined(BOOST_NO_STDC_NAMESPACE) && !defined(__LIBCOMO__)
53 #if BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x564)) || \
54 BOOST_WORKAROUND(__MWERKS__, <= 0x3003) \
61 namespace boost { namespace iostreams {
63 BOOST_IOSTREAMS_BOOL_TRAIT_DEF(is_string, std::basic_string, 3)
65 const std::streamsize default_increment = 5;
67 #if !BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x564)) && \
68 !BOOST_WORKAROUND(__MWERKS__, <= 0x3003) \
70 std::streamsize rand(std::streamsize inc)
72 static rand48 random_gen;
73 static uniform_smallint<int> random_dist(0, static_cast<int>(inc));
74 return random_dist(random_gen);
77 std::streamsize rand(std::streamsize inc)
79 return (std::rand() * inc + 1) / RAND_MAX;
83 class non_blocking_source {
85 typedef char char_type;
90 explicit non_blocking_source( const std::string& data,
91 std::streamsize inc = default_increment )
92 : data_(data), inc_(inc), pos_(0)
94 std::streamsize read(char* s, std::streamsize n)
97 if (pos_ == static_cast<streamsize>(data_.size()))
100 (std::min) (n, static_cast<streamsize>(data_.size() - pos_));
101 streamsize amt = (std::min) (rand(inc_), avail);
103 memcpy(s, data_.c_str() + pos_, static_cast<size_t>(amt));
111 data_[static_cast<std::string::size_type>(--pos_)] = c;
118 std::streamsize inc_, pos_;
121 class non_blocking_sink : public sink {
123 non_blocking_sink( std::string& dest,
124 std::streamsize inc = default_increment )
125 : dest_(dest), inc_(inc)
127 std::streamsize write(const char* s, std::streamsize n)
129 std::streamsize amt = (std::min) (rand(inc_), n);
130 dest_.insert(dest_.end(), s, s + amt);
134 non_blocking_sink& operator=(const non_blocking_sink&);
136 std::streamsize inc_;
139 //--------------Definition of test_input_filter-------------------------------//
141 template<typename Filter>
142 bool test_input_filter( Filter filter,
143 const std::string& input,
144 const std::string& output,
147 for ( int inc = default_increment;
148 inc < default_increment * 40;
149 inc += default_increment )
151 non_blocking_source src(input, inc);
153 iostreams::copy(compose(filter, src), iostreams::back_inserter(dest));
160 template<typename Filter, typename Source1, typename Source2>
161 bool test_input_filter( Filter filter,
162 const Source1& input,
163 const Source2& output,
168 iostreams::copy(input, iostreams::back_inserter(in));
169 iostreams::copy(output, iostreams::back_inserter(out));
170 return test_input_filter(filter, in, out);
173 template<typename Filter, typename Source1, typename Source2>
174 bool test_input_filter( Filter filter,
175 const Source1& input,
176 const Source2& output )
178 // Use tag dispatch to compensate for bad overload resolution.
179 return test_input_filter( filter, input, output,
180 is_string<Source1>() );
183 //--------------Definition of test_output_filter------------------------------//
185 template<typename Filter>
186 bool test_output_filter( Filter filter,
187 const std::string& input,
188 const std::string& output,
191 for ( int inc = default_increment;
192 inc < default_increment * 40;
193 inc += default_increment )
195 array_source src(input.data(), input.data() + input.size());
197 iostreams::copy(src, compose(filter, non_blocking_sink(dest, inc)));
204 template<typename Filter, typename Source1, typename Source2>
205 bool test_output_filter( Filter filter,
206 const Source1& input,
207 const Source2& output,
212 iostreams::copy(input, iostreams::back_inserter(in));
213 iostreams::copy(output, iostreams::back_inserter(out));
214 return test_output_filter(filter, in, out);
217 template<typename Filter, typename Source1, typename Source2>
218 bool test_output_filter( Filter filter,
219 const Source1& input,
220 const Source2& output )
222 // Use tag dispatch to compensate for bad overload resolution.
223 return test_output_filter( filter, input, output,
224 is_string<Source1>() );
227 //--------------Definition of test_filter_pair--------------------------------//
229 template<typename OutputFilter, typename InputFilter>
230 bool test_filter_pair( OutputFilter out,
232 const std::string& data,
235 for ( int inc = default_increment;
236 inc <= default_increment * 40;
237 inc += default_increment )
240 array_source src(data.data(), data.data() + data.size());
243 iostreams::copy(src, compose(out, non_blocking_sink(temp, inc)));
245 compose(in, non_blocking_source(temp, inc)),
246 iostreams::back_inserter(dest)
252 array_source src(data.data(), data.data() + data.size());
255 iostreams::copy(src, compose(out, non_blocking_sink(temp, inc)));
256 // truncate the file, this should not loop, it may throw
257 // std::ios_base::failure, which we swallow.
259 temp.resize(temp.size() / 2);
261 compose(in, non_blocking_source(temp, inc)),
262 iostreams::back_inserter(dest)
264 } catch(std::ios_base::failure&) {}
267 array_source src(data.data(), data.data() + data.size());
270 iostreams::copy(compose(out, src), non_blocking_sink(temp, inc));
272 non_blocking_source(temp, inc),
273 compose(in, iostreams::back_inserter(dest))
279 array_source src(data.data(), data.data() + data.size());
282 iostreams::copy(compose(out, src), non_blocking_sink(temp, inc));
283 // truncate the file, this should not loop, it may throw
284 // std::ios_base::failure, which we swallow.
286 temp.resize(temp.size() / 2);
288 non_blocking_source(temp, inc),
289 compose(in, iostreams::back_inserter(dest))
291 } catch(std::ios_base::failure&) {}
297 template<typename OutputFilter, typename InputFilter, typename Source>
298 bool test_filter_pair( OutputFilter out,
304 iostreams::copy(data, iostreams::back_inserter(str));
305 return test_filter_pair(out, in, str);
308 template<typename OutputFilter, typename InputFilter, typename Source>
309 bool test_filter_pair( OutputFilter out,
313 // Use tag dispatch to compensate for bad overload resolution.
314 return test_filter_pair(out, in, data, is_string<Source>());
317 } } // End namespaces iostreams, boost.
319 #endif // #ifndef BOOST_IOSTREAMS_FILTER_TEST_HPP_INCLUDED