/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2019, Danny Robson */ #pragma once #include "../view.hpp" #include "../introspection.hpp" #include "../log.hpp" #include namespace cruft::parse { namespace detail::enumeration { struct lookup_base { virtual ~lookup_base () = default; virtual i08 as_i08 (cruft::view &) const& = 0; virtual i16 as_i16 (cruft::view &) const& = 0; virtual i32 as_i32 (cruft::view &) const& = 0; virtual i64 as_i64 (cruft::view &) const& = 0; virtual u08 as_u08 (cruft::view &) const& = 0; virtual u16 as_u16 (cruft::view &) const& = 0; virtual u32 as_u32 (cruft::view &) const& = 0; virtual u64 as_u64 (cruft::view &) const& = 0; }; template struct lookup_concrete : public lookup_base { static_assert (std::is_enum_v); using underlying_type = std::underlying_type_t; using cache_type = std::map; lookup_concrete (cache_type _cache) : m_cache (std::move (_cache)) { ; } template ValueT get (cruft::view &str) const& { if constexpr (std::is_same_v) { for (auto const [key,val]: m_cache) { if (equal (key, str)) { str = str.consume (key.size ()); return val; } } throw std::invalid_argument ("Unknown enum value"); } else { throw std::runtime_error ("Invalid underlying type"); } } 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: cache_type m_cache; }; std::map>& cache (void); } template void setup (std::map mapping) { auto &cache = detail::enumeration::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 ()); } template EnumT enumeration (cruft::view &str) { auto const idx = cruft::typeidx (); auto const ® = detail::enumeration::cache (); auto const pos = reg.find (idx); if (pos == reg.cend ()) throw std::invalid_argument ("Unknown enumeration"); auto const &obj = *pos->second; static_assert ( sizeof (EnumT) == 1 || sizeof (EnumT) == 2 || sizeof (EnumT) == 4 || sizeof (EnumT) == 8 ); if constexpr (std::is_signed_v>) { if constexpr (sizeof (EnumT) == 1) return static_cast (obj.as_i08 (str)); if constexpr (sizeof (EnumT) == 2) return static_cast (obj.as_i16 (str)); if constexpr (sizeof (EnumT) == 4) return static_cast (obj.as_i32 (str)); if constexpr (sizeof (EnumT) == 8) return static_cast (obj.as_i64 (str)); unreachable (); } else { if constexpr (sizeof (EnumT) == 1) return static_cast (obj.as_u08 (str)); if constexpr (sizeof (EnumT) == 2) return static_cast (obj.as_u16 (str)); if constexpr (sizeof (EnumT) == 4) return static_cast (obj.as_u32 (str)); if constexpr (sizeof (EnumT) == 8) return static_cast (obj.as_u64 (str)); unreachable (); } } }