parse/enum: add basic typeid enum parsing
This commit is contained in:
parent
de33f8c8ce
commit
5e3af7f8fb
@ -409,6 +409,8 @@ list (
|
||||
parallel/queue.hpp
|
||||
parallel/stack.cpp
|
||||
parallel/stack.hpp
|
||||
parse/enum.cpp
|
||||
parse/enum.hpp
|
||||
parse/time.cpp
|
||||
parse/time.hpp
|
||||
parse/value.cpp
|
||||
@ -635,6 +637,7 @@ if (TESTS)
|
||||
memory/deleter
|
||||
parallel/queue
|
||||
parallel/stack
|
||||
parse/enum
|
||||
parse/value
|
||||
parse/time
|
||||
parse/si
|
||||
|
21
parse/enum.cpp
Normal file
21
parse/enum.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#include "enum.hpp"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace cruft::parse::detail::enumeration {
|
||||
std::map<int, std::unique_ptr<lookup_base>>&
|
||||
cache (void)
|
||||
{
|
||||
static std::map<int, std::unique_ptr<lookup_base>> s_cache;
|
||||
return s_cache;
|
||||
}
|
||||
}
|
133
parse/enum.hpp
Normal file
133
parse/enum.hpp
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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 <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../view.hpp"
|
||||
#include "../introspection.hpp"
|
||||
#include "../log.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace cruft::parse {
|
||||
namespace detail::enumeration {
|
||||
struct lookup_base {
|
||||
virtual ~lookup_base () = default;
|
||||
|
||||
virtual i08 as_i08 (cruft::view<char const*> &) const& = 0;
|
||||
virtual i16 as_i16 (cruft::view<char const*> &) const& = 0;
|
||||
virtual i32 as_i32 (cruft::view<char const*> &) const& = 0;
|
||||
virtual i64 as_i64 (cruft::view<char const*> &) const& = 0;
|
||||
|
||||
virtual u08 as_u08 (cruft::view<char const*> &) const& = 0;
|
||||
virtual u16 as_u16 (cruft::view<char const*> &) const& = 0;
|
||||
virtual u32 as_u32 (cruft::view<char const*> &) const& = 0;
|
||||
virtual u64 as_u64 (cruft::view<char const*> &) const& = 0;
|
||||
};
|
||||
|
||||
|
||||
template <typename EnumT>
|
||||
struct lookup_concrete : public lookup_base {
|
||||
static_assert (std::is_enum_v<EnumT>);
|
||||
|
||||
using underlying_type = std::underlying_type_t<EnumT>;
|
||||
using cache_type = std::map<std::string_view, EnumT>;
|
||||
|
||||
lookup_concrete (cache_type _cache)
|
||||
: m_cache (std::move (_cache))
|
||||
{ ; }
|
||||
|
||||
|
||||
template <typename ValueT>
|
||||
ValueT
|
||||
get (cruft::view<char const*> &str) const&
|
||||
{
|
||||
if constexpr (std::is_same_v<ValueT, underlying_type>) {
|
||||
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<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:
|
||||
cache_type m_cache;
|
||||
};
|
||||
|
||||
|
||||
std::map<int, std::unique_ptr<lookup_base>>& cache (void);
|
||||
}
|
||||
|
||||
|
||||
template <typename EnumT>
|
||||
void setup (std::map<std::string_view, EnumT> mapping)
|
||||
{
|
||||
auto &cache = detail::enumeration::cache ();
|
||||
|
||||
auto const index = cruft::typeidx<EnumT> ();
|
||||
auto lookup = std::make_unique<detail::enumeration::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> ());
|
||||
}
|
||||
|
||||
|
||||
template <typename EnumT>
|
||||
EnumT
|
||||
enumeration (cruft::view<char const*> &str)
|
||||
{
|
||||
auto const idx = cruft::typeidx<EnumT> ();
|
||||
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<std::underlying_type_t<EnumT>>) {
|
||||
if constexpr (sizeof (EnumT) == 1) return static_cast<EnumT> (obj.as_i08 (str));
|
||||
if constexpr (sizeof (EnumT) == 2) return static_cast<EnumT> (obj.as_i16 (str));
|
||||
if constexpr (sizeof (EnumT) == 4) return static_cast<EnumT> (obj.as_i32 (str));
|
||||
if constexpr (sizeof (EnumT) == 8) return static_cast<EnumT> (obj.as_i64 (str));
|
||||
|
||||
unreachable ();
|
||||
} else {
|
||||
if constexpr (sizeof (EnumT) == 1) return static_cast<EnumT> (obj.as_u08 (str));
|
||||
if constexpr (sizeof (EnumT) == 2) return static_cast<EnumT> (obj.as_u16 (str));
|
||||
if constexpr (sizeof (EnumT) == 4) return static_cast<EnumT> (obj.as_u32 (str));
|
||||
if constexpr (sizeof (EnumT) == 8) return static_cast<EnumT> (obj.as_u64 (str));
|
||||
|
||||
unreachable ();
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../view.hpp"
|
||||
#include "enum.hpp"
|
||||
|
||||
namespace cruft::parse {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -30,7 +31,14 @@ namespace cruft::parse {
|
||||
T
|
||||
from_string (cruft::view<const char*> data)
|
||||
{
|
||||
T res = value<T> (data);
|
||||
T res = [&] () {
|
||||
if constexpr (std::is_enum_v<T>) {
|
||||
return enumeration<T> (data);
|
||||
} else {
|
||||
return value<T> (data);
|
||||
}
|
||||
} ();
|
||||
|
||||
if (!data.empty ())
|
||||
throw std::invalid_argument ("unable to parse");
|
||||
return res;
|
||||
|
21
test/parse/enum.cpp
Normal file
21
test/parse/enum.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include "parse/enum.hpp"
|
||||
#include "parse/value.hpp"
|
||||
#include "std.hpp"
|
||||
#include "tap.hpp"
|
||||
|
||||
enum enumeration_t : u16 { FOO, BAR = 2, QUX = 257 };
|
||||
|
||||
int main ()
|
||||
{
|
||||
cruft::parse::setup<enumeration_t> ({
|
||||
{ "FOO", FOO },
|
||||
{ "BAR", BAR },
|
||||
{ "QUX", QUX },
|
||||
});
|
||||
|
||||
cruft::TAP::logger tap;
|
||||
tap.expect_eq (FOO, cruft::parse::from_string<enumeration_t> ("FOO"), "enumeration, FOO");
|
||||
tap.expect_eq (BAR, cruft::parse::from_string<enumeration_t> ("BAR"), "enumeration, BAR");
|
||||
tap.expect_eq (QUX, cruft::parse::from_string<enumeration_t> ("QUX"), "enumeration, QUX");
|
||||
return tap.status ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user