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