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_DETAIL_TYPEID_NAME_EXTRACT_HPP
30 #define PAGMO_DETAIL_TYPEID_NAME_EXTRACT_HPP
31 
32 #include <cstring>
33 #include <type_traits>
34 #include <typeinfo>
35 
36 #include <pagmo/type_traits.hpp>
37 
38 namespace pagmo
39 {
40 
41 namespace detail
42 {
43 
44 // This is an implementation of the extract() functionality
45 // for UDx classes based on the name() of the UDx C++ type,
46 // as returned by typeid().name(). This is needed
47 // because the dynamic_cast() used in the
48 // usual extract() implementations can fail on some
49 // compiler/platform/stdlib implementations
50 // when crossing boundaries between dlopened()
51 // modules. See:
52 // https://github.com/pybind/pybind11/issues/912#issuecomment-310157016
53 // https://bugs.llvm.org/show_bug.cgi?id=33542
54 template <typename T, typename C>
typeid_name_extract(C & class_inst)55 inline typename std::conditional<std::is_const<C>::value, const T *, T *>::type typeid_name_extract(C &class_inst)
56 {
57     // NOTE: typeid() strips away both reference and cv qualifiers. Thus,
58     // if T is cv-qualified or a reference type, return nullptr pre-empitvely
59     // (in any case, extraction cannot be successful in such cases).
60     if (!std::is_same<T, uncvref_t<T>>::value || std::is_reference<T>::value) {
61         return nullptr;
62     }
63 
64     if (std::strcmp(class_inst.get_type_index().name(), typeid(T).name())) {
65         // The names differ, return null.
66         return nullptr;
67     } else {
68         // The names match, cast to the correct type and return.
69         return static_cast<typename std::conditional<std::is_const<C>::value, const T *, T *>::type>(
70             class_inst.get_ptr());
71     }
72 }
73 
74 } // namespace detail
75 
76 } // namespace pagmo
77 
78 #endif
79