Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RTTI + Build time optimization #103

Merged
merged 15 commits into from
May 2, 2024
5 changes: 2 additions & 3 deletions cmake/library.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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})
2 changes: 1 addition & 1 deletion cmake/msvc.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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()
7 changes: 7 additions & 0 deletions include/Meta.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

#include "meta/Typeof.hpp"

#include "meta/NameOfType.h"
#include "meta/Rtti.h"
#include "meta/ThisT.h"
File renamed without changes.
4 changes: 4 additions & 0 deletions include/meta/NameOfType.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once

#include "nameOfType/NameOfType.h"
#include "nameOfType/NameOfTypeFmt.h"
12 changes: 12 additions & 0 deletions include/meta/Rtti.h
Original file line number Diff line number Diff line change
@@ -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"
7 changes: 7 additions & 0 deletions include/meta/ThisT.h
Original file line number Diff line number Diff line change
@@ -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"
32 changes: 32 additions & 0 deletions include/meta/Typeof.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include <type_traits>

namespace arch::meta::typeOf {
/// @brief Helper struct of typeof() macro
/// @brief (does nothing)
struct Helper {
Chris-plusplus marked this conversation as resolved.
Show resolved Hide resolved
/// @brief Helper casting operator
/// @brief (does nothing)
template<class T>
operator T() const;
/// @brief Helper dereference operator
/// @brief (does nothing)
Helper operator*();
};

/// @brief Helper multiplication operator
/// @brief (does nothing)
template<class T>
const T& operator*(const T&, Helper);
} // namespace arch::meta::typeOf

// if ... is a type -> dereference Helper, cast to ..., obtain decltype of result
// if ... is an expression -> multiply ... by Helper, obtain decltype of result
#define _typeofImpl(...) \
/* evil operator* and cast semantic level hacking */ \
std::remove_cvref_t<decltype((__VA_ARGS__) * arch::meta::typeOf::Helper{})>

/// @brief Queries non-const, non-reference type of expression or type given
/// @param x - type or expression to query
#define typeof(...) _typeofImpl(__VA_ARGS__)
Twarug marked this conversation as resolved.
Show resolved Hide resolved
20 changes: 20 additions & 0 deletions include/meta/nameOfType/NameOfType.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include <source_location>
#include <string_view>

namespace arch::meta::nameOfType {

/// @brief Helper function, which signature is used to determine name of type
template<class T>
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<class T>
constexpr std::string_view nameOf() noexcept;

} // namespace arch::meta::nameOfType

#include "NameOfType.hpp"
63 changes: 63 additions & 0 deletions include/meta/nameOfType/NameOfType.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#pragma once

#include <source_location>

#include "NameOfType.h"

namespace arch::meta::nameOfType {

/// @brief signature<T>() Specialization returning signature with 'int'
template<>
constexpr std::string_view signature<int>() noexcept {
// Major compilers do not return simply name of function: 'signature'
// but its signature: 'std::basic_string_view<...> signature<int>() 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<class T>
constexpr std::string_view nameOf() noexcept {
constexpr auto intSignature = signature<int>();
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__
__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 _nameOfTypeImpl(x) arch::meta::nameOfType::nameOf<x>()
Twarug marked this conversation as resolved.
Show resolved Hide resolved
/// @brief Returns nonstandardized name of given type (constexpr)
#define nameOfTypeNoFmt(x) _nameOfTypeImpl(x)
Twarug marked this conversation as resolved.
Show resolved Hide resolved
/// @brief Returns standardized name of given type (runtime only)
#define nameOfType(x) arch::meta::nameOfType::nameOfTypeFmt(nameOfTypeNoFmt(x))
Chris-plusplus marked this conversation as resolved.
Show resolved Hide resolved
11 changes: 11 additions & 0 deletions include/meta/nameOfType/NameOfTypeFmt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include <string>

namespace arch::meta::nameOfType {

/// @brief Standardises names returned by nameOf<T>()
/// @param name - name to standardize
std::string nameOfTypeFmt(std::string_view name) noexcept;

} // namespace arch::meta::nameOfType
34 changes: 34 additions & 0 deletions include/meta/rtti/EnableRTTI.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include "StaticTypedesc.hpp"
#include <concepts>

#include <meta/ThisT.h>

/// @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 \
Twarug marked this conversation as resolved.
Show resolved Hide resolved
\
public: \
/* Unique type used in RTTIEnabled concept */ \
template<std::same_as<_ARCH_THIS_T>> \
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<typeof(*this)>, "EnableRTTI requires THIS_T(T) class attribute"); \
return static_typedesc(*this); \
} \
/* friend operator */ \
template<class _ARCH_TEMPLATE_T> \
friend const arch::meta::rtti::TypeDescriptor& \
arch::meta::rtti::operator*(const _ARCH_TEMPLATE_T&, const arch::meta::rtti::Helper&) noexcept

10 changes: 10 additions & 0 deletions include/meta/rtti/HashTypeName.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include <string_view>

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
19 changes: 19 additions & 0 deletions include/meta/rtti/RTTIEnabled.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include <concepts>
#include <meta/thisT/UniqueGetter.hpp>

namespace arch::meta::rtti {

/// @brief Concept that checks whether type is usable in Archimedes RTTI system
/// @brief Non-polymorphic types satisfy RTIIEnabled
template<class T>
concept RTTIEnabled =
(std::is_polymorphic_v<T> ? std::same_as<
typename T::template _ARCH_RTTI_UNIQUE<T>::Unique,
typename T::template _ARCH_RTTI_UNIQUE<T>::Unique> and
std::same_as<typename arch::meta::thisT::UniqueGetter<T>::type,
typename T::template _ARCH_RTTI_UNIQUE<T>::Unique> :
true);

} // namespace arch::meta::rtti
12 changes: 12 additions & 0 deletions include/meta/rtti/StaticTypedesc.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#include <meta/Typeof.hpp>

#include "TypeDescriptor.h"
#include "TypeDescriptorOwner.h"

#define _staticTypedescImpl(...) arch::meta::rtti::TypeDescriptorOwner<typeof(__VA_ARGS__)>::get()

/// @brief Queries TypeDescriptor of given type, without usage of polymorphism
/// @param ... - type/expression which TypeDescriptor to access
#define static_typedesc(...) _staticTypedescImpl(__VA_ARGS__)
Chris-plusplus marked this conversation as resolved.
Show resolved Hide resolved
Chris-plusplus marked this conversation as resolved.
Show resolved Hide resolved
56 changes: 56 additions & 0 deletions include/meta/rtti/TypeDescriptor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#pragma once

#include <compare>
#include <string>
#include <typeinfo>

namespace arch {
namespace meta {
namespace rtti {
Chris-plusplus marked this conversation as resolved.
Show resolved Hide resolved
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<class T>
friend class TypeDescriptorOwner;

const std::type_info* _typeid;
};
} // namespace rtti

using rtti::TypeDescriptor;
} // namespace meta

using meta::TypeDescriptor;
} // namespace arch
22 changes: 22 additions & 0 deletions include/meta/rtti/TypeDescriptorOwner.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <memory>
#include <string>

#include "TypeDescriptor.h"

namespace arch::meta::rtti {
/// @brief Templated owner of TypeDescriptor
/// @tparam T - type which descriptor this class holds
template<class T>
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"
37 changes: 37 additions & 0 deletions include/meta/rtti/TypeDescriptorOwner.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once

#include "HashTypeName.h"
#include "TypeDescriptor.h"
#include "TypeDescriptorOwner.h"
#include <meta/NameOfType.h>

namespace arch::meta::rtti {

template<class T>
inline const TypeDescriptor& arch::meta::rtti::TypeDescriptorOwner<T>::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<void>::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
Loading
Loading