parse/enum: add lookup-by-function

This commit is contained in:
Danny Robson 2019-08-29 13:33:18 +10:00
parent e4c224ceaa
commit 458654c9a3
2 changed files with 101 additions and 14 deletions

View File

@ -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, /// A simple lookup from a supplied mapping of strings-to-underlying,
/// specialised on the EnumT that the lookup is targetting. /// specialised on the EnumT that the lookup is targetting.
template <typename EnumT> template <typename EnumT>
@ -118,6 +159,25 @@ namespace cruft::parse::enumeration {
std::unique_ptr<lookup_base> std::unique_ptr<lookup_base>
>& >&
cache (void); 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 cookie
setup [[nodiscard]] (std::map<std::string_view, EnumT> mapping) setup [[nodiscard]] (std::map<std::string_view, EnumT> mapping)
{ {
auto &cache = detail::cache (); return detail::setup<EnumT> (
std::make_unique<
auto const index = cruft::typeidx<EnumT> (); detail::lookup_concrete<EnumT>
auto lookup = std::make_unique<detail::lookup_concrete<EnumT>> (std::move (mapping)); > (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 {};
}; };
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. /// Lookup an enumeration value given a string representation.
/// ///
/// The string view is taken by reference and will be modified so that it /// The string view is taken by reference and will be modified so that it

View File

@ -3,15 +3,13 @@
#include "std.hpp" #include "std.hpp"
#include "tap.hpp" #include "tap.hpp"
enum enumeration_t : u16 { FOO, BAR = 2, QUX = 257 };
enum class enum_class { VALUE };
int main () int main ()
{ {
cruft::TAP::logger tap; cruft::TAP::logger tap;
{ {
enum enumeration_t : u16 { FOO, BAR = 2, QUX = 257 };
auto const cookie = cruft::parse::enumeration::setup<enumeration_t> ({ auto const cookie = cruft::parse::enumeration::setup<enumeration_t> ({
{ "FOO", FOO }, { "FOO", FOO },
{ "BAR", BAR }, { "BAR", BAR },
@ -34,6 +32,8 @@ int main ()
} }
{ {
enum class enum_class { VALUE };
auto const cookie = cruft::parse::enumeration::setup<enum_class> ({ auto const cookie = cruft::parse::enumeration::setup<enum_class> ({
{ "VALUE", enum_class::VALUE }, { "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 (); return tap.status ();
} }