-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement a c++20 constexpr type demangler
- Loading branch information
Showing
2 changed files
with
89 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,96 @@ | ||
/* Copyright 2022 Andrea Bocci, Antonio Di Pilato | ||
/* Copyright 2025 Andrea Bocci, Simeon Ehrig | ||
* SPDX-License-Identifier: MPL-2.0 | ||
*/ | ||
|
||
/* | ||
* C++20 compile-time demangled type name, based on | ||
* https://www.reddit.com/r/cpp/comments/lfi6jt/finally_a_possibly_portable_way_to_convert_types/ | ||
* https://rodusek.com/posts/2021/03/09/getting-an-unmangled-type-name-at-compile-time/ | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include "alpaka/core/BoostPredef.hpp" | ||
#include <array> | ||
#ifdef __cpp_lib_source_location | ||
# include <source_location> | ||
#endif | ||
#include <string_view> | ||
#include <utility> | ||
|
||
namespace | ||
{ | ||
// Generate a function name with full type signature that includes the user-provided type name. | ||
// Use the compiler-specific extensions for known compilers because nvc++ does not include the full type signature | ||
// in std::source_location::current().function_name() . | ||
template<typename T> | ||
consteval std::string_view embedTypeName() | ||
{ | ||
#if defined(__GNUC__) || defined(__clang__) || defined(__PGI) || defined(__NVCOMPILER) | ||
// gcc, clang, PGI, nvc++ | ||
return __PRETTY_FUNCTION__; | ||
#elif defined(_MSC_VER) | ||
// MSVC | ||
return __FUNCSIG__; | ||
#elif defined(__cpp_lib_source_location) | ||
// unknown compiler, use the c++20 standard function_name() | ||
return std::source_location::current().function_name(); | ||
#else | ||
// std::source_location is not supported, fail | ||
# error \ | ||
"This compiler is not recognised and it does not support std::source_location. Please add explicit support to \"alpaka/core/DemangleTypeNames.hpp\"." | ||
#endif | ||
} | ||
|
||
// Convert a string_view to a null-terminated array of bytes. | ||
template<std::size_t... Idxs> | ||
consteval auto substringAsArray(std::string_view str, std::index_sequence<Idxs...>) | ||
{ | ||
// Add null termination | ||
return std::array{str[Idxs]..., '\0'}; | ||
} | ||
|
||
// Use a fundamental type to detect the prefix and suffix, because MSVC includes the class, struct, or union | ||
// keyword in the type signature. | ||
using TestPatternType = double; | ||
|
||
constexpr std::string_view testPatternName("double"); | ||
|
||
#include <boost/core/demangle.hpp> | ||
// Embed the demangled type name into a function signature, then extract it and return it as a null-terminated | ||
// array of bytes. | ||
template<typename T> | ||
consteval auto demangleAsArray() | ||
{ | ||
constexpr std::string_view testPatternText = embedTypeName<TestPatternType>(); | ||
constexpr size_t prefixSize = testPatternText.find(testPatternName); | ||
constexpr size_t suffixSize = testPatternText.size() - prefixSize - testPatternName.size(); | ||
constexpr std::string_view text = embedTypeName<T>(); | ||
constexpr size_t start = prefixSize; | ||
constexpr size_t end = text.size() - suffixSize; | ||
static_assert(start < end); | ||
constexpr size_t length = end - start; | ||
constexpr std::string_view name = text.substr(start, length); | ||
return substringAsArray(name, std::make_index_sequence<name.size()>{}); | ||
} | ||
|
||
// Store the demangled type name as a null-terminated array of bytes. | ||
// Note: this could be a function-static constexpr variable in c++23. | ||
template<typename T> | ||
inline constexpr auto storage = demangleAsArray<T>(); | ||
|
||
// Return the demangled type name. | ||
template<typename T> | ||
consteval std::string_view demangle() | ||
{ | ||
return std::string_view{storage<T>.data(), storage<T>.size()}; | ||
} | ||
|
||
} // namespace | ||
|
||
namespace alpaka::core | ||
{ | ||
#if BOOST_COMP_CLANG | ||
# pragma clang diagnostic push | ||
# pragma clang diagnostic ignored "-Wexit-time-destructors" | ||
# pragma clang diagnostic ignored "-Wmissing-variable-declarations" | ||
#endif | ||
|
||
// constexpr template string_view that contains the demangled type name. | ||
template<typename T> | ||
inline const std::string demangled = boost::core::demangle(typeid(T).name()); | ||
#if BOOST_COMP_CLANG | ||
# pragma clang diagnostic pop | ||
#endif | ||
inline constexpr std::string_view demangled = demangle<T>(); | ||
|
||
} // namespace alpaka::core |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters