From 458654c9a3891e0f61258842a7b30b4d6cf246ed Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 29 Aug 2019 13:33:18 +1000 Subject: [PATCH] parse/enum: add lookup-by-function --- parse/enum.hpp | 87 +++++++++++++++++++++++++++++++++++++++------ test/parse/enum.cpp | 28 ++++++++++++--- 2 files changed, 101 insertions(+), 14 deletions(-) diff --git a/parse/enum.hpp b/parse/enum.hpp index 77d4e08a..bc969db1 100644 --- a/parse/enum.hpp +++ b/parse/enum.hpp @@ -60,6 +60,47 @@ namespace cruft::parse::enumeration { }; + template + struct lookup_callback : public lookup_base { + using function_t = std::function&)>; + + lookup_callback ( + function_t &&_callback + ) : m_callback (std::move (_callback)) + { ; } + + i08 as_i08 (cruft::view &str) const& override { return get (str); } + i16 as_i16 (cruft::view &str) const& override { return get (str); } + i32 as_i32 (cruft::view &str) const& override { return get (str); } + i64 as_i64 (cruft::view &str) const& override { return get (str); } + + u08 as_u08 (cruft::view &str) const& override { return get (str); } + u16 as_u16 (cruft::view &str) const& override { return get (str); } + u32 as_u32 (cruft::view &str) const& override { return get (str); } + u64 as_u64 (cruft::view &str) const& override { return get (str); } + + private: + template + ValueT + get (cruft::view &str) const& + { + if constexpr (std::is_same_v>) { + // 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 (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 @@ -118,6 +159,25 @@ namespace cruft::parse::enumeration { std::unique_ptr >& cache (void); + + + template + cookie + setup [[nodiscard]] (std::unique_ptr &&lookup) + { + auto &cache = detail::cache (); + auto const index = cruft::typeidx (); + + auto [pos, success] = cache.insert ({ + index, + std::move (lookup) + }); + + if (!success) + LOG_WARN ("duplicate parse setup for %! was ignored", cruft::type_name ()); + + return cookie {}; + } }; @@ -131,19 +191,26 @@ namespace cruft::parse::enumeration { cookie setup [[nodiscard]] (std::map mapping) { - auto &cache = detail::cache (); - - auto const index = cruft::typeidx (); - auto lookup = std::make_unique> (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 ()); - - return cookie {}; + return detail::setup ( + std::make_unique< + detail::lookup_concrete + > (std::move (mapping)) + ); }; + template + cookie + setup [[nodiscard]] (std::function&)> &&func) + { + return detail::setup ( + std::make_unique< + detail::lookup_callback + > (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 diff --git a/test/parse/enum.cpp b/test/parse/enum.cpp index 4be58f44..b524d144 100644 --- a/test/parse/enum.cpp +++ b/test/parse/enum.cpp @@ -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 ({ { "FOO", FOO }, { "BAR", BAR }, @@ -34,6 +32,8 @@ int main () } { + enum class enum_class { VALUE }; + auto const cookie = cruft::parse::enumeration::setup ({ { "VALUE", enum_class::VALUE }, }); @@ -45,5 +45,25 @@ int main () ); } + { + enum class func_enum { ASDF }; + + auto const cookie = cruft::parse::enumeration::setup ([] (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 ("ASDF"), + "function enum lookup" + ); + } + return tap.status (); } \ No newline at end of file