1 /* Copyright 2017-2021 PaGMO development team
2 
3 This file is part of the PaGMO library.
4 
5 The PaGMO library is free software; you can redistribute it and/or modify
6 it under the terms of either:
7 
8   * the GNU Lesser General Public License as published by the Free
9     Software Foundation; either version 3 of the License, or (at your
10     option) any later version.
11 
12 or
13 
14   * the GNU General Public License as published by the Free Software
15     Foundation; either version 3 of the License, or (at your option) any
16     later version.
17 
18 or both in parallel, as here.
19 
20 The PaGMO library is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23 for more details.
24 
25 You should have received copies of the GNU General Public License and the
26 GNU Lesser General Public License along with the PaGMO library.  If not,
27 see https://www.gnu.org/licenses/. */
28 
29 #ifndef PAGMO_TYPE_TRAITS_HPP
30 #define PAGMO_TYPE_TRAITS_HPP
31 
32 #include <cstddef>
33 #include <initializer_list>
34 #include <string>
35 #include <tuple>
36 #include <type_traits>
37 #include <utility>
38 
39 #include <pagmo/threading.hpp>
40 
41 namespace pagmo
42 {
43 
44 namespace detail
45 {
46 
47 // http://en.cppreference.com/w/cpp/experimental/is_detected
48 template <class Default, class AlwaysVoid, template <class...> class Op, class... Args>
49 struct detector {
50     using value_t = std::false_type;
51     using type = Default;
52 };
53 
54 template <class Default, template <class...> class Op, class... Args>
55 struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> {
56     using value_t = std::true_type;
57     using type = Op<Args...>;
58 };
59 
60 // http://en.cppreference.com/w/cpp/experimental/nonesuch
61 struct nonesuch {
62     nonesuch() = delete;
63     ~nonesuch() = delete;
64     nonesuch(nonesuch const &) = delete;
65     void operator=(nonesuch const &) = delete;
66 };
67 
68 // NOTE: we used to have custom implementations
69 // of these utilities in pre-C++17, but now we don't
70 // need them any more.
71 template <typename... Args>
72 using conjunction = std::conjunction<Args...>;
73 
74 template <typename... Args>
75 using disjunction = std::disjunction<Args...>;
76 
77 template <typename T>
78 using negation = std::negation<T>;
79 
80 template <std::size_t... Ints>
81 using index_sequence = std::index_sequence<Ints...>;
82 
83 template <std::size_t N>
84 using make_index_sequence = std::make_index_sequence<N>;
85 
86 template <typename T, typename F, std::size_t... Is>
apply_to_each_item(T && t,const F & f,index_sequence<Is...>)87 void apply_to_each_item(T &&t, const F &f, index_sequence<Is...>)
88 {
89     (void)std::initializer_list<int>{0, (void(f(std::get<Is>(std::forward<T>(t)))), 0)...};
90 }
91 
92 // Tuple for_each(). Execute the functor f on each element of the input Tuple.
93 // https://isocpp.org/blog/2015/01/for-each-arg-eric-niebler
94 // https://www.reddit.com/r/cpp/comments/2tffv3/for_each_argumentsean_parent/
95 // https://www.reddit.com/r/cpp/comments/33b06v/for_each_in_tuple/
96 template <class Tuple, class F>
tuple_for_each(Tuple && t,const F & f)97 void tuple_for_each(Tuple &&t, const F &f)
98 {
99     apply_to_each_item(std::forward<Tuple>(t), f,
100                        make_index_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>{});
101 }
102 
103 } // namespace detail
104 
105 /// Implementation of \p std::is_detected.
106 /**
107  * Implementation of \p std::is_detected, from C++17. See: http://en.cppreference.com/w/cpp/experimental/is_detected.
108  */
109 template <template <class...> class Op, class... Args>
110 using is_detected =
111 #if defined(PAGMO_DOXYGEN_INVOKED)
112     implementation_defined;
113 #else
114     typename detail::detector<detail::nonesuch, void, Op, Args...>::value_t;
115 #endif
116 
117 /// Implementation of \p std::detected_t.
118 /**
119  * Implementation of \p std::detected_t, from C++17. See: http://en.cppreference.com/w/cpp/experimental/is_detected.
120  */
121 template <template <class...> class Op, class... Args>
122 using detected_t =
123 #if defined(PAGMO_DOXYGEN_INVOKED)
124     implementation_defined;
125 #else
126     typename detail::detector<detail::nonesuch, void, Op, Args...>::type;
127 #endif
128 
129 /// Implementation of \p std::enable_if_t.
130 /**
131  * Implementation of \p std::enable_if_t, from C++14. See: http://en.cppreference.com/w/cpp/types/enable_if.
132  */
133 template <bool B, typename T = void>
134 using enable_if_t = typename std::enable_if<B, T>::type;
135 
136 namespace detail
137 {
138 
139 // SFINAE enablers for floating point types
140 template <typename T>
141 using enable_if_is_floating_point = enable_if_t<std::is_floating_point<T>::value, int>;
142 
143 template <typename T>
144 using enable_if_is_not_floating_point = enable_if_t<!std::is_floating_point<T>::value, int>;
145 
146 } // namespace detail
147 
148 /// Remove reference and cv qualifiers from type \p T.
149 template <typename T>
150 using uncvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
151 
152 /// Detect \p set_seed() method.
153 /**
154  * This type trait will be \p true if \p T provides a method with
155  * the following signature:
156  * @code{.unparsed}
157  * void set_seed(unsigned);
158  * @endcode
159  * The \p set_seed() method is part of the interface for the definition of problems and algorithms
160  * (see pagmo::problem and pagmo::algorithm).
161  */
162 template <typename T>
163 class has_set_seed
164 {
165     template <typename U>
166     using set_seed_t = decltype(std::declval<U &>().set_seed(1u));
167     static const bool implementation_defined = std::is_same<void, detected_t<set_seed_t, T>>::value;
168 
169 public:
170     /// Value of the type trait.
171     static const bool value = implementation_defined;
172 };
173 
174 template <typename T>
175 const bool has_set_seed<T>::value;
176 
177 /// Detect \p has_set_seed() method.
178 /**
179  * This type trait will be \p true if \p T provides a method with
180  * the following signature:
181  * @code{.unparsed}
182  * bool has_set_seed() const;
183  * @endcode
184  * The \p has_set_seed() method is part of the interface for the definition of problems and algorithms
185  * (see pagmo::problem and pagmo::algorithm).
186  */
187 template <typename T>
188 class override_has_set_seed
189 {
190     template <typename U>
191     using has_set_seed_t = decltype(std::declval<const U &>().has_set_seed());
192     static const bool implementation_defined = std::is_same<bool, detected_t<has_set_seed_t, T>>::value;
193 
194 public:
195     /// Value of the type trait.
196     static const bool value = implementation_defined;
197 };
198 
199 template <typename T>
200 const bool override_has_set_seed<T>::value;
201 
202 /// Detect \p get_name() method.
203 /**
204  * This type trait will be \p true if \p T provides a method with
205  * the following signature:
206  * @code{.unparsed}
207  * std::string get_name() const;
208  * @endcode
209  * The \p get_name() method is part of the interface for the definition of problems and algorithms
210  * (see pagmo::problem and pagmo::algorithm).
211  */
212 template <typename T>
213 class has_name
214 {
215     template <typename U>
216     using get_name_t = decltype(std::declval<const U &>().get_name());
217     static const bool implementation_defined = std::is_same<std::string, detected_t<get_name_t, T>>::value;
218 
219 public:
220     /// Value of the type trait.
221     static const bool value = implementation_defined;
222 };
223 
224 template <typename T>
225 const bool has_name<T>::value;
226 
227 /// Detect \p get_extra_info() method.
228 /**
229  * This type trait will be \p true if \p T provides a method with
230  * the following signature:
231  * @code{.unparsed}
232  * std::string get_extra_info() const;
233  * @endcode
234  * The \p get_extra_info() method is part of the interface for the definition of problems and algorithms
235  * (see pagmo::problem and pagmo::algorithm).
236  */
237 template <typename T>
238 class has_extra_info
239 {
240     template <typename U>
241     using get_extra_info_t = decltype(std::declval<const U &>().get_extra_info());
242     static const bool implementation_defined = std::is_same<std::string, detected_t<get_extra_info_t, T>>::value;
243 
244 public:
245     /// Value of the type trait.
246     static const bool value = implementation_defined;
247 };
248 
249 template <typename T>
250 const bool has_extra_info<T>::value;
251 
252 /// Detect \p get_thread_safety() method.
253 /**
254  * This type trait will be \p true if \p T provides a method with
255  * the following signature:
256  * @code{.unparsed}
257  * pagmo::thread_safety get_thread_safety() const;
258  * @endcode
259  * The \p get_thread_safety() method is part of the interface for the definition of problems and algorithms
260  * (see pagmo::problem and pagmo::algorithm).
261  */
262 template <typename T>
263 class has_get_thread_safety
264 {
265     template <typename U>
266     using get_thread_safety_t = decltype(std::declval<const U &>().get_thread_safety());
267     static const bool implementation_defined = std::is_same<thread_safety, detected_t<get_thread_safety_t, T>>::value;
268 
269 public:
270     /// Value of the type trait.
271     static const bool value = implementation_defined;
272 };
273 
274 template <typename T>
275 const bool has_get_thread_safety<T>::value;
276 
277 } // namespace pagmo
278 
279 #endif
280