parse/enum: allow translation of enum string to integer with typeidx

This commit is contained in:
Danny Robson 2019-05-30 12:33:28 +10:00
parent 5e3af7f8fb
commit cc7d4eb0a9
4 changed files with 66 additions and 22 deletions

View File

@ -11,7 +11,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
namespace cruft::parse::detail::enumeration { namespace cruft::parse::enumeration::detail {
std::map<int, std::unique_ptr<lookup_base>>& std::map<int, std::unique_ptr<lookup_base>>&
cache (void) cache (void)
{ {

View File

@ -14,8 +14,8 @@
#include <map> #include <map>
namespace cruft::parse { namespace cruft::parse::enumeration {
namespace detail::enumeration { namespace detail {
struct lookup_base { struct lookup_base {
virtual ~lookup_base () = default; virtual ~lookup_base () = default;
@ -77,16 +77,25 @@ namespace cruft::parse {
std::map<int, std::unique_ptr<lookup_base>>& cache (void); std::map<int, std::unique_ptr<lookup_base>>& cache (void);
}
template <typename EnumT, typename = void>
struct underlying_else_identity { using type = EnumT; };
template <typename EnumT>
struct underlying_else_identity<
EnumT,
std::enable_if_t<std::is_enum_v<EnumT>>
> { using type = std::underlying_type_t<EnumT>; };
};
template <typename EnumT> template <typename EnumT>
void setup (std::map<std::string_view, EnumT> mapping) void setup (std::map<std::string_view, EnumT> mapping)
{ {
auto &cache = detail::enumeration::cache (); auto &cache = detail::cache ();
auto const index = cruft::typeidx<EnumT> (); auto const index = cruft::typeidx<EnumT> ();
auto lookup = std::make_unique<detail::enumeration::lookup_concrete<EnumT>> (std::move (mapping)); auto lookup = std::make_unique<detail::lookup_concrete<EnumT>> (std::move (mapping));
auto [pos, success] = cache.insert ({ index, std::move (lookup) }); auto [pos, success] = cache.insert ({ index, std::move (lookup) });
if (!success) if (!success)
@ -96,10 +105,9 @@ namespace cruft::parse {
template <typename EnumT> template <typename EnumT>
EnumT EnumT
enumeration (cruft::view<char const*> &str) value (int const idx, cruft::view<char const*> &str)
{ {
auto const idx = cruft::typeidx<EnumT> (); auto const &reg = detail::cache ();
auto const &reg = detail::enumeration::cache ();
auto const pos = reg.find (idx); auto const pos = reg.find (idx);
if (pos == reg.cend ()) if (pos == reg.cend ())
@ -114,7 +122,10 @@ namespace cruft::parse {
sizeof (EnumT) == 8 sizeof (EnumT) == 8
); );
if constexpr (std::is_signed_v<std::underlying_type_t<EnumT>>) { using underlying_type = typename detail::underlying_else_identity<EnumT>::type;
static_assert (std::is_integral_v<underlying_type>);
if constexpr (std::is_signed_v<underlying_type>) {
if constexpr (sizeof (EnumT) == 1) return static_cast<EnumT> (obj.as_i08 (str)); if constexpr (sizeof (EnumT) == 1) return static_cast<EnumT> (obj.as_i08 (str));
if constexpr (sizeof (EnumT) == 2) return static_cast<EnumT> (obj.as_i16 (str)); if constexpr (sizeof (EnumT) == 2) return static_cast<EnumT> (obj.as_i16 (str));
if constexpr (sizeof (EnumT) == 4) return static_cast<EnumT> (obj.as_i32 (str)); if constexpr (sizeof (EnumT) == 4) return static_cast<EnumT> (obj.as_i32 (str));
@ -130,4 +141,31 @@ namespace cruft::parse {
unreachable (); unreachable ();
} }
} }
template <typename EnumT>
EnumT
value (cruft::view<char const*> &str)
{
return value<EnumT> (typeidx<EnumT> (), str);
}
template <typename EnumT>
EnumT
from_string (int const idx, cruft::view<char const*> src)
{
auto const res = value<EnumT> (idx, src);
if (!src.empty ())
throw std::runtime_error ("Invalid conversion");
return res;
}
template <typename EnumT>
EnumT
from_string (cruft::view<char const*> src)
{
return from_string<EnumT> (typeidx<EnumT> (), src);
}
} }

View File

@ -31,17 +31,14 @@ namespace cruft::parse {
T T
from_string (cruft::view<const char*> data) from_string (cruft::view<const char*> data)
{ {
T res = [&] () { if constexpr (std::is_enum_v<T>) {
if constexpr (std::is_enum_v<T>) { return enumeration::from_string<T> (data);
return enumeration<T> (data); } else {
} else { T res = value<T> (data);
return value<T> (data); if (!data.empty ())
} throw std::invalid_argument ("unable to parse");
} (); return res;
}
if (!data.empty ())
throw std::invalid_argument ("unable to parse");
return res;
} }
template <typename T> T from_string (const char *data) { return from_string<T> (cruft::view (data)); } template <typename T> T from_string (const char *data) { return from_string<T> (cruft::view (data)); }

View File

@ -7,7 +7,7 @@ enum enumeration_t : u16 { FOO, BAR = 2, QUX = 257 };
int main () int main ()
{ {
cruft::parse::setup<enumeration_t> ({ cruft::parse::enumeration::setup<enumeration_t> ({
{ "FOO", FOO }, { "FOO", FOO },
{ "BAR", BAR }, { "BAR", BAR },
{ "QUX", QUX }, { "QUX", QUX },
@ -17,5 +17,14 @@ int main ()
tap.expect_eq (FOO, cruft::parse::from_string<enumeration_t> ("FOO"), "enumeration, FOO"); tap.expect_eq (FOO, cruft::parse::from_string<enumeration_t> ("FOO"), "enumeration, FOO");
tap.expect_eq (BAR, cruft::parse::from_string<enumeration_t> ("BAR"), "enumeration, BAR"); tap.expect_eq (BAR, cruft::parse::from_string<enumeration_t> ("BAR"), "enumeration, BAR");
tap.expect_eq (QUX, cruft::parse::from_string<enumeration_t> ("QUX"), "enumeration, QUX"); tap.expect_eq (QUX, cruft::parse::from_string<enumeration_t> ("QUX"), "enumeration, QUX");
tap.expect_eq (
u16 {QUX},
cruft::parse::enumeration::from_string<u16> (
cruft::typeidx<enumeration_t> (),
"QUX"
),
"u16, QUX"
);
return tap.status (); return tap.status ();
} }