]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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.) | |
5 | ||
6 | // See http://www.boost.org/libs/iostreams for documentation. | |
7 | ||
8 | #ifndef BOOST_IOSTREAMS_FILTER_TEST_HPP_INCLUDED | |
9 | ||
10 | #if defined(_MSC_VER) | |
11 | # pragma once | |
12 | #endif | |
13 | ||
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(__BORLANDC__, BOOST_TESTED_AT(0x564)) || \ | |
19 | BOOST_WORKAROUND(__MWERKS__, <= 0x3003) \ | |
20 | /**/ | |
21 | # include <cstdlib> // rand. | |
22 | #endif | |
23 | #include <cstring> // memcpy, strlen. | |
24 | #include <iterator> | |
25 | #include <string> | |
26 | #include <vector> | |
27 | #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) && \ | |
28 | !BOOST_WORKAROUND(__MWERKS__, <= 0x3003) \ | |
29 | /**/ | |
30 | # include <boost/random/linear_congruential.hpp> | |
31 | # include <boost/random/uniform_smallint.hpp> | |
32 | #endif | |
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> | |
44 | ||
45 | #undef memcpy | |
46 | #undef rand | |
47 | #undef strlen | |
48 | ||
49 | #if defined(BOOST_NO_STDC_NAMESPACE) && !defined(__LIBCOMO__) | |
50 | namespace std { | |
51 | using ::memcpy; | |
52 | using ::strlen; | |
53 | #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) || \ | |
54 | BOOST_WORKAROUND(__MWERKS__, <= 0x3003) \ | |
55 | /**/ | |
56 | using ::rand; | |
57 | #endif | |
58 | } | |
59 | #endif | |
60 | ||
61 | namespace boost { namespace iostreams { | |
62 | ||
63 | BOOST_IOSTREAMS_BOOL_TRAIT_DEF(is_string, std::basic_string, 3) | |
64 | ||
65 | const std::streamsize default_increment = 5; | |
66 | ||
67 | #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) && \ | |
68 | !BOOST_WORKAROUND(__MWERKS__, <= 0x3003) \ | |
69 | /**/ | |
70 | std::streamsize rand(std::streamsize inc) | |
71 | { | |
72 | static rand48 random_gen; | |
73 | static uniform_smallint<int> random_dist(0, static_cast<int>(inc)); | |
74 | return random_dist(random_gen); | |
75 | } | |
76 | #else | |
77 | std::streamsize rand(std::streamsize inc) | |
78 | { | |
79 | return (std::rand() * inc + 1) / RAND_MAX; | |
80 | } | |
81 | #endif | |
82 | ||
83 | class non_blocking_source { | |
84 | public: | |
85 | typedef char char_type; | |
86 | struct category | |
87 | : source_tag, | |
88 | peekable_tag | |
89 | { }; | |
90 | explicit non_blocking_source( const std::string& data, | |
91 | std::streamsize inc = default_increment ) | |
92 | : data_(data), inc_(inc), pos_(0) | |
93 | { } | |
94 | std::streamsize read(char* s, std::streamsize n) | |
95 | { | |
96 | using namespace std; | |
97 | if (pos_ == static_cast<streamsize>(data_.size())) | |
98 | return -1; | |
99 | streamsize avail = | |
100 | (std::min) (n, static_cast<streamsize>(data_.size() - pos_)); | |
101 | streamsize amt = (std::min) (rand(inc_), avail); | |
102 | if (amt) | |
103 | memcpy(s, data_.c_str() + pos_, static_cast<size_t>(amt)); | |
104 | pos_ += amt; | |
105 | return amt; | |
106 | } | |
107 | ||
108 | bool putback(char c) | |
109 | { | |
110 | if (pos_ > 0) { | |
111 | data_[static_cast<std::string::size_type>(--pos_)] = c; | |
112 | return true; | |
113 | } | |
114 | return false; | |
115 | } | |
116 | private: | |
117 | std::string data_; | |
118 | std::streamsize inc_, pos_; | |
119 | }; | |
120 | ||
121 | class non_blocking_sink : public sink { | |
122 | public: | |
123 | non_blocking_sink( std::string& dest, | |
124 | std::streamsize inc = default_increment ) | |
125 | : dest_(dest), inc_(inc) | |
126 | { } | |
127 | std::streamsize write(const char* s, std::streamsize n) | |
128 | { | |
129 | std::streamsize amt = (std::min) (rand(inc_), n); | |
130 | dest_.insert(dest_.end(), s, s + amt); | |
131 | return amt; | |
132 | } | |
133 | private: | |
134 | non_blocking_sink& operator=(const non_blocking_sink&); | |
135 | std::string& dest_; | |
136 | std::streamsize inc_; | |
137 | }; | |
138 | ||
139 | //--------------Definition of test_input_filter-------------------------------// | |
140 | ||
141 | template<typename Filter> | |
142 | bool test_input_filter( Filter filter, | |
143 | const std::string& input, | |
144 | const std::string& output, | |
145 | mpl::true_ ) | |
146 | { | |
147 | for ( int inc = default_increment; | |
148 | inc < default_increment * 40; | |
149 | inc += default_increment ) | |
150 | { | |
151 | non_blocking_source src(input, inc); | |
152 | std::string dest; | |
153 | iostreams::copy(compose(filter, src), iostreams::back_inserter(dest)); | |
154 | if (dest != output) | |
155 | return false; | |
156 | } | |
157 | return true; | |
158 | } | |
159 | ||
160 | template<typename Filter, typename Source1, typename Source2> | |
161 | bool test_input_filter( Filter filter, | |
162 | const Source1& input, | |
163 | const Source2& output, | |
164 | mpl::false_ ) | |
165 | { | |
166 | std::string in; | |
167 | std::string out; | |
168 | iostreams::copy(input, iostreams::back_inserter(in)); | |
169 | iostreams::copy(output, iostreams::back_inserter(out)); | |
170 | return test_input_filter(filter, in, out); | |
171 | } | |
172 | ||
173 | template<typename Filter, typename Source1, typename Source2> | |
174 | bool test_input_filter( Filter filter, | |
175 | const Source1& input, | |
176 | const Source2& output ) | |
177 | { | |
178 | // Use tag dispatch to compensate for bad overload resolution. | |
179 | return test_input_filter( filter, input, output, | |
180 | is_string<Source1>() ); | |
181 | } | |
182 | ||
183 | //--------------Definition of test_output_filter------------------------------// | |
184 | ||
185 | template<typename Filter> | |
186 | bool test_output_filter( Filter filter, | |
187 | const std::string& input, | |
188 | const std::string& output, | |
189 | mpl::true_ ) | |
190 | { | |
191 | for ( int inc = default_increment; | |
192 | inc < default_increment * 40; | |
193 | inc += default_increment ) | |
194 | { | |
195 | array_source src(input.data(), input.data() + input.size()); | |
196 | std::string dest; | |
197 | iostreams::copy(src, compose(filter, non_blocking_sink(dest, inc))); | |
198 | if (dest != output ) | |
199 | return false; | |
200 | } | |
201 | return true; | |
202 | } | |
203 | ||
204 | template<typename Filter, typename Source1, typename Source2> | |
205 | bool test_output_filter( Filter filter, | |
206 | const Source1& input, | |
207 | const Source2& output, | |
208 | mpl::false_ ) | |
209 | { | |
210 | std::string in; | |
211 | std::string out; | |
212 | iostreams::copy(input, iostreams::back_inserter(in)); | |
213 | iostreams::copy(output, iostreams::back_inserter(out)); | |
214 | return test_output_filter(filter, in, out); | |
215 | } | |
216 | ||
217 | template<typename Filter, typename Source1, typename Source2> | |
218 | bool test_output_filter( Filter filter, | |
219 | const Source1& input, | |
220 | const Source2& output ) | |
221 | { | |
222 | // Use tag dispatch to compensate for bad overload resolution. | |
223 | return test_output_filter( filter, input, output, | |
224 | is_string<Source1>() ); | |
225 | } | |
226 | ||
227 | //--------------Definition of test_filter_pair--------------------------------// | |
228 | ||
229 | template<typename OutputFilter, typename InputFilter> | |
230 | bool test_filter_pair( OutputFilter out, | |
231 | InputFilter in, | |
232 | const std::string& data, | |
233 | mpl::true_ ) | |
234 | { | |
235 | for ( int inc = default_increment; | |
236 | inc <= default_increment * 40; | |
237 | inc += default_increment ) | |
238 | { | |
239 | { | |
240 | array_source src(data.data(), data.data() + data.size()); | |
241 | std::string temp; | |
242 | std::string dest; | |
243 | iostreams::copy(src, compose(out, non_blocking_sink(temp, inc))); | |
244 | iostreams::copy( | |
245 | compose(in, non_blocking_source(temp, inc)), | |
246 | iostreams::back_inserter(dest) | |
247 | ); | |
248 | if (dest != data) | |
249 | return false; | |
250 | } | |
251 | { | |
252 | array_source src(data.data(), data.data() + data.size()); | |
253 | std::string temp; | |
254 | std::string dest; | |
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. | |
258 | try { | |
259 | temp.resize(temp.size() / 2); | |
260 | iostreams::copy( | |
261 | compose(in, non_blocking_source(temp, inc)), | |
262 | iostreams::back_inserter(dest) | |
263 | ); | |
264 | } catch(std::ios_base::failure&) {} | |
265 | } | |
266 | { | |
267 | array_source src(data.data(), data.data() + data.size()); | |
268 | std::string temp; | |
269 | std::string dest; | |
270 | iostreams::copy(compose(out, src), non_blocking_sink(temp, inc)); | |
271 | iostreams::copy( | |
272 | non_blocking_source(temp, inc), | |
273 | compose(in, iostreams::back_inserter(dest)) | |
274 | ); | |
275 | if (dest != data) | |
276 | return false; | |
277 | } | |
278 | { | |
279 | array_source src(data.data(), data.data() + data.size()); | |
280 | std::string temp; | |
281 | std::string dest; | |
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. | |
285 | try { | |
286 | temp.resize(temp.size() / 2); | |
287 | iostreams::copy( | |
288 | non_blocking_source(temp, inc), | |
289 | compose(in, iostreams::back_inserter(dest)) | |
290 | ); | |
291 | } catch(std::ios_base::failure&) {} | |
292 | } | |
293 | } | |
294 | return true; | |
295 | } | |
296 | ||
297 | template<typename OutputFilter, typename InputFilter, typename Source> | |
298 | bool test_filter_pair( OutputFilter out, | |
299 | InputFilter in, | |
300 | const Source& data, | |
301 | mpl::false_ ) | |
302 | { | |
303 | std::string str; | |
304 | iostreams::copy(data, iostreams::back_inserter(str)); | |
305 | return test_filter_pair(out, in, str); | |
306 | } | |
307 | ||
308 | template<typename OutputFilter, typename InputFilter, typename Source> | |
309 | bool test_filter_pair( OutputFilter out, | |
310 | InputFilter in, | |
311 | const Source& data ) | |
312 | { | |
313 | // Use tag dispatch to compensate for bad overload resolution. | |
314 | return test_filter_pair(out, in, data, is_string<Source>()); | |
315 | } | |
316 | ||
317 | } } // End namespaces iostreams, boost. | |
318 | ||
319 | #endif // #ifndef BOOST_IOSTREAMS_FILTER_TEST_HPP_INCLUDED |