1 /*=============================================================================
2     Copyright (c) 2016 Lee Clagett
3 
4     Distributed under the Boost Software License, Version 1.0. (See accompanying
5     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 ==============================================================================*/
7 
8 #include <boost/fusion/sequence/comparison.hpp>
9 #include <boost/mpl/identity.hpp>
10 
11 namespace test_detail
12 {
13     struct convertible
14     {
convertibletest_detail::convertible15         convertible() : value_() {}
convertibletest_detail::convertible16         convertible(int value) : value_(value) {}
17         int value_;
18     };
19 
operator ==(convertible const & lhs,convertible const & rhs)20     bool operator==(convertible const& lhs, convertible const& rhs)
21     {
22         return lhs.value_ == rhs.value_;
23     }
24 
operator !=(convertible const & lhs,convertible const & rhs)25     bool operator!=(convertible const& lhs, convertible const& rhs)
26     {
27         return lhs.value_ != rhs.value_;
28     }
29 
30     // Testing conversion at function call allows for testing mutable lvalue,
31     // const lvalue, and rvalue as the source. mpl::identity prevents deduction
32     template <typename T>
implicit_construct(typename boost::mpl::identity<T>::type source)33     T implicit_construct(typename boost::mpl::identity<T>::type source)
34     {
35         return source;
36     }
37 
38     template <typename F, typename Source, typename Expected>
run(Source const & source,Expected const & expected)39     bool run(Source const& source, Expected const& expected)
40     {
41         return F()(source, expected);
42     }
43 
44     template <typename F, typename Source>
run(Source const & source)45     bool run(Source const& source)
46     {
47         return run<F>(source, source);
48     }
49 
50     template <typename T>
51     struct can_rvalue_implicit_construct
52     {
53         template<typename Source, typename Expected>
operator ()test_detail::can_rvalue_implicit_construct54         bool operator()(Source const& source, Expected const& expected) const
55         {
56             return expected == implicit_construct<T>(implicit_construct<Source>(source));
57         }
58     };
59 
60     template <typename T>
61     struct can_lvalue_implicit_construct
62     {
63         template <typename Source, typename Expected>
operator ()test_detail::can_lvalue_implicit_construct64         bool operator()(Source source, Expected const& expected) const
65         {
66             return expected == implicit_construct<T>(source);
67         }
68     };
69 
70     template <typename T>
71     struct can_const_lvalue_implicit_construct
72     {
73         template <typename Source, typename Expected>
operator ()test_detail::can_const_lvalue_implicit_construct74         bool operator()(Source const& source, Expected const& expected) const
75         {
76             return expected == implicit_construct<T>(source);
77         }
78     };
79 
80     template <typename T>
81     struct can_implicit_construct
82     {
83         template <typename Source, typename Expected>
operator ()test_detail::can_implicit_construct84         bool operator()(Source const& source, Expected const& expected) const
85         {
86             return
87                 run< can_rvalue_implicit_construct<T> >(source, expected) &&
88                 run< can_lvalue_implicit_construct<T> >(source, expected) &&
89                 run< can_const_lvalue_implicit_construct<T> >(source, expected);
90         }
91     };
92 
93     template <typename T>
94     struct can_rvalue_construct
95     {
96         template<typename Source, typename Expected>
operator ()test_detail::can_rvalue_construct97         bool operator()(Source const& source, Expected const& expected) const
98         {
99             return expected == T(implicit_construct<Source>(source));
100         }
101     };
102 
103     template <typename T>
104     struct can_lvalue_construct
105     {
106         template <typename Source, typename Expected>
operator ()test_detail::can_lvalue_construct107         bool operator()(Source source, Expected const& expected) const
108         {
109             return expected == T(source);
110         }
111     };
112 
113     template <typename T>
114     struct can_const_lvalue_construct
115     {
116         template <typename Source, typename Expected>
operator ()test_detail::can_const_lvalue_construct117         bool operator()(Source const& source, Expected const& expected) const
118         {
119             return expected == T(source);
120         }
121     };
122 
123     template <typename T>
124     struct can_construct
125     {
126         template <typename Source, typename Expected>
operator ()test_detail::can_construct127         bool operator()(Source const& source, Expected const& expected) const
128         {
129             return
130                 run< can_rvalue_construct<T> >(source, expected) &&
131                 run< can_lvalue_construct<T> >(source, expected) &&
132                 run< can_const_lvalue_construct<T> >(source, expected);
133         }
134     };
135 
136     template <typename T>
137     struct can_rvalue_assign
138     {
139         template <typename Source, typename Expected>
operator ()test_detail::can_rvalue_assign140         bool operator()(Source const& source, Expected const& expected) const
141         {
142             bool result = true;
143             {
144                 T seq;
145                 result &= (seq == expected || seq != expected);
146 
147                 seq = implicit_construct<Source>(source);
148                 result &= (seq == expected);
149             }
150             return result;
151         }
152     };
153 
154     template <typename T>
155     struct can_lvalue_assign
156     {
157 
158         template <typename Source, typename Expected>
operator ()test_detail::can_lvalue_assign159         bool operator()(Source source, Expected const& expected) const
160         {
161             bool result = true;
162             {
163                 T seq;
164                 result &= (seq == expected || seq != expected);
165 
166                 seq = source;
167                 result &= (seq == expected);
168             }
169             return result;
170         }
171     };
172 
173     template <typename T>
174     struct can_const_lvalue_assign
175     {
176         template <typename Source, typename Expected>
operator ()test_detail::can_const_lvalue_assign177         bool operator()(Source const& source, Expected const& expected) const
178         {
179             bool result = true;
180             {
181                 T seq;
182                 result &= (seq == expected || seq != expected);
183 
184                 seq = source;
185                 result &= (seq == expected);
186             }
187             return result;
188         }
189     };
190 
191     template <typename T>
192     struct can_assign
193     {
194         template <typename Source, typename Expected>
operator ()test_detail::can_assign195         bool operator()(Source const& source, Expected const& expected) const
196         {
197             return
198                 run< can_rvalue_assign<T> >(source, expected) &&
199                 run< can_lvalue_assign<T> >(source, expected) &&
200                 run< can_const_lvalue_assign<T> >(source, expected);
201         }
202     };
203 
204     template <typename T>
205     struct can_copy
206     {
207         template <typename Source, typename Expected>
operator ()test_detail::can_copy208         bool operator()(Source const& source, Expected const& expected) const
209         {
210             return
211                 run< can_construct<T> >(source, expected) &&
212                 run< can_implicit_construct<T> >(source, expected) &&
213                 run< can_assign<T> >(source, expected);
214         }
215     };
216 } // test_detail
217