diff options
-rw-r--r-- | icespider/core/Jamfile.jam | 4 | ||||
-rw-r--r-- | icespider/core/util-test.cpp | 12 | ||||
-rw-r--r-- | icespider/core/util.h | 71 |
3 files changed, 86 insertions, 1 deletions
diff --git a/icespider/core/Jamfile.jam b/icespider/core/Jamfile.jam index 15648b8..7b7bd19 100644 --- a/icespider/core/Jamfile.jam +++ b/icespider/core/Jamfile.jam @@ -2,9 +2,11 @@ lib adhocutil : : : : <include>/usr/include/adhocutil ; lib slicer : : : : <include>/usr/include/slicer ; lib stdc++fs ; +obj util-test : util-test.cpp ; + obj routeOptions : routeOptions.ice : <toolset>tidy:<checker>none ; lib icespider-core : - [ glob *.cpp ] + [ glob *.cpp : *-test.cpp ] routeOptions : <library>../common//icespider-common diff --git a/icespider/core/util-test.cpp b/icespider/core/util-test.cpp new file mode 100644 index 0000000..32a7c42 --- /dev/null +++ b/icespider/core/util-test.cpp @@ -0,0 +1,12 @@ +#include "util.h" + +namespace foo ::bar { + class really; +} + +static_assert(type_names<int>::name() == "int"); +static_assert(type_names<int>::namespaces() == 0); +static_assert(TypeName<int>::str() == "int"); +static_assert(type_names<foo::bar::really>::name() == "foo::bar::really"); +static_assert(type_names<foo::bar::really>::namespaces() == 2); +static_assert(TypeName<foo::bar::really>::str() == "foo.bar.really"); diff --git a/icespider/core/util.h b/icespider/core/util.h index 2089ce0..ca1350b 100644 --- a/icespider/core/util.h +++ b/icespider/core/util.h @@ -2,6 +2,8 @@ #define ICESPIDER_CORE_UTIL_H #include <Ice/Optional.h> +#include <array> +#include <string_view> namespace std::experimental::Ice { template<typename T, typename TF> @@ -37,4 +39,73 @@ orelse(const T & a, const T & b) return b; } +template<typename T> struct type_names { + static constexpr auto + pf() + { + return std::string_view {&__PRETTY_FUNCTION__[0], sizeof(__PRETTY_FUNCTION__)}; + } + + static constexpr auto + name() + { + const std::string_view with_T {"T = "}; + const auto start {pf().find(with_T) + with_T.length()}; + const auto end {pf().find(']', start)}; + return pf().substr(start, end - start); + } + + static constexpr auto + namespaces() + { + auto ns {0U}; + for (const auto & c : name()) { + // cppcheck-suppress useStlAlgorithm; (not constexpr) + ns += (c == ':') ? 1 : 0; + } + return ns / 2; + } + + using char_type = typename decltype(name())::value_type; +}; + +template<typename T> class TypeName : type_names<T> { +public: + constexpr static inline auto + str() + { + return std::string_view {buf.data(), buf.size() - 1}; + } + + constexpr static inline auto + c_str() + { + return buf.data(); + } + +private: + using tn = type_names<T>; + + constexpr static auto buf {[]() { + std::array<typename tn::char_type, tn::name().length() - tn::namespaces() + 1> buf {}; + auto out {buf.begin()}; + auto cln {false}; + for (const auto & in : tn::name()) { + if (in == ':') { + if (cln) { + *out++ = '.'; + } + else { + cln = true; + } + } + else { + *out++ = in; + cln = false; + } + } + return buf; + }()}; +}; + #endif |