Commit 86ec30e9 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

pretty_name

Summary:
[Folly] `pretty_name`, for getting static type pretty-names without RTTI.

Available as constant expressions - no runtime overhead.

Depends on per-platform non-specified magic symbols. May not work everywhere.

Reviewed By: aary

Differential Revision: D14019723

fbshipit-source-id: e50557261024298cd37957b94dad3a10c927ee97
parent ff5f718e
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <typeinfo>
#include <utility> #include <utility>
#include <double-conversion/double-conversion.h> // V8 JavaScript implementation #include <double-conversion/double-conversion.h> // V8 JavaScript implementation
...@@ -45,6 +44,7 @@ ...@@ -45,6 +44,7 @@
#include <folly/Traits.h> #include <folly/Traits.h>
#include <folly/Unit.h> #include <folly/Unit.h>
#include <folly/lang/Exception.h> #include <folly/lang/Exception.h>
#include <folly/lang/Pretty.h>
#include <folly/portability/Math.h> #include <folly/portability/Math.h>
namespace folly { namespace folly {
...@@ -1335,11 +1335,7 @@ convertTo(const Src& value) noexcept { ...@@ -1335,11 +1335,7 @@ convertTo(const Src& value) noexcept {
template <typename Tgt, typename Src> template <typename Tgt, typename Src>
inline std::string errorValue(const Src& value) { inline std::string errorValue(const Src& value) {
#if FOLLY_HAS_RTTI return to<std::string>("(", pretty_name<Tgt>(), ") ", value);
return to<std::string>("(", demangle(typeid(Tgt)), ") ", value);
#else
return to<std::string>(value);
#endif
} }
template <typename Tgt, typename Src> template <typename Tgt, typename Src>
......
...@@ -43,7 +43,7 @@ TEST(AsyncFunc, void_lambda) { ...@@ -43,7 +43,7 @@ TEST(AsyncFunc, void_lambda) {
auto lambda = [] { /*do something*/ return; }; auto lambda = [] { /*do something*/ return; };
auto future = async(lambda); auto future = async(lambda);
// Futures with a void returning function, return Unit type // Futures with a void returning function, return Unit type
EXPECT_EQ(typeid(Unit), typeid(std::move(future).get())); EXPECT_TRUE((std::is_same<Unit, decltype(std::move(future).get())>::value));
} }
TEST(AsyncFunc, moveonly_lambda) { TEST(AsyncFunc, moveonly_lambda) {
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <folly/executors/InlineExecutor.h> #include <folly/executors/InlineExecutor.h>
#include <folly/futures/detail/Core.h> #include <folly/futures/detail/Core.h>
#include <folly/lang/Pretty.h>
namespace folly { namespace folly {
...@@ -29,7 +30,7 @@ namespace detail { ...@@ -29,7 +30,7 @@ namespace detail {
template <typename T> template <typename T>
void coreDetachPromiseMaybeWithResult(Core<T>& core) { void coreDetachPromiseMaybeWithResult(Core<T>& core) {
if (!core.hasResult()) { if (!core.hasResult()) {
core.setResult(Try<T>(exception_wrapper(BrokenPromise(typeid(T).name())))); core.setResult(Try<T>(exception_wrapper(BrokenPromise(pretty_name<T>()))));
} }
core.detachPromise(); core.detachPromise();
} }
......
/*
* Copyright 2019-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <cstddef>
#include <folly/Portability.h>
namespace folly {
namespace detail {
template <std::size_t S>
struct pretty_carray {
char data[S];
};
template <std::size_t S>
static constexpr pretty_carray<S> pretty_carray_from(char const (&in)[S]) {
pretty_carray<S> out{};
for (std::size_t i = 0; i < S; ++i) {
out.data[i] = in[i];
}
return out;
}
struct pretty_info {
std::size_t b;
std::size_t e;
};
template <typename To, std::size_t S>
static constexpr To pretty_info_to(pretty_info info, char const (&name)[S]) {
return To(name + info.b, info.e - info.b);
}
template <std::size_t S>
static constexpr std::size_t pretty_lfind(
char const (&haystack)[S],
char const needle) {
for (std::size_t i = 0; i < S - 1; ++i) {
if (haystack[i] == needle) {
return i;
}
}
return ~std::size_t(0);
}
template <std::size_t S>
static constexpr std::size_t pretty_rfind(
char const (&haystack)[S],
char const needle) {
for (std::size_t i = S; i != 0; --i) {
if (haystack[i - 1] == needle) {
return i - 1;
}
}
return ~std::size_t(0);
}
template <typename T>
static constexpr auto pretty_raw() {
#if _MSC_VER
return pretty_carray_from(__FUNCSIG__);
#else
return pretty_carray_from(__PRETTY_FUNCTION__);
#endif
}
template <std::size_t S>
static constexpr pretty_info pretty_parse_msc(char const (&name)[S]) {
// void __cdecl folly::detail::pretty_raw<{...}>(void)
auto const la = pretty_lfind(name, '<');
auto const rp = pretty_rfind(name, '>');
return pretty_info{la + 1, rp};
}
template <std::size_t S>
static constexpr pretty_info pretty_parse_gcc(char const (&name)[S]) {
// void folly::detail::pretty_raw() [T = {...}]
auto const eq = pretty_lfind(name, '=');
auto const br = pretty_rfind(name, ']');
return pretty_info{eq + 2, br};
}
template <std::size_t S>
static constexpr pretty_info pretty_parse(char const (&name)[S]) {
return kMscVer ? detail::pretty_parse_msc(name)
: detail::pretty_parse_gcc(name);
}
template <typename T>
struct pretty_name_zarray {
static constexpr auto raw = pretty_raw<T>();
static constexpr auto info = pretty_parse(raw.data);
static constexpr auto size = info.e - info.b;
static constexpr pretty_carray<size + 1> zarray_() {
pretty_carray<size + 1> data{};
for (std::size_t i = 0; i < size; ++i) {
data.data[i] = raw.data[info.b + i];
}
data.data[size] = 0;
return data;
}
static constexpr pretty_carray<size + 1> zarray = zarray_();
};
template <typename T>
constexpr pretty_carray<pretty_name_zarray<T>::size + 1>
pretty_name_zarray<T>::zarray;
} // namespace detail
// pretty_name
//
// Returns a statically-allocated C string containing the pretty name of T.
//
// The pretty name of a type varies by compiler, may include tokens which
// would not be present in the type name as it is spelled in the source code
// or as it would be symbolized, and may not include tokens which would be
// present in the type name as it would be symbolized.
template <typename T>
constexpr char const* pretty_name() {
return detail::pretty_name_zarray<T>::zarray.data;
}
} // namespace folly
...@@ -21,23 +21,12 @@ ...@@ -21,23 +21,12 @@
#include <string> #include <string>
#include <folly/Portability.h> #include <folly/Portability.h>
#include <folly/lang/Pretty.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
template <typename Ex>
static std::string type_pretty_name() {
auto const name = __PRETTY_FUNCTION__;
auto const size = std::strlen(name);
auto const eq = std::find(name, name + size, '=');
auto const sc = std::find(name, name + size, ';');
auto const br = std::find(name, name + size, ']');
auto const bpos = name + size - eq >= 2 ? eq + 2 : name + size;
auto const epos = std::min(sc, br);
return epos < bpos ? "" : std::string(bpos, epos - bpos);
}
template <typename Ex> template <typename Ex>
static std::string message_for_terminate_with(std::string const& what) { static std::string message_for_terminate_with(std::string const& what) {
auto const name = type_pretty_name<Ex>(); auto const name = folly::pretty_name<Ex>();
auto const prefix = auto const prefix =
std::string("terminate called after throwing an instance of "); std::string("terminate called after throwing an instance of ");
// clang-format off // clang-format off
......
/*
* Copyright 2019-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/lang/Pretty.h>
#include <folly/portability/GTest.h>
namespace folly {
class PrettyTest : public testing::Test {};
TEST_F(PrettyTest, example) {
constexpr auto const name = pretty_name<int>();
EXPECT_STREQ("int", name);
}
TEST_F(PrettyTest, example_msc) {
constexpr auto const& name = "void __cdecl foo<int>(void)";
constexpr auto const info = detail::pretty_parse_msc(name);
EXPECT_EQ("int", detail::pretty_info_to<std::string>(info, name));
}
TEST_F(PrettyTest, example_gcc) {
constexpr auto const& name = "void foo() [T = int]";
constexpr auto const info = detail::pretty_parse_gcc(name);
EXPECT_EQ("int", detail::pretty_info_to<std::string>(info, name));
}
} // namespace folly
...@@ -1032,9 +1032,7 @@ namespace { ...@@ -1032,9 +1032,7 @@ namespace {
template <typename T, typename V> template <typename T, typename V>
std::string prefixWithType(V value) { std::string prefixWithType(V value) {
std::ostringstream oss; std::ostringstream oss;
#if FOLLY_HAS_RTTI oss << "(" << pretty_name<T>() << ") ";
oss << "(" << demangle(typeid(T)) << ") ";
#endif
oss << to<std::string>(value); oss << to<std::string>(value);
return oss.str(); return oss.str();
} }
......
...@@ -194,7 +194,7 @@ void clause11_21_4_2_k(String& test) { ...@@ -194,7 +194,7 @@ void clause11_21_4_2_k(String& test) {
EXPECT_EQ(s.size(), size); EXPECT_EQ(s.size(), size);
FOR_EACH_RANGE (i, 0, s.size()) { s[i] = random('a', 'z'); } FOR_EACH_RANGE (i, 0, s.size()) { s[i] = random('a', 'z'); }
test = std::move(s); test = std::move(s);
if (typeid(String) == typeid(fbstring)) { if (std::is_same<String, fbstring>::value) {
EXPECT_LE(s.size(), 128); EXPECT_LE(s.size(), 128);
} }
} }
...@@ -381,7 +381,7 @@ void clause11_21_4_6_3_a(String& test) { ...@@ -381,7 +381,7 @@ void clause11_21_4_6_3_a(String& test) {
EXPECT_EQ(test, s); EXPECT_EQ(test, s);
// move assign // move assign
test.assign(std::move(s)); test.assign(std::move(s));
if (typeid(String) == typeid(fbstring)) { if (std::is_same<String, fbstring>::value) {
EXPECT_LE(s.size(), 128); EXPECT_LE(s.size(), 128);
} }
} }
......
...@@ -179,7 +179,6 @@ THOUGHTS: ...@@ -179,7 +179,6 @@ THOUGHTS:
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <typeinfo>
#include <boost/iterator/iterator_adaptor.hpp> #include <boost/iterator/iterator_adaptor.hpp>
#include <boost/preprocessor.hpp> #include <boost/preprocessor.hpp>
...@@ -187,6 +186,7 @@ THOUGHTS: ...@@ -187,6 +186,7 @@ THOUGHTS:
#include <folly/Conv.h> #include <folly/Conv.h>
#include <folly/Portability.h> #include <folly/Portability.h>
#include <folly/ScopeGuard.h> #include <folly/ScopeGuard.h>
#include <folly/lang/Pretty.h>
#include <folly/portability/GFlags.h> #include <folly/portability/GFlags.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
...@@ -1042,7 +1042,7 @@ struct PrettyType { ...@@ -1042,7 +1042,7 @@ struct PrettyType {
if (is_same<T, uint64_t>::value) { if (is_same<T, uint64_t>::value) {
return "uint64_t"; return "uint64_t";
} }
return typeid(T).name(); return pretty_name<T>();
} }
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment