Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeInfo: Nicer & platform-independent type names #24

Merged
merged 1 commit into from
Oct 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions src/tests/stuff.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,17 +228,22 @@ void testMaybe() {
}

void testTypeInfo() {
ASSERT_EQ(typeInfo<float const &>().name(), string("float const&"));
ASSERT_EQ(typeInfo<int volatile const &>().name(), string("int const volatile&"));
#ifndef FWK_PLATFORM_WINDOWS
// TODO: on windows pointers are named __ptr64 ...
ASSERT_EQ(typeInfo<vector<const int *> const &>().name(),
string("fwk::Vector<int const*> const&"));
ASSERT_EQ(typeInfo<float const &>().name(), "float const &");
ASSERT_EQ(typeInfo<int volatile const &>().name(), "int const volatile &");

ASSERT_EQ(typeInfo<vector<const int *> const &>().name(), "fwk::Vector<int const *> const &");
ASSERT_EQ(typeInfo<int const *const *&>().referenceBase()->pointerBase()->name(),
string("int const* const"));
ASSERT_EQ(typeInfo<double *volatile>().asConst().name(), string("double* const volatile"));
#endif
ASSERT_EQ(typeInfo<double &>().asConst().name(), string("double&"));
"int const *const");
ASSERT_EQ(typeInfo<double *volatile>().asConst().name(), "double *const volatile");
ASSERT_EQ(typeInfo<double &>().asConst().name(), "double &");

using PairType = Pair<string, int>;
using ArrayType = array<unsigned char, 32>;
ASSERT_EQ(typeInfo<PairType>().name(), "std::pair<std::string, int>");
ASSERT_EQ(typeInfo<ArrayType>().name(), "fwk::Array<unsigned char, 32>");
ASSERT_EQ(typeInfo<vector<vector<int>>>().name(), "fwk::Vector<fwk::Vector<int>>");
ASSERT_EQ(typeInfo<int const *const *&>().name(), "int const *const *&");
ASSERT_EQ(typeInfo<int const **&>().name(), "int const **&");
}

void testFwdMember() {
Expand Down
86 changes: 40 additions & 46 deletions src/type_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,52 +10,6 @@
#include <cxxabi.h>
#endif

/*
// Problems with __PRETTY_FUNCTION__:
// - different compilers give different results in __PRETTY_FUNCTION__
// - a bit longer compile times?
// - cxa_demangle should give similar results

// __PRETTY_FUNCTION__ based type names:
template <int N> struct FixedString {
constexpr FixedString(char const *s) {
for(int i = 0; i < N; i++)
buf[i] = s[i];
buf[N] = 0;
}
char buf[N + 1];
};

static constexpr const char *getName() {
char const *name = __PRETTY_FUNCTION__;
while(*name++ != '=')
;
while(*name == ' ')
name++;
return name;
}

static constexpr int getNameSize() {
auto start = getName();
auto end = start;
int bracketCount = 1;
for(;; ++end) {
if(*end == '[')
bracketCount++;
if(*end == ']') {
--bracketCount;
if(!bracketCount)
return end - start;
}
}
return {};
}

#ifdef __clang__
static constexpr FixedString<getNameSize()> name{getName()};
#endif
*/

namespace fwk {
namespace detail {

Expand All @@ -74,13 +28,23 @@ namespace detail {
return 0;
}();

static constexpr Pair<const char *> replacements[] = {
{"std::basic_string<char,std::char_traits<char>,std::allocator<char> >", "std::string"},
{"std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >",
"std::string"},
#ifdef FWK_PLATFORM_MSVC
{"* __ptr64", "*"}
#endif
};

void addTypeName(const TypeInfoData &data, const char *mangled_name) {
#ifdef FWK_PLATFORM_MSVC
string demangled_name;
int length = strlen(mangled_name);
demangled_name.reserve(length);
Pair<const char *, int> prefixes[] = {{"struct ", 7}, {"class ", 6}, {"enum ", 5}};

// Removing redundant MSVC-specific qualifiers
for(int i = 0; i < length; i++) {
bool prefix_matched = false;
if(i == 0 || (!isalnum(mangled_name[i - 1]) && mangled_name[i - 1] != '_'))
Expand Down Expand Up @@ -108,8 +72,38 @@ namespace detail {
is_volatile = data.reference_base->is_volatile;
}

// Adding missing qualifiers
string name = format("%%%%", demangled_name, is_const ? " const" : "",
is_volatile ? " volatile" : "", data.reference_base ? "&" : "");

// Replacing long substrings with shorter ones
for(auto &replacement : replacements) {
ZStr source = replacement.first;
while(true) {
auto it = name.find(source.c_str(), 0, source.size());
if(it == string::npos)
break;
name.replace(it, source.size(), replacement.second);
}
}

// Normalizing spaces around pointers & references and in template parameters
auto is_ident = [](char c) { return isalnum(c) || c == '_' || c == '$'; };
string new_name;
new_name.reserve(name.size());
for(size_t i = 0; i < name.size(); i++) {
char prev = i == 0 ? 0 : name[i - 1];
char cur = name[i], next = i + 1 < name.size() ? name[i + 1] : 0;

if(cur == ' ' && ((prev == '*' || prev == '&') || (prev == '>' && next == '>')))
continue;
if(((cur == '*' || cur == '&') && (is_ident(prev) || prev == '>')) ||
(prev == ',' && cur != ' '))
new_name += ' ';
new_name += cur;
}
name.swap(new_name);

#ifndef FWK_PLATFORM_MSVC
free(demangled_name);
#endif
Expand Down
Loading