diff --git a/.circleci/config.yml b/.circleci/config.yml index 06e9d7032..95f298019 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,30 +17,30 @@ jobs: - run: name: Build and test command: bash ./tools/circleci_focal_gcc9_asan.sh - focal_clang9: + focal_gcc9_docs: docker: - image: circleci/buildpack-deps:focal steps: - checkout - run: name: Build and test - command: bash ./tools/circleci_focal_clang9.sh - bionic_clang6_release: + command: bash ./tools/circleci_focal_gcc9_docs.sh + focal_clang9: docker: - - image: circleci/buildpack-deps:bionic + - image: circleci/buildpack-deps:focal steps: - checkout - run: name: Build and test - command: bash ./tools/circleci_bionic_clang6_release.sh - bionic_gcc7_conda_docs: + command: bash ./tools/circleci_focal_clang9.sh + bionic_clang6_release: docker: - image: circleci/buildpack-deps:bionic steps: - checkout - run: name: Build and test - command: bash ./tools/circleci_bionic_gcc7_conda_docs.sh + command: bash ./tools/circleci_bionic_clang6_release.sh workflows: version: 2 @@ -50,4 +50,4 @@ workflows: - focal_gcc9_asan - focal_clang9 - bionic_clang6_release - - bionic_gcc7_conda_docs + - focal_gcc9_docs diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b8cd12be..5e68e3eee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -208,6 +208,7 @@ set(PAGMO_SRC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/detail/task_queue.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/detail/prime_numbers.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/detail/gte_getter.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/detail/type_name.cpp" ) # Some compilers choke on the cec2013/2014 data arrays. diff --git a/cmake_modules/yacma/LICENSE b/cmake_modules/yacma/LICENSE index 16577b9df..edd52cf34 100644 --- a/cmake_modules/yacma/LICENSE +++ b/cmake_modules/yacma/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016-2019 Francesco Biscani +Copyright (c) 2016-2020 Francesco Biscani Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/cmake_modules/yacma/YACMACompilerLinkerSettings.cmake b/cmake_modules/yacma/YACMACompilerLinkerSettings.cmake index d8c387594..7d7aa1bfc 100644 --- a/cmake_modules/yacma/YACMACompilerLinkerSettings.cmake +++ b/cmake_modules/yacma/YACMACompilerLinkerSettings.cmake @@ -44,36 +44,32 @@ endfunction() # Enable conditionally a CXX flag, if supported by the compiler. # This is for flags intended to be enabled in all configurations. -# NOTE: we use macros and go through temporary private variables -# because it's apparently impossible to append to an internal +# NOTE: we use macros because it's apparently impossible to append to an internal # CACHEd list. macro(_YACMA_CHECK_ENABLE_CXX_FLAG flag) set(CMAKE_REQUIRED_QUIET TRUE) - check_cxx_compiler_flag("${flag}" YACMA_CHECK_CXX_FLAG) + check_cxx_compiler_flag("${flag}" YACMA_CHECK_CXX_FLAG::${flag}) unset(CMAKE_REQUIRED_QUIET) - if(YACMA_CHECK_CXX_FLAG) + if(YACMA_CHECK_CXX_FLAG::${flag}) message(STATUS "'${flag}': flag is supported by the compiler, enabling.") list(APPEND _YACMA_CXX_FLAGS "${flag}") else() message(STATUS "'${flag}': flag is not supported by the compiler.") endif() - # NOTE: check_cxx_compiler stores variables in the cache. - unset(YACMA_CHECK_CXX_FLAG CACHE) endmacro() # Enable conditionally a debug CXX flag, is supported by the compiler. # This is for flags intended to be enabled in debug mode. macro(_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG flag) set(CMAKE_REQUIRED_QUIET TRUE) - check_cxx_compiler_flag("${flag}" YACMA_CHECK_DEBUG_CXX_FLAG) + check_cxx_compiler_flag("${flag}" YACMA_CHECK_DEBUG_CXX_FLAG::${flag}) unset(CMAKE_REQUIRED_QUIET) - if(YACMA_CHECK_DEBUG_CXX_FLAG) + if(YACMA_CHECK_DEBUG_CXX_FLAG::${flag}) message(STATUS "'${flag}': debug flag is supported by the compiler, enabling.") list(APPEND _YACMA_CXX_FLAGS_DEBUG "${flag}") else() message(STATUS "'${flag}': debug flag is not supported by the compiler.") endif() - unset(YACMA_CHECK_DEBUG_CXX_FLAG CACHE) endmacro() # What we want to avoid is to re-run the expensive flag checks. We will set cache variables @@ -86,6 +82,8 @@ if(NOT _YACMACompilerLinkerSettingsRun) # Configuration bits specific for GCC. if(YACMA_COMPILER_IS_GNUCXX) _YACMA_CHECK_ENABLE_CXX_FLAG(-fdiagnostics-color=auto) + # New in GCC 9. + _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Waddress-of-packed-member) endif() # Configuration bits specific for clang. @@ -94,7 +92,26 @@ if(NOT _YACMACompilerLinkerSettingsRun) # for the time being. _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wshadow) # Clang is better at this flag than GCC. - _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Werror) + # NOTE: enable unconditionally, as it seems like the CMake + # machinery for detecting this fails. Perhaps the source code + # used for checking the flag emits warnings? + list(APPEND _YACMA_CXX_FLAGS_DEBUG "-Werror") + # New warnings in clang 8. + # NOTE: a few issues with macros here, let's disable for now. + # _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wextra-semi-stmt) + # New warnings in clang 10. + _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wtautological-overlap-compare) + _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wtautological-compare) + _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wtautological-bitwise-compare) + _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wbitwise-conditional-parentheses) + _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wrange-loop-analysis) + _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wmisleading-indentation) + _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wc99-designator) + _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wreorder-init-list) + _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wsizeof-pointer-div) + _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wsizeof-array-div) + _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wxor-used-as-pow) + _YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wfinal-dtor-non-final-class) endif() # Common configuration for GCC, clang and Intel. diff --git a/config.hpp.in b/config.hpp.in index f831454b6..0708b4f88 100644 --- a/config.hpp.in +++ b/config.hpp.in @@ -29,6 +29,10 @@ see https://www.gnu.org/licenses/. */ #ifndef PAGMO_CONFIG_HPP #define PAGMO_CONFIG_HPP +// NOTE: include this so that we can +// detect _LIBCPP_VERSION below. +#include + // Start of defines instantiated by CMake. // clang-format off #define PAGMO_VERSION "@pagmo_VERSION@" @@ -54,4 +58,13 @@ see https://www.gnu.org/licenses/. */ #endif +#if defined(__clang__) && defined(_LIBCPP_VERSION) + +// When using clang + libc++, prefer the name-based +// extract() implementation for UDx classes. See +// the explanation in typeid_name_extract.hpp. +#define PAGMO_PREFER_TYPEID_NAME_EXTRACT + +#endif + #endif diff --git a/doc/sphinx/changelog.rst b/doc/sphinx/changelog.rst index a16b936ca..d37dcd251 100644 --- a/doc/sphinx/changelog.rst +++ b/doc/sphinx/changelog.rst @@ -9,6 +9,17 @@ Changelog New ~~~ +- The type-erased wrappers now have additional member functions + to interact at runtime with the contained user-defined objects. + Specifically, it is now possible to fetch ``void`` pointers to the + user-defined objects without knowing their type, and to query + at runtime the ``std::type_index`` of the user-defined objects + (`#410 `__). + +- The default ``get_name()`` implementations for the type-erased + wrappers now return the demangled C++ name on most platforms + (`#410 `__). + - Add a :cpp:func:`pagmo::base_bgl_topology::get_edge_weight()` function to fetch the weight of an edge in a BGL topology (`#407 `__). @@ -23,8 +34,19 @@ New Fix ~~~ +- Introduce a workaround for an issue present on some + compiler/standard library combinations, where + the ``dynamic_cast`` used in the ``extract()`` + implementations would fail when crossing the boundaries + between ``dlopen()``-ed libraries + (`#410 `__). + +- Build fixes for recent CMake versions + (`#410 `__). + - Various doc fixes - (`#405 `__). + (`#410 `__, + `#405 `__). 2.14.0 (2020-03-04) ------------------- diff --git a/doc/sphinx/docs/cpp/bfe.rst b/doc/sphinx/docs/cpp/bfe.rst index 1a6ffc02d..a44d6fc30 100644 --- a/doc/sphinx/docs/cpp/bfe.rst +++ b/doc/sphinx/docs/cpp/bfe.rst @@ -217,6 +217,44 @@ Batch fitness evaluator :return: ``false`` if *this* was moved from, ``true`` otherwise. + .. cpp:function:: std::type_index get_type_index() const + + .. versionadded:: 2.15 + + Get the type of the UDBFE. + + This function will return the type + of the UDBFE stored within this :cpp:class:`~pagmo::bfe` + instance. + + :return: the type of the UDBFE. + + .. cpp:function:: const void *get_ptr() const + .. cpp:function:: void *get_ptr() + + .. versionadded:: 2.15 + + Get a pointer to the UDBFE. + + These functions will return a raw (const) pointer + to the internal UDBFE instance. Differently from + the :cpp:func:`~pagmo::bfe::extract()` overloads, these functions + do not require to pass the correct type + in input. It is however the user's responsibility + to cast the returned void pointer to the correct type. + + .. note:: + + The returned value is a raw non-owning pointer: the lifetime of the pointee is tied to the lifetime + of ``this``, and ``delete`` must never be called on the pointer. + + .. note:: + + The ability to extract a mutable pointer is provided only in order to allow to call non-const + methods on the internal UDBFE instance. Assigning a new UDBFE via this pointer is undefined behaviour. + + :return: a pointer to the internal UDBFE. + .. cpp:function:: template void save(Archive &ar, unsigned) const .. cpp:function:: template void load(Archive &ar, unsigned) diff --git a/doc/sphinx/docs/cpp/r_policy.rst b/doc/sphinx/docs/cpp/r_policy.rst index d853d1903..4a2af8b98 100644 --- a/doc/sphinx/docs/cpp/r_policy.rst +++ b/doc/sphinx/docs/cpp/r_policy.rst @@ -218,6 +218,44 @@ Replacement policy :return: ``false`` if *this* was moved from, ``true`` otherwise. + .. cpp:function:: std::type_index get_type_index() const + + .. versionadded:: 2.15 + + Get the type of the UDRP. + + This function will return the type + of the UDRP stored within this :cpp:class:`~pagmo::r_policy` + instance. + + :return: the type of the UDRP. + + .. cpp:function:: const void *get_ptr() const + .. cpp:function:: void *get_ptr() + + .. versionadded:: 2.15 + + Get a pointer to the UDRP. + + These functions will return a raw (const) pointer + to the internal UDRP instance. Differently from + the :cpp:func:`~pagmo::r_policy::extract()` overloads, these functions + do not require to pass the correct type + in input. It is however the user's responsibility + to cast the returned void pointer to the correct type. + + .. note:: + + The returned value is a raw non-owning pointer: the lifetime of the pointee is tied to the lifetime + of ``this``, and ``delete`` must never be called on the pointer. + + .. note:: + + The ability to extract a mutable pointer is provided only in order to allow to call non-const + methods on the internal UDRP instance. Assigning a new UDRP via this pointer is undefined behaviour. + + :return: a pointer to the internal UDRP. + .. cpp:function:: template void save(Archive &ar, unsigned) const .. cpp:function:: template void load(Archive &ar, unsigned) diff --git a/doc/sphinx/docs/cpp/s_policy.rst b/doc/sphinx/docs/cpp/s_policy.rst index 8094406ea..c527a4e2c 100644 --- a/doc/sphinx/docs/cpp/s_policy.rst +++ b/doc/sphinx/docs/cpp/s_policy.rst @@ -211,6 +211,44 @@ Selection policy :return: ``false`` if *this* was moved from, ``true`` otherwise. + .. cpp:function:: std::type_index get_type_index() const + + .. versionadded:: 2.15 + + Get the type of the UDSP. + + This function will return the type + of the UDSP stored within this :cpp:class:`~pagmo::s_policy` + instance. + + :return: the type of the UDSP. + + .. cpp:function:: const void *get_ptr() const + .. cpp:function:: void *get_ptr() + + .. versionadded:: 2.15 + + Get a pointer to the UDSP. + + These functions will return a raw (const) pointer + to the internal UDSP instance. Differently from + the :cpp:func:`~pagmo::s_policy::extract()` overloads, these functions + do not require to pass the correct type + in input. It is however the user's responsibility + to cast the returned void pointer to the correct type. + + .. note:: + + The returned value is a raw non-owning pointer: the lifetime of the pointee is tied to the lifetime + of ``this``, and ``delete`` must never be called on the pointer. + + .. note:: + + The ability to extract a mutable pointer is provided only in order to allow to call non-const + methods on the internal UDSP instance. Assigning a new UDSP via this pointer is undefined behaviour. + + :return: a pointer to the internal UDSP. + .. cpp:function:: template void save(Archive &ar, unsigned) const .. cpp:function:: template void load(Archive &ar, unsigned) diff --git a/doc/sphinx/docs/cpp/topology.rst b/doc/sphinx/docs/cpp/topology.rst index 57c6fdcbe..cfe719e1c 100644 --- a/doc/sphinx/docs/cpp/topology.rst +++ b/doc/sphinx/docs/cpp/topology.rst @@ -240,6 +240,44 @@ Topology :return: ``false`` if *this* was moved from, ``true`` otherwise. + .. cpp:function:: std::type_index get_type_index() const + + .. versionadded:: 2.15 + + Get the type of the UDT. + + This function will return the type + of the UDT stored within this :cpp:class:`~pagmo::topology` + instance. + + :return: the type of the UDT. + + .. cpp:function:: const void *get_ptr() const + .. cpp:function:: void *get_ptr() + + .. versionadded:: 2.15 + + Get a pointer to the UDT. + + These functions will return a raw (const) pointer + to the internal UDT instance. Differently from + the :cpp:func:`~pagmo::topology::extract()` overloads, these functions + do not require to pass the correct type + in input. It is however the user's responsibility + to cast the returned void pointer to the correct type. + + .. note:: + + The returned value is a raw non-owning pointer: the lifetime of the pointee is tied to the lifetime + of ``this``, and ``delete`` must never be called on the pointer. + + .. note:: + + The ability to extract a mutable pointer is provided only in order to allow to call non-const + methods on the internal UDT instance. Assigning a new UDT via this pointer is undefined behaviour. + + :return: a pointer to the internal UDT. + .. cpp:function:: template void save(Archive &ar, unsigned) const .. cpp:function:: template void load(Archive &ar, unsigned) diff --git a/doc/sphinx/install.rst b/doc/sphinx/install.rst index 17bb8f781..e3f4c15a0 100644 --- a/doc/sphinx/install.rst +++ b/doc/sphinx/install.rst @@ -60,6 +60,7 @@ to the channels, and then we can immediately install pagmo: .. code-block:: console $ conda config --add channels conda-forge + $ conda config --set channel_priority strict $ conda install pagmo pagmo-devel The conda packages for pagmo are maintained by the core development team, diff --git a/doc/sphinx/overview.rst b/doc/sphinx/overview.rst index 7cdcd2f12..ac0f53f7f 100644 --- a/doc/sphinx/overview.rst +++ b/doc/sphinx/overview.rst @@ -86,7 +86,7 @@ Exponential Evolution Strategies (xNES) :cpp:class:`pagmo::xn Non-dominated Sorting GA (NSGA2) :cpp:class:`pagmo::nsga2` M-U-I Multi-objective EA vith Decomposition (MOEA/D) :cpp:class:`pagmo::moead` M-U Multi-objective Hypervolume-based ACO (MHACO) :cpp:class:`pagmo::maco` M-U-I -Non-dominated Sorting PSO (NSPSO) :cpp:class:`pagmo::nspso` M-U-I +Non-dominated Sorting PSO (NSPSO) :cpp:class:`pagmo::nspso` M-U ========================================================== ========================================= ========================= Local optimization diff --git a/include/pagmo/algorithm.hpp b/include/pagmo/algorithm.hpp index e86217f90..3ee9a7fab 100644 --- a/include/pagmo/algorithm.hpp +++ b/include/pagmo/algorithm.hpp @@ -33,14 +33,18 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include #include #include #include +#include #include #include +#include +#include #include #include #include @@ -186,6 +190,9 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS algo_inner_base { virtual std::string get_name() const = 0; virtual std::string get_extra_info() const = 0; virtual thread_safety get_thread_safety() const = 0; + virtual std::type_index get_type_index() const = 0; + virtual const void *get_ptr() const = 0; + virtual void *get_ptr() = 0; template void serialize(Archive &, unsigned) { @@ -311,7 +318,7 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS algo_inner final : algo_inner_base { template ::value, int> = 0> static std::string get_name_impl(const U &) { - return typeid(U).name(); + return detail::type_name(); } template ::value, int> = 0> static std::string get_extra_info_impl(const U &value) @@ -333,7 +340,20 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS algo_inner final : algo_inner_base { { return thread_safety::basic; } - + // Get the type at runtime. + virtual std::type_index get_type_index() const override final + { + return std::type_index(typeid(T)); + } + // Raw getters for the internal instance. + virtual const void *get_ptr() const override final + { + return &m_value; + } + virtual void *get_ptr() override final + { + return &m_value; + } // Serialization template void serialize(Archive &ar, unsigned) @@ -505,8 +525,12 @@ class PAGMO_DLL_PUBLIC algorithm template const T *extract() const noexcept { +#if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) + return detail::typeid_name_extract(*this); +#else auto p = dynamic_cast *>(ptr()); return p == nullptr ? nullptr : &(p->m_value); +#endif } /// Extract a pointer to the UDA. @@ -538,8 +562,12 @@ class PAGMO_DLL_PUBLIC algorithm template T *extract() noexcept { +#if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) + return detail::typeid_name_extract(*this); +#else auto p = dynamic_cast *>(ptr()); return p == nullptr ? nullptr : &(p->m_value); +#endif } /// Checks the user-defined algorithm type at run-time. @@ -640,6 +668,58 @@ class PAGMO_DLL_PUBLIC algorithm // Check if the algorithm is valid. bool is_valid() const; + // Get the type at runtime. + std::type_index get_type_index() const; + + /// Get a const pointer to the UDA. + /** + * \verbatim embed:rst:leading-asterisk + * .. versionadded:: 2.15 + * + * This function will return a raw const pointer + * to the internal UDA instance. Differently from + * :cpp:func:`~pagmo::algorithm::extract()`, this function + * does not require to pass the correct type + * in input. It is however the user's responsibility + * to cast the returned void pointer to the correct type. + * + * .. note:: + * + * The returned value is a raw non-owning pointer: the lifetime of the pointee is tied to the lifetime + * of ``this``, and ``delete`` must never be called on the pointer. + * \endverbatim + * + * @return a pointer to the internal UDA. + */ + const void *get_ptr() const; + + /// Get a mutable pointer to the UDA. + /** + * \verbatim embed:rst:leading-asterisk + * .. versionadded:: 2.15 + * + * This function will return a raw pointer + * to the internal UDA instance. Differently from + * :cpp:func:`~pagmo::algorithm::extract()`, this function + * does not require to pass the correct type + * in input. It is however the user's responsibility + * to cast the returned void pointer to the correct type. + * + * .. note:: + * + * The returned value is a raw non-owning pointer: the lifetime of the pointee is tied to the lifetime + * of ``this``, and ``delete`` must never be called on the pointer. + * + * .. note:: + * + * The ability to extract a mutable pointer is provided only in order to allow to call non-const + * methods on the internal UDA instance. Assigning a new UDA via this pointer is undefined behaviour. + * \endverbatim + * + * @return a pointer to the internal UDA. + */ + void *get_ptr(); + /// Save to archive. /** * This method will save \p this into the archive \p ar. diff --git a/include/pagmo/bfe.hpp b/include/pagmo/bfe.hpp index 9b63cca44..13ecfd5a7 100644 --- a/include/pagmo/bfe.hpp +++ b/include/pagmo/bfe.hpp @@ -34,14 +34,18 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include #include #include #include +#include #include #include +#include +#include #include #include #include @@ -118,6 +122,9 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS bfe_inner_base { virtual std::string get_name() const = 0; virtual std::string get_extra_info() const = 0; virtual thread_safety get_thread_safety() const = 0; + virtual std::type_index get_type_index() const = 0; + virtual const void *get_ptr() const = 0; + virtual void *get_ptr() = 0; template void serialize(Archive &, unsigned) { @@ -167,7 +174,7 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS bfe_inner final : bfe_inner_base { template ::value, int> = 0> static std::string get_name_impl(const U &) { - return typeid(U).name(); + return detail::type_name(); } template ::value, int> = 0> static std::string get_extra_info_impl(const U &value) @@ -189,6 +196,20 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS bfe_inner final : bfe_inner_base { { return thread_safety::basic; } + // Get the type at runtime. + virtual std::type_index get_type_index() const override final + { + return std::type_index(typeid(T)); + } + // Raw getters for the internal instance. + virtual const void *get_ptr() const override final + { + return &m_value; + } + virtual void *get_ptr() override final + { + return &m_value; + } // Serialization. template void serialize(Archive &ar, unsigned) @@ -272,14 +293,22 @@ class PAGMO_DLL_PUBLIC bfe template const T *extract() const noexcept { +#if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) + return detail::typeid_name_extract(*this); +#else auto p = dynamic_cast *>(ptr()); return p == nullptr ? nullptr : &(p->m_value); +#endif } template T *extract() noexcept { +#if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) + return detail::typeid_name_extract(*this); +#else auto p = dynamic_cast *>(ptr()); return p == nullptr ? nullptr : &(p->m_value); +#endif } template bool is() const noexcept @@ -307,6 +336,15 @@ class PAGMO_DLL_PUBLIC bfe // Check if the bfe is valid. bool is_valid() const; + // Get the type at runtime. + std::type_index get_type_index() const; + + // Get a const pointer to the UDBFE. + const void *get_ptr() const; + + // Get a mutable pointer to the UDBFE. + void *get_ptr(); + // Serialisation support. template void save(Archive &ar, unsigned) const diff --git a/include/pagmo/detail/type_name.hpp b/include/pagmo/detail/type_name.hpp new file mode 100644 index 000000000..62cd7c10b --- /dev/null +++ b/include/pagmo/detail/type_name.hpp @@ -0,0 +1,85 @@ +/* Copyright 2017-2020 PaGMO development team + +This file is part of the PaGMO library. + +The PaGMO library is free software; you can redistribute it and/or modify +it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + +or + + * the GNU General Public License as published by the Free Software + Foundation; either version 3 of the License, or (at your option) any + later version. + +or both in parallel, as here. + +The PaGMO library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received copies of the GNU General Public License and the +GNU Lesser General Public License along with the PaGMO library. If not, +see https://www.gnu.org/licenses/. */ + +#ifndef PAGMO_DETAIL_TYPE_NAME_HPP +#define PAGMO_DETAIL_TYPE_NAME_HPP + +#include +#include +#include + +#include + +namespace pagmo +{ + +namespace detail +{ + +PAGMO_DLL_PUBLIC std::string demangle_from_typeid(const char *); + +// Determine the name of the type T at runtime. +template +inline std::string type_name() +{ + // Get the demangled name without cvref. + auto ret + = demangle_from_typeid(typeid(typename std::remove_cv::type>::type).name()); + + // Redecorate it with cv qualifiers. + constexpr unsigned flag = unsigned(std::is_const::type>::value) + + (unsigned(std::is_volatile::type>::value) << 1); + switch (flag) { + case 0u: + // NOTE: handle this explicitly to keep compiler warnings at bay. + break; + case 1u: + ret += " const"; + break; + case 2u: + ret += " volatile"; + break; + case 3u: + ret += " const volatile"; + } + + // Re-add the reference, if necessary. + if (std::is_lvalue_reference::value) { + ret += " &"; + } else if (std::is_rvalue_reference::value) { + ret += " &&"; + } + + return ret; +} + +} // namespace detail + +} // namespace pagmo + +#endif diff --git a/include/pagmo/detail/typeid_name_extract.hpp b/include/pagmo/detail/typeid_name_extract.hpp new file mode 100644 index 000000000..e50edfb74 --- /dev/null +++ b/include/pagmo/detail/typeid_name_extract.hpp @@ -0,0 +1,78 @@ +/* Copyright 2017-2020 PaGMO development team + +This file is part of the PaGMO library. + +The PaGMO library is free software; you can redistribute it and/or modify +it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + +or + + * the GNU General Public License as published by the Free Software + Foundation; either version 3 of the License, or (at your option) any + later version. + +or both in parallel, as here. + +The PaGMO library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received copies of the GNU General Public License and the +GNU Lesser General Public License along with the PaGMO library. If not, +see https://www.gnu.org/licenses/. */ + +#ifndef PAGMO_DETAIL_TYPEID_NAME_EXTRACT_HPP +#define PAGMO_DETAIL_TYPEID_NAME_EXTRACT_HPP + +#include +#include +#include + +#include + +namespace pagmo +{ + +namespace detail +{ + +// This is an implementation of the extract() functionality +// for UDx classes based on the name() of the UDx C++ type, +// as returned by typeid().name(). This is needed +// because the dynamic_cast() used in the +// usual extract() implementations can fail on some +// compiler/platform/stdlib implementations +// when crossing boundaries between dlopened() +// modules. See: +// https://github.com/pybind/pybind11/issues/912#issuecomment-310157016 +// https://bugs.llvm.org/show_bug.cgi?id=33542 +template +inline typename std::conditional::value, const T *, T *>::type typeid_name_extract(C &class_inst) +{ + // NOTE: typeid() strips away both reference and cv qualifiers. Thus, + // if T is cv-qualified or a reference type, return nullptr pre-empitvely + // (in any case, extraction cannot be successful in such cases). + if (!std::is_same>::value || std::is_reference::value) { + return nullptr; + } + + if (std::strcmp(class_inst.get_type_index().name(), typeid(T).name())) { + // The names differ, return null. + return nullptr; + } else { + // The names match, cast to the correct type and return. + return static_cast::value, const T *, T *>::type>( + class_inst.get_ptr()); + } +} + +} // namespace detail + +} // namespace pagmo + +#endif diff --git a/include/pagmo/island.hpp b/include/pagmo/island.hpp index 75b8d2720..90c78f214 100644 --- a/include/pagmo/island.hpp +++ b/include/pagmo/island.hpp @@ -38,6 +38,7 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include #include #include @@ -48,11 +49,14 @@ see https://www.gnu.org/licenses/. */ #include #include +#include #include #include #include #include #include +#include +#include #include #include #include @@ -147,6 +151,9 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS isl_inner_base { virtual void run_evolve(island &) const = 0; virtual std::string get_name() const = 0; virtual std::string get_extra_info() const = 0; + virtual std::type_index get_type_index() const = 0; + virtual const void *get_ptr() const = 0; + virtual void *get_ptr() = 0; template void serialize(Archive &, unsigned) { @@ -191,7 +198,7 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS isl_inner final : isl_inner_base { template ::value, int> = 0> static std::string get_name_impl(const U &) { - return typeid(U).name(); + return detail::type_name(); } template ::value, int> = 0> static std::string get_extra_info_impl(const U &value) @@ -203,6 +210,20 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS isl_inner final : isl_inner_base { { return ""; } + // Get the type at runtime. + virtual std::type_index get_type_index() const override final + { + return std::type_index(typeid(T)); + } + // Raw getters for the internal instance. + virtual const void *get_ptr() const override final + { + return &m_value; + } + virtual void *get_ptr() override final + { + return &m_value; + } // Serialization template void serialize(Archive &ar, unsigned) @@ -992,8 +1013,12 @@ class PAGMO_DLL_PUBLIC island template const T *extract() const noexcept { +#if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) + return detail::typeid_name_extract(*this); +#else auto isl = dynamic_cast *>(m_ptr->isl_ptr.get()); return isl == nullptr ? nullptr : &(isl->m_value); +#endif } /// Extract a pointer to the UDI used for construction. /** @@ -1021,8 +1046,12 @@ class PAGMO_DLL_PUBLIC island template T *extract() noexcept { +#if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) + return detail::typeid_name_extract(*this); +#else auto isl = dynamic_cast *>(m_ptr->isl_ptr.get()); return isl == nullptr ? nullptr : &(isl->m_value); +#endif } /// Check if the UDI used for construction is of type \p T. /** @@ -1105,6 +1134,59 @@ class PAGMO_DLL_PUBLIC island // Check if the island is valid. bool is_valid() const; + + // Get the type at runtime. + std::type_index get_type_index() const; + + /// Get a const pointer to the UDI. + /** + * \verbatim embed:rst:leading-asterisk + * .. versionadded:: 2.15 + * + * This function will return a raw const pointer + * to the internal UDI instance. Differently from + * :cpp:func:`~pagmo::island::extract()`, this function + * does not require to pass the correct type + * in input. It is however the user's responsibility + * to cast the returned void pointer to the correct type. + * + * .. note:: + * + * The returned value is a raw non-owning pointer: the lifetime of the pointee is tied to the lifetime + * of ``this``, and ``delete`` must never be called on the pointer. + * \endverbatim + * + * @return a pointer to the internal UDI. + */ + const void *get_ptr() const; + + /// Get a mutable pointer to the UDI. + /** + * \verbatim embed:rst:leading-asterisk + * .. versionadded:: 2.15 + * + * This function will return a raw pointer + * to the internal UDI instance. Differently from + * :cpp:func:`~pagmo::island::extract()`, this function + * does not require to pass the correct type + * in input. It is however the user's responsibility + * to cast the returned void pointer to the correct type. + * + * .. note:: + * + * The returned value is a raw non-owning pointer: the lifetime of the pointee is tied to the lifetime + * of ``this``, and ``delete`` must never be called on the pointer. + * + * .. note:: + * + * The ability to extract a mutable pointer is provided only in order to allow to call non-const + * methods on the internal UDI instance. Assigning a new UDI via this pointer is undefined behaviour. + * \endverbatim + * + * @return a pointer to the internal UDI. + */ + void *get_ptr(); + /// Save to archive. /** * This method will save \p this to the archive \p ar. diff --git a/include/pagmo/problem.hpp b/include/pagmo/problem.hpp index f763f624b..1415df3e5 100644 --- a/include/pagmo/problem.hpp +++ b/include/pagmo/problem.hpp @@ -35,6 +35,7 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include #include #include @@ -42,9 +43,12 @@ see https://www.gnu.org/licenses/. */ #include #include +#include #include -#include #include +#include +#include +#include #include #include #include @@ -538,6 +542,9 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS prob_inner_base { virtual std::string get_name() const = 0; virtual std::string get_extra_info() const = 0; virtual thread_safety get_thread_safety() const = 0; + virtual std::type_index get_type_index() const = 0; + virtual const void *get_ptr() const = 0; + virtual void *get_ptr() = 0; template void serialize(Archive &, unsigned) { @@ -886,7 +893,7 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS prob_inner final : prob_inner_base { template ::value, int> = 0> static std::string get_name_impl(const U &) { - return typeid(U).name(); + return detail::type_name(); } template ::value, int> = 0> static std::string get_extra_info_impl(const U &value) @@ -908,6 +915,20 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS prob_inner final : prob_inner_base { { return thread_safety::basic; } + // Get the type at runtime. + virtual std::type_index get_type_index() const override final + { + return std::type_index(typeid(T)); + } + // Raw getters for the internal instance. + virtual const void *get_ptr() const override final + { + return &m_value; + } + virtual void *get_ptr() override final + { + return &m_value; + } // Serialization. template void serialize(Archive &ar, unsigned) @@ -1157,8 +1178,12 @@ class PAGMO_DLL_PUBLIC problem template const T *extract() const noexcept { +#if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) + return detail::typeid_name_extract(*this); +#else auto p = dynamic_cast *>(ptr()); return p == nullptr ? nullptr : &(p->m_value); +#endif } /// Extract a pointer to the UDP used for construction. @@ -1187,8 +1212,12 @@ class PAGMO_DLL_PUBLIC problem template T *extract() noexcept { +#if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) + return detail::typeid_name_extract(*this); +#else auto p = dynamic_cast *>(ptr()); return p == nullptr ? nullptr : &(p->m_value); +#endif } /// Check if the UDP used for construction is of type \p T. @@ -1591,6 +1620,58 @@ class PAGMO_DLL_PUBLIC problem // Check if the problem is in a valid state. bool is_valid() const; + // Get the type at runtime. + std::type_index get_type_index() const; + + /// Get a const pointer to the UDP. + /** + * \verbatim embed:rst:leading-asterisk + * .. versionadded:: 2.15 + * + * This function will return a raw const pointer + * to the internal UDP instance. Differently from + * :cpp:func:`~pagmo::problem::extract()`, this function + * does not require to pass the correct type + * in input. It is however the user's responsibility + * to cast the returned void pointer to the correct type. + * + * .. note:: + * + * The returned value is a raw non-owning pointer: the lifetime of the pointee is tied to the lifetime + * of ``this``, and ``delete`` must never be called on the pointer. + * \endverbatim + * + * @return a pointer to the internal UDP. + */ + const void *get_ptr() const; + + /// Get a mutable pointer to the UDP. + /** + * \verbatim embed:rst:leading-asterisk + * .. versionadded:: 2.15 + * + * This function will return a raw pointer + * to the internal UDP instance. Differently from + * :cpp:func:`~pagmo::problem::extract()`, this function + * does not require to pass the correct type + * in input. It is however the user's responsibility + * to cast the returned void pointer to the correct type. + * + * .. note:: + * + * The returned value is a raw non-owning pointer: the lifetime of the pointee is tied to the lifetime + * of ``this``, and ``delete`` must never be called on the pointer. + * + * .. note:: + * + * The ability to extract a mutable pointer is provided only in order to allow to call non-const + * methods on the internal UDP instance. Assigning a new UDP via this pointer is undefined behaviour. + * \endverbatim + * + * @return a pointer to the internal UDP. + */ + void *get_ptr(); + /// Save to archive. /** * This method will save \p this into the archive \p ar. diff --git a/include/pagmo/problems/decompose.hpp b/include/pagmo/problems/decompose.hpp index 489031da1..25599573e 100644 --- a/include/pagmo/problems/decompose.hpp +++ b/include/pagmo/problems/decompose.hpp @@ -180,10 +180,29 @@ class PAGMO_DLL_PUBLIC decompose // Problem's thread safety level. thread_safety get_thread_safety() const; - // Getter for the inner problem. + /// Getter for the inner problem. + /** + * Returns a const reference to the inner pagmo::problem. + * + * @return a const reference to the inner pagmo::problem. + */ const problem &get_inner_problem() const; - // Getter for the inner problem. + /// Getter for the inner problem. + /** + * Returns a reference to the inner pagmo::problem. + * + * \verbatim embed:rst:leading-asterisk + * .. note:: + * + * The ability to extract a non const reference is provided only in order to allow to call + * non-const methods on the internal :cpp:class:`pagmo::problem` instance. Assigning a new + * :class:`pagmo::problem` via this reference is undefined behaviour. + * + * \endverbatim + * + * @return a reference to the inner pagmo::problem. + */ problem &get_inner_problem(); // Object serialization. diff --git a/include/pagmo/problems/translate.hpp b/include/pagmo/problems/translate.hpp index 5c0161515..49de72a3d 100644 --- a/include/pagmo/problems/translate.hpp +++ b/include/pagmo/problems/translate.hpp @@ -154,10 +154,29 @@ class PAGMO_DLL_PUBLIC translate // Problem's thread safety level. thread_safety get_thread_safety() const; - // Getter for the inner problem. + /// Getter for the inner problem. + /** + * Returns a const reference to the inner pagmo::problem. + * + * @return a const reference to the inner pagmo::problem. + */ const problem &get_inner_problem() const; - // Getter for the inner problem. + /// Getter for the inner problem. + /** + * Returns a reference to the inner pagmo::problem. + * + * \verbatim embed:rst:leading-asterisk + * .. note:: + * + * The ability to extract a non const reference is provided only in order to allow to call + * non-const methods on the internal :cpp:class:`pagmo::problem` instance. Assigning a new + * :cpp:class:`pagmo::problem` via this reference is undefined behaviour. + * + * \endverbatim + * + * @return a reference to the inner pagmo::problem. + */ problem &get_inner_problem(); // Object serialization diff --git a/include/pagmo/problems/unconstrain.hpp b/include/pagmo/problems/unconstrain.hpp index c376a3315..75e7d202e 100644 --- a/include/pagmo/problems/unconstrain.hpp +++ b/include/pagmo/problems/unconstrain.hpp @@ -127,10 +127,29 @@ class PAGMO_DLL_PUBLIC unconstrain // Problem's thread safety level. thread_safety get_thread_safety() const; - // Getter for the inner problem. + /// Getter for the inner problem. + /** + * Returns a const reference to the inner pagmo::problem. + * + * @return a const reference to the inner pagmo::problem. + */ const problem &get_inner_problem() const; - // Getter for the inner problem. + /// Getter for the inner problem. + /** + * Returns a reference to the inner pagmo::problem. + * + * \verbatim embed:rst:leading-asterisk + * .. note:: + * + * The ability to extract a non const reference is provided only in order to allow to call + * non-const methods on the internal :cpp:class:`pagmo::problem` instance. Assigning a new + * :cpp:class:`pagmo::problem` via this reference is undefined behaviour. + * + * \endverbatim + * + * @return a reference to the inner pagmo::problem. + */ problem &get_inner_problem(); // Problem name. diff --git a/include/pagmo/r_policy.hpp b/include/pagmo/r_policy.hpp index 138b57d0f..965ded66e 100644 --- a/include/pagmo/r_policy.hpp +++ b/include/pagmo/r_policy.hpp @@ -34,14 +34,18 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include #include #include #include +#include #include #include +#include +#include #include #include #include @@ -122,6 +126,9 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS r_pol_inner_base { const vector_double &, const individuals_group_t &) const = 0; virtual std::string get_name() const = 0; virtual std::string get_extra_info() const = 0; + virtual std::type_index get_type_index() const = 0; + virtual const void *get_ptr() const = 0; + virtual void *get_ptr() = 0; template void serialize(Archive &, unsigned) { @@ -169,7 +176,7 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS r_pol_inner final : r_pol_inner_base { template ::value, int> = 0> static std::string get_name_impl(const U &) { - return typeid(U).name(); + return detail::type_name(); } template ::value, int> = 0> static std::string get_extra_info_impl(const U &value) @@ -181,6 +188,20 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS r_pol_inner final : r_pol_inner_base { { return ""; } + // Get the type at runtime. + virtual std::type_index get_type_index() const override final + { + return std::type_index(typeid(T)); + } + // Raw getters for the internal instance. + virtual const void *get_ptr() const override final + { + return &m_value; + } + virtual void *get_ptr() override final + { + return &m_value; + } // Serialization template void serialize(Archive &ar, unsigned) @@ -245,14 +266,22 @@ class PAGMO_DLL_PUBLIC r_policy template const T *extract() const noexcept { +#if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) + return detail::typeid_name_extract(*this); +#else auto p = dynamic_cast *>(ptr()); return p == nullptr ? nullptr : &(p->m_value); +#endif } template T *extract() noexcept { +#if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) + return detail::typeid_name_extract(*this); +#else auto p = dynamic_cast *>(ptr()); return p == nullptr ? nullptr : &(p->m_value); +#endif } template bool is() const noexcept @@ -277,6 +306,15 @@ class PAGMO_DLL_PUBLIC r_policy // Check if the r_policy is valid. bool is_valid() const; + // Get the type at runtime. + std::type_index get_type_index() const; + + // Get a const pointer to the UDRP. + const void *get_ptr() const; + + // Get a mutable pointer to the UDRP. + void *get_ptr(); + // Serialisation support. template void save(Archive &ar, unsigned) const diff --git a/include/pagmo/rng.hpp b/include/pagmo/rng.hpp index 7297a2e91..01794e6bb 100644 --- a/include/pagmo/rng.hpp +++ b/include/pagmo/rng.hpp @@ -57,7 +57,11 @@ using random_engine_type = std::mt19937; */ struct PAGMO_DLL_PUBLIC random_device { static unsigned next(); - static void set_seed(unsigned); + +#if !defined(PAGMO_DOXYGEN_INVOKED) + // Sets the seed for the PRS. + static void set_seed(unsigned seed); +#endif }; } // namespace pagmo diff --git a/include/pagmo/s_policy.hpp b/include/pagmo/s_policy.hpp index eeb8accb1..f82c857b5 100644 --- a/include/pagmo/s_policy.hpp +++ b/include/pagmo/s_policy.hpp @@ -34,14 +34,18 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include #include #include #include +#include #include #include +#include +#include #include #include #include @@ -122,6 +126,9 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS s_pol_inner_base { const vector_double &) const = 0; virtual std::string get_name() const = 0; virtual std::string get_extra_info() const = 0; + virtual std::type_index get_type_index() const = 0; + virtual const void *get_ptr() const = 0; + virtual void *get_ptr() = 0; template void serialize(Archive &, unsigned) { @@ -169,7 +176,7 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS s_pol_inner final : s_pol_inner_base { template ::value, int> = 0> static std::string get_name_impl(const U &) { - return typeid(U).name(); + return detail::type_name(); } template ::value, int> = 0> static std::string get_extra_info_impl(const U &value) @@ -181,6 +188,20 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS s_pol_inner final : s_pol_inner_base { { return ""; } + // Get the type at runtime. + virtual std::type_index get_type_index() const override final + { + return std::type_index(typeid(T)); + } + // Raw getters for the internal instance. + virtual const void *get_ptr() const override final + { + return &m_value; + } + virtual void *get_ptr() override final + { + return &m_value; + } // Serialization template void serialize(Archive &ar, unsigned) @@ -245,14 +266,22 @@ class PAGMO_DLL_PUBLIC s_policy template const T *extract() const noexcept { +#if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) + return detail::typeid_name_extract(*this); +#else auto p = dynamic_cast *>(ptr()); return p == nullptr ? nullptr : &(p->m_value); +#endif } template T *extract() noexcept { +#if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) + return detail::typeid_name_extract(*this); +#else auto p = dynamic_cast *>(ptr()); return p == nullptr ? nullptr : &(p->m_value); +#endif } template bool is() const noexcept @@ -277,6 +306,15 @@ class PAGMO_DLL_PUBLIC s_policy // Check if the s_policy is valid. bool is_valid() const; + // Get the type at runtime. + std::type_index get_type_index() const; + + // Get a const pointer to the UDSP. + const void *get_ptr() const; + + // Get a mutable pointer to the UDSP. + void *get_ptr(); + // Serialisation support. template void save(Archive &ar, unsigned) const diff --git a/include/pagmo/topology.hpp b/include/pagmo/topology.hpp index 9eb74d0e3..2eb6bb3a3 100644 --- a/include/pagmo/topology.hpp +++ b/include/pagmo/topology.hpp @@ -35,6 +35,7 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include #include #include @@ -43,8 +44,11 @@ see https://www.gnu.org/licenses/. */ #include #include +#include #include #include +#include +#include #include #include #include @@ -171,6 +175,9 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS topo_inner_base { virtual std::pair, vector_double> get_connections(std::size_t) const = 0; virtual void push_back() = 0; virtual bgl_graph_t to_bgl() const = 0; + virtual std::type_index get_type_index() const = 0; + virtual const void *get_ptr() const = 0; + virtual void *get_ptr() = 0; template void serialize(Archive &, unsigned) { @@ -236,7 +243,7 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS topo_inner final : topo_inner_base { template ::value, int> = 0> static std::string get_name_impl(const U &) { - return typeid(U).name(); + return detail::type_name(); } template ::value, int> = 0> static std::string get_extra_info_impl(const U &value) @@ -248,6 +255,20 @@ struct PAGMO_DLL_PUBLIC_INLINE_CLASS topo_inner final : topo_inner_base { { return ""; } + // Get the type at runtime. + virtual std::type_index get_type_index() const override final + { + return std::type_index(typeid(T)); + } + // Raw getters for the internal instance. + virtual const void *get_ptr() const override final + { + return &m_value; + } + virtual void *get_ptr() override final + { + return &m_value; + } // Serialization template void serialize(Archive &ar, unsigned) @@ -315,14 +336,22 @@ class PAGMO_DLL_PUBLIC topology template const T *extract() const noexcept { +#if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) + return detail::typeid_name_extract(*this); +#else auto p = dynamic_cast *>(ptr()); return p == nullptr ? nullptr : &(p->m_value); +#endif } template T *extract() noexcept { +#if defined(PAGMO_PREFER_TYPEID_NAME_EXTRACT) + return detail::typeid_name_extract(*this); +#else auto p = dynamic_cast *>(ptr()); return p == nullptr ? nullptr : &(p->m_value); +#endif } template bool is() const noexcept @@ -353,6 +382,15 @@ class PAGMO_DLL_PUBLIC topology // Convert to BGL. bgl_graph_t to_bgl() const; + // Get the type at runtime. + std::type_index get_type_index() const; + + // Get a const pointer to the UDT. + const void *get_ptr() const; + + // Get a mutable pointer to the UDT. + void *get_ptr(); + // Serialization. template void save(Archive &ar, unsigned) const diff --git a/include/pagmo/utils/hv_algos/hv_algorithm.hpp b/include/pagmo/utils/hv_algos/hv_algorithm.hpp index c13ef1bbb..541b40493 100644 --- a/include/pagmo/utils/hv_algos/hv_algorithm.hpp +++ b/include/pagmo/utils/hv_algos/hv_algorithm.hpp @@ -147,6 +147,7 @@ class PAGMO_DLL_PUBLIC hv_algorithm // Contributions method virtual std::vector contributions(std::vector &, const vector_double &) const; +#if !defined(PAGMO_DOXYGEN_INVOKED) /// Verification of input /** * This method serves as a verification method. @@ -157,6 +158,7 @@ class PAGMO_DLL_PUBLIC hv_algorithm */ virtual void verify_before_compute(const std::vector &points, const vector_double &r_point) const = 0; +#endif /// Clone method. /** diff --git a/src/algorithm.cpp b/src/algorithm.cpp index 76e394e77..18ca9255e 100644 --- a/src/algorithm.cpp +++ b/src/algorithm.cpp @@ -28,10 +28,12 @@ see https://www.gnu.org/licenses/. */ #include #include +#include #include #include #include +#include #include #include @@ -197,6 +199,33 @@ bool algorithm::is_valid() const return static_cast(m_ptr); } +/// Get the type of the UDA. +/** + * \verbatim embed:rst:leading-asterisk + * .. versionadded:: 2.15 + * + * This function will return the type + * of the UDA stored within this algorithm + * instance. + * \endverbatim + * + * @return the type of the UDA. + */ +std::type_index algorithm::get_type_index() const +{ + return ptr()->get_type_index(); +} + +const void *algorithm::get_ptr() const +{ + return ptr()->get_ptr(); +} + +void *algorithm::get_ptr() +{ + return ptr()->get_ptr(); +} + /// Streaming operator for pagmo::algorithm /** * This function will stream to \p os a human-readable representation of the input @@ -217,6 +246,7 @@ std::ostream &operator<<(std::ostream &os, const algorithm &a) } else { stream(os, " [stochastic]"); } + os << "\n\tC++ class name: " << detail::demangle_from_typeid(a.get_type_index().name()) << '\n'; stream(os, "\n\tThread safety: ", a.get_thread_safety(), '\n'); const auto extra_str = a.get_extra_info(); if (!extra_str.empty()) { diff --git a/src/bfe.cpp b/src/bfe.cpp index d3cf56f02..aac533a80 100644 --- a/src/bfe.cpp +++ b/src/bfe.cpp @@ -28,6 +28,7 @@ see https://www.gnu.org/licenses/. */ #include #include +#include #include #include @@ -35,6 +36,7 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include #include @@ -119,12 +121,28 @@ bool bfe::is_valid() const return static_cast(m_ptr); } +std::type_index bfe::get_type_index() const +{ + return ptr()->get_type_index(); +} + +const void *bfe::get_ptr() const +{ + return ptr()->get_ptr(); +} + +void *bfe::get_ptr() +{ + return ptr()->get_ptr(); +} + #if !defined(PAGMO_DOXYGEN_INVOKED) // Stream operator. std::ostream &operator<<(std::ostream &os, const bfe &b) { - os << "BFE name: " << b.get_name() << '\n'; + os << "BFE name: " << b.get_name(); + os << "\n\tC++ class name: " << detail::demangle_from_typeid(b.get_type_index().name()) << '\n'; os << "\n\tThread safety: " << b.get_thread_safety() << '\n'; const auto extra_str = b.get_extra_info(); if (!extra_str.empty()) { diff --git a/src/detail/type_name.cpp b/src/detail/type_name.cpp new file mode 100644 index 000000000..e4bf5c3cb --- /dev/null +++ b/src/detail/type_name.cpp @@ -0,0 +1,71 @@ +/* Copyright 2017-2020 PaGMO development team + +This file is part of the PaGMO library. + +The PaGMO library is free software; you can redistribute it and/or modify +it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + +or + + * the GNU General Public License as published by the Free Software + Foundation; either version 3 of the License, or (at your option) any + later version. + +or both in parallel, as here. + +The PaGMO library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received copies of the GNU General Public License and the +GNU Lesser General Public License along with the PaGMO library. If not, +see https://www.gnu.org/licenses/. */ + +#include + +#if defined(__GNUC__) || (defined(__clang__) && !defined(_MSC_VER)) + +// GCC demangle. This is available also for clang, both with libstdc++ and libc++. +#include +#include +#include + +#endif + +#include + +namespace pagmo +{ + +namespace detail +{ + +std::string demangle_from_typeid(const char *s) +{ +#if defined(__GNUC__) || (defined(__clang__) && !defined(_MSC_VER)) + // NOTE: wrap std::free() in a local lambda, so we avoid + // potential ambiguities when taking the address of std::free(). + // See: + // https://stackoverflow.com/questions/27440953/stdunique-ptr-for-c-functions-that-need-free + auto deleter = [](void *ptr) { std::free(ptr); }; + + // NOTE: abi::__cxa_demangle will return a pointer allocated by std::malloc, which we will delete via std::free(). + std::unique_ptr res{::abi::__cxa_demangle(s, nullptr, nullptr, nullptr), deleter}; + + // NOTE: return the original string if demangling fails. + return res ? std::string(res.get()) : std::string(s); +#else + // If no demangling is available, just return the mangled name. + // NOTE: MSVC already returns the demangled name from typeid. + return std::string(s); +#endif +} + +} // namespace detail + +} // namespace pagmo diff --git a/src/island.cpp b/src/island.cpp index 063edb8fe..0c24f2308 100644 --- a/src/island.cpp +++ b/src/island.cpp @@ -42,6 +42,7 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include #include #include @@ -863,12 +865,40 @@ std::string island::get_extra_info() const return m_ptr->isl_ptr->get_extra_info(); } +/// Get the type of the UDI. +/** + * \verbatim embed:rst:leading-asterisk + * .. versionadded:: 2.15 + * + * This function will return the type + * of the UDI stored within this island + * instance. + * \endverbatim + * + * @return the type of the UDI. + */ +std::type_index island::get_type_index() const +{ + return m_ptr->isl_ptr->get_type_index(); +} + +const void *island::get_ptr() const +{ + return m_ptr->isl_ptr->get_ptr(); +} + +void *island::get_ptr() +{ + return m_ptr->isl_ptr->get_ptr(); +} + #if !defined(PAGMO_DOXYGEN_INVOKED) // Stream operator for pagmo::island. std::ostream &operator<<(std::ostream &os, const island &isl) { stream(os, "Island name: ", isl.get_name()); + os << "\n\tC++ class name: " << detail::demangle_from_typeid(isl.get_type_index().name()) << '\n'; stream(os, "\n\tStatus: ", isl.status(), "\n\n"); const auto extra_str = isl.get_extra_info(); if (!extra_str.empty()) { diff --git a/src/problem.cpp b/src/problem.cpp index 02b21417b..7284e9e9f 100644 --- a/src/problem.cpp +++ b/src/problem.cpp @@ -35,12 +35,14 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -741,6 +743,33 @@ bool problem::is_valid() const return static_cast(m_ptr); } +/// Get the type of the UDP. +/** + * \verbatim embed:rst:leading-asterisk + * .. versionadded:: 2.15 + * + * This function will return the type + * of the UDP stored within this problem + * instance. + * \endverbatim + * + * @return the type of the UDP. + */ +std::type_index problem::get_type_index() const +{ + return ptr()->get_type_index(); +} + +const void *problem::get_ptr() const +{ + return ptr()->get_ptr(); +} + +void *problem::get_ptr() +{ + return ptr()->get_ptr(); +} + /// Streaming operator /** * This function will stream to \p os a human-readable representation of the input @@ -759,6 +788,7 @@ std::ostream &operator<<(std::ostream &os, const problem &p) if (p.is_stochastic()) { stream(os, " [stochastic]"); } + os << "\n\tC++ class name: " << detail::demangle_from_typeid(p.get_type_index().name()) << '\n'; os << "\n\tGlobal dimension:\t\t\t" << p.get_nx() << '\n'; os << "\tInteger dimension:\t\t\t" << p.get_nix() << '\n'; os << "\tFitness dimension:\t\t\t" << p.get_nf() << '\n'; diff --git a/src/problems/decompose.cpp b/src/problems/decompose.cpp index de9d2b80e..72559fb78 100644 --- a/src/problems/decompose.cpp +++ b/src/problems/decompose.cpp @@ -275,32 +275,11 @@ thread_safety decompose::get_thread_safety() const return m_problem.get_thread_safety(); } -/// Getter for the inner problem. -/** - * Returns a const reference to the inner pagmo::problem. - * - * @return a const reference to the inner pagmo::problem. - */ const problem &decompose::get_inner_problem() const { return m_problem; } -/// Getter for the inner problem. -/** - * Returns a reference to the inner pagmo::problem. - * - * \verbatim embed:rst:leading-asterisk - * .. note:: - * - * The ability to extract a non const reference is provided only in order to allow to call - * non-const methods on the internal :cpp:class:`pagmo::problem` instance. Assigning a new - * :class:`pagmo::problem` via this reference is undefined behaviour. - * - * \endverbatim - * - * @return a reference to the inner pagmo::problem. - */ problem &decompose::get_inner_problem() { return m_problem; diff --git a/src/problems/translate.cpp b/src/problems/translate.cpp index 4abd72bc2..3b6e247cd 100644 --- a/src/problems/translate.cpp +++ b/src/problems/translate.cpp @@ -380,32 +380,11 @@ thread_safety translate::get_thread_safety() const return m_problem.get_thread_safety(); } -/// Getter for the inner problem. -/** - * Returns a const reference to the inner pagmo::problem. - * - * @return a const reference to the inner pagmo::problem. - */ const problem &translate::get_inner_problem() const { return m_problem; } -/// Getter for the inner problem. -/** - * Returns a reference to the inner pagmo::problem. - * - * \verbatim embed:rst:leading-asterisk - * .. note:: - * - * The ability to extract a non const reference is provided only in order to allow to call - * non-const methods on the internal :cpp:class:`pagmo::problem` instance. Assigning a new - * :cpp:class:`pagmo::problem` via this reference is undefined behaviour. - * - * \endverbatim - * - * @return a reference to the inner pagmo::problem. - */ problem &translate::get_inner_problem() { return m_problem; diff --git a/src/problems/unconstrain.cpp b/src/problems/unconstrain.cpp index ba4491155..ac31f8d72 100644 --- a/src/problems/unconstrain.cpp +++ b/src/problems/unconstrain.cpp @@ -269,32 +269,11 @@ thread_safety unconstrain::get_thread_safety() const return m_problem.get_thread_safety(); } -/// Getter for the inner problem. -/** - * Returns a const reference to the inner pagmo::problem. - * - * @return a const reference to the inner pagmo::problem. - */ const problem &unconstrain::get_inner_problem() const { return m_problem; } -/// Getter for the inner problem. -/** - * Returns a reference to the inner pagmo::problem. - * - * \verbatim embed:rst:leading-asterisk - * .. note:: - * - * The ability to extract a non const reference is provided only in order to allow to call - * non-const methods on the internal :cpp:class:`pagmo::problem` instance. Assigning a new - * :cpp:class:`pagmo::problem` via this reference is undefined behaviour. - * - * \endverbatim - * - * @return a reference to the inner pagmo::problem. - */ problem &unconstrain::get_inner_problem() { return m_problem; diff --git a/src/r_policy.cpp b/src/r_policy.cpp index a27110e5b..7045c75db 100644 --- a/src/r_policy.cpp +++ b/src/r_policy.cpp @@ -32,8 +32,10 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include +#include #include #include #include @@ -236,12 +238,29 @@ bool r_policy::is_valid() const return static_cast(m_ptr); } +// Get the type of the UDRP. +std::type_index r_policy::get_type_index() const +{ + return ptr()->get_type_index(); +} + +const void *r_policy::get_ptr() const +{ + return ptr()->get_ptr(); +} + +void *r_policy::get_ptr() +{ + return ptr()->get_ptr(); +} + #if !defined(PAGMO_DOXYGEN_INVOKED) // Stream operator. std::ostream &operator<<(std::ostream &os, const r_policy &r) { - os << "Replacement policy name: " << r.get_name() << '\n'; + os << "Replacement policy name: " << r.get_name(); + os << "\n\tC++ class name: " << detail::demangle_from_typeid(r.get_type_index().name()) << '\n'; const auto extra_str = r.get_extra_info(); if (!extra_str.empty()) { os << "\nExtra info:\n" << extra_str << '\n'; diff --git a/src/rng.cpp b/src/rng.cpp index 3e8d3cb24..bd463ad69 100644 --- a/src/rng.cpp +++ b/src/rng.cpp @@ -61,6 +61,8 @@ unsigned random_device::next() return static_cast(detail::global_rng()); } +#if !defined(PAGMO_DOXYGEN_INVOKED) + /// Sets the seed for the PRS /** * This static method sets a new seed for the PRS, so that all the @@ -75,4 +77,6 @@ void random_device::set_seed(unsigned seed) detail::global_rng.seed(static_cast(seed)); } +#endif + } // namespace pagmo diff --git a/src/s_policy.cpp b/src/s_policy.cpp index 73487329b..8285b322f 100644 --- a/src/s_policy.cpp +++ b/src/s_policy.cpp @@ -32,8 +32,10 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include +#include #include #include #include @@ -219,12 +221,29 @@ bool s_policy::is_valid() const return static_cast(m_ptr); } +// Get the type of the UDSP. +std::type_index s_policy::get_type_index() const +{ + return ptr()->get_type_index(); +} + +const void *s_policy::get_ptr() const +{ + return ptr()->get_ptr(); +} + +void *s_policy::get_ptr() +{ + return ptr()->get_ptr(); +} + #if !defined(PAGMO_DOXYGEN_INVOKED) // Stream operator. std::ostream &operator<<(std::ostream &os, const s_policy &s) { - os << "Selection policy name: " << s.get_name() << '\n'; + os << "Selection policy name: " << s.get_name(); + os << "\n\tC++ class name: " << detail::demangle_from_typeid(s.get_type_index().name()) << '\n'; const auto extra_str = s.get_extra_info(); if (!extra_str.empty()) { os << "\nExtra info:\n" << extra_str << '\n'; diff --git a/src/topology.cpp b/src/topology.cpp index 845cd7e4f..fdfbf2341 100644 --- a/src/topology.cpp +++ b/src/topology.cpp @@ -31,9 +31,11 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include #include +#include #include #include #include @@ -157,11 +159,28 @@ bgl_graph_t topology::to_bgl() const return ptr()->to_bgl(); } +// Get the type of the UDT. +std::type_index topology::get_type_index() const +{ + return ptr()->get_type_index(); +} + +const void *topology::get_ptr() const +{ + return ptr()->get_ptr(); +} + +void *topology::get_ptr() +{ + return ptr()->get_ptr(); +} + #if !defined(PAGMO_DOXYGEN_INVOKED) std::ostream &operator<<(std::ostream &os, const topology &t) { os << "Topology name: " << t.get_name(); + os << "\n\tC++ class name: " << detail::demangle_from_typeid(t.get_type_index().name()) << '\n'; const auto extra_str = t.get_extra_info(); if (!extra_str.empty()) { os << "\nExtra info:\n" << extra_str; diff --git a/tests/algorithm.cpp b/tests/algorithm.cpp index 4aeeeb367..e9b12eda5 100644 --- a/tests/algorithm.cpp +++ b/tests/algorithm.cpp @@ -30,10 +30,13 @@ see https://www.gnu.org/licenses/. */ #define BOOST_TEST_DYN_LINK #include +#include #include #include #include #include +#include +#include #include #include @@ -42,6 +45,7 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include #include #include @@ -117,7 +121,7 @@ BOOST_AUTO_TEST_CASE(algorithm_construction_test) BOOST_CHECK_THROW(algo_minimal.set_verbosity(1u), not_implemented_error); // We check that at construction the name has been assigned BOOST_CHECK(algo_full.get_name() == "name"); - BOOST_CHECK(algo_minimal.get_name().find("al_02") != std::string::npos); + BOOST_CHECK(algo_minimal.get_name() == detail::type_name()); // Default constructor. algorithm a0; BOOST_CHECK((a0.extract() != nullptr)); @@ -497,3 +501,27 @@ BOOST_AUTO_TEST_CASE(generic_assignment) BOOST_CHECK((!std::is_assignable::value)); BOOST_CHECK((!std::is_assignable::value)); } + +BOOST_AUTO_TEST_CASE(type_index) +{ + algorithm p0; + BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(null_algorithm))); + p0 = algorithm{al_01{}}; + BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(al_01))); +} + +BOOST_AUTO_TEST_CASE(get_ptr) +{ + algorithm p0; + BOOST_CHECK(p0.get_ptr() == p0.extract()); + BOOST_CHECK(static_cast(p0).get_ptr() + == static_cast(p0).extract()); + p0 = algorithm{al_01{}}; + BOOST_CHECK(p0.get_ptr() == p0.extract()); + BOOST_CHECK(static_cast(p0).get_ptr() == static_cast(p0).extract()); +} + +BOOST_AUTO_TEST_CASE(stream_operator) +{ + std::cout << algorithm{} << '\n'; +} diff --git a/tests/bfe.cpp b/tests/bfe.cpp index 1a36f9628..a788e246c 100644 --- a/tests/bfe.cpp +++ b/tests/bfe.cpp @@ -38,11 +38,14 @@ see https://www.gnu.org/licenses/. */ #include #include +#include #include #include #include #include #include +#include +#include #include #include @@ -50,6 +53,7 @@ see https://www.gnu.org/licenses/. */ #include #include +#include #include #include #include @@ -152,6 +156,7 @@ BOOST_AUTO_TEST_CASE(basic_tests) BOOST_CHECK(bfe0.is()); BOOST_CHECK(!bfe0.is()); BOOST_CHECK(bfe0.get_name() == "Default batch fitness evaluator"); + BOOST_CHECK(bfe{udbfe1{}}.get_name() == detail::type_name()); BOOST_CHECK(bfe0.get_extra_info().empty()); BOOST_CHECK(bfe0.get_thread_safety() == thread_safety::basic); @@ -340,6 +345,7 @@ BOOST_AUTO_TEST_CASE(stream_operator) BOOST_CHECK(boost::contains(st, "bartoppo")); BOOST_CHECK(boost::contains(st, "Extra info:")); } + std::cout << bfe{} << '\n'; } BOOST_AUTO_TEST_CASE(call_operator) @@ -506,3 +512,21 @@ BOOST_AUTO_TEST_CASE(generic_assignment) BOOST_CHECK((!std::is_assignable::value)); BOOST_CHECK((!std::is_assignable::value)); } + +BOOST_AUTO_TEST_CASE(type_index) +{ + bfe p0; + BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(default_bfe))); + p0 = bfe{udbfe1{}}; + BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(udbfe1))); +} + +BOOST_AUTO_TEST_CASE(get_ptr) +{ + bfe p0; + BOOST_CHECK(p0.get_ptr() == p0.extract()); + BOOST_CHECK(static_cast(p0).get_ptr() == static_cast(p0).extract()); + p0 = bfe{udbfe1{}}; + BOOST_CHECK(p0.get_ptr() == p0.extract()); + BOOST_CHECK(static_cast(p0).get_ptr() == static_cast(p0).extract()); +} diff --git a/tests/island.cpp b/tests/island.cpp index c352dca83..0b1712fd0 100644 --- a/tests/island.cpp +++ b/tests/island.cpp @@ -38,6 +38,8 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include +#include #include #include @@ -49,6 +51,7 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include #include #include #include @@ -80,6 +83,10 @@ struct udi_01 { } }; +struct udi_01a { + void run_evolve(island &) const {} +}; + struct udi_02 { void run_evolve(island &); }; @@ -391,6 +398,7 @@ BOOST_AUTO_TEST_CASE(island_name_info_stream) oss << isl; BOOST_CHECK(!oss.str().empty()); BOOST_CHECK(isl.get_name() == "udi_01"); + BOOST_CHECK((island{udi_01a{}, de{}, population{rosenbrock{}, 25}}.get_name()) == detail::type_name()); BOOST_CHECK(isl.get_extra_info() == "extra bits"); BOOST_CHECK(boost::contains(oss.str(), "Replacement policy: Fair replace")); BOOST_CHECK(boost::contains(oss.str(), "Selection policy: Select best")); @@ -524,7 +532,9 @@ BOOST_AUTO_TEST_CASE(island_extract) BOOST_CHECK((std::is_same(isl).extract())>::value)); BOOST_CHECK(isl.is()); +#if !defined(_MSC_VER) || defined(__clang__) BOOST_CHECK(isl.extract() == nullptr); +#endif BOOST_CHECK(isl.extract() == nullptr); BOOST_CHECK(!isl.is()); isl = island(udi_01{}, stateful_algo{}, null_problem{}, 20); @@ -535,7 +545,9 @@ BOOST_AUTO_TEST_CASE(island_extract) BOOST_CHECK((std::is_same())>::value)); BOOST_CHECK((std::is_same(isl).extract())>::value)); BOOST_CHECK(isl.is()); +#if !defined(_MSC_VER) || defined(__clang__) BOOST_CHECK(isl.extract() == nullptr); +#endif } // Constructors with bfe arguments. @@ -631,3 +643,21 @@ BOOST_AUTO_TEST_CASE(is_valid) p0 = island{udi_01{}, de{}, population{rosenbrock{}, 25}}; BOOST_CHECK(p0.is_valid()); } + +BOOST_AUTO_TEST_CASE(type_index) +{ + island p0; + BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(thread_island))); + p0 = island{udi_01a{}, de{}, population{rosenbrock{}, 25}}; + BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(udi_01a))); +} + +BOOST_AUTO_TEST_CASE(get_ptr) +{ + island p0; + BOOST_CHECK(p0.get_ptr() == p0.extract()); + BOOST_CHECK(static_cast(p0).get_ptr() == static_cast(p0).extract()); + p0 = island{udi_01a{}, de{}, population{rosenbrock{}, 25}}; + BOOST_CHECK(p0.get_ptr() == p0.extract()); + BOOST_CHECK(static_cast(p0).get_ptr() == static_cast(p0).extract()); +} diff --git a/tests/problem.cpp b/tests/problem.cpp index 1227d200f..d1a761e5d 100644 --- a/tests/problem.cpp +++ b/tests/problem.cpp @@ -36,12 +36,15 @@ see https://www.gnu.org/licenses/. */ #include #include #include +#include +#include #include #include #include #include +#include #include #include #include @@ -714,7 +717,7 @@ BOOST_AUTO_TEST_CASE(problem_getters_test) BOOST_CHECK(p1.get_name() == "A base toy problem"); BOOST_CHECK(p1.get_extra_info() == "Nothing to report"); // Default - BOOST_CHECK(p3.get_name() == typeid(*p3.extract()).name()); + BOOST_CHECK(p3.get_name() == detail::demangle_from_typeid(typeid(*p3.extract()).name())); BOOST_CHECK(p3.get_extra_info() == ""); } @@ -1593,3 +1596,22 @@ BOOST_AUTO_TEST_CASE(generic_assignment) BOOST_CHECK((!std::is_assignable::value)); BOOST_CHECK((!std::is_assignable::value)); } + +BOOST_AUTO_TEST_CASE(type_index) +{ + problem p0; + BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(null_problem))); + p0 = problem{grad_p_override{}}; + BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(grad_p_override))); +} + +BOOST_AUTO_TEST_CASE(get_ptr) +{ + problem p0; + BOOST_CHECK(p0.get_ptr() == p0.extract()); + BOOST_CHECK(static_cast(p0).get_ptr() == static_cast(p0).extract()); + p0 = problem{grad_p_override{}}; + BOOST_CHECK(p0.get_ptr() == p0.extract()); + BOOST_CHECK(static_cast(p0).get_ptr() + == static_cast(p0).extract()); +} diff --git a/tests/r_policy.cpp b/tests/r_policy.cpp index dd0751295..ad73496ca 100644 --- a/tests/r_policy.cpp +++ b/tests/r_policy.cpp @@ -38,17 +38,21 @@ see https://www.gnu.org/licenses/. */ #include #include +#include #include #include #include #include #include #include +#include +#include #include #include #include +#include #include #include #include @@ -148,7 +152,7 @@ BOOST_AUTO_TEST_CASE(basic_tests) BOOST_CHECK(!r.get_extra_info().empty()); BOOST_CHECK(r_policy(udrp1{}).get_extra_info().empty()); - BOOST_CHECK(!r_policy(udrp1{}).get_name().empty()); + BOOST_CHECK(r_policy(udrp1{}).get_name() == detail::type_name()); // Constructors, assignments. // Generic constructor with copy. @@ -212,6 +216,8 @@ BOOST_AUTO_TEST_CASE(basic_tests) BOOST_CHECK(before == boost::lexical_cast(r)); BOOST_CHECK(r.is()); } + + std::cout << r_policy{} << '\n'; } BOOST_AUTO_TEST_CASE(optional_tests) @@ -586,3 +592,22 @@ BOOST_AUTO_TEST_CASE(generic_assignment) BOOST_CHECK((!std::is_assignable::value)); BOOST_CHECK((!std::is_assignable::value)); } + +BOOST_AUTO_TEST_CASE(type_index) +{ + r_policy p0; + BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(fair_replace))); + p0 = r_policy{udrp1{}}; + BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(udrp1))); +} + +BOOST_AUTO_TEST_CASE(get_ptr) +{ + r_policy p0; + BOOST_CHECK(p0.get_ptr() == p0.extract()); + BOOST_CHECK(static_cast(p0).get_ptr() + == static_cast(p0).extract()); + p0 = r_policy{udrp1{}}; + BOOST_CHECK(p0.get_ptr() == p0.extract()); + BOOST_CHECK(static_cast(p0).get_ptr() == static_cast(p0).extract()); +} diff --git a/tests/s_policy.cpp b/tests/s_policy.cpp index b999f9100..24dbb436f 100644 --- a/tests/s_policy.cpp +++ b/tests/s_policy.cpp @@ -38,17 +38,21 @@ see https://www.gnu.org/licenses/. */ #include #include +#include #include #include #include #include #include #include +#include +#include #include #include #include +#include #include #include #include @@ -148,7 +152,7 @@ BOOST_AUTO_TEST_CASE(basic_tests) BOOST_CHECK(!r.get_extra_info().empty()); BOOST_CHECK(s_policy(udsp1{}).get_extra_info().empty()); - BOOST_CHECK(!s_policy(udsp1{}).get_name().empty()); + BOOST_CHECK(s_policy(udsp1{}).get_name() == detail::type_name()); // Constructors, assignments. // Generic constructor with copy. @@ -212,6 +216,8 @@ BOOST_AUTO_TEST_CASE(basic_tests) BOOST_CHECK(before == boost::lexical_cast(r)); BOOST_CHECK(r.is()); } + + std::cout << s_policy{} << '\n'; } BOOST_AUTO_TEST_CASE(optional_tests) @@ -547,3 +553,22 @@ BOOST_AUTO_TEST_CASE(generic_assignment) BOOST_CHECK((!std::is_assignable::value)); BOOST_CHECK((!std::is_assignable::value)); } + +BOOST_AUTO_TEST_CASE(type_index) +{ + s_policy p0; + BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(select_best))); + p0 = s_policy{udsp1{}}; + BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(udsp1))); +} + +BOOST_AUTO_TEST_CASE(get_ptr) +{ + s_policy p0; + BOOST_CHECK(p0.get_ptr() == p0.extract()); + BOOST_CHECK(static_cast(p0).get_ptr() + == static_cast(p0).extract()); + p0 = s_policy{udsp1{}}; + BOOST_CHECK(p0.get_ptr() == p0.extract()); + BOOST_CHECK(static_cast(p0).get_ptr() == static_cast(p0).extract()); +} diff --git a/tests/topology.cpp b/tests/topology.cpp index 67af00191..075bb3137 100644 --- a/tests/topology.cpp +++ b/tests/topology.cpp @@ -32,17 +32,21 @@ see https://www.gnu.org/licenses/. */ #include #include +#include #include #include #include #include #include +#include +#include #include #include #include #include +#include #include #include #include @@ -100,6 +104,14 @@ struct udt00 { int n_pushed = 0; }; +struct udt00a { + std::pair, vector_double> get_connections(std::size_t) const + { + return {{0, 1, 2}, {0.1, 0.2, 0.3}}; + } + void push_back() {} +}; + PAGMO_S11N_TOPOLOGY_EXPORT(udt00) struct udt01 { @@ -158,6 +170,7 @@ BOOST_AUTO_TEST_CASE(topology_basic_tests) BOOST_CHECK(t0.extract() == nullptr); BOOST_CHECK(static_cast(t0).extract() == nullptr); BOOST_CHECK(t0.get_name() == "udt00"); + BOOST_CHECK(topology{udt00a{}}.get_name() == detail::type_name()); BOOST_CHECK(t0.get_extra_info().empty()); t0.push_back(); @@ -321,6 +334,8 @@ BOOST_AUTO_TEST_CASE(topology_stream_test) BOOST_CHECK(boost::contains(str, "Topology name: udt00")); } + + std::cout << topology{} << '\n'; } BOOST_AUTO_TEST_CASE(topology_push_back_n_test) @@ -356,3 +371,22 @@ BOOST_AUTO_TEST_CASE(topology_to_bgl_test) BOOST_CHECK(boost::num_vertices(topology{udt01{}}.to_bgl()) == 0); } + +BOOST_AUTO_TEST_CASE(type_index) +{ + topology p0; + BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(unconnected))); + p0 = topology{udt00a{}}; + BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(udt00a))); +} + +BOOST_AUTO_TEST_CASE(get_ptr) +{ + topology p0; + BOOST_CHECK(p0.get_ptr() == p0.extract()); + BOOST_CHECK(static_cast(p0).get_ptr() + == static_cast(p0).extract()); + p0 = topology{udt00a{}}; + BOOST_CHECK(p0.get_ptr() == p0.extract()); + BOOST_CHECK(static_cast(p0).get_ptr() == static_cast(p0).extract()); +} diff --git a/tools/circleci_bionic_gcc7_conda_docs.sh b/tools/circleci_focal_gcc9_docs.sh similarity index 96% rename from tools/circleci_bionic_gcc7_conda_docs.sh rename to tools/circleci_focal_gcc9_docs.sh index c475f4735..c6a22a06f 100644 --- a/tools/circleci_bionic_gcc7_conda_docs.sh +++ b/tools/circleci_focal_gcc9_docs.sh @@ -7,7 +7,7 @@ set -x set -e # Core deps. -sudo apt-get install build-essential wget +sudo apt-get install build-essential wget doxygen graphviz # Install conda+deps. wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh @@ -15,7 +15,7 @@ export deps_dir=$HOME/local export PATH="$HOME/miniconda/bin:$PATH" bash miniconda.sh -b -p $HOME/miniconda conda config --add channels conda-forge --force -conda_pkgs="cmake eigen nlopt ipopt boost-cpp tbb tbb-devel python=3.7 sphinx sphinx_rtd_theme breathe doxygen graphviz" +conda_pkgs="cmake eigen nlopt ipopt boost-cpp tbb tbb-devel python=3.7 sphinx sphinx_rtd_theme breathe" conda create -q -p $deps_dir -y source activate $deps_dir conda install $conda_pkgs -y