// license:BSD-3-Clause // copyright-holders:Couriersud /// /// \file test_penum.cpp /// /// tests for penum /// #include "plib/putil.h" #include "plib/pexception.h" #include "plib/pstring.h" #include #include #include #if 0 namespace plib { template struct functor { using is_defined = std::false_type; }; template struct functor_base { public: using is_defined = std::true_type; using size = std::integral_constant; constexpr operator E () const noexcept { return m_v; } constexpr functor_base(const E v) noexcept : m_v(v) { }; protected: constexpr functor_base(const char *s, const char * const vals[size::value]) noexcept : m_v(E::PENUM_UNKNOWN) { for (std::size_t i = 0; i < size::value; i++) if (vals[i] == s) { m_v = static_cast(i); return; } } E m_v; private: //static constexpr const char *m_str[PNARGS(__VA_ARGS__)] = { PSTRINGIFY_VA(__VA_ARGS__) }; }; } // namespace plib #define PENUM(ename, ...) \ enum class ename { __VA_ARGS__ , PENUM_UNKNOWN }; \ PENUM_FUNCTOR(ename, __VA_ARGS__) #define PENUM_NS(ns, ename, ...) \ namespace ns { enum class ename { __VA_ARGS__ , PENUM_UNKNOWN }; } \ PENUM_FUNCTOR(ns :: ename, __VA_ARGS__) #define PENUM_FUNCTOR(ename, ...) \ template <> struct plib::functor : plib::functor_base \ { \ public: \ using plib::functor_base::functor_base; \ constexpr functor(const char *s) noexcept : functor_base(s, m_str) { } \ constexpr operator const char * () const noexcept { return m_str[static_cast(m_v)]; } \ private: \ static constexpr const char *m_str[3] = { PSTRINGIFY_VA(__VA_ARGS__) }; \ }; #else #if 1 namespace plib::enum_static { template struct functor_static { using is_defined = std::false_type; using size = std::integral_constant; static constexpr const char *m_str[1] = { "" }; }; } // namespace plib::enum_static #endif namespace plib { template struct functor { public: using staticf = enum_static::functor_static; using is_defined = typename staticf::is_defined; using size = typename staticf::size; constexpr functor(const E v) noexcept : m_v(v) { } constexpr functor(const char *s) noexcept : m_v(E::PENUM_UNKNOWN) { for (std::size_t i = 0; i < size::value; i++) if (staticf::m_str[i] == s) { m_v = static_cast(i); return; } } constexpr operator const char * () const noexcept { return staticf::m_str[static_cast(m_v)]; } constexpr operator E () const noexcept { return m_v; } protected: E m_v; private: //static constexpr const char *m_str[PNARGS(__VA_ARGS__)] = { PSTRINGIFY_VA(__VA_ARGS__) }; }; // template deduction guide template functor(E) -> functor; template static inline typename std::enable_if::is_defined::value, const char *>::type penum_to_string(E e) { using staticf = enum_static::functor_static; return staticf::m_str[static_cast(e)]; } template static inline typename std::enable_if::is_defined::value, E>::type string_to_penum(const char *s) { using staticf = enum_static::functor_static; for (std::size_t i = 0; i < staticf::size::value; i++) if (staticf::m_str[i] == s) return static_cast(i); return E::PENUM_UNKNOWN; } } // namespace plib #define PENUM(ename, ...) \ enum class ename { __VA_ARGS__ , PENUM_UNKNOWN }; \ PENUM_FUNCTOR(ename, __VA_ARGS__) #define PENUM_NS(ns, ename, ...) \ namespace ns { enum class ename { __VA_ARGS__ , PENUM_UNKNOWN }; } \ PENUM_FUNCTOR(ns :: ename, __VA_ARGS__) #define PENUM_FUNCTOR(ename, ...) \ namespace plib::enum_static { \ template <> struct functor_static \ { \ public: \ using is_defined = std::true_type; \ using size = std::integral_constant; \ static constexpr const char *m_str[size::value] = { PSTRINGIFY_VA(__VA_ARGS__) }; \ }; \ } // namespace plib::enum_static #endif template typename std::enable_if::value && plib::enum_static::functor_static::is_defined::value, O&>::type operator << (O& os, const E &p) { os << static_cast(plib::functor(p)); return os; } #if 1 template inline typename std::enable_if::is_defined::value, bool>::type operator == (const char * lhs, const E &rhs) { return lhs == plib::functor(rhs); } template inline typename std::enable_if::is_defined::value, bool>::type operator == (const E &lhs, const char * rhs) { return lhs == plib::functor(rhs); } #endif // --------------------------------------- template struct ret_t { bool success; T value; }; template constexpr ret_t stl_h(std::string_view sv) { T r(0); for (const auto &c : sv) { if (c >= '0' && c < '0' + std::min(10,BASE)) { r = r * BASE + (c - '0'); } else if (c >= 'A' && c < ('A' + BASE - 10)) { r = r * BASE + (10 + c - 'A'); } else if (c >= 'a' && c < ('a' + BASE - 10)) { r = r * BASE + (10 + c - 'a'); } else return { false, T(0) }; } return { true, r }; } template constexpr ret_t stl(std::string_view sv) { if constexpr (BASE == 0) { if (sv.size() > 2) { if (sv.substr(0,2) == "0x" || sv.substr(0,2) == "0X") return stl_h(sv.substr(2)); if (sv.substr(0,2) == "0b") return stl_h(sv.substr(2)); } if (sv.size() > 1 && sv.substr(0,1) == "0" ) return stl_h(sv.substr(1)); return stl_h(sv); } return stl_h(sv); } #include "plib/ptests.h" //PENUM_NS(plibx, teste, A, B, C) namespace plibx { enum class teste; } PENUM(plibx::teste, A, B, C) enum class pure { X, Y }; PENUM(testf, A, B, C) PTEST(penum, conversion) { static_assert(stl("0xa0bc").success,"no"); static_assert(stl("0xa0bc").value==0xa0bc,"no"); static_assert(stl("0b1010").value==0b1010,"no"); static_assert(stl("0123").value==0123,"no"); //const auto x(stl("123")); //static_assert(x.value==123,"no"); plibx::teste x = plib::functor("A"); PEXPECT_NE(x, plibx::teste::B); PEXPECT_NE(plib::functor("A"), plibx::teste::B); PEXPECT_NE(plib::functor("A"), testf::B); //PEXPECT_EQ(plib::functor("A"), testf::B); PEXPECT_EQ(testf::B, "B"); PEXPECT_EQ("A", testf::A); PEXPECT_NE(plib::functor(testf::A), "B"); PEXPECT_FALSE(plib::functor::is_defined::value); PEXPECT_EQ(plib::penum_to_string(testf::B), "B"); PEXPECT_NE(plib::string_to_penum("B"), testf::A); //PEXPECT_EQ(pure::X, pure::Y); }