parse/enum: allow translation of enum string to integer with typeidx
This commit is contained in:
parent
5e3af7f8fb
commit
cc7d4eb0a9
@ -11,7 +11,7 @@
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace cruft::parse::detail::enumeration {
|
||||
namespace cruft::parse::enumeration::detail {
|
||||
std::map<int, std::unique_ptr<lookup_base>>&
|
||||
cache (void)
|
||||
{
|
||||
|
@ -14,8 +14,8 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace cruft::parse {
|
||||
namespace detail::enumeration {
|
||||
namespace cruft::parse::enumeration {
|
||||
namespace detail {
|
||||
struct lookup_base {
|
||||
virtual ~lookup_base () = default;
|
||||
|
||||
@ -77,16 +77,25 @@ namespace cruft::parse {
|
||||
|
||||
|
||||
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>
|
||||
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 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) });
|
||||
if (!success)
|
||||
@ -96,10 +105,9 @@ namespace cruft::parse {
|
||||
|
||||
template <typename 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 ® = detail::enumeration::cache ();
|
||||
auto const ® = detail::cache ();
|
||||
auto const pos = reg.find (idx);
|
||||
|
||||
if (pos == reg.cend ())
|
||||
@ -114,7 +122,10 @@ namespace cruft::parse {
|
||||
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) == 2) return static_cast<EnumT> (obj.as_i16 (str));
|
||||
if constexpr (sizeof (EnumT) == 4) return static_cast<EnumT> (obj.as_i32 (str));
|
||||
@ -130,4 +141,31 @@ namespace cruft::parse {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -31,17 +31,14 @@ namespace cruft::parse {
|
||||
T
|
||||
from_string (cruft::view<const char*> data)
|
||||
{
|
||||
T res = [&] () {
|
||||
if constexpr (std::is_enum_v<T>) {
|
||||
return enumeration<T> (data);
|
||||
} else {
|
||||
return value<T> (data);
|
||||
}
|
||||
} ();
|
||||
|
||||
if (!data.empty ())
|
||||
throw std::invalid_argument ("unable to parse");
|
||||
return res;
|
||||
if constexpr (std::is_enum_v<T>) {
|
||||
return enumeration::from_string<T> (data);
|
||||
} else {
|
||||
T res = value<T> (data);
|
||||
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)); }
|
||||
|
@ -7,7 +7,7 @@ enum enumeration_t : u16 { FOO, BAR = 2, QUX = 257 };
|
||||
|
||||
int main ()
|
||||
{
|
||||
cruft::parse::setup<enumeration_t> ({
|
||||
cruft::parse::enumeration::setup<enumeration_t> ({
|
||||
{ "FOO", FOO },
|
||||
{ "BAR", BAR },
|
||||
{ "QUX", QUX },
|
||||
@ -17,5 +17,14 @@ int main ()
|
||||
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 (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 ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user