diff --git a/Source/Engine/Utilities/Nameof.h b/Source/Engine/Utilities/Nameof.h new file mode 100644 index 000000000..8a50b7e39 --- /dev/null +++ b/Source/Engine/Utilities/Nameof.h @@ -0,0 +1,95 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Core/Types/StringView.h" + +// Helper utility to get type name at compile time. Example: +// constexpr StringAnsiView name = Nameof::Get() + +namespace Nameof +{ + // [Reference: https://github.com/Neargye/nameof] + constexpr StringAnsiView PrettyName(StringAnsiView name) noexcept + { + if (name.Length() >= 1 && (name.Get()[0] == '"' || name.Get()[0] == '\'')) + return {}; + if (name.Length() >= 2 && name.Get()[0] == 'R' && (name.Get()[1] == '"' || name.Get()[1] == '\'')) + return {}; + if (name.Length() >= 2 && name.Get()[0] == 'L' && (name.Get()[1] == '"' || name.Get()[1] == '\'')) + return {}; + if (name.Length() >= 2 && name.Get()[0] == 'U' && (name.Get()[1] == '"' || name.Get()[1] == '\'')) + return {}; + if (name.Length() >= 2 && name.Get()[0] == 'u' && (name.Get()[1] == '"' || name.Get()[1] == '\'')) + return {}; + if (name.Length() >= 3 && name.Get()[0] == 'u' && name.Get()[1] == '8' && (name.Get()[2] == '"' || name.Get()[2] == '\'')) + return {}; + if (name.Length() >= 1 && (name.Get()[0] >= '0' && name.Get()[0] <= '9')) + return {}; + for (int32 i = name.Length(), h = 0, s = 0; i > 0; --i) + { + if (name.Get()[i - 1] == ')') + { + ++h; + ++s; + continue; + } + if (name.Get()[i - 1] == '(') + { + --h; + ++s; + continue; + } + if (h == 0) + { + name = StringAnsiView(*name, name.Length() - s); + break; + } + ++s; + } + int32 s = 0; + for (int32 i = name.Length(), h = 0; i > 0; --i) + { + if (name.Get()[i - 1] == '>') + { + ++h; + ++s; + continue; + } + if (name.Get()[i - 1] == '<') + { + --h; + ++s; + continue; + } + if (h == 0) + break; + ++s; + } + for (int32 i = name.Length() - s; i > 0; --i) + { + if (!((name.Get()[i - 1] >= '0' && name.Get()[i - 1] <= '9') || (name.Get()[i - 1] >= 'a' && name.Get()[i - 1] <= 'z') || (name.Get()[i - 1] >= 'A' && name.Get()[i - 1] <= 'Z') || (name.Get()[i - 1] == '_'))) + { + name = StringAnsiView(*name + i, name.Length() - i); + break; + } + } + name = StringAnsiView(*name, name.Length() - s); + if (name.Length() > 0 && ((name.Get()[0] >= 'a' && name.Get()[0] <= 'z') || (name.Get()[0] >= 'A' && name.Get()[0] <= 'Z') || (name.Get()[0] == '_'))) + return name; + return {}; + } + + // Gets the type name as constant expression (compile-time string) + template + constexpr StringAnsiView Get() noexcept + { +#if defined(__clang__) || defined(__GNUC__) + return PrettyName(StringAnsiView(__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2)); +#elif defined(_MSC_VER) + return PrettyName(StringAnsiView(__FUNCSIG__, sizeof(__FUNCSIG__) - 17)); +#else +#error "Unsupported compiler." +#endif + } +}