Skip to content

Commit

Permalink
Implement a c++20 constexpr type demangler
Browse files Browse the repository at this point in the history
  • Loading branch information
fwyzard committed Feb 2, 2025
1 parent 78eee52 commit 90105cf
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 14 deletions.
97 changes: 85 additions & 12 deletions include/alpaka/core/DemangleTypeNames.hpp
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
6 changes: 4 additions & 2 deletions include/alpaka/kernel/TaskKernelGpuUniformCudaHipRt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "alpaka/workdiv/WorkDivMembers.hpp"

#include <stdexcept>
#include <string>
#include <tuple>
#include <type_traits>

Expand Down Expand Up @@ -291,8 +292,9 @@ namespace alpaka
}
if constexpr(ALPAKA_DEBUG >= ALPAKA_DEBUG_MINIMAL)
{
auto const msg
= std::string{"execution of kernel '" + core::demangled<TKernelFnObj> + "' failed with"};
using namespace std::literals;
std::string const msg
= "execution of kernel '"s + std::string(core::demangled<TKernelFnObj>) + "' failed with"s;
::alpaka::uniform_cuda_hip::detail::rtCheckLastError<TApi, true>(msg.c_str(), __FILE__, __LINE__);
}
}
Expand Down

0 comments on commit 90105cf

Please sign in to comment.