diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index 2739674..109ab61 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -1016,6 +1016,49 @@ namespace std }; } +namespace meta_hpp::detail +{ + namespace impl + { + template < typename T > + struct name_of_wrapper_impl {}; + + template < typename T > + [[nodiscard]] constexpr std::string_view name_of_impl() noexcept { +#if META_HPP_DETAIL_COMPILER_ID == META_HPP_DETAIL_CLANG_COMPILER_ID + constexpr auto prefix = std::string_view{"[T = "}; + constexpr auto suffix = std::string_view{"]"}; + constexpr auto fnsign = std::string_view{__PRETTY_FUNCTION__}; +#elif META_HPP_DETAIL_COMPILER_ID == META_HPP_DETAIL_GCC_COMPILER_ID + constexpr auto prefix = std::string_view{"with T = "}; + constexpr auto suffix = std::string_view{"]"}; + constexpr auto fnsign = std::string_view{__PRETTY_FUNCTION__}; +#elif META_HPP_DETAIL_COMPILER_ID == META_HPP_DETAIL_MSVC_COMPILER_ID + constexpr auto prefix = std::string_view{"name_of_wrapper_impl<"}; + constexpr auto suffix = std::string_view{">>(void)"}; + constexpr auto fnsign = std::string_view{__FUNCSIG__}; +#else + constexpr auto prefix = std::string_view{"<"}; + constexpr auto suffix = std::string_view{">"}; + constexpr auto fnsign = std::string_view{""}; +#endif + constexpr auto b = fnsign.find(prefix) + prefix.size(); + constexpr auto e = fnsign.rfind(suffix); + static_assert(b < e); + + auto n = fnsign.substr(b, e - b); + n.remove_prefix(std::min(n.find_first_not_of(' '), n.size())); + n.remove_suffix(std::min(n.size() - n.find_last_not_of(' ') - 1, n.size())); + return n; + } + } + + template < typename T > + [[nodiscard]] constexpr std::string_view name_of() noexcept { + return impl::name_of_impl>(); + } +} + namespace meta_hpp::detail { class noncopyable { diff --git a/develop/untests/meta_base/name_of_tests.cpp b/develop/untests/meta_base/name_of_tests.cpp new file mode 100644 index 0000000..8edaf4f --- /dev/null +++ b/develop/untests/meta_base/name_of_tests.cpp @@ -0,0 +1,44 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/meta.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2021-2023, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include +#include + +namespace meta_tests_ns +{ + struct A { + int member{42}; + int add(int) {return 42;} + static int sub(int) { return 42;} + }; + + enum class E {}; +} + +TEST_CASE("meta/meta_base/name_of") { + namespace meta = meta_hpp; + using meta::detail::name_of; + +#if META_HPP_DETAIL_COMPILER_ID == META_HPP_DETAIL_MSVC_COMPILER_ID + CHECK(name_of() == "enum meta_tests_ns::E"); + + CHECK(name_of() == "struct meta_tests_ns::A"); + CHECK(name_of() == "struct meta_tests_ns::A [0]"); + CHECK(name_of() == "struct meta_tests_ns::A *"); + CHECK(name_of() == "struct meta_tests_ns::A &"); + CHECK(name_of() == "struct meta_tests_ns::A const &"); + + CHECK(name_of() == "int (__cdecl meta_tests_ns::A::*)(int)"); + CHECK(name_of() == "int (__cdecl*)(int)"); + CHECK(name_of() == "int meta_tests_ns::A::*"); + + CHECK(name_of() == "int"); + CHECK(name_of() == "float"); + + CHECK(name_of() == "void"); + CHECK(name_of() == "void const"); +#endif +} diff --git a/headers/meta.hpp/meta_base.hpp b/headers/meta.hpp/meta_base.hpp index 6312f06..58c0169 100644 --- a/headers/meta.hpp/meta_base.hpp +++ b/headers/meta.hpp/meta_base.hpp @@ -18,6 +18,7 @@ #include "meta_base/insert_or_assign.hpp" #include "meta_base/is_in_place_type.hpp" #include "meta_base/memory_buffer.hpp" +#include "meta_base/name_of.hpp" #include "meta_base/noncopyable.hpp" #include "meta_base/nonesuch.hpp" #include "meta_base/overloaded.hpp" diff --git a/headers/meta.hpp/meta_base/name_of.hpp b/headers/meta.hpp/meta_base/name_of.hpp new file mode 100644 index 0000000..0b19314 --- /dev/null +++ b/headers/meta.hpp/meta_base/name_of.hpp @@ -0,0 +1,52 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/meta.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2021-2023, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#pragma once + +#include "base.hpp" + +namespace meta_hpp::detail +{ + namespace impl + { + template < typename T > + struct name_of_wrapper_impl {}; + + template < typename T > + [[nodiscard]] constexpr std::string_view name_of_impl() noexcept { +#if META_HPP_DETAIL_COMPILER_ID == META_HPP_DETAIL_CLANG_COMPILER_ID + constexpr auto prefix = std::string_view{"[T = "}; + constexpr auto suffix = std::string_view{"]"}; + constexpr auto fnsign = std::string_view{__PRETTY_FUNCTION__}; +#elif META_HPP_DETAIL_COMPILER_ID == META_HPP_DETAIL_GCC_COMPILER_ID + constexpr auto prefix = std::string_view{"with T = "}; + constexpr auto suffix = std::string_view{"]"}; + constexpr auto fnsign = std::string_view{__PRETTY_FUNCTION__}; +#elif META_HPP_DETAIL_COMPILER_ID == META_HPP_DETAIL_MSVC_COMPILER_ID + constexpr auto prefix = std::string_view{"name_of_wrapper_impl<"}; + constexpr auto suffix = std::string_view{">>(void)"}; + constexpr auto fnsign = std::string_view{__FUNCSIG__}; +#else + constexpr auto prefix = std::string_view{"<"}; + constexpr auto suffix = std::string_view{">"}; + constexpr auto fnsign = std::string_view{""}; +#endif + constexpr auto b = fnsign.find(prefix) + prefix.size(); + constexpr auto e = fnsign.rfind(suffix); + static_assert(b < e); + + auto n = fnsign.substr(b, e - b); + n.remove_prefix(std::min(n.find_first_not_of(' '), n.size())); + n.remove_suffix(std::min(n.size() - n.find_last_not_of(' ') - 1, n.size())); + return n; + } + } + + template < typename T > + [[nodiscard]] constexpr std::string_view name_of() noexcept { + return impl::name_of_impl>(); + } +}