@@ -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); | |||
} |