]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/numeric/conversion/test/udt_support_test.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / numeric / conversion / test / udt_support_test.cpp
1 // (C) Copyright 2003, Fernando Luis Cacciola Carballal.
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 //
7 //
8 #include<iostream>
9 #include<iomanip>
10 #include<string>
11 #include<typeinfo>
12 #include<vector>
13 #include<algorithm>
14
15 #include "boost/numeric/conversion/converter.hpp"
16
17 #ifdef __BORLANDC__
18 #pragma hdrstop
19 #endif
20
21 #include "test_helpers.cpp"
22 #include "test_helpers2.cpp"
23 #include "test_helpers3.cpp"
24
25 using namespace std ;
26 using namespace boost ;
27 using namespace numeric ;
28 using namespace MyUDT ;
29
30 //-------------------------------------------------------------------------
31 // These are the typical steps that are required to install support for
32 // conversions from/to UDT which need special treatment.
33 //-------------------------------------------------------------------------
34
35
36
37 //
38 // (1) Instantiate specific convesions traits.
39 // This step is only for convenience.
40 // These traits instances are required in order to define the specializations
41 // that follow (and which *are required* to make the library work with MyInt and MyFloat)
42 //
43 namespace MyUDT {
44
45 typedef conversion_traits<double , MyFloat> MyFloat_to_double_Traits;
46 typedef conversion_traits<int , MyFloat> MyFloat_to_int_Traits;
47 typedef conversion_traits<MyInt , MyFloat> MyFloat_to_MyInt_Traits;
48 typedef conversion_traits<int , MyInt > MyInt_to_int_Traits;
49 typedef conversion_traits<MyFloat, MyInt > MyInt_to_MyFloat_Traits;
50 typedef conversion_traits<MyInt , double > double_to_MyInt_Traits;
51
52 } // namespace MyUDT
53
54
55 //
56 // (2) Define suitable raw converters.
57 //
58 // Our sample UDTs don't support implicit conversions.
59 // Therefore, the default raw_converter<> doesn't work,
60 // and we need to define our own.
61 //
62 // There are two ways of doing this:
63 //
64 // (a) One is to simply specialize boost::numeric::raw_converter<> directly.
65 // This way, the default converter will work out of the box, which means, for instance,
66 // that numeric_cast<> can be used with these UDTs.
67 //
68 // (b) Define a user class with the appropriate interface and supply it explicitely
69 // as a policy to a converter instance.
70 //
71 // This test uses chice (a).
72 //
73 namespace boost {
74
75 namespace numeric {
76
77 template<>
78 struct raw_converter<MyUDT::MyFloat_to_double_Traits>
79 {
80 static double low_level_convert ( MyUDT::MyFloat const& s )
81 { return s.to_builtin() ; }
82 } ;
83
84 template<>
85 struct raw_converter<MyUDT::MyFloat_to_int_Traits>
86 {
87 static int low_level_convert ( MyUDT::MyFloat const& s )
88 { return static_cast<int>( s.to_builtin() ) ; }
89 } ;
90
91 template<>
92 struct raw_converter<MyUDT::MyFloat_to_MyInt_Traits>
93 {
94 static MyUDT::MyInt low_level_convert ( MyUDT::MyFloat const& s )
95 { return MyUDT::MyInt( static_cast<int>(s.to_builtin()) ) ; }
96 } ;
97
98 template<>
99 struct raw_converter<MyUDT::MyInt_to_int_Traits>
100 {
101 static int low_level_convert ( MyUDT::MyInt const& s ) { return s.to_builtin() ; }
102 } ;
103
104 template<>
105 struct raw_converter<MyUDT::MyInt_to_MyFloat_Traits>
106 {
107 static MyUDT::MyFloat low_level_convert ( MyUDT::MyInt const& s )
108 {
109 return MyUDT::MyFloat( static_cast<double>(s.to_builtin()) ) ;
110 }
111 } ;
112
113 template<>
114 struct raw_converter<MyUDT::double_to_MyInt_Traits>
115 {
116 static MyUDT::MyInt low_level_convert ( double s )
117 { return MyUDT::MyInt( static_cast<int>(s) ) ; }
118 } ;
119
120 } // namespace numeric
121
122 } // namespace boost
123
124
125
126 //
127 // (3) Define suitable range checkers
128 //
129 // By default, if a UDT is involved in a conversion, internal range checking is disabled.
130 // This is so because a UDT type can have any sort of range, even unbounded, thus
131 // the library doesn't attempt to automatically figure out the appropriate range checking logic.
132 // (as it does when builtin types are involved)
133 // However, this situation is a bit unsufficient in practice, specially from doing narrowing (subranged)
134 // conversions from UDTs.
135 // The library provides a rudimentary hook to help this out: The user can plug in his own
136 // range checker to the converter instance.
137 //
138 // This test shows how to define and use a custom range checker.
139 //
140
141 namespace MyUDT {
142
143 //
144 // The following are metaprogramming tools to allow us the implement the
145 // MyCustomRangeChecker generically, for either builtin or UDT types.
146 //
147
148 // get_builtin_type<N>::type extracts the built-in type of our UDT's
149 //
150 template<class N> struct get_builtin_type { typedef N type ; } ;
151 template<> struct get_builtin_type<MyInt> { typedef int type ; } ;
152 template<> struct get_builtin_type<MyFloat> { typedef double type ; } ;
153
154 // U extract_builtin ( T s ) returns 's' converted to the corresponding built-in type U.
155 //
156 template<class N>
157 struct extract_builtin
158 {
159 static N apply ( N n ) { return n ; }
160 } ;
161 template<>
162 struct extract_builtin<MyInt>
163 {
164 static int apply ( MyInt const& n ) { return n.to_builtin() ; }
165 } ;
166 template<>
167 struct extract_builtin<MyFloat>
168 {
169 static double apply ( MyFloat const& n ) { return n.to_builtin() ; }
170 } ;
171
172 template<class Traits>
173 struct MyCustomRangeChecker
174 {
175 typedef typename Traits::argument_type argument_type ;
176
177 // This custom range checker uses the fact that our 'fake' UDT are merely wrappers
178 // around builtin types; so it just forward the logic to the correspoding range
179 // checkers for the wrapped builtin types.
180 //
181 typedef typename Traits::source_type S ;
182 typedef typename Traits::target_type T ;
183
184 // NOTE: S and/or T can be either UDT or builtin types.
185
186 typedef typename get_builtin_type<S>::type builtinS ;
187 typedef typename get_builtin_type<T>::type builtinT ;
188
189 // NOTE: The internal range checker used by default is *built* when you instantiate
190 // a converter<> with a given Traits according to the properties of the involved types.
191 // Currently, there is no way to instantiate this range checker as a separate class.
192 // However, you can see it as part of the interface of the converter
193 // (since the converter inherits from it)
194 // Therefore, here we instantiate a converter corresponding to the builtin types to access
195 // their associated builtin range checker.
196 //
197 typedef boost::numeric::converter<builtinT,builtinS> InternalConverter ;
198
199 static range_check_result out_of_range ( argument_type s )
200 {
201 return InternalConverter::out_of_range( extract_builtin<S>::apply(s) );
202 }
203
204 static void validate_range ( argument_type s )
205 {
206 return InternalConverter::validate_range( extract_builtin<S>::apply(s) );
207 }
208 } ;
209
210 } // namespace MyUDT
211
212
213
214
215
216
217
218
219 //
220 // Test here
221 //
222
223 void test_udt_conversions_with_defaults()
224 {
225 cout << "Testing UDT conversion with default policies\n" ;
226
227 // MyInt <--> int
228
229 int mibv = rand();
230 MyInt miv(mibv);
231 TEST_SUCCEEDING_CONVERSION_DEF(MyInt,int,miv,mibv);
232 TEST_SUCCEEDING_CONVERSION_DEF(int,MyInt,mibv,miv);
233
234 // MyFloat <--> double
235
236 double mfbv = static_cast<double>(rand()) / 3.0 ;
237 MyFloat mfv (mfbv);
238 TEST_SUCCEEDING_CONVERSION_DEF(MyFloat,double,mfv,mfbv);
239 TEST_SUCCEEDING_CONVERSION_DEF(double,MyFloat,mfbv,mfv);
240
241 // MyInt <--> MyFloat
242
243 MyInt miv2 ( static_cast<int>(mfbv) );
244 MyFloat miv2F ( static_cast<int>(mfbv) );
245 MyFloat mfv2 ( static_cast<double>(mibv) );
246 MyInt mfv2I ( static_cast<double>(mibv) );
247 TEST_SUCCEEDING_CONVERSION_DEF(MyFloat,MyInt,miv2F,miv2);
248 TEST_SUCCEEDING_CONVERSION_DEF(MyInt,MyFloat,mfv2I,mfv2);
249 }
250
251 template<class T, class S>
252 struct GenerateCustomConverter
253 {
254 typedef conversion_traits<T,S> Traits;
255
256 typedef def_overflow_handler OverflowHandler ;
257 typedef Trunc<S> Float2IntRounder ;
258 typedef raw_converter<Traits> RawConverter ;
259 typedef MyCustomRangeChecker<Traits> RangeChecker ;
260
261 typedef converter<T,S,Traits,OverflowHandler,Float2IntRounder,RawConverter,RangeChecker> type ;
262 } ;
263
264 void test_udt_conversions_with_custom_range_checking()
265 {
266 cout << "Testing UDT conversions with custom range checker\n" ;
267
268 int mibv = rand();
269 MyFloat mfv ( static_cast<double>(mibv) );
270
271 typedef GenerateCustomConverter<MyFloat,int>::type int_to_MyFloat_Conv ;
272
273 TEST_SUCCEEDING_CONVERSION( int_to_MyFloat_Conv, MyFloat, int, mfv, mibv );
274
275 int mibv2 = rand();
276 MyInt miv (mibv2);
277 MyFloat mfv2 ( static_cast<double>(mibv2) );
278
279 typedef GenerateCustomConverter<MyFloat,MyInt>::type MyInt_to_MyFloat_Conv ;
280
281 TEST_SUCCEEDING_CONVERSION( MyInt_to_MyFloat_Conv, MyFloat, MyInt, mfv2, miv );
282
283 double mfbv = bounds<double>::highest();
284 typedef GenerateCustomConverter<MyInt,double>::type double_to_MyInt_Conv ;
285
286 TEST_POS_OVERFLOW_CONVERSION( double_to_MyInt_Conv, MyInt, double, mfbv );
287
288 MyFloat mfv3 ( bounds<double>::lowest() ) ;
289 typedef GenerateCustomConverter<int,MyFloat>::type MyFloat_to_int_Conv ;
290
291 TEST_NEG_OVERFLOW_CONVERSION( MyFloat_to_int_Conv, int, MyFloat, mfv3 );
292 }
293
294
295 int test_main( int, char* [] )
296 {
297 cout << setprecision( numeric_limits<long double>::digits10 ) ;
298
299 test_udt_conversions_with_defaults();
300 test_udt_conversions_with_custom_range_checking();
301
302 return 0;
303 }
304
305
306
307
308
309