| @@ -0,0 +1,3 @@ | |||||
| [submodule "cmake/modules"] | |||||
| path = cmake/modules | |||||
| url = https://git.bergmann89.de/cpp/CmakeModules.git | |||||
| @@ -0,0 +1,6 @@ | |||||
| { | |||||
| "files.trimTrailingWhitespace": true, | |||||
| "files.trimFinalNewlines": true, | |||||
| "files.insertFinalNewline": true, | |||||
| "files.eol": "\n" | |||||
| } | |||||
| @@ -0,0 +1,63 @@ | |||||
| # Initialize CMake ################################################################################ | |||||
| CMake_Minimum_Required ( VERSION 3.12.0 FATAL_ERROR ) | |||||
| # Set CMAKE_BUILD_TYPE | |||||
| If ( NOT CMAKE_BUILD_TYPE ) | |||||
| Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE ) | |||||
| EndIf ( NOT CMAKE_BUILD_TYPE ) | |||||
| Set_Property ( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel ) | |||||
| # Set CMAKE_MODULE_PATH | |||||
| If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) | |||||
| Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} | |||||
| "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) | |||||
| EndIf ( ) | |||||
| If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) | |||||
| Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} | |||||
| "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) | |||||
| EndIf ( ) | |||||
| # Project ######################################################################################### | |||||
| Include ( GNUInstallDirs ) | |||||
| Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cpprtti-options.cmake ) | |||||
| Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cpprtti-const.cmake ) | |||||
| Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cpprtti-var.cmake ) | |||||
| Project ( ${CPPRTTI_PROJECT_NAME} | |||||
| DESCRIPTION "${CPPRTTI_PROJECT_DESCRIPTION}" | |||||
| VERSION "${CPPRTTI_VERSION}" ) | |||||
| Include ( CTest ) | |||||
| # Subdirectories | |||||
| Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src ) | |||||
| Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test ) | |||||
| # Install | |||||
| If ( NOT CPPRTTI_HAS_EXPORT | |||||
| OR NOT CPPRTTI_INSTALL_PACKAGE ) | |||||
| Return ( ) | |||||
| EndIf ( ) | |||||
| Include ( CMakePackageConfigHelpers ) | |||||
| Write_Basic_Package_Version_File ( "${CMAKE_CURRENT_BINARY_DIR}/cmake/cpprtti-config-version.cmake" | |||||
| VERSION ${CPPRTTI_VERSION} | |||||
| COMPATIBILITY AnyNewerVersion ) | |||||
| Configure_File ( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cpprtti-config.cmake" | |||||
| "${CMAKE_CURRENT_BINARY_DIR}/cmake/cpprtti-config.cmake" | |||||
| @ONLY ) | |||||
| Set ( ConfigPackageLocation "${CPPRTTI_INSTALL_DIR_SHARE}/cmake" ) | |||||
| Install ( EXPORT | |||||
| cpprtti | |||||
| NAMESPACE | |||||
| cpprtti:: | |||||
| DESTINATION | |||||
| ${ConfigPackageLocation} ) | |||||
| Install ( FILES | |||||
| "${CMAKE_CURRENT_BINARY_DIR}/cmake/cpprtti-config.cmake" | |||||
| "${CMAKE_CURRENT_BINARY_DIR}/cmake/cpprtti-config-version.cmake" | |||||
| DESTINATION | |||||
| ${ConfigPackageLocation} | |||||
| COMPONENT | |||||
| Devel ) | |||||
| @@ -0,0 +1,34 @@ | |||||
| Set ( CPPCORE_REPOSITORY https://git.bergmann89.de/cpp/cppcore.git ) | |||||
| Set ( CPPCORE_COMMIT master ) | |||||
| Set ( CPPCORE_CHECKOUT_DIR ${CMAKE_BINARY_DIR}/sources/cppcore ) | |||||
| # Clone Repository | |||||
| If ( NOT EXISTS ${CPPCORE_CHECKOUT_DIR} ) | |||||
| Execute_Process ( COMMAND | |||||
| git clone ${CPPCORE_REPOSITORY} ${CPPCORE_CHECKOUT_DIR} | |||||
| RESULT_VARIABLE | |||||
| CLONE_RET ) | |||||
| If ( NOT ${CLONE_RET} EQUAL 0 ) | |||||
| Return ( ) | |||||
| EndIf ( ) | |||||
| EndIf ( ) | |||||
| # Checkout Specific Commit | |||||
| Execute_Process ( COMMAND | |||||
| git -C ${CPPCORE_CHECKOUT_DIR} -c advice.detachedHead=false checkout origin/${CPPCORE_COMMIT} | |||||
| COMMAND | |||||
| git -C ${CPPCORE_CHECKOUT_DIR} submodule update --init --recursive | |||||
| RESULT_VARIABLE | |||||
| CHECKOUT_RET ) | |||||
| If ( NOT ${CHECKOUT_RET} EQUAL 0 ) | |||||
| Return ( ) | |||||
| EndIf ( ) | |||||
| # Include Cloned Repository | |||||
| Include ( ${CMAKE_CURRENT_LIST_DIR}/modules/find_local_module.cmake ) | |||||
| FindLocalModule ( cppcore ${CPPCORE_CHECKOUT_DIR} ) | |||||
| # Create Alias Targets | |||||
| If ( NOT TARGET cppcore::cppcore ) | |||||
| Add_Library ( cppcore::cppcore ALIAS cppcore ) | |||||
| EndIf ( ) | |||||
| @@ -0,0 +1,34 @@ | |||||
| Set ( CPPMP_REPOSITORY https://git.bergmann89.de/cpp/cppmp.git ) | |||||
| Set ( CPPMP_COMMIT master ) | |||||
| Set ( CPPMP_CHECKOUT_DIR ${CMAKE_BINARY_DIR}/sources/cppmp ) | |||||
| # Clone Repository | |||||
| If ( NOT EXISTS ${CPPMP_CHECKOUT_DIR} ) | |||||
| Execute_Process ( COMMAND | |||||
| git clone ${CPPMP_REPOSITORY} ${CPPMP_CHECKOUT_DIR} | |||||
| RESULT_VARIABLE | |||||
| CLONE_RET ) | |||||
| If ( NOT ${CLONE_RET} EQUAL 0 ) | |||||
| Return ( ) | |||||
| EndIf ( ) | |||||
| EndIf ( ) | |||||
| # Checkout Specific Commit | |||||
| Execute_Process ( COMMAND | |||||
| git -C ${CPPMP_CHECKOUT_DIR} -c advice.detachedHead=false checkout origin/${CPPMP_COMMIT} | |||||
| COMMAND | |||||
| git -C ${CPPMP_CHECKOUT_DIR} submodule update --init --recursive | |||||
| RESULT_VARIABLE | |||||
| CHECKOUT_RET ) | |||||
| If ( NOT ${CHECKOUT_RET} EQUAL 0 ) | |||||
| Return ( ) | |||||
| EndIf ( ) | |||||
| # Include Cloned Repository | |||||
| Include ( ${CMAKE_CURRENT_LIST_DIR}/modules/find_local_module.cmake ) | |||||
| FindLocalModule ( cppmp ${CPPMP_CHECKOUT_DIR} ) | |||||
| # Create Alias Targets | |||||
| If ( NOT TARGET cppmp::cppmp ) | |||||
| Add_Library ( cppmp::cppmp ALIAS cppmp ) | |||||
| EndIf ( ) | |||||
| @@ -0,0 +1,9 @@ | |||||
| # cpprtti-config.cmake - package configuration file | |||||
| # Include ( CMakeFindDependencyMacro ) | |||||
| # Find_Dependency ( <dependency> ) | |||||
| Include ( FindPackageHandleStandardArgs ) | |||||
| Set ( ${CMAKE_FIND_PACKAGE_NAME}_CONFIG ${CMAKE_CURRENT_LIST_FILE} ) | |||||
| Find_Package_Handle_Standard_Args ( cpprtti CONFIG_MODE ) | |||||
| Include ( "${CMAKE_CURRENT_LIST_DIR}/cpprtti.cmake") | |||||
| @@ -0,0 +1,28 @@ | |||||
| # This file contains constant variables that are fixed to this project | |||||
| # Version | |||||
| Set ( CPPRTTI_VERSION_MAJOR 1 ) | |||||
| Set ( CPPRTTI_VERSION_MINOR 0 ) | |||||
| Set ( CPPRTTI_VERSION_PATCH 0 ) | |||||
| Set ( CPPRTTI_VERSION_BUILD 0 ) | |||||
| Set ( CPPRTTI_VERSION_HASH "" ) | |||||
| Set ( CPPRTTI_VERSION_BEHIND 0 ) | |||||
| Set ( CPPRTTI_VERSION_DIRTY 0 ) | |||||
| # Names | |||||
| Set ( CPPRTTI_PROJECT_NAME "cpprtti" ) | |||||
| Set ( CPPRTTI_PROJECT_DESCRIPTION "A simple hello world library" ) | |||||
| # Include generated variables for further usage | |||||
| Include ( ${CMAKE_CURRENT_LIST_DIR}/cpprtti-var.cmake ) | |||||
| # Install directories | |||||
| Set ( CPPRTTI_INSTALL_DIR_INCLUDE "${CMAKE_INSTALL_INCLUDEDIR}/${CPPRTTI_NAME}" ) | |||||
| Set ( CPPRTTI_INSTALL_DIR_LIB "${CMAKE_INSTALL_LIBDIR}" ) | |||||
| Set ( CPPRTTI_INSTALL_DIR_SHARE "${CMAKE_INSTALL_DATAROOTDIR}/${CPPRTTI_NAME}" ) | |||||
| # C Standard | |||||
| Set ( CMAKE_C_STANDARD 11 ) | |||||
| Set ( CMAKE_CXX_STANDARD 17 ) | |||||
| Set ( CMAKE_C_STANDARD_REQUIRED ON ) | |||||
| Set ( CMAKE_CXX_STANDARD_REQUIRED ON ) | |||||
| @@ -0,0 +1,23 @@ | |||||
| # This file contains options that can be passed to the cmake command | |||||
| Option ( CPPRTTI_INSTALL_HEADER | |||||
| "Install headers of cpprtti." | |||||
| ON ) | |||||
| Option ( CPPRTTI_INSTALL_STATIC | |||||
| "Install static library of cpprtti." | |||||
| ON ) | |||||
| Option ( CPPRTTI_INSTALL_SHARED | |||||
| "Install shared library of cpprtti." | |||||
| ON ) | |||||
| Option ( CPPRTTI_INSTALL_DEBUG | |||||
| "Install the stripped debug informations of cpprtti." | |||||
| OFF ) | |||||
| Option ( CPPRTTI_INSTALL_PACKAGE | |||||
| "Install the cmake package of cpprtti." | |||||
| ON ) | |||||
| Option ( CPPRTTI_NO_STRIP | |||||
| "Do not strip debug symbols from binary." | |||||
| OFF ) | |||||
| Option ( CPPRTTI_USE_GIT_VERSION | |||||
| "Read the git tags to get the version of cpprtti" | |||||
| ON ) | |||||
| @@ -0,0 +1,26 @@ | |||||
| # This file contains generated variables that are needed for the project | |||||
| # Git Version | |||||
| If ( CPPRTTI_USE_GIT_VERSION ) | |||||
| Include ( git_helper OPTIONAL RESULT_VARIABLE HAS_GIT_HELPER ) | |||||
| If ( HAS_GIT_HELPER ) | |||||
| GitGetVersion ( ${CMAKE_CURRENT_LIST_DIR}/.. | |||||
| CPPRTTI_VERSION_MAJOR | |||||
| CPPRTTI_VERSION_MINOR | |||||
| CPPRTTI_VERSION_PATCH | |||||
| CPPRTTI_VERSION_BUILD | |||||
| CPPRTTI_VERSION_HASH | |||||
| CPPRTTI_VERSION_BEHIND | |||||
| CPPRTTI_VERSION_DIRTY ) | |||||
| EndIf ( ) | |||||
| EndIf ( ) | |||||
| # Strings | |||||
| Set ( CPPRTTI_VERSION_SHORT "${CPPRTTI_VERSION_MAJOR}.${CPPRTTI_VERSION_MINOR}" ) | |||||
| Set ( CPPRTTI_VERSION "${CPPRTTI_VERSION_SHORT}.${CPPRTTI_VERSION_PATCH}.${CPPRTTI_VERSION_BUILD}" ) | |||||
| Set ( CPPRTTI_VERSION_COMPLETE "${CPPRTTI_VERSION}" ) | |||||
| Set ( CPPRTTI_NAME "${CPPRTTI_PROJECT_NAME}-${CPPRTTI_VERSION_SHORT}" ) | |||||
| Set ( CPPRTTI_OUTPUTNAME "${CPPRTTI_PROJECT_NAME}" ) | |||||
| If ( CPPRTTI_VERSION_BEHIND ) | |||||
| Set ( CPPRTTI_VERSION_COMPLETE "${CPPRTTI_VERSION_COMPLETE}+${CPPRTTI_VERSION_BEHIND}" ) | |||||
| EndIf ( ) | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit ebbae4fbb42d671331b4c6e9d1d142f41dcacc1b | |||||
| @@ -0,0 +1,6 @@ | |||||
| #pragma once | |||||
| #include <cpprtti/misc.h> | |||||
| #include <cpprtti/registry.h> | |||||
| #include <cpprtti/traits.h> | |||||
| #include <cpprtti/types.h> | |||||
| @@ -0,0 +1,9 @@ | |||||
| #pragma once | |||||
| #include "misc/exception.h" | |||||
| #include "misc/helper.h" | |||||
| #include "misc/variant.h" | |||||
| #include "misc/exception.inl" | |||||
| #include "misc/helper.inl" | |||||
| #include "misc/variant.inl" | |||||
| @@ -0,0 +1,76 @@ | |||||
| #pragma once | |||||
| #include <string> | |||||
| #include <cppcore/misc/exception.h> | |||||
| namespace cpprtti | |||||
| { | |||||
| enum class error_code | |||||
| { | |||||
| unknown = -1, | |||||
| none = 0, | |||||
| /* registry */ | |||||
| registry_error = 1000, | |||||
| registry_type_not_found, //!< Unable to find the requested type. | |||||
| registry_id_already_exsists, //!< Unable to create type: The type ID does already exist! | |||||
| registry_name_already_exsists, //!< Unable to create type: The type name does already exist! | |||||
| registry_type_does_not_match, //!< Unable to get type: The implementation of the type does not match! | |||||
| /* variant */ | |||||
| variant_error = 2000, | |||||
| variant_is_empty, //!< The variant does not store any value! | |||||
| variant_type_mismatch, //!< The variant does not store the requested type! | |||||
| variant_invalid_cast, //!< The value stored in the variant could not be cast to the requested type! | |||||
| /* class */ | |||||
| class_error = 3000, | |||||
| class_member_already_exists, //!< Unable to create member: Name is already in use! | |||||
| class_type_mismatch, //!< Type does not match the. | |||||
| class_member_not_readable, //!< Member variable is not readable! | |||||
| class_member_not_writable, //!< Member variable is not writable! | |||||
| }; | |||||
| /** | |||||
| * @brief Get the string representation of the passed error code. | |||||
| */ | |||||
| inline std::string get_error_code_str(error_code err); | |||||
| /** | |||||
| * @brief Exception to represent curl errors. | |||||
| */ | |||||
| struct exception | |||||
| : public ::cppcore::exception | |||||
| { | |||||
| public: | |||||
| error_code error; | |||||
| const std::string detail; | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline exception( | |||||
| error_code p_error); | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline exception( | |||||
| error_code p_error, | |||||
| const std::string& p_detail); | |||||
| protected: | |||||
| /** | |||||
| * @brief Print the message of the exception to the passed stream. | |||||
| * | |||||
| * @param[in] os Stream to print message of the exception to. | |||||
| */ | |||||
| inline void print_message(std::ostream& os) const override; | |||||
| }; | |||||
| } | |||||
| #include "exception.inl" | |||||
| @@ -0,0 +1,81 @@ | |||||
| #pragma once | |||||
| #include <cppcore/conversion/enum.h> | |||||
| #include <cppcore/conversion/convert_cast.h> | |||||
| #include "exception.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| struct error_code_enum_values | |||||
| { | |||||
| using enum_type = error_code; | |||||
| using enum_value_pair_type = std::pair<enum_type, std::string>; | |||||
| using enum_value_vector_type = std::vector<enum_value_pair_type>; | |||||
| static const enum_value_vector_type& get_enum_values() | |||||
| { | |||||
| static const enum_value_vector_type values({ | |||||
| { error_code::unknown, "Unknown error" }, | |||||
| { error_code::none, "No error" }, | |||||
| /* registry */ | |||||
| { error_code::registry_error, "Registry error" }, | |||||
| { error_code::registry_type_not_found, "Unable to find the requested type!" }, | |||||
| { error_code::registry_id_already_exsists, "Unable to create type: The type ID does already exist!" }, | |||||
| { error_code::registry_name_already_exsists, "Unable to create type: The type name does already exist!" }, | |||||
| { error_code::registry_type_does_not_match, "Unable to get type: The implementation of the type does not match!" }, | |||||
| /* variant */ | |||||
| { error_code::variant_error, "Variant error" }, | |||||
| { error_code::variant_is_empty, "The variant does not store any value!" }, | |||||
| { error_code::variant_type_mismatch, "The variant does not store the requested type!" }, | |||||
| { error_code::variant_invalid_cast, "The value stored in the variant could not be cast to the requested type!" }, | |||||
| /* class */ | |||||
| { error_code::class_error, "Class error" }, | |||||
| { error_code::class_member_already_exists, "Unable to create member: Name is already in use!" }, | |||||
| { error_code::class_type_mismatch, "Type does not match the." }, | |||||
| { error_code::class_member_not_readable, "Member variable is not readable!" }, | |||||
| { error_code::class_member_not_writable, "Member variable is not writable!" }, | |||||
| }); | |||||
| return values; | |||||
| } | |||||
| }; | |||||
| using error_code_enum_conversion_traits = ::cppcore::enum_conversion_traits<error_code, error_code_enum_values>; | |||||
| using error_code_enum_conversion = ::cppcore::enum_conversion <error_code, error_code_enum_conversion_traits>; | |||||
| std::string get_error_code_str(error_code err) | |||||
| { return error_code_enum_conversion::to_string(err); } | |||||
| /* exception */ | |||||
| exception::exception( | |||||
| error_code p_error) | |||||
| : cppcore::exception() | |||||
| , error (p_error) | |||||
| , detail () | |||||
| { } | |||||
| exception::exception( | |||||
| error_code p_error, | |||||
| const std::string& p_detail) | |||||
| : cppcore::exception(p_detail) | |||||
| , error (p_error) | |||||
| , detail (p_detail) | |||||
| { } | |||||
| void exception | |||||
| ::print_message(std::ostream& os) const | |||||
| { | |||||
| os << get_error_code_str(error) | |||||
| << '(' | |||||
| << cppcore::convert_cast<std::underlying_type_t<error_code>>(error) | |||||
| << "): " | |||||
| << message; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,25 @@ | |||||
| #pragma once | |||||
| #include <map> | |||||
| #include <memory> | |||||
| namespace cpprtti | |||||
| { | |||||
| using type_id = size_t; | |||||
| /** | |||||
| * @brief Get the ID of a certain C++ type. | |||||
| */ | |||||
| template<typename X> | |||||
| inline type_id get_type_id(); | |||||
| /** | |||||
| * @brief Get the name of a certain C++ type. | |||||
| */ | |||||
| template<typename X> | |||||
| inline const std::string& get_type_name(); | |||||
| } | |||||
| #include "helper.inl" | |||||
| @@ -0,0 +1,43 @@ | |||||
| #pragma once | |||||
| #include <cxxabi.h> | |||||
| #include "helper.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| namespace __impl | |||||
| { | |||||
| inline type_id create_type_id() | |||||
| { | |||||
| static type_id value { }; | |||||
| return ++value; | |||||
| } | |||||
| template<typename X> | |||||
| inline std::string create_type_name() | |||||
| { | |||||
| int status; | |||||
| auto name = abi::__cxa_demangle(typeid(X).name(), nullptr, nullptr, &status); | |||||
| return std::string(name ? name : typeid(X).name()); | |||||
| } | |||||
| } | |||||
| template<typename X> | |||||
| type_id get_type_id() | |||||
| { | |||||
| static const auto value = __impl::create_type_id(); | |||||
| return value; | |||||
| } | |||||
| template<typename X> | |||||
| const std::string& get_type_name() | |||||
| { | |||||
| static const auto value = __impl::create_type_name<X>(); | |||||
| return value; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,102 @@ | |||||
| #pragma once | |||||
| #include <memory> | |||||
| #include <cppmp/misc/generic_predicate.h> | |||||
| #include "helper.h" | |||||
| #include "../types/type.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| namespace __impl | |||||
| { | |||||
| /* make_variant_impl */ | |||||
| template<typename X, typename = void> | |||||
| struct variant_builder; | |||||
| /* variant_impl */ | |||||
| struct variant_impl | |||||
| { | |||||
| const type& type; | |||||
| void * data { nullptr }; | |||||
| bool is_const { false }; | |||||
| bool is_reference { false }; | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline variant_impl(const cpprtti::type& p_type); | |||||
| }; | |||||
| using variant_impl_ptr_s = std::shared_ptr<const variant_impl>; | |||||
| } | |||||
| struct variant | |||||
| { | |||||
| public: | |||||
| template<typename X, typename> | |||||
| friend struct __impl::variant_builder; | |||||
| private: | |||||
| __impl::variant_impl_ptr_s _impl; //!< Implementation of the variant | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline variant(__impl::variant_impl_ptr_s p_impl); | |||||
| public: | |||||
| /** | |||||
| * @brief Default constructor. | |||||
| */ | |||||
| inline variant(); | |||||
| /** | |||||
| * @brief Get type information of the stored value. | |||||
| */ | |||||
| inline const type& type() const; | |||||
| /** | |||||
| * @brief Check if the stored type is a reference. | |||||
| */ | |||||
| inline bool is_reference() const; | |||||
| /** | |||||
| * @brief Check if the stored type is a constant. | |||||
| */ | |||||
| inline bool is_const() const; | |||||
| /** | |||||
| * @brief Get the stored value. | |||||
| */ | |||||
| template<typename T> | |||||
| inline T get() const; | |||||
| /** | |||||
| * @brief Check if the variant contains a value. | |||||
| */ | |||||
| inline bool empty(); | |||||
| /** | |||||
| * @brief Check if the variant contains a value. | |||||
| */ | |||||
| inline operator bool() const; | |||||
| private: | |||||
| /** | |||||
| * @brief Check if the variant has a value assigned, if not throw an exception. | |||||
| */ | |||||
| inline void check_impl() const; | |||||
| }; | |||||
| constexpr decltype(auto) make_variant = cppmp::generic_predicate<__impl::variant_builder> { }; | |||||
| } | |||||
| #include "variant.inl" | |||||
| @@ -0,0 +1,256 @@ | |||||
| #pragma once | |||||
| #include <cppcore/misc/string_builder.h> | |||||
| #include <cppmp/core/checker.h> | |||||
| #include <cppmp/core/modifier.h> | |||||
| #include <cppmp/core/conditionals.h> | |||||
| #include <cppmp/misc/generic_predicate.h> | |||||
| #include "variant.h" | |||||
| #include "exception.h" | |||||
| #include "../registry.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| namespace __impl | |||||
| { | |||||
| /* variant_impl */ | |||||
| variant_impl::variant_impl( | |||||
| const cpprtti::type& p_type) | |||||
| : type(p_type) | |||||
| { } | |||||
| /* variant_builder - default */ | |||||
| template<typename X, typename> | |||||
| struct variant_builder | |||||
| { | |||||
| using is_default = cppmp::true_t; | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&...) | |||||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for make_variant(...)!"); } | |||||
| }; | |||||
| /* variant_builder - not lvalue reference */ | |||||
| template<typename T_registry, typename T> | |||||
| struct variant_builder< | |||||
| cppmp::list<T_registry, T>, | |||||
| cppmp::enable_if_t< | |||||
| cppmp::is_same_v<cppmp::decay_t<T_registry>, registry> | |||||
| && !cppmp::is_lvalue_reference_v<T> | |||||
| > | |||||
| > | |||||
| { | |||||
| struct impl | |||||
| : public variant_impl | |||||
| { | |||||
| T storage; | |||||
| template<typename X> | |||||
| inline impl(const cpprtti::type& p_type, X&& x) | |||||
| : variant_impl (p_type) | |||||
| , storage (std::forward<X>(x)) | |||||
| { | |||||
| data = reinterpret_cast<void*>(const_cast<cppmp::decay_t<T>*>(&storage)); | |||||
| is_const = cppmp::is_const_v<cppmp::remove_reference_t<T>>; | |||||
| is_reference = false; | |||||
| } | |||||
| }; | |||||
| template<typename X_registry, typename X> | |||||
| static constexpr decltype(auto) apply(X_registry& p_registry, X&& x) | |||||
| { | |||||
| return variant(std::make_shared<impl>( | |||||
| p_registry.template get<cppmp::decay_t<T>>(), | |||||
| std::forward<X>(x))); | |||||
| } | |||||
| }; | |||||
| /* variant_builder - lvalue reference */ | |||||
| template<typename T_registry, typename T> | |||||
| struct variant_builder< | |||||
| cppmp::list<T_registry, T>, | |||||
| cppmp::enable_if_t< | |||||
| cppmp::is_same_v<cppmp::decay_t<T_registry>, registry> | |||||
| && cppmp::is_lvalue_reference_v<T> | |||||
| > | |||||
| > | |||||
| { | |||||
| struct impl | |||||
| : public variant_impl | |||||
| { | |||||
| template<typename X> | |||||
| inline impl(const cpprtti::type& p_type, X&& x) | |||||
| : variant_impl(p_type) | |||||
| { | |||||
| data = reinterpret_cast<void*>(const_cast<cppmp::decay_t<T>*>(&x)); | |||||
| is_const = cppmp::is_const_v<cppmp::remove_reference_t<T>>; | |||||
| is_reference = true; | |||||
| } | |||||
| }; | |||||
| template<typename X_registry, typename X> | |||||
| static constexpr decltype(auto) apply(X_registry& p_registry, X&& x) | |||||
| { | |||||
| return variant(std::make_shared<impl>( | |||||
| p_registry.template get<cppmp::decay_t<T>>(), | |||||
| std::forward<X>(x))); | |||||
| } | |||||
| }; | |||||
| /* variant_builder - variant */ | |||||
| template<typename T_registry, typename T> | |||||
| struct variant_builder< | |||||
| cppmp::list<T_registry, T>, | |||||
| cppmp::enable_if_t< | |||||
| cppmp::is_same_v<cppmp::decay_t<T_registry>, registry> | |||||
| && cppmp::is_same_v<cppmp::decay_t<T_registry>, variant> | |||||
| > | |||||
| > | |||||
| { | |||||
| template<typename X_registry, typename X> | |||||
| static constexpr decltype(auto) apply(X_registry& p_registry, X&& x) | |||||
| { return std::forward<X>(x); } | |||||
| }; | |||||
| /* value_extractor - default */ | |||||
| template<typename X, typename = void> | |||||
| struct value_extractor | |||||
| { | |||||
| using is_default = cppmp::true_t; | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&...) | |||||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for variant.get(...)!"); } | |||||
| }; | |||||
| /* value_extractor - T&& */ | |||||
| template<typename T> | |||||
| struct value_extractor< | |||||
| cppmp::list< | |||||
| const variant_impl&, | |||||
| const cppmp::type_t<T&&>&>, | |||||
| void> | |||||
| { | |||||
| static constexpr decltype(auto) apply( | |||||
| const variant_impl& impl, | |||||
| const cppmp::type_t<T&&>&) | |||||
| { | |||||
| if (impl.is_const) | |||||
| { | |||||
| throw exception( | |||||
| error_code::variant_invalid_cast, | |||||
| "Can not move constant value"); | |||||
| } | |||||
| return std::move(*reinterpret_cast<T*>(impl.data)); | |||||
| } | |||||
| }; | |||||
| /* value_extractor - normal */ | |||||
| template<typename T> | |||||
| struct value_extractor< | |||||
| cppmp::list< | |||||
| const variant_impl&, | |||||
| const cppmp::type_t<T>&>, | |||||
| void> | |||||
| { | |||||
| static constexpr decltype(auto) apply( | |||||
| const variant_impl& impl, | |||||
| const cppmp::type_t<T>&) | |||||
| { | |||||
| bool is_const = cppmp::is_const_v<cppmp::remove_reference_t<T>>; | |||||
| bool is_reference = cppmp::is_reference_v<T>; | |||||
| if ( is_reference | |||||
| && !is_const | |||||
| && impl.is_const) | |||||
| { | |||||
| throw exception( | |||||
| error_code::variant_invalid_cast, | |||||
| "Can not get a reference to a const value"); | |||||
| } | |||||
| return *reinterpret_cast<cppmp::remove_reference_t<T>*>(impl.data); | |||||
| } | |||||
| }; | |||||
| constexpr decltype(auto) extract_value = cppmp::generic_predicate<__impl::value_extractor> { }; | |||||
| } | |||||
| /* variant */ | |||||
| variant::variant(__impl::variant_impl_ptr_s p_impl) | |||||
| : _impl(p_impl) | |||||
| { } | |||||
| variant::variant() | |||||
| : _impl() | |||||
| { } | |||||
| const type& variant::type() const | |||||
| { | |||||
| check_impl(); | |||||
| return _impl->type; | |||||
| } | |||||
| bool variant::is_reference() const | |||||
| { | |||||
| check_impl(); | |||||
| return _impl->is_reference; | |||||
| } | |||||
| bool variant::is_const() const | |||||
| { | |||||
| check_impl(); | |||||
| return _impl->is_const; | |||||
| } | |||||
| template<typename T> | |||||
| T variant::get() const | |||||
| { | |||||
| check_impl(); | |||||
| if (_impl->type.id() != get_type_id<cppmp::decay_t<T>>()) | |||||
| { | |||||
| throw exception( | |||||
| error_code::variant_type_mismatch, | |||||
| cppcore::string_builder() | |||||
| << "The vaiant does not store the requested type (requested=" | |||||
| << get_type_name<cppmp::decay_t<T>>() | |||||
| << ", stored=" | |||||
| << _impl->type.name() | |||||
| << ")"); | |||||
| } | |||||
| return __impl::extract_value(*_impl, cppmp::type_v<T>); | |||||
| } | |||||
| bool variant::empty() | |||||
| { return !static_cast<bool>(_impl); } | |||||
| variant::operator bool() const | |||||
| { return static_cast<bool>(_impl); } | |||||
| void variant::check_impl() const | |||||
| { | |||||
| if (!_impl) | |||||
| { | |||||
| throw exception( | |||||
| error_code::variant_is_empty, | |||||
| "The variant does not store any value!"); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,96 @@ | |||||
| #pragma once | |||||
| #include <map> | |||||
| #include <memory> | |||||
| #include "types/type.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| struct registry | |||||
| { | |||||
| public: | |||||
| using type_ptr_s = std::shared_ptr<type>; | |||||
| using type_id_map = std::map<type_id, type_ptr_s>; | |||||
| using type_name_map = std::map<std::string, type_ptr_s>; | |||||
| private: | |||||
| type_id_map _id_map; | |||||
| type_name_map _name_map; | |||||
| public: | |||||
| /** | |||||
| * @brief Get a type from the registry. | |||||
| * | |||||
| * This method will return the type for the requested parameter. | |||||
| * It may create a new type object with the default implementation, | |||||
| * if the type does not exist. | |||||
| */ | |||||
| template<typename T_type> | |||||
| inline auto& get(); | |||||
| /** | |||||
| * @brief Get a type from the registry. | |||||
| * | |||||
| * This method will return the type for the requested parameter. | |||||
| * If the type was not found, an exception is thrown. | |||||
| */ | |||||
| template<typename T_type> | |||||
| inline const auto& get() const; | |||||
| /** | |||||
| * @brief Get a type from the registry. | |||||
| * | |||||
| * This method will return the type for the requested parameter. | |||||
| * It may create a new type object with the passed implementation, | |||||
| * if the type does not exist. | |||||
| * If the type implementation does not match the requested one, | |||||
| * an exception is thrown. | |||||
| */ | |||||
| template<typename T_type, typename T_impl> | |||||
| inline auto& get(); | |||||
| /** | |||||
| * @brief Search a type by it's represented C++ type. | |||||
| */ | |||||
| template<typename T_type> | |||||
| inline type * find(); | |||||
| /** | |||||
| * @brief Search a type by it's represented C++ type. | |||||
| */ | |||||
| template<typename T_type> | |||||
| inline const type * find() const; | |||||
| /** | |||||
| * @brief Search a type by it's ID. | |||||
| */ | |||||
| inline type * find(type_id id); | |||||
| /** | |||||
| * @brief Search a type by it's ID. | |||||
| */ | |||||
| inline const type * find(type_id id) const; | |||||
| /** | |||||
| * @brief Search a type by it's name. | |||||
| */ | |||||
| inline type * find(const std::string& name); | |||||
| /** | |||||
| * @brief Search a type by it's name. | |||||
| */ | |||||
| inline const type * find(const std::string& name) const; | |||||
| private: | |||||
| /** | |||||
| * @brief Create a new type for the passed C++ type with the passed implementation type. | |||||
| */ | |||||
| template<typename T_impl> | |||||
| inline T_impl& create(); | |||||
| }; | |||||
| } | |||||
| #include "registry.inl" | |||||
| @@ -0,0 +1,140 @@ | |||||
| #pragma once | |||||
| #include <cppcore/misc/string_builder.h> | |||||
| #include "registry.h" | |||||
| #include "misc/exception.h" | |||||
| #include "traits/default_type.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| /* registry */ | |||||
| template<typename T_type> | |||||
| auto& registry::get() | |||||
| { return get<T_type, default_type_t<T_type>>(); } | |||||
| template<typename T_type> | |||||
| const auto& registry::get() const | |||||
| { | |||||
| using impl_type = default_type_t<T_type>; | |||||
| auto * t = find<T_type>(); | |||||
| if (!t) | |||||
| { | |||||
| throw exception( | |||||
| error_code::registry_type_not_found, | |||||
| cppcore::string_builder() | |||||
| << "The requested type could not be found: " | |||||
| << get_type_name<T_type>()); | |||||
| } | |||||
| auto * ret = dynamic_cast<const impl_type *>(t); | |||||
| if (!ret) | |||||
| { | |||||
| throw exception( | |||||
| error_code::registry_type_does_not_match, | |||||
| cppcore::string_builder() | |||||
| << "The type does not match the expected implementation: " | |||||
| << get_type_name<impl_type>()); | |||||
| } | |||||
| return *ret; | |||||
| } | |||||
| template<typename T_type, typename T_impl> | |||||
| auto& registry::get() | |||||
| { | |||||
| auto * t = find<T_type>(); | |||||
| if (!t) | |||||
| t = &create<T_impl>(); | |||||
| auto * ret = dynamic_cast<T_impl *>(t); | |||||
| if (!ret) | |||||
| { | |||||
| throw exception( | |||||
| error_code::registry_type_does_not_match, | |||||
| cppcore::string_builder() | |||||
| << "The type does not match the expected implementation: " | |||||
| << get_type_name<T_impl>()); | |||||
| } | |||||
| return * ret; | |||||
| } | |||||
| template<typename T_type> | |||||
| type * registry::find() | |||||
| { return find(get_type_id<cppmp::decay_t<T_type>>()); } | |||||
| template<typename T_type> | |||||
| const type * registry::find() const | |||||
| { return find(get_type_id<cppmp::decay_t<T_type>>()); } | |||||
| type * registry::find(type_id id) | |||||
| { | |||||
| auto it = _id_map.find(id); | |||||
| return it == _id_map.end() | |||||
| ? nullptr | |||||
| : it->second.get(); | |||||
| } | |||||
| const type * registry::find(type_id id) const | |||||
| { | |||||
| auto it = _id_map.find(id); | |||||
| return it == _id_map.end() | |||||
| ? nullptr | |||||
| : it->second.get(); | |||||
| } | |||||
| type * registry::find(const std::string& name) | |||||
| { | |||||
| auto it = _name_map.find(name); | |||||
| return it == _name_map.end() | |||||
| ? nullptr | |||||
| : it->second.get(); | |||||
| } | |||||
| const type * registry::find(const std::string& name) const | |||||
| { | |||||
| auto it = _name_map.find(name); | |||||
| return it == _name_map.end() | |||||
| ? nullptr | |||||
| : it->second.get(); | |||||
| } | |||||
| template<typename T_impl> | |||||
| T_impl& registry::create() | |||||
| { | |||||
| auto impl = std::make_shared<T_impl>(*this); | |||||
| auto id_it = _id_map.find(impl->id()); | |||||
| if (id_it != _id_map.end()) | |||||
| { | |||||
| throw exception( | |||||
| error_code::registry_id_already_exsists, | |||||
| cppcore::string_builder() | |||||
| << "A type with the id '" | |||||
| << impl->id() | |||||
| << "' is already registered!"); | |||||
| } | |||||
| auto name_it = _name_map.find(impl->name()); | |||||
| if (name_it != _name_map.end()) | |||||
| { | |||||
| throw exception( | |||||
| error_code::registry_name_already_exsists, | |||||
| cppcore::string_builder() | |||||
| << "A type with the name '" | |||||
| << impl->name() | |||||
| << "' is already registered!"); | |||||
| } | |||||
| _id_map.emplace_hint(id_it, impl->id(), impl); | |||||
| _name_map.emplace_hint(name_it, impl->name(), impl); | |||||
| return *impl; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,5 @@ | |||||
| #pragma once | |||||
| #include "traits/default_type.h" | |||||
| #include "traits/default_type.inl" | |||||
| @@ -0,0 +1,14 @@ | |||||
| #pragma once | |||||
| namespace cpprtti | |||||
| { | |||||
| template<typename T, typename = void> | |||||
| struct default_type_trait; | |||||
| template<typename T> | |||||
| using default_type_t = typename default_type_trait<cppmp::decay_t<T>>::type; | |||||
| } | |||||
| #include "default_type.inl" | |||||
| @@ -0,0 +1,27 @@ | |||||
| #pragma once | |||||
| #include "default_type.h" | |||||
| #include "../types/class_type_tpl.h" | |||||
| #include "../types/fundamental_type_tpl.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| template<typename T> | |||||
| struct default_type_trait< | |||||
| T, | |||||
| std::enable_if_t<std::is_fundamental_v<T>>> | |||||
| { | |||||
| using type = fundamental_type_tpl<T>; | |||||
| }; | |||||
| template<typename T> | |||||
| struct default_type_trait< | |||||
| T, | |||||
| std::enable_if_t<std::is_class_v<T>>> | |||||
| { | |||||
| using type = class_type_tpl<T>; | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,14 @@ | |||||
| #pragma once | |||||
| #include "types/class_type_tpl.h" | |||||
| #include "types/class_type.h" | |||||
| #include "types/fundamental_type_tpl.h" | |||||
| #include "types/fundamental_type.h" | |||||
| #include "types/member.h" | |||||
| #include "types/type.h" | |||||
| #include "types/class_type_tpl.inl" | |||||
| #include "types/class_type.inl" | |||||
| #include "types/fundamental_type_tpl.inl" | |||||
| #include "types/fundamental_type.inl" | |||||
| #include "types/type.inl" | |||||
| @@ -0,0 +1,55 @@ | |||||
| #pragma once | |||||
| #include <map> | |||||
| #include <memory> | |||||
| #include "type.h" | |||||
| #include "member/member.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| struct class_type | |||||
| : public type | |||||
| { | |||||
| private: | |||||
| using member_ptr_u = std::unique_ptr<member>; | |||||
| using member_map = std::map<std::string, member_ptr_u>; | |||||
| private: | |||||
| member_map _members; | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline class_type( | |||||
| cpprtti::registry& p_registry, | |||||
| type_id p_id, | |||||
| const std::string& p_name); | |||||
| /** | |||||
| * @brief Get a map of all registered members. | |||||
| */ | |||||
| const member_map& members() const; | |||||
| /** | |||||
| * @brief Register a new member variable. | |||||
| */ | |||||
| template<typename... T_args> | |||||
| auto& add_member_variable( | |||||
| const std::string& p_name, | |||||
| T_args&&... p_args); | |||||
| /** | |||||
| * @brief Register a new member method. | |||||
| */ | |||||
| template<typename... T_args> | |||||
| auto& add_member_method( | |||||
| const std::string& p_name, | |||||
| T_args&&... p_args); | |||||
| }; | |||||
| } | |||||
| #include "class_type.inl" | |||||
| @@ -0,0 +1,71 @@ | |||||
| #pragma once | |||||
| #include "class_type.h" | |||||
| #include "member/member_method.h" | |||||
| #include "member/member_variable.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| /* class_type */ | |||||
| class_type::class_type( | |||||
| cpprtti::registry& p_registry, | |||||
| type_id p_id, | |||||
| const std::string& p_name) | |||||
| : type(p_registry, p_id, p_name, rtti_type_t::class_type) | |||||
| { } | |||||
| const class_type::member_map& class_type | |||||
| ::members() const | |||||
| { return _members; } | |||||
| template<typename... T_args> | |||||
| auto& class_type | |||||
| ::add_member_variable( | |||||
| const std::string& p_name, | |||||
| T_args&&... p_args) | |||||
| { | |||||
| auto it = _members.find(p_name); | |||||
| if (it != _members.end()) | |||||
| { | |||||
| throw exception( | |||||
| error_code::class_member_already_exists, | |||||
| cppcore::string_builder() | |||||
| << "Member with the name '" | |||||
| << p_name | |||||
| << "' already exists"); | |||||
| } | |||||
| auto ptr = make_member_variable(*this, p_name, std::forward<T_args>(p_args)...); | |||||
| auto& ret = *ptr; | |||||
| _members.emplace_hint(it, p_name, std::move(ptr)); | |||||
| return ret; | |||||
| } | |||||
| template<typename... T_args> | |||||
| auto& class_type | |||||
| ::add_member_method( | |||||
| const std::string& p_name, | |||||
| T_args&&... p_args) | |||||
| { | |||||
| auto it = _members.find(p_name); | |||||
| if (it != _members.end()) | |||||
| { | |||||
| throw exception( | |||||
| error_code::class_member_already_exists, | |||||
| cppcore::string_builder() | |||||
| << "Member with the name '" | |||||
| << p_name | |||||
| << "' already exists"); | |||||
| } | |||||
| auto ptr = make_member_method(*this, p_name, std::forward<T_args>(p_args)...); | |||||
| auto& ret = *ptr; | |||||
| _members.emplace_hint(it, p_name, std::move(ptr)); | |||||
| return ret; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,25 @@ | |||||
| #pragma once | |||||
| #include "class_type.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| template<typename T_value> | |||||
| struct class_type_tpl | |||||
| : public class_type | |||||
| { | |||||
| public: | |||||
| using value_type = T_value; | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline class_type_tpl( | |||||
| cpprtti::registry& p_registry); | |||||
| }; | |||||
| } | |||||
| #include "class_type_tpl.inl" | |||||
| @@ -0,0 +1,20 @@ | |||||
| #pragma once | |||||
| #include "class_type_tpl.h" | |||||
| #include "../misc/helper.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| /* class_type_tpl */ | |||||
| template<typename T_value> | |||||
| class_type_tpl<T_value>::class_type_tpl( | |||||
| cpprtti::registry& p_registry) | |||||
| : class_type( | |||||
| p_registry, | |||||
| get_type_id<value_type>(), | |||||
| get_type_name<value_type>()) | |||||
| { } | |||||
| } | |||||
| @@ -0,0 +1,23 @@ | |||||
| #pragma once | |||||
| #include "type.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| struct fundamental_type | |||||
| : public type | |||||
| { | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline fundamental_type( | |||||
| cpprtti::registry& p_registry, | |||||
| size_t p_id, | |||||
| const std::string& p_name); | |||||
| }; | |||||
| } | |||||
| #include "fundamental_type.inl" | |||||
| @@ -0,0 +1,17 @@ | |||||
| #pragma once | |||||
| #include "fundamental_type.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| /* fundamental_type */ | |||||
| fundamental_type::fundamental_type( | |||||
| cpprtti::registry& p_registry, | |||||
| size_t p_id, | |||||
| const std::string& p_name) | |||||
| : type(p_registry, p_id, p_name, rtti_type_t::fundamental_type) | |||||
| { } | |||||
| } | |||||
| @@ -0,0 +1,25 @@ | |||||
| #pragma once | |||||
| #include "fundamental_type.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| template<typename T_value> | |||||
| struct fundamental_type_tpl | |||||
| : public fundamental_type | |||||
| { | |||||
| public: | |||||
| using value_type = T_value; | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline fundamental_type_tpl( | |||||
| cpprtti::registry& p_registry); | |||||
| }; | |||||
| } | |||||
| #include "fundamental_type_tpl.inl" | |||||
| @@ -0,0 +1,19 @@ | |||||
| #pragma once | |||||
| #include "fundamental_type_tpl.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| /* fundamental_type_tpl */ | |||||
| template<typename T_value> | |||||
| fundamental_type_tpl<T_value>::fundamental_type_tpl( | |||||
| cpprtti::registry& p_registry) | |||||
| : fundamental_type( | |||||
| p_registry, | |||||
| get_type_id<value_type>(), | |||||
| get_type_name<value_type>()) | |||||
| { } | |||||
| } | |||||
| @@ -0,0 +1,9 @@ | |||||
| #pragma once | |||||
| #include "member/member_method.h" | |||||
| #include "member/member_variable.h" | |||||
| #include "member/member.h" | |||||
| #include "member/member_method.inl" | |||||
| #include "member/member_variable.inl" | |||||
| #include "member/member.inl" | |||||
| @@ -0,0 +1,56 @@ | |||||
| #pragma once | |||||
| #include <string> | |||||
| #include "../../types/type.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| enum class member_type | |||||
| { | |||||
| unknown = 0, | |||||
| variable, | |||||
| method, | |||||
| }; | |||||
| struct member | |||||
| { | |||||
| protected: | |||||
| cpprtti::type& _owner; | |||||
| std::string _name; | |||||
| member_type _member_type; | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline member( | |||||
| cpprtti::type& p_owner, | |||||
| const std::string& p_name, | |||||
| member_type p_member_type); | |||||
| /** | |||||
| * @brief Destructor. | |||||
| */ | |||||
| virtual ~member() = default; | |||||
| /** | |||||
| * @brief Type that owns this member. | |||||
| */ | |||||
| inline const cpprtti::type& owner() const; | |||||
| /** | |||||
| * @brief Get the name of the member. | |||||
| */ | |||||
| inline const std::string& name() const; | |||||
| /** | |||||
| * @brief Type of the member. | |||||
| */ | |||||
| inline cpprtti::member_type member_type() const; | |||||
| }; | |||||
| } | |||||
| #include "member.inl" | |||||
| @@ -0,0 +1,28 @@ | |||||
| #pragma once | |||||
| #include "member.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| /* member */ | |||||
| member::member( | |||||
| cpprtti::type& p_owner, | |||||
| const std::string& p_name, | |||||
| cpprtti::member_type p_member_type) | |||||
| : _owner (p_owner) | |||||
| , _name (p_name) | |||||
| , _member_type (p_member_type) | |||||
| { } | |||||
| const cpprtti::type& member::owner() const | |||||
| { return _owner; } | |||||
| const std::string& member::name() const | |||||
| { return _name; } | |||||
| member_type cpprtti::member::member_type() const | |||||
| { return _member_type; } | |||||
| } | |||||
| @@ -0,0 +1,46 @@ | |||||
| #pragma once | |||||
| #include <cppmp/misc/generic_predicate.h> | |||||
| #include "member.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| namespace __impl | |||||
| { | |||||
| template<typename X, typename = void> | |||||
| struct member_method_builder; | |||||
| } | |||||
| struct member_method | |||||
| : public member | |||||
| { | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline member_method( | |||||
| cpprtti::type& p_owner, | |||||
| const std::string& p_name); | |||||
| /** | |||||
| * @brief Invoke the member method. | |||||
| */ | |||||
| template<typename T_object, typename... T_args> | |||||
| inline variant invoke(T_object&& obj, T_args&&... args) const; | |||||
| protected: | |||||
| /** | |||||
| * @brief Invoke the member method. | |||||
| */ | |||||
| virtual variant invoke_impl(const variant& obj, const std::vector<variant>& args) const = 0; | |||||
| }; | |||||
| constexpr decltype(auto) make_member_method = cppmp::generic_predicate<__impl::member_method_builder> { }; | |||||
| } | |||||
| #include "member_method.inl" | |||||
| @@ -0,0 +1,113 @@ | |||||
| #pragma once | |||||
| #include <cppmp/traits/lambda_traits.h> | |||||
| #include "member_method.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| /* member_method */ | |||||
| member_method::member_method( | |||||
| cpprtti::type& p_owner, | |||||
| const std::string& p_name) | |||||
| : member( | |||||
| p_owner, | |||||
| p_name, | |||||
| cpprtti::member_type::method) | |||||
| { } | |||||
| template<typename T_object, typename... T_args> | |||||
| variant member_method | |||||
| ::invoke(T_object&& obj, T_args&&... args) const | |||||
| { | |||||
| return invoke_impl( | |||||
| make_variant(_owner.registry(), std::forward<T_object>(obj)), | |||||
| std::vector<variant>({ | |||||
| make_variant(_owner.registry(), std::forward<T_args>(args))... | |||||
| })); | |||||
| } | |||||
| namespace __impl | |||||
| { | |||||
| /* member_method_builder - default */ | |||||
| template<typename X, typename> | |||||
| struct member_method_builder | |||||
| { | |||||
| using is_default = cppmp::true_t; | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&...) | |||||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for make_member_method(...)!"); } | |||||
| }; | |||||
| /* member_method_builder - member method */ | |||||
| template<typename T_method> | |||||
| struct member_method_builder< | |||||
| cppmp::list<class_type&, const std::string&, T_method>, | |||||
| cppmp::enable_if_t< | |||||
| cppmp::is_valid_v<cppmp::lambda_traits<T_method>> | |||||
| && !cppmp::lambda_traits<T_method>::is_static_v | |||||
| > | |||||
| > | |||||
| { | |||||
| using method_type = T_method; | |||||
| using lambda_trait = cppmp::lambda_traits<method_type>; | |||||
| using object_type = typename lambda_trait::object_type; | |||||
| struct member_impl | |||||
| : public member_method | |||||
| { | |||||
| private: | |||||
| method_type _member; | |||||
| public: | |||||
| inline member_impl( | |||||
| cpprtti::type& p_owner, | |||||
| const std::string& p_name, | |||||
| method_type p_member) | |||||
| : member_method(p_owner, p_name) | |||||
| , _member(p_member) | |||||
| { | |||||
| if (_owner.id() != get_type_id<cppmp::decay_t<object_type>>()) | |||||
| { | |||||
| throw exception( | |||||
| error_code::class_type_mismatch, | |||||
| "Object type of the member method does not match the type of the owner!"); | |||||
| } | |||||
| } | |||||
| protected: | |||||
| variant invoke_impl(const variant& obj, const std::vector<variant>& args) const override | |||||
| { return invoke_helper(obj, args, std::make_index_sequence<lambda_trait::argument_count_v> { }); } | |||||
| private: | |||||
| template<size_t... I> | |||||
| inline variant invoke_helper(const variant& obj, const std::vector<variant>& args, std::index_sequence<I...>) const | |||||
| { | |||||
| return make_variant( | |||||
| _owner.registry(), | |||||
| (obj.get<object_type&>().*_member)( | |||||
| args[I].get<typename lambda_trait::template argument_t<I>>()... | |||||
| ) | |||||
| ); | |||||
| } | |||||
| }; | |||||
| template<typename X_member> | |||||
| static constexpr decltype(auto) apply(type& owner, const std::string& name, X_member&& member) | |||||
| { | |||||
| return std::make_unique<member_impl>( | |||||
| owner, | |||||
| name, | |||||
| std::forward<X_member>(member)); | |||||
| } | |||||
| }; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,79 @@ | |||||
| #pragma once | |||||
| #include <cppmp/misc/generic_predicate.h> | |||||
| #include "member.h" | |||||
| #include "../../misc/variant.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| namespace __impl | |||||
| { | |||||
| template<typename X, typename = void> | |||||
| struct member_variable_builder; | |||||
| } | |||||
| struct member_variable | |||||
| : public member | |||||
| { | |||||
| protected: | |||||
| cpprtti::type& _type; | |||||
| bool _is_readale { true }; | |||||
| bool _is_writable { true }; | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline member_variable( | |||||
| cpprtti::type& p_owner, | |||||
| const std::string& p_name, | |||||
| cpprtti::type& p_type); | |||||
| /** | |||||
| * @brief RTTI type of that member represents. | |||||
| */ | |||||
| const cpprtti::type& type() const; | |||||
| /** | |||||
| * @brief Check if the variable is readable. | |||||
| */ | |||||
| bool is_readale() const; | |||||
| /** | |||||
| * @brief Check if the variable is writable. | |||||
| */ | |||||
| bool is_writable() const; | |||||
| /** | |||||
| * @brief Get the current value of the member. | |||||
| */ | |||||
| template<typename T_object> | |||||
| inline variant get(T_object& obj) const; | |||||
| /** | |||||
| * @brief Set the new value of the member. | |||||
| */ | |||||
| template<typename T_object, typename T_value> | |||||
| inline void set(T_object& obj, const T_value& value) const; | |||||
| protected: | |||||
| /** | |||||
| * @brief Get the current value of the member. | |||||
| */ | |||||
| virtual variant get_impl(const variant& obj) const = 0; | |||||
| /** | |||||
| * @brief Set the new value of the member. | |||||
| */ | |||||
| virtual void set_impl(const variant& obj, const variant& value) const = 0; | |||||
| }; | |||||
| constexpr decltype(auto) make_member_variable = cppmp::generic_predicate<__impl::member_variable_builder> { }; | |||||
| } | |||||
| #include "member_variable.inl" | |||||
| @@ -0,0 +1,387 @@ | |||||
| #pragma once | |||||
| #include <cppmp/misc/getter.h> | |||||
| #include <cppmp/misc/setter.h> | |||||
| #include "member_variable.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| /* member_variable */ | |||||
| member_variable::member_variable( | |||||
| cpprtti::type& p_owner, | |||||
| const std::string& p_name, | |||||
| cpprtti::type& p_type) | |||||
| : member( | |||||
| p_owner, | |||||
| p_name, | |||||
| member_type::variable) | |||||
| , _type(p_type) | |||||
| { } | |||||
| const cpprtti::type& member_variable::type() const | |||||
| { return _type; } | |||||
| bool member_variable::is_readale() const | |||||
| { return _is_readale; } | |||||
| bool member_variable::is_writable() const | |||||
| { return _is_writable; } | |||||
| template<typename T_object> | |||||
| variant member_variable::get(T_object& obj) const | |||||
| { | |||||
| if (!_is_readale) | |||||
| { | |||||
| throw exception( | |||||
| error_code::class_member_not_readable, | |||||
| cppcore::string_builder() | |||||
| << "Member variable '" | |||||
| << _name | |||||
| << "' of '" | |||||
| << _owner.name() | |||||
| << " is not readable!"); | |||||
| } | |||||
| return get_impl(make_variant(_owner.registry(), obj)); | |||||
| } | |||||
| template<typename T_object, typename T_value> | |||||
| inline void member_variable::set(T_object& obj, const T_value& value) const | |||||
| { | |||||
| if (!_is_writable) | |||||
| { | |||||
| throw exception( | |||||
| error_code::class_member_not_writable, | |||||
| cppcore::string_builder() | |||||
| << "Member variable '" | |||||
| << _name | |||||
| << "' of '" | |||||
| << _owner.name() | |||||
| << " is not writable!"); | |||||
| } | |||||
| return set_impl(make_variant(_owner.registry(), obj), make_variant(_owner.registry(), value)); | |||||
| } | |||||
| namespace __impl | |||||
| { | |||||
| /* getter_info_trait */ | |||||
| template<typename T_getter, typename = void> | |||||
| struct getter_info_trait; | |||||
| template<typename T_getter> | |||||
| struct getter_info_trait< | |||||
| T_getter, | |||||
| cppmp::enable_if_t< | |||||
| decltype(cppmp::make_getter)::is_valid_v<T_getter> | |||||
| > | |||||
| > | |||||
| { | |||||
| using getter_type = decltype(cppmp::make_getter(std::declval<T_getter>())); | |||||
| using object_type = typename getter_type::object_type; | |||||
| using value_type = typename getter_type::value_type; | |||||
| static constexpr decltype(auto) is_read_only_v = | |||||
| cppmp::is_const_v<cppmp::remove_reference_t<object_type>> | |||||
| || cppmp::is_const_v<cppmp::remove_reference_t<value_type>>; | |||||
| }; | |||||
| /* setter_info_trait */ | |||||
| template<typename T_setter, typename = void> | |||||
| struct setter_info_trait; | |||||
| template<typename T_setter> | |||||
| struct setter_info_trait< | |||||
| T_setter, | |||||
| cppmp::enable_if_t< | |||||
| decltype(cppmp::make_setter)::is_valid_v<T_setter> | |||||
| > | |||||
| > | |||||
| { | |||||
| using setter_type = decltype(cppmp::make_setter(std::declval<T_setter>())); | |||||
| using object_type = typename setter_type::object_type; | |||||
| using value_type = typename setter_type::value_type; | |||||
| static constexpr decltype(auto) is_write_only_v = | |||||
| !cppmp::is_base_of_v<cppmp::tag_setter_member_var, setter_type>; | |||||
| }; | |||||
| /* member_variable_builder - default */ | |||||
| template<typename X, typename> | |||||
| struct member_variable_builder | |||||
| { | |||||
| using is_default = cppmp::true_t; | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&...) | |||||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for make_member_variable(...)!"); } | |||||
| }; | |||||
| /* member_variable_builder - read-write getter */ | |||||
| template<typename T_getter> | |||||
| struct member_variable_builder< | |||||
| cppmp::list<class_type&, const std::string&, T_getter>, | |||||
| cppmp::enable_if_t< | |||||
| decltype(cppmp::make_getter)::is_valid_v<T_getter> | |||||
| && !getter_info_trait<T_getter>::is_read_only_v | |||||
| > | |||||
| > | |||||
| { | |||||
| using getter_type = cppmp::decay_t<decltype(cppmp::make_getter(std::declval<T_getter>()))>; | |||||
| using object_type = typename getter_type::object_type; | |||||
| using value_type = typename getter_type::value_type; | |||||
| struct member_impl | |||||
| : public member_variable | |||||
| { | |||||
| private: | |||||
| getter_type _getter; | |||||
| public: | |||||
| inline member_impl( | |||||
| cpprtti::type& p_owner, | |||||
| const std::string& p_name, | |||||
| getter_type p_getter) | |||||
| : member_variable(p_owner, p_name, p_owner.registry().get<value_type>()) | |||||
| , _getter(p_getter) | |||||
| { | |||||
| if (_owner.id() != get_type_id<cppmp::decay_t<object_type>>()) | |||||
| { | |||||
| throw exception( | |||||
| error_code::class_type_mismatch, | |||||
| "Object type of the getter does not match the type of the owner!"); | |||||
| } | |||||
| _is_readale = true; | |||||
| _is_writable = true; | |||||
| } | |||||
| protected: | |||||
| variant get_impl(const variant& obj) const override | |||||
| { | |||||
| return obj.is_const() | |||||
| ? make_variant(_owner.registry(), _getter(obj.get<const object_type&>())) | |||||
| : make_variant(_owner.registry(), _getter(obj.get<object_type&>())); | |||||
| } | |||||
| void set_impl(const variant& obj, const variant& value) const override | |||||
| { _getter(obj.get<object_type&>()) = value.get<value_type&>(); } | |||||
| }; | |||||
| template<typename X_getter> | |||||
| static constexpr decltype(auto) apply(type& owner, const std::string& name, X_getter&& getter) | |||||
| { | |||||
| return std::make_unique<member_impl>( | |||||
| owner, | |||||
| name, | |||||
| cppmp::make_getter(std::forward<X_getter>(getter))); | |||||
| } | |||||
| }; | |||||
| /* member_variable_builder - read-only getter */ | |||||
| template<typename T_getter> | |||||
| struct member_variable_builder< | |||||
| cppmp::list<class_type&, const std::string&, T_getter>, | |||||
| cppmp::enable_if_t< | |||||
| decltype(cppmp::make_getter)::is_valid_v<T_getter> | |||||
| && getter_info_trait<T_getter>::is_read_only_v | |||||
| > | |||||
| > | |||||
| { | |||||
| using getter_type = cppmp::decay_t<decltype(cppmp::make_getter(std::declval<T_getter>()))>; | |||||
| using object_type = typename getter_type::object_type; | |||||
| using value_type = typename getter_type::value_type; | |||||
| struct member_impl | |||||
| : public member_variable | |||||
| { | |||||
| private: | |||||
| getter_type _getter; | |||||
| public: | |||||
| inline member_impl( | |||||
| cpprtti::type& p_owner, | |||||
| const std::string& p_name, | |||||
| getter_type p_getter) | |||||
| : member_variable(p_owner, p_name, p_owner.registry().get<value_type>()) | |||||
| , _getter(p_getter) | |||||
| { | |||||
| if (_owner.id() != get_type_id<cppmp::decay_t<object_type>>()) | |||||
| { | |||||
| throw exception( | |||||
| error_code::class_type_mismatch, | |||||
| "Object type of the getter does not match the type of the owner!"); | |||||
| } | |||||
| _is_readale = true; | |||||
| _is_writable = false; | |||||
| } | |||||
| protected: | |||||
| variant get_impl(const variant& obj) const override | |||||
| { return make_variant(_owner.registry(), _getter(obj.get<const object_type&>())); } | |||||
| void set_impl(const variant& obj, const variant& value) const override | |||||
| { } | |||||
| }; | |||||
| template<typename X_getter> | |||||
| static constexpr decltype(auto) apply(type& owner, const std::string& name, X_getter&& getter) | |||||
| { | |||||
| return std::make_unique<member_impl>( | |||||
| owner, | |||||
| name, | |||||
| cppmp::make_getter(std::forward<X_getter>(getter))); | |||||
| } | |||||
| }; | |||||
| /* member_variable_builder - write-only setter */ | |||||
| template<typename T_setter> | |||||
| struct member_variable_builder< | |||||
| cppmp::list<class_type&, const std::string&, T_setter>, | |||||
| cppmp::enable_if_t< | |||||
| decltype(cppmp::make_setter)::is_valid_v<T_setter> | |||||
| && setter_info_trait<T_setter>::is_write_only_v | |||||
| > | |||||
| > | |||||
| { | |||||
| using setter_type = cppmp::decay_t<decltype(cppmp::make_setter(std::declval<T_setter>()))>; | |||||
| using object_type = typename setter_type::object_type; | |||||
| using value_type = typename setter_type::value_type; | |||||
| struct member_impl | |||||
| : public member_variable | |||||
| { | |||||
| private: | |||||
| setter_type _setter; | |||||
| public: | |||||
| inline member_impl( | |||||
| cpprtti::type& p_owner, | |||||
| const std::string& p_name, | |||||
| setter_type p_setter) | |||||
| : member_variable(p_owner, p_name, p_owner.registry().get<value_type>()) | |||||
| , _setter(p_setter) | |||||
| { | |||||
| if (_owner.id() != get_type_id<cppmp::decay_t<object_type>>()) | |||||
| { | |||||
| throw exception( | |||||
| error_code::class_type_mismatch, | |||||
| "Object type of the setter does not match the type of the owner!"); | |||||
| } | |||||
| _is_readale = false; | |||||
| _is_writable = true; | |||||
| } | |||||
| protected: | |||||
| variant get_impl(const variant& obj) const override | |||||
| { return variant(); } | |||||
| void set_impl(const variant& obj, const variant& value) const override | |||||
| { _setter(obj.get<object_type&>(), value.get<const value_type&>()); } | |||||
| }; | |||||
| template<typename X_setter> | |||||
| static constexpr decltype(auto) apply(type& owner, const std::string& name, X_setter&& setter) | |||||
| { | |||||
| return std::make_unique<member_impl>( | |||||
| owner, | |||||
| name, | |||||
| cppmp::make_setter(std::forward<X_setter>(setter))); | |||||
| } | |||||
| }; | |||||
| /* member_variable_builder - read-write getter/setter */ | |||||
| template<typename T_getter, typename T_setter> | |||||
| struct member_variable_builder< | |||||
| cppmp::list<class_type&, const std::string&, T_getter, T_setter>, | |||||
| cppmp::enable_if_t< | |||||
| decltype(cppmp::make_getter)::is_valid_v<T_getter> | |||||
| && decltype(cppmp::make_setter)::is_valid_v<T_setter> | |||||
| > | |||||
| > | |||||
| { | |||||
| using getter_type = cppmp::decay_t<decltype(cppmp::make_getter(std::declval<T_getter>()))>; | |||||
| using getter_object_type = typename getter_type::object_type; | |||||
| using getter_value_type = typename getter_type::value_type; | |||||
| using setter_type = cppmp::decay_t<decltype(cppmp::make_setter(std::declval<T_setter>()))>; | |||||
| using setter_object_type = typename setter_type::object_type; | |||||
| using setter_value_type = typename setter_type::value_type; | |||||
| using object_type = cppmp::decay_t<getter_object_type>; | |||||
| using value_type = cppmp::decay_t<getter_value_type>; | |||||
| static_assert(cppmp::is_same_v< | |||||
| cppmp::decay_t<getter_object_type>, | |||||
| cppmp::decay_t<setter_object_type>>, | |||||
| "object type does not match"); | |||||
| static_assert(cppmp::is_same_v< | |||||
| cppmp::decay_t<getter_value_type>, | |||||
| cppmp::decay_t<setter_value_type>>, | |||||
| "value type does not match"); | |||||
| struct member_impl | |||||
| : public member_variable | |||||
| { | |||||
| private: | |||||
| getter_type _getter; | |||||
| setter_type _setter; | |||||
| public: | |||||
| inline member_impl( | |||||
| cpprtti::type& p_owner, | |||||
| const std::string& p_name, | |||||
| getter_type p_getter, | |||||
| setter_type p_setter) | |||||
| : member_variable(p_owner, p_name, p_owner.registry().get<value_type>()) | |||||
| , _getter(p_getter) | |||||
| , _setter(p_setter) | |||||
| { | |||||
| if (_owner.id() != get_type_id<cppmp::decay_t<object_type>>()) | |||||
| { | |||||
| throw exception( | |||||
| error_code::class_type_mismatch, | |||||
| "Object type of the setter does not match the type of the owner!"); | |||||
| } | |||||
| _is_readale = true; | |||||
| _is_writable = true; | |||||
| } | |||||
| protected: | |||||
| variant get_impl(const variant& obj) const override | |||||
| { | |||||
| return obj.is_const() | |||||
| ? make_variant(_owner.registry(), _getter(obj.get<const getter_object_type&>())) | |||||
| : make_variant(_owner.registry(), _getter(obj.get<getter_object_type&>())); | |||||
| } | |||||
| void set_impl(const variant& obj, const variant& value) const override | |||||
| { _setter(obj.get<setter_object_type&>(), value.get<setter_value_type>()); } | |||||
| }; | |||||
| template<typename X_getter, typename X_setter> | |||||
| static constexpr decltype(auto) apply(type& owner, const std::string& name, X_getter&& getter, X_setter&& setter) | |||||
| { | |||||
| return std::make_unique<member_impl>( | |||||
| owner, | |||||
| name, | |||||
| cppmp::make_getter(std::forward<X_getter>(getter)), | |||||
| cppmp::make_setter(std::forward<X_setter>(setter))); | |||||
| } | |||||
| }; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,75 @@ | |||||
| #pragma once | |||||
| #include <string> | |||||
| #include <cpprtti/misc/helper.h> | |||||
| namespace cpprtti | |||||
| { | |||||
| struct registry; | |||||
| enum class rtti_type | |||||
| { | |||||
| unknown = 0, //!< unknown | |||||
| fundamental_type, //!< fundamental C++ type (like int, float, ...) | |||||
| class_type, //!< C++ class/struct | |||||
| }; | |||||
| using rtti_type_t = enum rtti_type; | |||||
| /** | |||||
| * @brief represents any C++ type | |||||
| */ | |||||
| struct type | |||||
| { | |||||
| protected: | |||||
| cpprtti::registry& _registry; //!< Type registry this type belongs to. | |||||
| type_id _id; //!< Unique ID | |||||
| std::string _name; //!< Name of the type. | |||||
| rtti_type_t _rtti_type; //!< Type specialization | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline type( | |||||
| cpprtti::registry& p_registry, | |||||
| size_t p_id, | |||||
| const std::string& p_name, | |||||
| rtti_type_t p_rtti_type); | |||||
| /** | |||||
| * @brief Destructor. | |||||
| */ | |||||
| virtual ~type() = default; | |||||
| /** | |||||
| * @brief Type registry this type belongs to. | |||||
| */ | |||||
| inline cpprtti::registry& registry(); | |||||
| /** | |||||
| * @brief Type registry this type belongs to. | |||||
| */ | |||||
| inline const cpprtti::registry& registry() const; | |||||
| /** | |||||
| * @brief Get the ID of this type. | |||||
| */ | |||||
| inline type_id id() const; | |||||
| /** | |||||
| * @brief Get the name of this type. | |||||
| */ | |||||
| inline const std::string& name() const; | |||||
| /** | |||||
| * @brief Get the RTTI type of this type object. | |||||
| */ | |||||
| inline rtti_type_t rtti_type() const; | |||||
| }; | |||||
| } | |||||
| #include "type.inl" | |||||
| @@ -0,0 +1,36 @@ | |||||
| #pragma once | |||||
| #include "type.h" | |||||
| namespace cpprtti | |||||
| { | |||||
| /* type */ | |||||
| type::type( | |||||
| cpprtti::registry& p_registry, | |||||
| size_t p_id, | |||||
| const std::string& p_name, | |||||
| rtti_type_t p_rtti_type) | |||||
| : _registry (p_registry) | |||||
| , _id (p_id) | |||||
| , _name (p_name) | |||||
| , _rtti_type(p_rtti_type) | |||||
| { } | |||||
| cpprtti::registry& type::registry() | |||||
| { return _registry; } | |||||
| const cpprtti::registry& type::registry() const | |||||
| { return _registry; } | |||||
| type_id type::id() const | |||||
| { return _id; } | |||||
| const std::string& type::name() const | |||||
| { return _name; } | |||||
| rtti_type_t type::rtti_type() const | |||||
| { return _rtti_type; } | |||||
| } | |||||
| @@ -0,0 +1,38 @@ | |||||
| # Initialize ###################################################################################### | |||||
| Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) | |||||
| Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) | |||||
| Include ( strip_symbols OPTIONAL RESULT_VARIABLE HAS_STRIP_SYMBOLS ) | |||||
| Find_Package ( cppcore ) | |||||
| Find_Package ( cppmp ) | |||||
| # Object Library ################################################################################## | |||||
| Set ( CPPRTTI_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | |||||
| Add_Library ( cpprtti | |||||
| INTERFACE ) | |||||
| Target_Include_Directories ( cpprtti | |||||
| INTERFACE | |||||
| $<BUILD_INTERFACE:${CPPRTTI_INCLUDE_DIR}> | |||||
| $<INSTALL_INTERFACE:${CPPRTTI_INSTALL_DIR_INCLUDE}> ) | |||||
| Target_Link_Libraries ( cpprtti | |||||
| INTERFACE | |||||
| cppcore | |||||
| cppmp ) | |||||
| # Install ######################################################################################### | |||||
| Set ( CPPRTTI_HAS_EXPORT False PARENT_SCOPE ) | |||||
| # Header | |||||
| If ( CPPRTTI_INSTALL_HEADER ) | |||||
| Set ( CPPRTTI_HAS_EXPORT True PARENT_SCOPE ) | |||||
| Install ( FILES ${CPPRTTI_INCLUDE_DIR}/cpprtti.h | |||||
| DESTINATION ${CPPRTTI_INSTALL_DIR_INCLUDE} ) | |||||
| Install ( DIRECTORY ${CPPRTTI_INCLUDE_DIR}/cpprtti | |||||
| DESTINATION ${CPPRTTI_INSTALL_DIR_INCLUDE} ) | |||||
| Install ( TARGETS cpprtti | |||||
| EXPORT cpprtti | |||||
| DESTINATION ${CPPRTTI_INSTALL_DIR_INCLUDE} ) | |||||
| EndIf ( ) | |||||
| @@ -0,0 +1,52 @@ | |||||
| # Initialize ###################################################################################### | |||||
| Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) | |||||
| Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) | |||||
| Include ( cmake_tests OPTIONAL RESULT_VARIABLE HAS_CMAKE_TESTS ) | |||||
| # Test ############################################################################################ | |||||
| Find_Package ( GTest ) | |||||
| If ( NOT "${GTest_FOUND}" ) | |||||
| Return ( ) | |||||
| EndIf ( ) | |||||
| File ( GLOB_RECURSE CPPRTTI_TEST_HEADER_FILES | |||||
| ${CMAKE_CURRENT_SOURCE_DIR}/*.h ) | |||||
| File ( GLOB_RECURSE CPPRTTI_TEST_INLINE_FILES | |||||
| ${CMAKE_CURRENT_SOURCE_DIR}/*.inl ) | |||||
| File ( GLOB_RECURSE CPPRTTI_TEST_SOURCE_FILES | |||||
| RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} | |||||
| ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) | |||||
| ForEach ( FILE IN LISTS CPPRTTI_TEST_SOURCE_FILES ) | |||||
| # add test | |||||
| Get_Filename_Component ( TEST_DIR ${FILE} DIRECTORY ) | |||||
| Get_Filename_Component ( TEST_NAME ${FILE} NAME_WE ) | |||||
| Set ( TEST_NAME "${TEST_DIR}/${TEST_NAME}" ) | |||||
| String ( REPLACE "\\" "-" TEST_NAME "${TEST_NAME}" ) | |||||
| String ( REPLACE "/" "-" TEST_NAME "${TEST_NAME}" ) | |||||
| String ( REPLACE "_" "-" TEST_NAME "${TEST_NAME}" ) | |||||
| Set ( TEST_NAME "test-${TEST_NAME}" ) | |||||
| Add_Executable ( ${TEST_NAME} | |||||
| EXCLUDE_FROM_ALL | |||||
| ${CPPRTTI_TEST_HEADER_FILES} | |||||
| ${CPPRTTI_TEST_INLINE_FILES} | |||||
| ${FILE} ) | |||||
| Target_Link_Libraries ( ${TEST_NAME} | |||||
| PUBLIC | |||||
| cpprtti | |||||
| GTest::Main ) | |||||
| # pedantic | |||||
| If ( HAS_PEDANTIC ) | |||||
| Pedantic_Apply_Flags_Target ( ${TEST_NAME} ALL ) | |||||
| EndIf ( ) | |||||
| # test | |||||
| If ( HAS_CMAKE_TESTS ) | |||||
| Add_CMake_Test ( NAME ${TEST_NAME} TARGET ${TEST_NAME} GROUP cpprtti ) | |||||
| Else ( ) | |||||
| Add_Test ( NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) | |||||
| EndIf ( ) | |||||
| EndForEach ( ) | |||||
| @@ -0,0 +1,101 @@ | |||||
| #include <gtest/gtest.h> | |||||
| #include <cpprtti/misc/variant.h> | |||||
| using namespace cpprtti; | |||||
| TEST(variant_test, empty) | |||||
| { | |||||
| variant v; | |||||
| EXPECT_TRUE (v.empty()); | |||||
| EXPECT_FALSE(static_cast<bool>(v)); | |||||
| } | |||||
| TEST(variant_test, store_normal_value) | |||||
| { | |||||
| registry reg; | |||||
| int i = 6; | |||||
| auto v = make_variant(reg, static_cast<int>(i)); | |||||
| EXPECT_FALSE (v.is_reference()); | |||||
| EXPECT_FALSE (v.is_const()); | |||||
| EXPECT_EQ (v.get<int>(), 6); | |||||
| EXPECT_EQ (v.get<int&>(), 6); | |||||
| EXPECT_EQ (v.get<int&&>(), 6); | |||||
| EXPECT_EQ (v.get<const int>(), 6); | |||||
| EXPECT_EQ (v.get<const int&>(), 6); | |||||
| EXPECT_EQ (v.get<const int&&>(), 6); | |||||
| } | |||||
| TEST(variant_test, store_constant_value) | |||||
| { | |||||
| registry reg; | |||||
| int i = 6; | |||||
| auto v = make_variant(reg, static_cast<int>(i)); | |||||
| EXPECT_FALSE (v.is_reference()); | |||||
| EXPECT_FALSE (v.is_const()); | |||||
| EXPECT_EQ (v.get<int>(), 6); | |||||
| EXPECT_EQ (v.get<int&>(), 6); | |||||
| EXPECT_EQ (v.get<int&&>(), 6); | |||||
| EXPECT_EQ (v.get<const int>(), 6); | |||||
| EXPECT_EQ (v.get<const int&>(), 6); | |||||
| EXPECT_EQ (v.get<const int&&>(), 6); | |||||
| } | |||||
| TEST(variant_test, store_lvalue_reference) | |||||
| { | |||||
| registry reg; | |||||
| int i = 6; | |||||
| auto v = make_variant(reg, static_cast<int&>(i)); | |||||
| EXPECT_TRUE (v.is_reference()); | |||||
| EXPECT_FALSE (v.is_const()); | |||||
| EXPECT_EQ (v.get<int>(), 6); | |||||
| EXPECT_EQ (v.get<int&>(), 6); | |||||
| EXPECT_EQ (v.get<int&&>(), 6); | |||||
| EXPECT_EQ (v.get<const int>(), 6); | |||||
| EXPECT_EQ (v.get<const int&>(), 6); | |||||
| EXPECT_EQ (v.get<const int&&>(), 6); | |||||
| } | |||||
| TEST(variant_test, store_constant_lvalue_reference) | |||||
| { | |||||
| registry reg; | |||||
| int i = 6; | |||||
| auto v = make_variant(reg, static_cast<const int&>(i)); | |||||
| EXPECT_TRUE (v.is_reference()); | |||||
| EXPECT_TRUE (v.is_const()); | |||||
| EXPECT_EQ (v.get<int>(), 6); | |||||
| EXPECT_ANY_THROW(v.get<int&>()); | |||||
| EXPECT_ANY_THROW(v.get<int&&>()); | |||||
| EXPECT_EQ (v.get<const int>(), 6); | |||||
| EXPECT_EQ (v.get<const int&>(), 6); | |||||
| EXPECT_ANY_THROW(v.get<const int&&>()); | |||||
| } | |||||
| TEST(variant_test, store_rvalue_reference) | |||||
| { | |||||
| registry reg; | |||||
| int i = 6; | |||||
| auto v = make_variant(reg, std::move(i)); | |||||
| EXPECT_FALSE (v.is_reference()); | |||||
| EXPECT_FALSE (v.is_const()); | |||||
| EXPECT_EQ (v.get<int>(), 6); | |||||
| EXPECT_EQ (v.get<int&>(), 6); | |||||
| EXPECT_EQ (v.get<int&&>(), 6); | |||||
| EXPECT_EQ (v.get<const int>(), 6); | |||||
| EXPECT_EQ (v.get<const int&>(), 6); | |||||
| EXPECT_EQ (v.get<const int&&>(), 6); | |||||
| } | |||||
| @@ -0,0 +1,111 @@ | |||||
| #include <gtest/gtest.h> | |||||
| #include <cpprtti.h> | |||||
| using namespace cpprtti; | |||||
| struct test_class | |||||
| { | |||||
| public: | |||||
| int i; | |||||
| std::string read_only; | |||||
| std::string write_only; | |||||
| std::string read_write; | |||||
| public: | |||||
| inline const std::string& get_read_only() const | |||||
| { return read_only; } | |||||
| inline void set_write_only(const std::string& value) | |||||
| { write_only = value; } | |||||
| inline const std::string& get_read_write() const | |||||
| { return read_write; } | |||||
| inline void set_read_write(const std::string& value) | |||||
| { read_write = value; } | |||||
| inline int add(int value) | |||||
| { return i += value; } | |||||
| }; | |||||
| TEST(class_type_tests, member_variable_read_write_getter) | |||||
| { | |||||
| registry reg; | |||||
| auto& c = reg.get<test_class>(); | |||||
| test_class obj; | |||||
| obj.i = 10; | |||||
| auto& m = c.add_member_variable("i", &test_class::i); | |||||
| auto v = m.get(obj); | |||||
| EXPECT_TRUE (m.is_readale()); | |||||
| EXPECT_TRUE (m.is_writable()); | |||||
| EXPECT_TRUE (v.is_reference()); | |||||
| EXPECT_FALSE(v.is_const()); | |||||
| EXPECT_EQ (v.get<int>(), 10); | |||||
| } | |||||
| TEST(class_type_tests, member_variable_read_only_getter) | |||||
| { | |||||
| registry reg; | |||||
| auto& c = reg.get<test_class>(); | |||||
| test_class obj; | |||||
| obj.read_only = "read_only"; | |||||
| auto& m = c.add_member_variable("read_only", &test_class::get_read_only); | |||||
| auto v = m.get(obj); | |||||
| EXPECT_TRUE (m.is_readale()); | |||||
| EXPECT_FALSE(m.is_writable()); | |||||
| EXPECT_TRUE (v.is_reference()); | |||||
| EXPECT_TRUE (v.is_const()); | |||||
| EXPECT_EQ (v.get<std::string>(), "read_only"); | |||||
| } | |||||
| TEST(class_type_tests, member_variable_write_only_setter) | |||||
| { | |||||
| registry reg; | |||||
| auto& c = reg.get<test_class>(); | |||||
| test_class obj; | |||||
| auto& m = c.add_member_variable("write_only", &test_class::set_write_only); | |||||
| EXPECT_FALSE(m.is_readale()); | |||||
| EXPECT_TRUE (m.is_writable()); | |||||
| m.set(obj, std::string("fuuu")); | |||||
| EXPECT_EQ(obj.write_only, "fuuu"); | |||||
| } | |||||
| TEST(class_type_tests, member_variable_read_write_getter_setter) | |||||
| { | |||||
| registry reg; | |||||
| auto& c = reg.get<test_class>(); | |||||
| test_class obj; | |||||
| obj.read_write = "read_write"; | |||||
| auto& m = c.add_member_variable("read_write", &test_class::get_read_write, &test_class::set_read_write); | |||||
| auto v = m.get(obj); | |||||
| EXPECT_TRUE (m.is_readale()); | |||||
| EXPECT_TRUE (m.is_writable()); | |||||
| EXPECT_TRUE (v.is_reference()); | |||||
| EXPECT_TRUE (v.is_const()); | |||||
| EXPECT_EQ (v.get<std::string>(), "read_write"); | |||||
| m.set(obj, std::string("fuuu")); | |||||
| EXPECT_EQ(obj.read_write, "fuuu"); | |||||
| } | |||||
| TEST(class_type_tests, member_method) | |||||
| { | |||||
| registry reg; | |||||
| auto& c = reg.get<test_class>(); | |||||
| test_class obj; | |||||
| obj.i = 10; | |||||
| auto& m = c.add_member_method("add", &test_class::add); | |||||
| auto v = m.invoke(obj, 5); | |||||
| EXPECT_EQ(v.get<int>(), 15); | |||||
| EXPECT_EQ(obj.i, 15); | |||||
| } | |||||