From 3e0bc52c32a2a7ae2c6ca0adc2c85a2131c9dbb5 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 29 Sep 2021 19:13:12 +0300 Subject: [PATCH] Add --- include/boost/core/type_name.hpp | 412 +++++++++++++++++++++++++++++++ test/Jamfile.v2 | 2 + test/type_name_test.cpp | 153 ++++++++++++ 3 files changed, 567 insertions(+) create mode 100644 include/boost/core/type_name.hpp create mode 100644 test/type_name_test.cpp diff --git a/include/boost/core/type_name.hpp b/include/boost/core/type_name.hpp new file mode 100644 index 0000000..6b139a2 --- /dev/null +++ b/include/boost/core/type_name.hpp @@ -0,0 +1,412 @@ +#ifndef BOOST_CORE_TYPE_NAME_HPP_INCLUDED +#define BOOST_CORE_TYPE_NAME_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// std::string boost::core::type_name() +// +// Copyright 2021 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ +namespace core +{ + +namespace detail +{ + +// tn_identity + +template struct tn_identity +{ + typedef T type; +}; + +// typeid_name + +template std::string typeid_name() +{ + std::string r = boost::core::demangle( typeid(T).name() ); + +#if defined(_MSC_VER) + + if( r.substr( 0, 6 ) == "class " ) + { + r = r.substr( 6 ); + } + + if( r.substr( 0, 7 ) == "struct " ) + { + r = r.substr( 7 ); + } + +#endif + + return r; +} + +// tn_to_string + +#if defined(BOOST_MSVC) +# pragma warning( push ) +# pragma warning( disable: 4996 ) +#endif + +inline std::string tn_to_string( unsigned long n ) +{ + char buffer[ 32 ]; + std::sprintf( buffer, "%lu", n ); + + return buffer; +} + +#if defined(BOOST_MSVC) +# pragma warning( pop ) +#endif + +// template names + +template std::string class_template_name() +{ + std::string r = typeid_name(); + return r.substr( 0, r.find( '<' ) ); +} + +template std::string sequence_template_name() +{ + return class_template_name(); +} + +template std::string set_template_name() +{ + return class_template_name(); +} + +template std::string map_template_name() +{ + return class_template_name(); +} + +// tn_add_each + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +template int tn_add_each_impl( std::string& st ) +{ + if( !st.empty() ) st += ", "; + st += type_name( tn_identity() ); + return 0; +}; + +template std::string tn_add_each() +{ + std::string st; + + using A = int[ sizeof...(T) + 1 ]; + (void)A{ 0, tn_add_each_impl( st )... }; + + return st; +}; + +#endif + +// primary + +template std::string type_name( tn_identity ) +{ + return typeid_name(); +} + +// cv + +template std::string type_name( tn_identity ) +{ + return type_name( tn_identity() ) + " const"; +} + +template std::string type_name( tn_identity ) +{ + return type_name( tn_identity() ) + " volatile"; +} + +template std::string type_name( tn_identity ) +{ + return type_name( tn_identity() ) + " const volatile"; +} + +// refs + +template std::string type_name( tn_identity ) +{ + return type_name( tn_identity() ) + "&"; +} + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + +template std::string type_name( tn_identity ) +{ + return type_name( tn_identity() ) + "&&"; +} + +#endif + +// function types + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +template std::string type_name( tn_identity ) +{ + return type_name( tn_identity() ) + '(' + tn_add_each() + ')'; +} + +#endif + +// pointers + +template std::string type_name( tn_identity ) +{ + return type_name( tn_identity() ) + "*"; +} + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +// function pointers + +template std::string type_name( tn_identity ) +{ + return type_name( tn_identity() ) + "(*)(" + tn_add_each() + ')'; +} + +template std::string type_name( tn_identity ) +{ + return type_name( tn_identity() ) + "(*&)(" + tn_add_each() + ')'; +} + +template std::string type_name( tn_identity ) +{ + return type_name( tn_identity() ) + "(* const)(" + tn_add_each() + ')'; +} + +template std::string type_name( tn_identity ) +{ + return type_name( tn_identity() ) + "(* const&)(" + tn_add_each() + ')'; +} + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + +template std::string type_name( tn_identity ) +{ + return type_name( tn_identity() ) + "(*&&)(" + tn_add_each() + ')'; +} + +template std::string type_name( tn_identity ) +{ + return type_name( tn_identity() ) + "(* const&&)(" + tn_add_each() + ')'; +} + +#endif + +#endif + +// arrays + +template std::pair array_prefix_suffix( tn_identity ) +{ + return std::pair( type_name( tn_identity() ), "" ); +} + +template std::pair array_prefix_suffix( tn_identity ) +{ + std::pair r = array_prefix_suffix( tn_identity() ); + + r.second = '[' + tn_to_string( static_cast( N ) ) + ']' + r.second; + + return r; +} + +template std::string array_type_name( tn_identity ) +{ + std::pair r = array_prefix_suffix( tn_identity() ); + return r.first + "[]" + r.second; +} + +template std::string type_name( tn_identity ) +{ + return array_type_name( tn_identity() ); +} + +template std::string type_name( tn_identity ) +{ + return array_type_name( tn_identity() ); +} + +template std::string type_name( tn_identity ) +{ + return array_type_name( tn_identity() ); +} + +template std::string type_name( tn_identity ) +{ + return array_type_name( tn_identity() ); +} + +template std::string array_type_name( tn_identity ) +{ + std::pair r = array_prefix_suffix( tn_identity() ); + return r.first + r.second; +} + +template std::string type_name( tn_identity ) +{ + return array_type_name( tn_identity() ); +} + +template std::string type_name( tn_identity ) +{ + return array_type_name( tn_identity() ); +} + +template std::string type_name( tn_identity ) +{ + return array_type_name( tn_identity() ); +} + +template std::string type_name( tn_identity ) +{ + return array_type_name( tn_identity() ); +} + +// nullptr_t + +#if !defined(BOOST_NO_CXX11_NULLPTR) + +inline std::string type_name( tn_identity ) +{ + return "std::nullptr_t"; +} + +#endif + +// strings + +inline std::string type_name( tn_identity ) +{ + return "std::string"; +} + +inline std::string type_name( tn_identity ) +{ + return "std::wstring"; +} + +#if !defined(BOOST_NO_CXX11_CHAR16_T) + +inline std::string type_name( tn_identity ) +{ + return "std::u16string"; +} + +#endif + +#if !defined(BOOST_NO_CXX11_CHAR32_T) + +inline std::string type_name( tn_identity ) +{ + return "std::u32string"; +} + +#endif + +#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L + +inline std::string type_name( tn_identity ) +{ + return "std::u8string"; +} + +#endif + +// class templates + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +template class L, class... T> std::string type_name( tn_identity< L > ) +{ + std::string tn = class_template_name< L >(); + std::string st = tn_add_each(); + + return tn + '<' + st + '>'; +} + +#endif + +// sequence containers + +template class L, class T> std::string type_name( tn_identity< L > > ) +{ + std::string tn = sequence_template_name< L > >(); + return tn + '<' + type_name( tn_identity() ) + '>'; +} + +// set + +template class L, class T> std::string type_name( tn_identity< L, std::allocator > > ) +{ + std::string tn = set_template_name< L, std::allocator > >(); + return tn + '<' + type_name( tn_identity() ) + '>'; +} + +// map + +template class L, class T, class U> std::string type_name( tn_identity< L, std::allocator > > > ) +{ + std::string tn = map_template_name< L, std::allocator > > >(); + return tn + '<' + type_name( tn_identity() ) + ", " + type_name( tn_identity() ) + '>'; +} + +#if !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) + +// unordered_set + +template class L, class T> std::string type_name( tn_identity< L, std::equal_to, std::allocator > > ) +{ + std::string tn = set_template_name< L, std::equal_to, std::allocator > >(); + return tn + '<' + type_name( tn_identity() ) + '>'; +} + +// unordered_map + +template class L, class T, class U> std::string type_name( tn_identity< L, std::equal_to, std::allocator > > > ) +{ + std::string tn = map_template_name< L, std::equal_to, std::allocator > > >(); + return tn + '<' + type_name( tn_identity() ) + ", " + type_name( tn_identity() ) + '>'; +} + +#endif + +} // namespace detail + +template std::string type_name() +{ + return core::detail::type_name( core::detail::tn_identity() ); +} + +} // namespace core +} // namespace boost + +#endif // #ifndef BOOST_CORE_TYPE_NAME_HPP_INCLUDED diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 867c99c..63f516f 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -245,5 +245,7 @@ run bit_ceil_test.cpp ; run bit_popcount_test.cpp ; run bit_endian_test.cpp ; +run type_name_test.cpp ; + use-project /boost/core/swap : ./swap ; build-project ./swap ; diff --git a/test/type_name_test.cpp b/test/type_name_test.cpp new file mode 100644 index 0000000..6381a22 --- /dev/null +++ b/test/type_name_test.cpp @@ -0,0 +1,153 @@ +// Copyright 2021 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) +# include +#endif + +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP) +# include +#endif + +// + +#define TEST(...) BOOST_TEST_EQ((boost::core::type_name<__VA_ARGS__>()), std::string(#__VA_ARGS__)) + +struct A +{ +}; + +class B +{ +}; + +template struct X +{ +}; + +int main() +{ + TEST(int); + + TEST(A); + TEST(B); + + TEST(A const); + TEST(A volatile); + TEST(A const volatile); + + TEST(B&); + TEST(B const&); + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + + TEST(B&&); + TEST(B const&&); + +#endif + + TEST(void); + TEST(void const); + TEST(void volatile); + TEST(void const volatile); + + TEST(A*); + TEST(B const* volatile*); + + TEST(void*); + TEST(void const* volatile*); + + TEST(A[]); + TEST(A const[]); + TEST(A volatile[]); + TEST(A const volatile[]); + + TEST(B[1]); + TEST(B const[1]); + TEST(B volatile[1]); + TEST(B const volatile[1]); + + TEST(A[][2][3]); + TEST(A const[][2][3]); + + TEST(B[1][2][3]); + TEST(B const volatile[1][2][3]); + +#if !defined(BOOST_NO_CXX11_NULLPTR) + + TEST(std::nullptr_t); + +#endif + + TEST(std::pair); + TEST(std::pair volatile&); + + TEST(std::string); + TEST(std::wstring); + +#if BOOST_CXX_VERSION >= 201100L + + TEST(std::u16string); + TEST(std::u32string); + +#endif + +#if BOOST_CXX_VERSION >= 202000L + + TEST(std::u8string); + +#endif + + TEST(X); + TEST(X volatile&); + + TEST(std::vector); + TEST(std::vector); + TEST(std::vector); + + TEST(std::list); + TEST(std::list); + TEST(std::list); + + TEST(std::deque); + TEST(std::deque); + TEST(std::deque); + + TEST(std::set); + TEST(std::set); + TEST(std::set); + + TEST(std::map); + TEST(std::map); + TEST(std::map const*> const&); + +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) + + TEST(std::unordered_set); + TEST(std::unordered_set); + +#endif + +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP) + + TEST(std::unordered_map); + TEST(std::unordered_map); + TEST(std::unordered_map*>); + +#endif + + return boost::report_errors(); +}