]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/safe_numerics/test/test_interval.cpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / safe_numerics / test / test_interval.cpp
1 // Copyright (c) 2012 Robert Ramey
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 #include <iostream>
8 #include <limits>
9 #include <functional>
10 #include <array>
11
12 #include <boost/core/demangle.hpp>
13 #include <boost/safe_numerics/checked_result.hpp>
14 #include <boost/safe_numerics/checked_result_operations.hpp>
15 #include <boost/safe_numerics/interval.hpp>
16
17 template<typename T>
18 using fptr = T (*)(const T &, const T &);
19 template<typename T>
20 using fptr_interval = fptr<boost::safe_numerics::interval<T>>;
21
22 template<typename T>
23 struct op {
24 const fptr<T> m_f;
25 const fptr_interval<T> m_finterval;
26 const char * m_symbol;
27 const bool skip_zeros;
28 };
29
30 template<
31 typename T,
32 unsigned int N
33 >
34 bool test_type_operator(
35 const T (&value)[N],
36 const op<T> & opi
37 ){
38 using namespace boost::safe_numerics;
39
40 // for each pair of values p1, p2 (100)
41 for(const T & l1 : value)
42 for(const T & u1 : value){
43 if(l1 > u1) continue; // skip reverse range
44 const interval<T> p1(l1, u1);
45 for(const T & l2 : value)
46 for(const T & u2 : value){
47 if(l2 > u2) continue; // skip reverse range
48 const interval<T> p2(l2, u2);
49
50 // maybe skip intervals which include zero
51 if(opi.skip_zeros){
52 if(l2 == safe_numerics_error::range_error
53 || l2 == safe_numerics_error::domain_error
54 || u2 == safe_numerics_error::range_error
55 || u2 == safe_numerics_error::domain_error
56 || p2.includes(T(0))
57 )
58 continue;
59 }
60
61 // create a new interval from the operation
62 const interval<T> result_interval = opi.m_finterval(p1, p2);
63 std::cout
64 << p1 << opi.m_symbol << p2 << " -> " << result_interval << std::endl;
65
66 // if resulting interval is null
67 if(result_interval.u < result_interval.l)
68 continue;
69
70 // for each pair test values
71 for(const T r1 : value)
72 for(const T r2 : value){
73 // calculate result of operation
74 const T result = opi.m_f(r1, r2);
75 if(result != safe_numerics_error::range_error
76 && result != safe_numerics_error::domain_error ){
77 // note usage of tribool logic here !!!
78 // includes returns indeterminate the conditional
79 // returns false in both cases and this is what we want.
80 // This is very subtle, don't skim over this.
81 // if both r1 and r2 are within they're respective bounds
82 if(p1.includes(r1) && p2.includes(r2)
83 && ! result_interval.includes(result)){
84 return false;
85 }
86 }
87 }
88 }
89 }
90 return true;
91 }
92
93 // values
94 // note: need to explicitly specify number of elements to avoid msvc failure
95 template<typename T>
96 const boost::safe_numerics::checked_result<T> value[8] = {
97 boost::safe_numerics::safe_numerics_error::negative_overflow_error,
98 std::numeric_limits<T>::lowest(),
99 T(-1),
100 T(0),
101 T(1),
102 std::numeric_limits<T>::max(),
103 boost::safe_numerics::safe_numerics_error::positive_overflow_error,
104 boost::safe_numerics::safe_numerics_error::domain_error
105 };
106
107 // note: need to explicitly specify number of elements to avoid msvc failure
108 template<typename T>
109 const boost::safe_numerics::checked_result<T> unsigned_value[6] = {
110 boost::safe_numerics::safe_numerics_error::negative_overflow_error,
111 T(0),
112 T(1),
113 std::numeric_limits<T>::max(),
114 boost::safe_numerics::safe_numerics_error::positive_overflow_error,
115 boost::safe_numerics::safe_numerics_error::domain_error
116 };
117
118 // invoke for each type
119 struct test_type {
120 unsigned int m_error_count;
121 test_type() :
122 m_error_count(0)
123 {}
124 template<typename T>
125 bool operator()(const T &){
126 using namespace boost::safe_numerics;
127 std::cout
128 << "** testing "
129 << boost::core::demangle(typeid(T).name())
130 << std::endl;
131
132 using R = checked_result<T>;
133 // pointers to operands for types T
134 static const std::array<op<R>, 5> op_table{{
135 {operator+, operator+, "+", false},
136 {operator-, operator-, "-", false},
137 {operator*, operator*, "*", false},
138 {operator<<, operator<<, "<<", false},
139 {operator>>, operator>>, ">>", false},
140 }};
141
142 //for(unsigned int i = 0; i < sizeof(op_table)/sizeof(op) / sizeof(fptr<R>); ++i){
143 for(const op<R> & o : op_table){
144 if(std::is_signed<T>::value){
145 if(! test_type_operator(value<T>, o)){
146 ++m_error_count;
147 return false;
148 }
149 }
150 else{
151 if(! test_type_operator(unsigned_value<T>, o)){
152 ++m_error_count;
153 return false;
154 }
155 }
156 }
157 return true;
158 }
159 };
160
161 #include <boost/mp11/list.hpp>
162 #include <boost/mp11/algorithm.hpp>
163
164 int main(int, char *[]){
165 using namespace boost::mp11;
166 // list of signed types
167 using signed_types = mp_list<std::int8_t, std::int16_t, std::int32_t, std::int64_t>;
168 // list of unsigned types
169 using unsigned_types = mp_list<std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t>;
170
171 test_type t;
172 mp_for_each<unsigned_types>(t);
173 mp_for_each<signed_types>(t);
174
175 std::cout << (t.m_error_count == 0 ? "success!" : "failure") << std::endl;
176 return t.m_error_count ;
177 }