diff --git a/cmake/library.cmake b/cmake/library.cmake index 77fcf96..6e3de37 100644 --- a/cmake/library.cmake +++ b/cmake/library.cmake @@ -4,11 +4,10 @@ include("${PROJECT_SOURCE_DIR}/cmake/conan.cmake") add_library(${PROJECT_NAME}) -include_directories(include) - # find source files file(GLOB_RECURSE ARCHIMEDES_SOURCE src/**.cpp) -target_sources(${PROJECT_NAME} PUBLIC ${ARCHIMEDES_SOURCE}) +target_sources(${PROJECT_NAME} PRIVATE ${ARCHIMEDES_SOURCE}) +target_include_directories(${PROJECT_NAME} PUBLIC include) # link conan libraries target_link_libraries(${PROJECT_NAME} PUBLIC ${ARCHIMEDES_LIBRARIES}) diff --git a/cmake/msvc.cmake b/cmake/msvc.cmake index c64b311..9ac0d02 100644 --- a/cmake/msvc.cmake +++ b/cmake/msvc.cmake @@ -2,7 +2,7 @@ include_guard() # msvc specific compile flags if(MSVC) + add_compile_options("/permissive-") add_compile_options("/Zc:__cplusplus") add_compile_options("/Zc:preprocessor") - add_compile_options("/permissive-") endif() diff --git a/include/Meta.h b/include/Meta.h new file mode 100644 index 0000000..ced7912 --- /dev/null +++ b/include/Meta.h @@ -0,0 +1,7 @@ +#pragma once + +#include "meta/Typeof.hpp" + +#include "meta/NameOfType.h" +#include "meta/Rtti.h" +#include "meta/ThisT.h" diff --git a/include/net.h b/include/Net.h similarity index 100% rename from include/net.h rename to include/Net.h diff --git a/include/meta/NameOfType.h b/include/meta/NameOfType.h new file mode 100644 index 0000000..bb724a8 --- /dev/null +++ b/include/meta/NameOfType.h @@ -0,0 +1,4 @@ +#pragma once + +#include "nameOfType/NameOfType.h" +#include "nameOfType/NameOfTypeFmt.h" diff --git a/include/meta/Rtti.h b/include/meta/Rtti.h new file mode 100644 index 0000000..41a0a50 --- /dev/null +++ b/include/meta/Rtti.h @@ -0,0 +1,12 @@ +#pragma once + +#include "rtti/EnableRTTI.hpp" +#include "rtti/RTTIEnabled.hpp" +#include "rtti/StaticTypedesc.hpp" + +#include "rtti/HashTypeName.h" +#include "rtti/TypeDescriptor.h" +#include "rtti/TypeDescriptorOwner.h" +#include "rtti/TypeDescriptorWrapper.h" +#include "rtti/TypeDescriptorWrapperHash.h" +#include "rtti/Typedesc.h" diff --git a/include/meta/ThisT.h b/include/meta/ThisT.h new file mode 100644 index 0000000..b2b4f52 --- /dev/null +++ b/include/meta/ThisT.h @@ -0,0 +1,7 @@ +#pragma once + +#include "thisT/HasThisT.hpp" +#include "thisT/ThisT.hpp" +#include "thisT/ThisTCheck.hpp" +#include "thisT/ThisTUnique.hpp" +#include "thisT/UniqueGetter.hpp" diff --git a/include/meta/Typeof.hpp b/include/meta/Typeof.hpp new file mode 100644 index 0000000..0f5679f --- /dev/null +++ b/include/meta/Typeof.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +namespace arch::meta::typeOf::_details { +/// @brief Helper struct of typeof() macro +/// @brief (does nothing) +struct Helper { + /// @brief Helper casting operator + /// @brief (does nothing) + template + operator T() const; + /// @brief Helper dereference operator + /// @brief (does nothing) + Helper operator*(); +}; + +/// @brief Helper multiplication operator +/// @brief (does nothing) +template +const T& operator*(const T&, Helper); +} // namespace arch::meta::typeOf::_details + +// if ... is a type -> dereference Helper, cast to ..., obtain decltype of result +// if ... is an expression -> multiply ... by Helper, obtain decltype of result +#define _ARCH_TYPEOF_IMPL(...) \ + /* evil operator* and cast semantic level hacking */ \ + std::remove_cvref_t + +/// @brief Queries non-const, non-reference type of expression or type given +/// @param x - type or expression to query +#define typeof(...) _ARCH_TYPEOF_IMPL(__VA_ARGS__) diff --git a/include/meta/nameOfType/NameOfType.h b/include/meta/nameOfType/NameOfType.h new file mode 100644 index 0000000..d34f03d --- /dev/null +++ b/include/meta/nameOfType/NameOfType.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +namespace arch::meta::nameOfType { + +/// @brief Helper function, which signature is used to determine name of type +template +constexpr std::string_view signature() noexcept = delete; + +/// @brief Returns implementation-dependent name of type T +/// @brief To standardize output use nameOfFmt() +/// @tparam T - type to get type of +template +constexpr std::string_view nameOf() noexcept; + +} // namespace arch::meta::nameOfType + +#include "NameOfType.hpp" diff --git a/include/meta/nameOfType/NameOfType.hpp b/include/meta/nameOfType/NameOfType.hpp new file mode 100644 index 0000000..042a63b --- /dev/null +++ b/include/meta/nameOfType/NameOfType.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include + +#include "NameOfType.h" + +namespace arch::meta::nameOfType { + +/// @brief signature() Specialization returning signature with 'int' +template<> +constexpr std::string_view signature() noexcept { + // Major compilers do not return simply name of function: 'signature' + // but its signature: 'std::basic_string_view<...> signature() noexcept' + // this allows to capture position of 'int' in signature + const auto location = std::source_location::current( +#if __INTELLISENSE__ // Visual Studio cannot into constexpr + __builtin_LINE(), + __builtin_COLUMN(), + __builtin_FILE(), + __FUNCSIG__ +#endif + ); + return location.function_name(); +} + +template +constexpr std::string_view nameOf() noexcept { + constexpr auto intSignature = signature(); + auto found = intSignature.find("int"); + auto len = intSignature.length(); + + auto suffix = intSignature.substr(found + (sizeof("int") - 1)); + + // renaming signature -> nameOf + found -= sizeof("signature"); + found += sizeof("nameOf"); + + auto prefix = intSignature.substr(0, found); + + const auto location = std::source_location::current( +#if __INTELLISENSE__ // Visual Studio cannot into constexpr + __builtin_LINE(), + __builtin_COLUMN(), + __builtin_FILE(), + __FUNCSIG__ +#endif + ); + std::string_view functionName = location.function_name(); + + // trimming function signature + return std::string_view( + functionName.data() + prefix.length(), + functionName.length() - prefix.length() - suffix.length() + ); +} + +} // namespace arch::meta::nameOfType + +#define _ARCH_NAMEOF_TYPE_NO_FMT_IMPL(...) arch::meta::nameOfType::nameOf<__VA_ARGS__>() +/// @brief Returns nonstandardized name of given type (constexpr) +#define nameOfTypeNoFmt(...) _ARCH_NAMEOF_TYPE_NO_FMT_IMPL(__VA_ARGS__) +/// @brief Returns standardized name of given type (runtime only) +#define nameOfType(...) arch::meta::nameOfType::nameOfFmt(nameOfTypeNoFmt(__VA_ARGS__)) diff --git a/include/meta/nameOfType/NameOfTypeFmt.h b/include/meta/nameOfType/NameOfTypeFmt.h new file mode 100644 index 0000000..67bbd6a --- /dev/null +++ b/include/meta/nameOfType/NameOfTypeFmt.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace arch::meta::nameOfType { + +/// @brief Standardises names returned by nameOf() +/// @param name - name to standardize +std::string nameOfFmt(std::string_view name) noexcept; + +} // namespace arch::meta::nameOfType diff --git a/include/meta/rtti/EnableRTTI.hpp b/include/meta/rtti/EnableRTTI.hpp new file mode 100644 index 0000000..85c88f2 --- /dev/null +++ b/include/meta/rtti/EnableRTTI.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include "StaticTypedesc.hpp" +#include + +#include + +/// @brief Unique RTTI type name macro for internal usage +#define _ARCH_RTTI_UNIQUE _RTTIUnique + +/// @brief Class attribute enabling typedesc() macro usage (requires THIS_T attribute to be set) +/// @brief Obsolete for non-polymorphic types +/// @see std::is_polymorphic_v +/// @details If not used, typedesc() will return incorrect TypeDescriptor when used on base class pointer or reference +#define EnableRTTI \ + \ +public: \ + /* Unique type used in RTTIEnabled concept */ \ + template> \ + struct _ARCH_RTTI_UNIQUE { \ + using Unique = _ARCH_THIS_T_UNIQUE; \ + }; \ + \ +private: \ + /* virtual method returning TypeDescriptor */ \ + virtual inline const arch::TypeDescriptor& _getTypeDescriptor() const noexcept { \ + static_assert(arch::meta::thisT::HasThisT, "EnableRTTI requires THIS_T(T) class attribute"); \ + return staticTypedesc(*this); \ + } \ + /* friend operator */ \ + template \ + friend const arch::meta::rtti::TypeDescriptor& \ + arch::meta::rtti::_details::operator*(const _ARCH_TEMPLATE_T&, const arch::meta::rtti::_details::Helper&) noexcept + diff --git a/include/meta/rtti/HashTypeName.h b/include/meta/rtti/HashTypeName.h new file mode 100644 index 0000000..207a07b --- /dev/null +++ b/include/meta/rtti/HashTypeName.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace arch::meta::rtti { +/// @brief Type name hashing function, guarantees same output on different machines +/// @details Uses cyclic polynomial method +/// @param typeName - type name to hash +size_t hashTypeName(std::string_view typeName) noexcept; +} // namespace arch::meta::rtti diff --git a/include/meta/rtti/RTTIEnabled.hpp b/include/meta/rtti/RTTIEnabled.hpp new file mode 100644 index 0000000..df7bfbc --- /dev/null +++ b/include/meta/rtti/RTTIEnabled.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +namespace arch::meta::rtti { + +/// @brief Concept that checks whether type is usable in Archimedes RTTI system +/// @brief Non-polymorphic types satisfy RTIIEnabled +template +concept RTTIEnabled = + (std::is_polymorphic_v ? std::same_as< + typename T::template _ARCH_RTTI_UNIQUE::Unique, + typename T::template _ARCH_RTTI_UNIQUE::Unique> and + std::same_as::type, + typename T::template _ARCH_RTTI_UNIQUE::Unique> : + true); + +} // namespace arch::meta::rtti diff --git a/include/meta/rtti/StaticTypedesc.hpp b/include/meta/rtti/StaticTypedesc.hpp new file mode 100644 index 0000000..5ced527 --- /dev/null +++ b/include/meta/rtti/StaticTypedesc.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +#include "TypeDescriptor.h" +#include "TypeDescriptorOwner.h" + +#define _ARCH_STATIC_TYPEDESC_IMPL(...) arch::meta::rtti::TypeDescriptorOwner::get() + +/// @brief Queries TypeDescriptor of given type, without usage of polymorphism +/// @param ... - type/expression which TypeDescriptor to access +#define staticTypedesc(...) _ARCH_STATIC_TYPEDESC_IMPL(__VA_ARGS__) diff --git a/include/meta/rtti/TypeDescriptor.h b/include/meta/rtti/TypeDescriptor.h new file mode 100644 index 0000000..a9575b9 --- /dev/null +++ b/include/meta/rtti/TypeDescriptor.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include + +namespace arch::meta::rtti { + +class TypeDescriptorWrapper; + +/// @brief Class containing type data +/// @brief It is guaranteed that only one TypeDescriptor exists per type +class TypeDescriptor { +public: + + /// @brief Standardized type name + std::string name; + /// @brief Size of type + size_t size; + /// @brief Alignment of type + size_t alignment; + /// @brief Standardized hash of name + /// @details Computed using cyclic polynomial rolling hash algorithm + size_t hash; + + /// @brief Equality operator + /// @param other - TypeDescriptor to compare + bool operator==(const TypeDescriptor& other) const noexcept; + /// @brief Equality operator + /// @param other - std::type_info to compare + bool operator==(const std::type_info& other) const noexcept; + /// @brief Comparision operator + /// @param other - TypeDescriptor to compare + std::strong_ordering operator<=>(const TypeDescriptor& other) const noexcept; + + /// @brief Wraps this TypeDescriptor + /// @return TypeDescriptorWrapper(*this) + TypeDescriptorWrapper wrap() const noexcept; + +private: + // used only by TypeDescriptorOwner + TypeDescriptor() = default; + + template + friend class TypeDescriptorOwner; + + const std::type_info* _typeid; +}; + +} // namespace arch::meta::rtti + +namespace arch::meta { +using rtti::TypeDescriptor; +} + +namespace arch { +using meta::TypeDescriptor; +} diff --git a/include/meta/rtti/TypeDescriptorOwner.h b/include/meta/rtti/TypeDescriptorOwner.h new file mode 100644 index 0000000..78fe85d --- /dev/null +++ b/include/meta/rtti/TypeDescriptorOwner.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +#include "TypeDescriptor.h" + +namespace arch::meta::rtti { +/// @brief Templated owner of TypeDescriptor +/// @tparam T - type which descriptor this class holds +template +class TypeDescriptorOwner { +public: + /// @brief Returns TypeDescriptor of T, initializes if not present + static const TypeDescriptor& get() noexcept; + +private: + static inline TypeDescriptor _desc; +}; +} // namespace arch::meta::rtti + +#include "TypeDescriptorOwner.hpp" diff --git a/include/meta/rtti/TypeDescriptorOwner.hpp b/include/meta/rtti/TypeDescriptorOwner.hpp new file mode 100644 index 0000000..7bf4fac --- /dev/null +++ b/include/meta/rtti/TypeDescriptorOwner.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "HashTypeName.h" +#include "TypeDescriptor.h" +#include "TypeDescriptorOwner.h" +#include + +namespace arch::meta::rtti { + +template +inline const TypeDescriptor& arch::meta::rtti::TypeDescriptorOwner::get() noexcept { + if (_desc.name.empty()) { // descriptor was not yet initialized + _desc.name = nameOfType(T); + _desc.size = sizeof(T); + _desc.alignment = alignof(T); + _desc.hash = hashTypeName(_desc.name); + _desc._typeid = &typeid(T); + } + + return _desc; +} + +template<> +inline const TypeDescriptor& arch::meta::rtti::TypeDescriptorOwner::get() noexcept { + // sizeof and alignof does not work for void + if (_desc.name.empty()) { // descriptor was not yet initialized + _desc.name = nameOfType(void); + _desc.size = 0; + _desc.alignment = 0; + _desc.hash = hashTypeName(_desc.name); + _desc._typeid = &typeid(void); + } + + return _desc; +} + +} // namespace arch::meta::rtti diff --git a/include/meta/rtti/TypeDescriptorWrapper.h b/include/meta/rtti/TypeDescriptorWrapper.h new file mode 100644 index 0000000..5abdbc7 --- /dev/null +++ b/include/meta/rtti/TypeDescriptorWrapper.h @@ -0,0 +1,65 @@ +#pragma once + +#include + +#include "TypeDescriptor.h" + +namespace arch::meta::rtti { + +class TypeDescriptor; + +/// @brief Wrapper class for TypeDescriptor +class TypeDescriptorWrapper { +public: + + /// @brief Descriptor constructor + /// @param desc - TypeDescriptor to set + TypeDescriptorWrapper(const TypeDescriptor& desc) noexcept; + /// @brief Default copy constructor + TypeDescriptorWrapper(const TypeDescriptorWrapper&) noexcept = default; + /// @brief Default move constructor + TypeDescriptorWrapper(TypeDescriptorWrapper&&) noexcept = default; + + /// @brief Descriptor assignment operator + /// @param desc - TypeDescriptor to set + TypeDescriptorWrapper& operator=(const TypeDescriptor& desc) noexcept; + /// @brief Default copy-assignment operator + TypeDescriptorWrapper& operator=(const TypeDescriptorWrapper&) noexcept = default; + /// @brief Default move-assignment operator + TypeDescriptorWrapper& operator=(TypeDescriptorWrapper&&) noexcept = default; + + /// @brief Equality operator + /// @param other - wrapper to compare + bool operator==(const TypeDescriptorWrapper& other) const noexcept; + /// @brief Comparision operator + /// @param other - wrapper to compare + std::strong_ordering operator<=>(const TypeDescriptorWrapper& other) const noexcept; + + /// @brief Returns held TypeDescriptor + const TypeDescriptor& get() const noexcept; + /// @brief Returns held TypeDescriptor + const TypeDescriptor& operator*() const noexcept; + + /// @brief Returns name from TypeDescriptor + std::string_view name() const noexcept; + /// @brief Returns size from TypeDescriptor + size_t size() const noexcept; + /// @brief Returns alignment from TypeDescriptor + size_t alignment() const noexcept; + /// @brief Returns hash from TypeDescriptor + size_t hash() const noexcept; + +private: + + const TypeDescriptor* _desc; +}; + +} // namespace arch::meta::rtti + +namespace arch::meta { +using rtti::TypeDescriptorWrapper; +} + +namespace arch { +using meta::TypeDescriptorWrapper; +} diff --git a/include/meta/rtti/TypeDescriptorWrapperHash.h b/include/meta/rtti/TypeDescriptorWrapperHash.h new file mode 100644 index 0000000..8f0f137 --- /dev/null +++ b/include/meta/rtti/TypeDescriptorWrapperHash.h @@ -0,0 +1,27 @@ +#pragma once + +#include "TypeDescriptor.h" + +/// @brief Specialization of std::hash, enabling usage of TypeDescriptorWrapper as key in hash containers +template<> +struct std::hash { +public: + /// @brief Default constructor. + hash() = default; + /// @brief Copy constructor. + hash(const hash&) = default; + /// @brief Move constructor. + hash(hash&&) = default; + + /// @brief Copy-assignment operator. + hash& operator=(const hash&) = default; + /// @brief Move-assignment operator. + hash& operator=(hash&&) = default; + + /// @brief Call operator + /// @param desc - TypeDescriptorWrapper to hash + /// @return desc.hash() + size_t operator()(const arch::meta::rtti::TypeDescriptorWrapper& desc) const noexcept; +}; + +// #include "TypeDesciptorWrapperHash.hpp" diff --git a/include/meta/rtti/Typedesc.h b/include/meta/rtti/Typedesc.h new file mode 100644 index 0000000..b6bce10 --- /dev/null +++ b/include/meta/rtti/Typedesc.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include + +#include "TypeDescriptor.h" + +namespace arch::meta::rtti::_details { + +/// @brief Helper struct of typedesc() macro +struct Helper { + /// @brief Pointer casting operator, used only for type deduction + /// @tparam T - type to which pointer cast to + /// @return nullptr + template + operator const T*() const noexcept; + /// @brief Reference casting operator, used only for type deduction + /// @tparam T - type to which refernce cast to + /// @return Casted (*this) + template + requires(not std::default_initializable) + operator const T&() const noexcept; + // #ifndef _MSC_VER // works without it on MSVC + /// @brief Casting operator, used only for type deduction + /// @tparam T - type to which refernce cast to + /// @return T() + template + operator T() const noexcept; + // #endif + /// @brief Helper dereference operator + /// @return (*this) + Helper operator*() const noexcept; +}; + +/// @brief Instance of Helper object +static inline constexpr Helper helper{}; + +/// @brief Helper multiplication operator +/// @brief If T is polymorphic and RTTIEnabled, obtains TypeDescriptor from lhs +/// @brief Else obtains TypeDescriptor by staticTypedesc(T) +/// @tparam T - type of lhs +/// @param lhs - object which TypeDescriptor to obtain +/// @param rhs - Helper object +template +const TypeDescriptor& operator*(const T& lhs, const Helper& rhs) noexcept; + +/// @brief Obtains TypeDescriptor of type pointed to by argument +/// @tparam T - type whose TypeDescriptor needs to be obtained +/// @param - pointer to object whose TypeDescriptor needs to be obtained. +/// @return Obtained TypeDescriptor +template +const TypeDescriptor& ptrToTypeDesc(const T*) noexcept; + +/// @brief Specialization of ptrToTypeDesc for TypeDescriptor, dereferences given TypeDescriptor +/// @param desc - TypeDescriptor to dereference +template<> +const TypeDescriptor& ptrToTypeDesc(const TypeDescriptor* desc) noexcept; + +/// @brief Const version of std::addressof +/// @tparam T - type of object to obtain address of +/// @param val - object to obtain address of +/// @return Pointer to val +template +const T* toPtr(const T& val) noexcept; + +} // namespace arch::meta::rtti::_details + +#include "Typedesc.hpp" diff --git a/include/meta/rtti/Typedesc.hpp b/include/meta/rtti/Typedesc.hpp new file mode 100644 index 0000000..be4f998 --- /dev/null +++ b/include/meta/rtti/Typedesc.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include "RTTIEnabled.hpp" +#include "StaticTypedesc.hpp" +#include + +#include "Typedesc.h" +#include + +namespace arch::meta::rtti::_details { + +template +Helper::operator const T*() const noexcept { + return (const T*)(nullptr); +} + +template +requires(not std::default_initializable) +Helper::operator const T&() const noexcept { + // this used to avoid null-reference + return (const T&)*(const T*)(this); +} + +template +Helper::operator T() const noexcept { + return T(); +} + +template +const TypeDescriptor& operator*(const T& lhs, const Helper& rhs) noexcept { + if constexpr (std::is_polymorphic_v and RTTIEnabled) { + const TypeDescriptor& td = lhs._getTypeDescriptor(); + if (td != typeid(lhs)) { + arch::Logger::error( + "typedesc(): '{}' reference points to object of not RTTIEnabled type", + staticTypedesc(T).name + ); + arch::Logger::info( + "hint: check types derived from '{}' for missing EnableRTTI attribute", + staticTypedesc(T).name + ); + } + + return td; + } else { + if constexpr (not RTTIEnabled) { + arch::Logger::warn("typedesc(): type '{}' is polymorphic, but not RTTIEnabled", staticTypedesc(T).name); + } + return staticTypedesc(T); + } +} + +template +const TypeDescriptor& ptrToTypeDesc(const T*) noexcept { + return staticTypedesc(T); +} + +template +const T* toPtr(const T& val) noexcept { + return std::addressof(val); +} + +} // namespace arch::meta::rtti::_details + +// if ... is a type -> cast helper to ..., obtain pointer, staticTypedesc of pointed type +// if ... is a object -> multiply ... by helper (obtain TypeDescriptor), convert it to pointer, dereference pointer +#define _ARCH_TYPEDESC_IMPL(...) \ + arch::meta::rtti::_details::ptrToTypeDesc( \ + arch::meta::rtti::_details::toPtr((__VA_ARGS__) * arch::meta::rtti::_details::helper) \ + ) + +/// @brief Queries TypeDescriptor of given type, may use polymorphism +/// @param ... - type/object which TypeDescriptor to access +#define typedesc(...) (_ARCH_TYPEDESC_IMPL(__VA_ARGS__)) diff --git a/include/meta/thisT/HasThisT.hpp b/include/meta/thisT/HasThisT.hpp new file mode 100644 index 0000000..2e95356 --- /dev/null +++ b/include/meta/thisT/HasThisT.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "ThisT.hpp" +#include + +namespace arch::meta::thisT { + +/// @brief Helper concept, which checks if T had THIS_T specified inside +template +concept HasThisT = requires { typename T::ThisT; }; + +} // namespace arch::meta::thisT diff --git a/include/meta/thisT/ThisT.hpp b/include/meta/thisT/ThisT.hpp new file mode 100644 index 0000000..7f3dc1d --- /dev/null +++ b/include/meta/thisT/ThisT.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "ThisTCheck.hpp" +#include "ThisTUnique.hpp" + +/// @brief Unique ThisT type name macro for internal usage +#define _ARCH_THIS_T ThisT + +/// @brief Class attribute creating alias ThisT for T inside class +#define THIS_T(T) \ + \ +private: \ + friend struct arch::meta::thisT::UniqueGetter; \ + /* Unique type */ \ + struct _ARCH_THIS_T_UNIQUE {}; \ + \ +public: \ + using _ARCH_THIS_T = T; \ + \ +private: \ + static_assert(arch::meta::thisT::ThisTCheck, "Used wrong type in THIS_T(T)") + diff --git a/include/meta/thisT/ThisTCheck.hpp b/include/meta/thisT/ThisTCheck.hpp new file mode 100644 index 0000000..92e2ce5 --- /dev/null +++ b/include/meta/thisT/ThisTCheck.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "ThisTUnique.hpp" +#include + +namespace arch::meta::thisT { + +/// @brief Helper concept, which checks if current class was specified in THIS_T(T) +/// @tparam T - T specified in THIS_T +/// @tparam Unique - struct _ThisTUnique from current class +template +concept ThisTCheck = std::same_as; + +} // namespace arch::meta::thisT diff --git a/include/meta/thisT/ThisTUnique.hpp b/include/meta/thisT/ThisTUnique.hpp new file mode 100644 index 0000000..857f01c --- /dev/null +++ b/include/meta/thisT/ThisTUnique.hpp @@ -0,0 +1,4 @@ +#pragma once + +/// @brief Unique ThisT type name macro for internal usage +#define _ARCH_THIS_T_UNIQUE _ThisTUnique diff --git a/include/meta/thisT/UniqueGetter.hpp b/include/meta/thisT/UniqueGetter.hpp new file mode 100644 index 0000000..4411672 --- /dev/null +++ b/include/meta/thisT/UniqueGetter.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "ThisT.hpp" + +namespace arch::meta::thisT { + +/// @brief Helper class used in RTTIEnabled concept +template +struct UniqueGetter { + using type = typename T::_ARCH_THIS_T_UNIQUE; +}; + +} // namespace arch::meta::thisT diff --git a/src/meta/nameOfType/NameOfTypeFmt.cpp b/src/meta/nameOfType/NameOfTypeFmt.cpp new file mode 100644 index 0000000..9821e6d --- /dev/null +++ b/src/meta/nameOfType/NameOfTypeFmt.cpp @@ -0,0 +1,508 @@ +#include +#include +#include + +#include + +namespace arch::meta::nameOfType { + +/// @brief Enum with types of tokens present in typeOf() result +enum TokenType { + white, // spaces + str, // string literals + strEnd, // end of string literal + ch, // character literals + chEnd, // end of character literal + forceStr, // force char in string literal + forceCh, // force char in char literal + alpha, // symbols + num, // numerical literals + fltExp, // exponential float + punct, // punctuation +}; + +/// @brief Returns TokenType of character c, depending on context +/// @param c - character to check +/// @param context - current TokenType +TokenType getTokenType(char c, TokenType context) { + if (isspace(c)) { + // 1. separator of tokens + // 2. inside char literal + // 3. inside string literal + if (context == white or context == alpha or context == num or context == punct) { // 1 + return white; + } else if (context == forceCh) { // 2 + return ch; + } else if (context == forceStr) { // 3 + return str; + } else { // 2, 3 + return context; + } + } else if (ispunct(c) and c != '_') { + if (c == '"') { // double quote character + // 1. beginning of string literal + // 2. ending of string literal + // 3. forced char in string literal + // 4. char in char literal + if (context == ch or context == forceCh) { // 4 + return ch; + } else if (context == str) { // 2 + return strEnd; + } else { // 1, 3 + return str; + } + } else if (c == '\'') { // quote character + // 1. beginning of char literal + // 2. ending of char literal + // 3. forced char in char literal + // 4. char in string literal + // 5. separator in numerical literal + if (context == str or context == forceStr) { // 4 + return str; + } else if (context == ch) { // 2 + return chEnd; + } else if (context == num) { // 5 + return num; + } else { // 1, 3 + return ch; + } + } else if (c == '\\') { + if (context == str) { + return forceStr; + } else if (context == ch) { + return forceCh; + } else if (context == forceStr) { + return str; + } else if (context == forceCh) { + return ch; + } + } else if (c == '+' or c == '-' and context == fltExp) { + return num; + } + if (c == '.' and context == num) { + return num; + } else if (context == white or context == alpha or context == punct) { + return punct; + } else if (context == str or context == forceStr) { + return str; + } else if (context == ch or context == forceCh) { + return ch; + } else { + return white; + } + } else if (isalpha(c) or c == '_') { + // 1. inside string + // 2. inside char + // 3. numerical literal + // 4. symbols + if (context == str or context == forceStr) { // 1 + return str; + } else if (context == ch or context == forceCh) { // 2 + return ch; + } else if (context == num) { // 3 + if (c == 'e' or c == 'E' or c == 'p' or c == 'P') { + return fltExp; + } + return num; + } else { // 4 + return alpha; + } + } else if (isdigit(c)) { + // 1. in string + // 2. in char + // 3. in symbol + // 4. in numerical string + if (context == str or context == forceStr) { // 1 + return str; + } else if (context == ch or context == forceCh) { // 2 + return ch; + } else if (context == alpha) { + return alpha; + } else { + return num; + } + } else { + return white; + } +} + +/// @brief Postition indicator of token +struct CurrentTokenT { + size_t begin; + size_t count; +}; + +/// @brief Parses given type name into tokens +/// @param name - type name to parse +/// @param tokens - vector to save tokens to +void parseTokens(std::string_view& name, std::vector& tokens) { + TokenType context = white; + CurrentTokenT currentToken{ 0, 0 }; + + // saves current token to vector and resets currentToken + auto saveToken = [&]() { + tokens.emplace_back(name.substr(currentToken.begin, currentToken.count)); + currentToken.begin += currentToken.count; + currentToken.count = 0; + context = white; + }; + + for (size_t i = 0; i != name.length(); ++i) { + TokenType type = getTokenType(name[i], context); + switch (context) { // context -> symbol + case white: // between tokens + switch (type) { // new symbol + case alpha: + case punct: + case str: + case ch: + case num: + context = type; + currentToken.begin = i; + currentToken.count = 1; + break; + } + break; + case str: + ++currentToken.count; + switch (type) { + case strEnd: saveToken(); break; + case forceStr: context = forceStr; break; + } + break; + case ch: + ++currentToken.count; + switch (type) { + case chEnd: saveToken(); break; + case forceCh: context = forceCh; break; + } + break; + case forceStr: + ++currentToken.count; + context = str; + break; + case forceCh: + ++currentToken.count; + context = ch; + break; + case num: + switch (type) { + case num: ++currentToken.count; break; + case fltExp: + ++currentToken.count; + context = fltExp; + break; + default: + saveToken(); + --i; + break; + } + break; + case fltExp: + switch (type) { + case num: + ++currentToken.count; + context = num; + break; + } + case punct: + switch (type) { + case punct: ++currentToken.count; break; + default: + saveToken(); + --i; + break; + } + break; + case alpha: + switch (type) { + case alpha: ++currentToken.count; break; + default: + saveToken(); + --i; + break; + } + break; + } + } + if (currentToken.count != 0) { + saveToken(); + } +} + +/// @brief Returns true if token is one of the following: +/// @brief struct, class, enum, constexpr, constinit, consteval +/// @param token - token to check +bool specifierErasePred(const std::string_view& token) { + return token == "struct" or token == "class" or token == "enum" or token == "constexpr" or token == "constinit" or + token == "consteval"; +} + +#define _ARCH_HANDLE_CV_IMPL(...) \ + (multitoken.contains("const") ? \ + (multitoken.contains("volatile") ? "const volatile " __VA_ARGS__ : "const " __VA_ARGS__) : \ + (multitoken.contains("volatile") ? "volatile " __VA_ARGS__ : "" __VA_ARGS__)) + +#define _ARCH_HANDLE_CV(...) _ARCH_HANDLE_CV_IMPL(__VA_ARGS__) + +/// @brief Standardizes order of combination of tokens that form one type +/// @details C++ standard says that ex. unsigned long long == long unsigned long +/// @param multitoken - multiset of tokens to standardize +/// @return Tokens in standardized order +std::string_view multitokenToToken(std::multiset& multitoken) { + if (multitoken.contains("char")) { + if (multitoken.contains("unsigned")) { + return _ARCH_HANDLE_CV("unsigned char"); + } else if (multitoken.contains("signed")) { + return _ARCH_HANDLE_CV("signed char"); + } else { + return _ARCH_HANDLE_CV("char"); + } + } else if (multitoken.contains("short")) { + if (multitoken.contains("unsigned")) { + return _ARCH_HANDLE_CV("unsigned short"); + } else { + return _ARCH_HANDLE_CV("short"); + } + } else if (multitoken.contains("long")) { + if (multitoken.count("long") == 1) { + if (multitoken.contains("double")) { + return _ARCH_HANDLE_CV("long double"); + } else if (multitoken.contains("unsigned")) { + return _ARCH_HANDLE_CV("unsigned long"); + } else { + return _ARCH_HANDLE_CV("long"); + } + } else { // count == 2 + if (multitoken.contains("unsigned")) { + return _ARCH_HANDLE_CV("unsigned long long"); + } else { + return _ARCH_HANDLE_CV("long long"); + } + } + } else if (multitoken.contains("int")) { + if (multitoken.contains("unsigned")) { + return _ARCH_HANDLE_CV("unsigned int"); + } else { + return _ARCH_HANDLE_CV("int"); + } + } else if (multitoken.contains("const")) { + if (multitoken.contains("volatile")) { + return "const volatile"; + } else { + return "const"; + } + } else if (multitoken.contains("volatile")) { + return "volatile"; + } else { + return ""; + } +} + +/// @brief Formats numerical values +/// @param token - numerical value to format +/// @param toReturn - string to append formatted value to +void fmtNumeric(std::string_view& token, std::string& toReturn) { + std::string formattedToken; + if (token.find('.') != token.npos) { // floating point literal + if (token.ends_with('f') or token.ends_with('F')) { // float + formattedToken = token; + formattedToken = std::to_string(std::stof(formattedToken)); + } else if (token.ends_with('l') or token.ends_with('L')) { // long double + formattedToken = token; + formattedToken = std::to_string(std::stold(formattedToken)); + } else { // double + formattedToken = token; + formattedToken = std::to_string(std::stod(formattedToken)); + } + } else { // integer literal + formattedToken = token; + formattedToken = std::to_string(std::stoull(formattedToken)); + } + + toReturn += formattedToken; +} + +/// @brief Formats string literal +/// @param tokens - vector of all tokens +/// @param i - index of current token +/// @param token - current token +/// @param toReturn - string to append formatted string to +void fmtString(std::vector& tokens, size_t i, std::string_view& token, std::string& toReturn) { + // processing literal type + if (i != 0) { + if (tokens[i - 1] == "L") { + toReturn.pop_back(); + toReturn += "wchar_t{"; + } else if (tokens[i - 1] == "u8") { + toReturn.pop_back(); + toReturn.pop_back(); + toReturn += "char8_t{"; + } else if (tokens[i - 1] == "u") { + toReturn.pop_back(); + toReturn += "char16_t{"; + } else if (tokens[i - 1] == "U") { + toReturn.pop_back(); + toReturn += "char32_t{"; + } else { + goto __addChar; + } + } else { +__addChar: + toReturn += "char{"; + } + + // appending chars + for (size_t j = 1; j != token.length() - 1; ++j) { + if (token[j] == '\\') { // escape sequence + std::string temp; + size_t processed; + switch (token[j + 1]) { + case '\'': toReturn += std::to_string(0x27) + ','; break; + case '\"': toReturn += std::to_string(0x22) + ','; break; + case '?': toReturn += std::to_string(0x3f) + ','; break; + case '\\': toReturn += std::to_string(0x5c) + ','; break; + case 'a': toReturn += std::to_string(0x07) + ','; break; + case 'b': toReturn += std::to_string(0x08) + ','; break; + case 'f': toReturn += std::to_string(0x0c) + ','; break; + case 'n': toReturn += std::to_string(0x0a) + ','; break; + case 'r': toReturn += std::to_string(0x0d) + ','; break; + case 't': toReturn += std::to_string(0x09) + ','; break; + case 'v': toReturn += std::to_string(0x0b) + ','; break; + case 'e': toReturn += std::to_string(0x1b) + ','; break; + case 'x': // hex literal + temp = token.substr(j + 2); + toReturn += std::to_string(std::stoull(temp, &processed, 16)) + ','; + j += processed + 1; + break; + case 'u': // unicode 4 digits + temp = token.substr(j + 2, 4); + toReturn += std::to_string(std::stoull(temp, nullptr, 16)) + ','; + j += 4 + 1; + break; + case 'U': // unicode 8 digits + temp = token.substr(j + 2, 8); + toReturn += std::to_string(std::stoull(temp, nullptr, 16)) + ','; + j += 8 + 1; + break; + default: // octal literal + temp = token.substr(j + 1, 3); + toReturn += std::to_string(std::stoull(temp, &processed, 8)) + ','; + j += processed; + break; + } + ++j; + } else { + toReturn += std::to_string((int)token[j]) + ','; + } + } + toReturn += "0}"; +} + +/// @brief Formats character literal +/// @param token - current token +/// @param toReturn - string to append formatted character to +void fmtChar(std::string_view& token, std::string& toReturn) { + for (size_t j = 1; j < token.length() - 1; ++j) { + if (token[j] == '\\') { // escape character + std::string temp; + size_t processed; + switch (token[j + 1]) { + case '\'': toReturn += 0x27; break; + case '\"': toReturn += 0x22; break; + case '?': toReturn += 0x3f; break; + case '\\': toReturn += 0x5c; break; + case 'a': toReturn += 0x07; break; + case 'b': toReturn += 0x08; break; + case 'f': toReturn += 0x0c; break; + case 'n': toReturn += 0x0a; break; + case 'r': toReturn += 0x0d; break; + case 't': toReturn += 0x09; break; + case 'v': toReturn += 0x0b; break; + case 'e': toReturn += 0x1b; break; + case 'x': // hex literal + temp = token.substr(j + 2); + toReturn += std::to_string(std::stoull(temp, &processed, 16)); + j += processed + 1; + break; + case 'u': // unicode 4 digits + temp = token.substr(j + 2, 4); + toReturn += std::to_string(std::stoull(temp, nullptr, 16)); + j += 4 + 1; + break; + case 'U': // unicode 8 digits + temp = token.substr(j + 2, 8); + toReturn += std::to_string(std::stoull(temp, nullptr, 16)); + j += 8 + 1; + break; + default: // octal literal + temp = token.substr(j + 1, 3); + toReturn += std::to_string(std::stoull(temp, &processed, 8)); + j += processed; + break; + } + ++j; + } else { + toReturn += std::to_string((int)token[j]); + } + } +} + +/// @brief Main formatting function +/// @param tokens - vector of tokens to format +/// @return Formatted type name +std::string finalFmt(std::vector& tokens) { + std::string toReturn; + std::multiset multitoken; + for (size_t i = 0; i != tokens.size(); ++i) { // format literals + auto&& token = tokens[i]; + if (isdigit(token[0])) { // format numerical literal + fmtNumeric(token, toReturn); + } else if (token[0] == '"') { // string literal + fmtString(tokens, i, token, toReturn); + } else if (token[0] == '\'') { // char literal + fmtChar(token, toReturn); + } else if (token == "true") { + toReturn += '1'; + } else if (token == "false") { + toReturn += '0'; + } else if (token == "signed" or token == "unsigned" or token == "char" or token == "short" or token == "int" or + token == "long" or token == "double" or token == "volatile" or token == "const") { + multitoken.insert(token); + } +#ifdef _MSC_VER // integer aliases used by MSVC + else if (token == "__int8") { + multitoken.insert("char"); + } else if (token == "__int16") { + multitoken.insert("short"); + } else if (token == "__int32") { + multitoken.insert("int"); + } else if (token == "__int64") { + multitoken.insert("long"); + multitoken.insert("long"); + } +#endif + else { + if (not multitoken.empty()) { + toReturn += multitokenToToken(multitoken); + multitoken.clear(); + } + toReturn += token; + } + } + if (not multitoken.empty()) { + toReturn += multitokenToToken(multitoken); + multitoken.clear(); + } + + return toReturn; +} + +std::string nameOfFmt(std::string_view name) noexcept { + std::vector tokens; + parseTokens(name, tokens); + std::erase_if(tokens, specifierErasePred); + return finalFmt(tokens); +} + +} // namespace arch::meta::nameOfType diff --git a/src/meta/rtti/HashNameType.cpp b/src/meta/rtti/HashNameType.cpp new file mode 100644 index 0000000..0969890 --- /dev/null +++ b/src/meta/rtti/HashNameType.cpp @@ -0,0 +1,19 @@ +#include + +namespace arch::meta::rtti { +size_t hashTypeName(std::string_view typeName) noexcept { + constexpr size_t m = (1ull << 61ull) - 1ull; // 2^61 - 1 + constexpr size_t p = 101; + + size_t result = 0; + + // cyclic polynomial method + for (size_t i = 0; i != typeName.length(); ++i) { + result ^= typeName[i]; + result *= p; + result %= m; + } + + return result; +} +} // namespace arch::meta::rtti diff --git a/src/meta/rtti/Helper.cpp b/src/meta/rtti/Helper.cpp new file mode 100644 index 0000000..c50520c --- /dev/null +++ b/src/meta/rtti/Helper.cpp @@ -0,0 +1,9 @@ +#include + +namespace arch::meta::rtti::_details { + +Helper Helper::operator*() const noexcept { + return const_cast(*this); +} + +} // namespace arch::meta::rtti::_details diff --git a/src/meta/rtti/TypeDesciptorWrapperHash.cpp b/src/meta/rtti/TypeDesciptorWrapperHash.cpp new file mode 100644 index 0000000..d9895b0 --- /dev/null +++ b/src/meta/rtti/TypeDesciptorWrapperHash.cpp @@ -0,0 +1,8 @@ +#include +#include + +size_t std::hash::operator()( + const arch::meta::rtti::TypeDescriptorWrapper& desc +) const noexcept { + return desc.hash(); +} diff --git a/src/meta/rtti/TypeDescriptor.cpp b/src/meta/rtti/TypeDescriptor.cpp new file mode 100644 index 0000000..6f477d7 --- /dev/null +++ b/src/meta/rtti/TypeDescriptor.cpp @@ -0,0 +1,23 @@ +#include +#include + +namespace arch::meta::rtti { +bool TypeDescriptor::operator==(const TypeDescriptor& other) const noexcept { + return this == &other; +} + +bool TypeDescriptor::operator==(const std::type_info& other) const noexcept { + return *_typeid == other; +} + +std::strong_ordering TypeDescriptor::operator<=>(const TypeDescriptor& other) const noexcept { + if (*this == other) { + return std::strong_ordering::equal; + } + return name <=> other.name; +} + +TypeDescriptorWrapper TypeDescriptor::wrap() const noexcept { + return TypeDescriptorWrapper(*this); +} +} // namespace arch::meta::rtti diff --git a/src/meta/rtti/TypeDescriptorWrapper.cpp b/src/meta/rtti/TypeDescriptorWrapper.cpp new file mode 100644 index 0000000..e84fb47 --- /dev/null +++ b/src/meta/rtti/TypeDescriptorWrapper.cpp @@ -0,0 +1,45 @@ +#include + +namespace arch::meta::rtti { + +TypeDescriptorWrapper::TypeDescriptorWrapper(const TypeDescriptor& desc) noexcept: _desc{ &desc } {} + +TypeDescriptorWrapper& arch::meta::rtti::TypeDescriptorWrapper::operator=(const TypeDescriptor& desc) noexcept { + _desc = &desc; + + return *this; +} + +bool TypeDescriptorWrapper::operator==(const TypeDescriptorWrapper& other) const noexcept { + return get() == other.get(); +} + +std::strong_ordering TypeDescriptorWrapper::operator<=>(const TypeDescriptorWrapper& other) const noexcept { + return get() <=> other.get(); +} + +const TypeDescriptor& TypeDescriptorWrapper::get() const noexcept { + return *_desc; +} + +const TypeDescriptor& TypeDescriptorWrapper::operator*() const noexcept { + return *_desc; +} + +std::string_view TypeDescriptorWrapper::name() const noexcept { + return _desc->name; +} + +size_t TypeDescriptorWrapper::size() const noexcept { + return _desc->size; +} + +size_t TypeDescriptorWrapper::alignment() const noexcept { + return _desc->alignment; +} + +size_t TypeDescriptorWrapper::hash() const noexcept { + return _desc->hash; +} + +} // namespace arch::meta::rtti diff --git a/src/meta/rtti/Typedesc.cpp b/src/meta/rtti/Typedesc.cpp new file mode 100644 index 0000000..7f6aad0 --- /dev/null +++ b/src/meta/rtti/Typedesc.cpp @@ -0,0 +1,10 @@ +#include + +namespace arch::meta::rtti::_details { + +template<> +const TypeDescriptor& ptrToTypeDesc(const TypeDescriptor* desc) noexcept { + return *desc; +} + +} // namespace arch::meta::rtti::_details diff --git a/tests/meta/rtti/EnableRTTI_Test.cpp b/tests/meta/rtti/EnableRTTI_Test.cpp new file mode 100644 index 0000000..d28a5a6 --- /dev/null +++ b/tests/meta/rtti/EnableRTTI_Test.cpp @@ -0,0 +1,47 @@ +#include +#include + +class FooBase { + THIS_T(FooBase); + EnableRTTI; + +public: + + virtual ~FooBase() noexcept = default; +}; + +class FooBase2 { + THIS_T(FooBase2); + // EnableRTTI; + +public: + + virtual ~FooBase2() noexcept = default; +}; + +class FooRTTIEnabled: public FooBase, public FooBase2 { + THIS_T(FooRTTIEnabled); + EnableRTTI; + +public: + + virtual ~FooRTTIEnabled() noexcept = default; +}; + +class FooRTTIDisabled: public FooBase, public FooBase2 { + THIS_T(FooRTTIDisabled); + // EnableRTTI; + +public: + + virtual ~FooRTTIDisabled() noexcept = default; +}; + +TEST(RTTITest, AttributeChecking) { + using arch::meta::rtti::RTTIEnabled; + + EXPECT_TRUE(RTTIEnabled); + EXPECT_FALSE(RTTIEnabled); + EXPECT_TRUE(RTTIEnabled); + EXPECT_FALSE(RTTIEnabled); +} diff --git a/tests/meta/rtti/ErrorsAndEquality_Test.cpp b/tests/meta/rtti/ErrorsAndEquality_Test.cpp new file mode 100644 index 0000000..4f14bd1 --- /dev/null +++ b/tests/meta/rtti/ErrorsAndEquality_Test.cpp @@ -0,0 +1,94 @@ +#include +#include + +class FooBase { + THIS_T(FooBase); + EnableRTTI; + +public: + + virtual ~FooBase() noexcept = default; +}; + +class FooBase2 { + THIS_T(FooBase2); + EnableRTTI; + +public: + + virtual ~FooBase2() noexcept = default; +}; + +class FooRTTIEnabled: public FooBase, public FooBase2 { + THIS_T(FooRTTIEnabled); + EnableRTTI; + +public: + + virtual ~FooRTTIEnabled() noexcept = default; +}; + +class FooRTTIDisabled: public FooBase, public FooBase2 { + THIS_T(FooRTTIDisabled); + // EnableRTTI; + +public: + + virtual ~FooRTTIDisabled() noexcept = default; +}; + +TEST(RTTITest, Typedesc) { + arch::Logger::init(arch::LogLevel::debug); + + FooRTTIEnabled fooRTTIEnabled; + FooRTTIDisabled fooRTTIDisabled; + + EXPECT_EQ(typedesc(fooRTTIEnabled), typedesc(FooRTTIEnabled)); + std::cout << "expected message:\n"; + EXPECT_EQ(typedesc(fooRTTIDisabled), typedesc(FooRTTIDisabled)); + + FooBase& fooBaseRTTIEnabled = fooRTTIEnabled; + FooBase& fooBaseRTTIDisabled = fooRTTIDisabled; + FooBase* fooBasePtrRTTIEnabled = &fooRTTIEnabled; + FooBase* fooBasePtrRTTIDisabled = &fooRTTIDisabled; + + EXPECT_EQ(typedesc(fooBaseRTTIEnabled), typedesc(FooRTTIEnabled)); + std::cout << "expected message:\n"; + EXPECT_NE(typedesc(fooBaseRTTIDisabled), typedesc(FooRTTIDisabled)); + std::cout << "expected message:\n"; + EXPECT_EQ(typedesc(fooBaseRTTIDisabled), typedesc(FooBase)); + + EXPECT_EQ(typedesc(*fooBasePtrRTTIEnabled), typedesc(FooRTTIEnabled)); + std::cout << "expected message:\n"; + EXPECT_NE(typedesc(*fooBasePtrRTTIDisabled), typedesc(FooRTTIDisabled)); + std::cout << "expected message:\n"; + EXPECT_EQ(typedesc(*fooBasePtrRTTIDisabled), typedesc(FooBase)); +} + +TEST(RTTITest, Typedesc2) { + arch::Logger::init(arch::LogLevel::debug); + + FooRTTIEnabled fooRTTIEnabled; + FooRTTIDisabled fooRTTIDisabled; + + EXPECT_EQ(typedesc(fooRTTIEnabled), typedesc(FooRTTIEnabled)); + std::cout << "expected message:\n"; + EXPECT_EQ(typedesc(fooRTTIDisabled), typedesc(FooRTTIDisabled)); + + FooBase2& fooBaseRTTIEnabled = fooRTTIEnabled; + FooBase2& fooBaseRTTIDisabled = fooRTTIDisabled; + FooBase2* fooBasePtrRTTIEnabled = &fooRTTIEnabled; + FooBase2* fooBasePtrRTTIDisabled = &fooRTTIDisabled; + + EXPECT_EQ(typedesc(fooBaseRTTIEnabled), typedesc(FooRTTIEnabled)); + std::cout << "expected message:\n"; + EXPECT_NE(typedesc(fooBaseRTTIDisabled), typedesc(FooRTTIDisabled)); + std::cout << "expected message:\n"; + EXPECT_EQ(typedesc(fooBaseRTTIDisabled), typedesc(FooBase2)); + + EXPECT_EQ(typedesc(*fooBasePtrRTTIEnabled), typedesc(FooRTTIEnabled)); + std::cout << "expected message:\n"; + EXPECT_NE(typedesc(*fooBasePtrRTTIDisabled), typedesc(FooRTTIDisabled)); + std::cout << "expected message:\n"; + EXPECT_EQ(typedesc(*fooBasePtrRTTIDisabled), typedesc(FooBase2)); +} diff --git a/tests/net/Host_Test.cpp b/tests/net/Host_Test.cpp index 6284d7d..e88c8bd 100644 --- a/tests/net/Host_Test.cpp +++ b/tests/net/Host_Test.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include TEST(Host, LocalHost) { // ~15ms arch::net::Init::init(); diff --git a/tests/net/IPv4Network_Test.cpp b/tests/net/IPv4Network_Test.cpp index 2c0a9ae..67586c2 100644 --- a/tests/net/IPv4Network_Test.cpp +++ b/tests/net/IPv4Network_Test.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include TEST(IPv4Mask, Get) { arch::net::IPv4Mask mask(23); diff --git a/tests/net/IPv4_Test.cpp b/tests/net/IPv4_Test.cpp index b86b1df..33db1cc 100644 --- a/tests/net/IPv4_Test.cpp +++ b/tests/net/IPv4_Test.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include TEST(IPv4, StringToBinary) { arch::net::IPv4 ip; diff --git a/tests/net/async/Host_Test.cpp b/tests/net/async/Host_Test.cpp index e970848..10a5e7b 100644 --- a/tests/net/async/Host_Test.cpp +++ b/tests/net/async/Host_Test.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include TEST(AsyncHost, LocalHost) { namespace net = arch::net;