parse/enum: add lookup-by-function
This commit is contained in:
parent
e4c224ceaa
commit
458654c9a3
@ -60,6 +60,47 @@ namespace cruft::parse::enumeration {
|
||||
};
|
||||
|
||||
|
||||
template <typename EnumT>
|
||||
struct lookup_callback : public lookup_base {
|
||||
using function_t = std::function<EnumT(cruft::view<char const*>&)>;
|
||||
|
||||
lookup_callback (
|
||||
function_t &&_callback
|
||||
) : m_callback (std::move (_callback))
|
||||
{ ; }
|
||||
|
||||
i08 as_i08 (cruft::view<char const*> &str) const& override { return get<i08> (str); }
|
||||
i16 as_i16 (cruft::view<char const*> &str) const& override { return get<i16> (str); }
|
||||
i32 as_i32 (cruft::view<char const*> &str) const& override { return get<i32> (str); }
|
||||
i64 as_i64 (cruft::view<char const*> &str) const& override { return get<i64> (str); }
|
||||
|
||||
u08 as_u08 (cruft::view<char const*> &str) const& override { return get<u08> (str); }
|
||||
u16 as_u16 (cruft::view<char const*> &str) const& override { return get<u16> (str); }
|
||||
u32 as_u32 (cruft::view<char const*> &str) const& override { return get<u32> (str); }
|
||||
u64 as_u64 (cruft::view<char const*> &str) const& override { return get<u64> (str); }
|
||||
|
||||
private:
|
||||
template <typename ValueT>
|
||||
ValueT
|
||||
get (cruft::view<char const*> &str) const&
|
||||
{
|
||||
if constexpr (std::is_same_v<ValueT, underlying_else_identity_t<EnumT>>) {
|
||||
// Double check the callee changes the remaining string size.
|
||||
auto const len = str.size ();
|
||||
auto const res = m_callback (str);
|
||||
if (len == str.size ())
|
||||
throw std::invalid_argument ("Unknown enum value");
|
||||
return static_cast<ValueT> (res);
|
||||
} else {
|
||||
throw std::runtime_error ("Invalid underlying type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function_t m_callback;
|
||||
};
|
||||
|
||||
|
||||
/// A simple lookup from a supplied mapping of strings-to-underlying,
|
||||
/// specialised on the EnumT that the lookup is targetting.
|
||||
template <typename EnumT>
|
||||
@ -118,6 +159,25 @@ namespace cruft::parse::enumeration {
|
||||
std::unique_ptr<lookup_base>
|
||||
>&
|
||||
cache (void);
|
||||
|
||||
|
||||
template <typename EnumT>
|
||||
cookie
|
||||
setup [[nodiscard]] (std::unique_ptr<lookup_base> &&lookup)
|
||||
{
|
||||
auto &cache = detail::cache ();
|
||||
auto const index = cruft::typeidx<EnumT> ();
|
||||
|
||||
auto [pos, success] = cache.insert ({
|
||||
index,
|
||||
std::move (lookup)
|
||||
});
|
||||
|
||||
if (!success)
|
||||
LOG_WARN ("duplicate parse setup for %! was ignored", cruft::type_name<EnumT> ());
|
||||
|
||||
return cookie {};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -131,19 +191,26 @@ namespace cruft::parse::enumeration {
|
||||
cookie
|
||||
setup [[nodiscard]] (std::map<std::string_view, EnumT> mapping)
|
||||
{
|
||||
auto &cache = detail::cache ();
|
||||
|
||||
auto const index = cruft::typeidx<EnumT> ();
|
||||
auto lookup = std::make_unique<detail::lookup_concrete<EnumT>> (std::move (mapping));
|
||||
|
||||
auto [pos, success] = cache.insert ({ index, std::move (lookup) });
|
||||
if (!success)
|
||||
LOG_WARN ("duplicate parse setup for %! was ignored", cruft::type_name<EnumT> ());
|
||||
|
||||
return cookie {};
|
||||
return detail::setup<EnumT> (
|
||||
std::make_unique<
|
||||
detail::lookup_concrete<EnumT>
|
||||
> (std::move (mapping))
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
template <typename EnumT>
|
||||
cookie
|
||||
setup [[nodiscard]] (std::function<EnumT(cruft::view<char const*>&)> &&func)
|
||||
{
|
||||
return detail::setup<EnumT> (
|
||||
std::make_unique<
|
||||
detail::lookup_callback<EnumT>
|
||||
> (std::move (func))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// Lookup an enumeration value given a string representation.
|
||||
///
|
||||
/// The string view is taken by reference and will be modified so that it
|
||||
|
@ -3,15 +3,13 @@
|
||||
#include "std.hpp"
|
||||
#include "tap.hpp"
|
||||
|
||||
enum enumeration_t : u16 { FOO, BAR = 2, QUX = 257 };
|
||||
|
||||
enum class enum_class { VALUE };
|
||||
|
||||
int main ()
|
||||
{
|
||||
cruft::TAP::logger tap;
|
||||
|
||||
{
|
||||
enum enumeration_t : u16 { FOO, BAR = 2, QUX = 257 };
|
||||
|
||||
auto const cookie = cruft::parse::enumeration::setup<enumeration_t> ({
|
||||
{ "FOO", FOO },
|
||||
{ "BAR", BAR },
|
||||
@ -34,6 +32,8 @@ int main ()
|
||||
}
|
||||
|
||||
{
|
||||
enum class enum_class { VALUE };
|
||||
|
||||
auto const cookie = cruft::parse::enumeration::setup<enum_class> ({
|
||||
{ "VALUE", enum_class::VALUE },
|
||||
});
|
||||
@ -45,5 +45,25 @@ int main ()
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
enum class func_enum { ASDF };
|
||||
|
||||
auto const cookie = cruft::parse::enumeration::setup<func_enum> ([] (auto &str) {
|
||||
if (equal (str, "ASDF")) {
|
||||
str = str.consume (4);
|
||||
return func_enum::ASDF;
|
||||
}
|
||||
throw std::runtime_error ("Invalid enum value");
|
||||
});
|
||||
|
||||
(void)cookie;
|
||||
|
||||
tap.expect_eq (
|
||||
func_enum::ASDF,
|
||||
cruft::parse::from_string<func_enum> ("ASDF"),
|
||||
"function enum lookup"
|
||||
);
|
||||
}
|
||||
|
||||
return tap.status ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user