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,
/// 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

View File

@ -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 ();
}