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_S_POLICY_HPP 30 #define PAGMO_S_POLICY_HPP 31 32 #include <cassert> 33 #include <iostream> 34 #include <memory> 35 #include <string> 36 #include <type_traits> 37 #include <typeindex> 38 #include <typeinfo> 39 #include <utility> 40 41 #include <boost/type_traits/integral_constant.hpp> 42 43 #include <pagmo/config.hpp> 44 #include <pagmo/detail/support_xeus_cling.hpp> 45 #include <pagmo/detail/type_name.hpp> 46 #include <pagmo/detail/typeid_name_extract.hpp> 47 #include <pagmo/detail/visibility.hpp> 48 #include <pagmo/s11n.hpp> 49 #include <pagmo/type_traits.hpp> 50 #include <pagmo/types.hpp> 51 52 #define PAGMO_S11N_S_POLICY_EXPORT_KEY(s) \ 53 BOOST_CLASS_EXPORT_KEY2(pagmo::detail::s_pol_inner<s>, "udsp " #s) \ 54 BOOST_CLASS_TRACKING(pagmo::detail::s_pol_inner<s>, boost::serialization::track_never) 55 56 #define PAGMO_S11N_S_POLICY_IMPLEMENT(s) BOOST_CLASS_EXPORT_IMPLEMENT(pagmo::detail::s_pol_inner<s>) 57 58 #define PAGMO_S11N_S_POLICY_EXPORT(s) \ 59 PAGMO_S11N_S_POLICY_EXPORT_KEY(s) \ 60 PAGMO_S11N_S_POLICY_IMPLEMENT(s) 61 62 namespace pagmo 63 { 64 65 // Check if T has a select() member function conforming to the UDSP requirements. 66 template <typename T> 67 class has_select 68 { 69 template <typename U> 70 using select_t = decltype(std::declval<const U &>().select( 71 std::declval<const individuals_group_t &>(), std::declval<const vector_double::size_type &>(), 72 std::declval<const vector_double::size_type &>(), std::declval<const vector_double::size_type &>(), 73 std::declval<const vector_double::size_type &>(), std::declval<const vector_double::size_type &>(), 74 std::declval<const vector_double &>())); 75 static const bool implementation_defined = std::is_same<detected_t<select_t, T>, individuals_group_t>::value; 76 77 public: 78 static const bool value = implementation_defined; 79 }; 80 81 template <typename T> 82 const bool has_select<T>::value; 83 84 namespace detail 85 { 86 87 // Specialise this to true in order to disable all the UDSP checks and mark a type 88 // as a UDSP regardless of the features provided by it. 89 // NOTE: this is needed when implementing the machinery for Python s_policies. 90 // NOTE: leave this as an implementation detail for now. 91 template <typename> 92 struct disable_udsp_checks : std::false_type { 93 }; 94 95 } // namespace detail 96 97 // Detect UDSPs 98 template <typename T> 99 class is_udsp 100 { 101 static const bool implementation_defined 102 = detail::disjunction<detail::conjunction<std::is_same<T, uncvref_t<T>>, std::is_default_constructible<T>, 103 std::is_copy_constructible<T>, std::is_move_constructible<T>, 104 std::is_destructible<T>, has_select<T>>, 105 detail::disable_udsp_checks<T>>::value; 106 107 public: 108 // Value of the type trait. 109 static const bool value = implementation_defined; 110 }; 111 112 template <typename T> 113 const bool is_udsp<T>::value; 114 115 namespace detail 116 { 117 118 struct PAGMO_DLL_PUBLIC_INLINE_CLASS s_pol_inner_base { ~s_pol_inner_basepagmo::detail::s_pol_inner_base119 virtual ~s_pol_inner_base() {} 120 virtual std::unique_ptr<s_pol_inner_base> clone() const = 0; 121 virtual individuals_group_t select(const individuals_group_t &, const vector_double::size_type &, 122 const vector_double::size_type &, const vector_double::size_type &, 123 const vector_double::size_type &, const vector_double::size_type &, 124 const vector_double &) const = 0; 125 virtual std::string get_name() const = 0; 126 virtual std::string get_extra_info() const = 0; 127 virtual std::type_index get_type_index() const = 0; 128 virtual const void *get_ptr() const = 0; 129 virtual void *get_ptr() = 0; 130 131 private: 132 friend class boost::serialization::access; 133 template <typename Archive> serializepagmo::detail::s_pol_inner_base134 void serialize(Archive &, unsigned) 135 { 136 } 137 }; 138 139 template <typename T> 140 struct PAGMO_DLL_PUBLIC_INLINE_CLASS s_pol_inner final : s_pol_inner_base { 141 // We just need the def ctor, delete everything else. 142 s_pol_inner() = default; 143 s_pol_inner(const s_pol_inner &) = delete; 144 s_pol_inner(s_pol_inner &&) = delete; 145 s_pol_inner &operator=(const s_pol_inner &) = delete; 146 s_pol_inner &operator=(s_pol_inner &&) = delete; 147 // Constructors from T. s_pol_innerpagmo::detail::s_pol_inner148 explicit s_pol_inner(const T &x) : m_value(x) {} s_pol_innerpagmo::detail::s_pol_inner149 explicit s_pol_inner(T &&x) : m_value(std::move(x)) {} 150 // The clone method, used in the copy constructor of s_policy. clonepagmo::detail::s_pol_inner151 std::unique_ptr<s_pol_inner_base> clone() const final 152 { 153 return std::make_unique<s_pol_inner>(m_value); 154 } 155 // The mandatory select() method. selectpagmo::detail::s_pol_inner156 individuals_group_t select(const individuals_group_t &inds, const vector_double::size_type &nx, 157 const vector_double::size_type &nix, const vector_double::size_type &nobj, 158 const vector_double::size_type &nec, const vector_double::size_type &nic, 159 const vector_double &tol) const final 160 { 161 return m_value.select(inds, nx, nix, nobj, nec, nic, tol); 162 } 163 // Optional methods. get_namepagmo::detail::s_pol_inner164 std::string get_name() const final 165 { 166 return get_name_impl(m_value); 167 } get_extra_infopagmo::detail::s_pol_inner168 std::string get_extra_info() const final 169 { 170 return get_extra_info_impl(m_value); 171 } 172 template <typename U, enable_if_t<has_name<U>::value, int> = 0> get_name_implpagmo::detail::s_pol_inner173 static std::string get_name_impl(const U &value) 174 { 175 return value.get_name(); 176 } 177 template <typename U, enable_if_t<!has_name<U>::value, int> = 0> get_name_implpagmo::detail::s_pol_inner178 static std::string get_name_impl(const U &) 179 { 180 return detail::type_name<U>(); 181 } 182 template <typename U, enable_if_t<has_extra_info<U>::value, int> = 0> get_extra_info_implpagmo::detail::s_pol_inner183 static std::string get_extra_info_impl(const U &value) 184 { 185 return value.get_extra_info(); 186 } 187 template <typename U, enable_if_t<!has_extra_info<U>::value, int> = 0> get_extra_info_implpagmo::detail::s_pol_inner188 static std::string get_extra_info_impl(const U &) 189 { 190 return ""; 191 } 192 // Get the type at runtime. get_type_indexpagmo::detail::s_pol_inner193 std::type_index get_type_index() const final 194 { 195 return std::type_index(typeid(T)); 196 } 197 // Raw getters for the internal instance. get_ptrpagmo::detail::s_pol_inner198 const void *get_ptr() const final 199 { 200 return &m_value; 201 } get_ptrpagmo::detail::s_pol_inner202 void *get_ptr() final 203 { 204 return &m_value; 205 } 206 207 private: 208 friend class boost::serialization::access; 209 // Serialization 210 template <typename Archive> serializepagmo::detail::s_pol_inner211 void serialize(Archive &ar, unsigned) 212 { 213 detail::archive(ar, boost::serialization::base_object<s_pol_inner_base>(*this), m_value); 214 } 215 216 public: 217 T m_value; 218 }; 219 220 } // namespace detail 221 222 } // namespace pagmo 223 224 // Disable Boost.Serialization tracking for the implementation 225 // details of s_policy. 226 BOOST_CLASS_TRACKING(pagmo::detail::s_pol_inner_base, boost::serialization::track_never) 227 228 namespace pagmo 229 { 230 231 // Selection policy. 232 class PAGMO_DLL_PUBLIC s_policy 233 { 234 // Enable the generic ctor only if T is not an s_policy (after removing 235 // const/reference qualifiers), and if T is a udsp. 236 template <typename T> 237 using generic_ctor_enabler = enable_if_t< 238 detail::conjunction<detail::negation<std::is_same<s_policy, uncvref_t<T>>>, is_udsp<uncvref_t<T>>>::value, int>; 239 // Implementation of the generic ctor. 240 void generic_ctor_impl(); 241 242 public: 243 // Default constructor. 244 s_policy(); 245 // Constructor from a UDSP. 246 template <typename T, generic_ctor_enabler<T> = 0> s_policy(T && x)247 explicit s_policy(T &&x) : m_ptr(std::make_unique<detail::s_pol_inner<uncvref_t<T>>>(std::forward<T>(x))) 248 { 249 generic_ctor_impl(); 250 } 251 // Copy constructor. 252 s_policy(const s_policy &); 253 // Move constructor. 254 s_policy(s_policy &&) noexcept; 255 // Move assignment operator 256 s_policy &operator=(s_policy &&) noexcept; 257 // Copy assignment operator 258 s_policy &operator=(const s_policy &); 259 // Assignment from a UDSP. 260 template <typename T, generic_ctor_enabler<T> = 0> operator =(T && x)261 s_policy &operator=(T &&x) 262 { 263 return (*this) = s_policy(std::forward<T>(x)); 264 } 265 266 // Extraction and related. 267 template <typename T> extract() const268 const T *extract() const noexcept 269 { 270 #if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) 271 return detail::typeid_name_extract<T>(*this); 272 #else 273 auto p = dynamic_cast<const detail::s_pol_inner<T> *>(ptr()); 274 return p == nullptr ? nullptr : &(p->m_value); 275 #endif 276 } 277 template <typename T> extract()278 T *extract() noexcept 279 { 280 #if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) 281 return detail::typeid_name_extract<T>(*this); 282 #else 283 auto p = dynamic_cast<detail::s_pol_inner<T> *>(ptr()); 284 return p == nullptr ? nullptr : &(p->m_value); 285 #endif 286 } 287 template <typename T> is() const288 bool is() const noexcept 289 { 290 return extract<T>() != nullptr; 291 } 292 293 // Select. 294 individuals_group_t select(const individuals_group_t &, const vector_double::size_type &, 295 const vector_double::size_type &, const vector_double::size_type &, 296 const vector_double::size_type &, const vector_double::size_type &, 297 const vector_double &) const; 298 299 // Name. get_name() const300 std::string get_name() const 301 { 302 return m_name; 303 } 304 // Extra info. 305 std::string get_extra_info() const; 306 307 // Check if the s_policy is valid. 308 bool is_valid() const; 309 310 // Get the type at runtime. 311 std::type_index get_type_index() const; 312 313 // Get a const pointer to the UDSP. 314 const void *get_ptr() const; 315 316 // Get a mutable pointer to the UDSP. 317 void *get_ptr(); 318 319 private: 320 friend class boost::serialization::access; 321 // Serialisation support. 322 template <typename Archive> save(Archive & ar,unsigned) const323 void save(Archive &ar, unsigned) const 324 { 325 detail::to_archive(ar, m_ptr, m_name); 326 } 327 template <typename Archive> load(Archive & ar,unsigned)328 void load(Archive &ar, unsigned) 329 { 330 try { 331 detail::from_archive(ar, m_ptr, m_name); 332 } catch (...) { 333 *this = s_policy{}; 334 throw; 335 } 336 } BOOST_SERIALIZATION_SPLIT_MEMBER()337 BOOST_SERIALIZATION_SPLIT_MEMBER() 338 339 // Just two small helpers to make sure that whenever we require 340 // access to the pointer it actually points to something. 341 detail::s_pol_inner_base const *ptr() const 342 { 343 assert(m_ptr.get() != nullptr); 344 return m_ptr.get(); 345 } ptr()346 detail::s_pol_inner_base *ptr() 347 { 348 assert(m_ptr.get() != nullptr); 349 return m_ptr.get(); 350 } 351 // Helper to check the inputs and outputs of the select() function. 352 PAGMO_DLL_LOCAL void verify_select_input(const individuals_group_t &, const vector_double::size_type &, 353 const vector_double::size_type &, const vector_double::size_type &, 354 const vector_double::size_type &, const vector_double::size_type &, 355 const vector_double &) const; 356 PAGMO_DLL_LOCAL void verify_select_output(const individuals_group_t &, vector_double::size_type, 357 vector_double::size_type) const; 358 359 // Pointer to the inner base s_pol. 360 std::unique_ptr<detail::s_pol_inner_base> m_ptr; 361 // Various properties determined at construction time 362 // from the udsp. These will be constant for the lifetime 363 // of s_policy, but we cannot mark them as such because we want to be 364 // able to assign and deserialise s_policies. 365 std::string m_name; 366 }; 367 368 #if !defined(PAGMO_DOXYGEN_INVOKED) 369 370 // Stream operator. 371 PAGMO_DLL_PUBLIC std::ostream &operator<<(std::ostream &, const s_policy &); 372 373 #endif 374 375 } // namespace pagmo 376 377 // Add some repr support for CLING 378 PAGMO_IMPLEMENT_XEUS_CLING_REPR(s_policy) 379 380 #endif 381