From 38d7045685d4904d013ea4990a3aa7f5e78309cf Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 22 Oct 2022 17:57:47 +0100 Subject: Add magic support to printing/parsing/validating enumerations --- lib/enumDetails.hpp | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 lib/enumDetails.hpp (limited to 'lib/enumDetails.hpp') diff --git a/lib/enumDetails.hpp b/lib/enumDetails.hpp new file mode 100644 index 0000000..ace6252 --- /dev/null +++ b/lib/enumDetails.hpp @@ -0,0 +1,133 @@ +#pragma once + +#include +#include +#include +#include +#include + +/// EnumTypeDetails +// Extracts the fully qualified name of the enumeration +template struct EnumTypeDetails { +#ifndef ENUM_PROBE +protected: +#endif + constexpr static std::string_view SEARCH_TYPE {"E = "}; + constexpr static auto + typeraw() + { + return std::string_view {__PRETTY_FUNCTION__}; + }; + constexpr static auto typeNameStart {typeraw().find(SEARCH_TYPE) + SEARCH_TYPE.length()}; + constexpr static auto typeNameEnd {typeraw().find_first_of("];", typeNameStart)}; + constexpr static auto typeNameLen {typeNameEnd - typeNameStart}; + constexpr static auto typeNameArr {[]() { + std::array out; + typeraw().copy(out.begin(), typeNameEnd - typeNameStart, typeNameStart); + return out; + }()}; + +public: + constexpr static std::string_view typeName {typeNameArr.data(), typeNameArr.size()}; +}; + +/// EnumValueDetails +// Extracts the value name and constructs string_views of the parts +template struct EnumValueDetails : public EnumTypeDetails { +#ifndef ENUM_PROBE +private: +#endif + using T = EnumTypeDetails; + constexpr static auto + raw() + { + return std::string_view {__PRETTY_FUNCTION__}; + }; + constexpr static auto nameStart {raw().find_last_of(": ") + 1}; + constexpr static auto nameEnd {raw().find_first_of("];", nameStart)}; + constexpr static auto nameLen {nameEnd - nameStart}; + constexpr static auto nameArr {[]() { + std::array out; + raw().copy(out.begin(), nameLen, nameStart); + return out; + }()}; + +public: + constexpr static std::string_view valueName {nameArr.data(), nameArr.size()}; + constexpr static auto valid {valueName.back() < '0' || valueName.back() > '9'}; + constexpr static auto raw_value {value}; +}; + +template struct EnumValueCollection { + using Vs = std::make_integer_sequence; +}; + +template struct EnumDetails { +public: + using EVC = EnumValueCollection; + +#ifndef ENUM_PROBE +private: +#endif + template + constexpr static auto + get_valids(std::integer_sequence) + { + return std::array {EnumValueDetails(n)>::valid...}; + } + template + constexpr static auto + get_values(std::integer_sequence) + { + return std::array {EnumValueDetails(n)>::raw_value...}; + } + template + constexpr static auto + get_valueNames(std::integer_sequence) + { + return std::array {EnumValueDetails::valueName...}; + } + + constexpr static auto valid_flags {get_valids(typename EVC::Vs {})}; + constexpr static auto valid_count {std::count_if(valid_flags.begin(), valid_flags.end(), std::identity {})}; + +public: + constexpr static auto values {[]() { + constexpr auto values {get_values(typename EVC::Vs {})}; + static_assert(std::is_sorted(values.begin(), values.end()), "Candidate values must be sorted"); + std::array out; + auto write = out.begin(); + for (auto v = values.begin(); const bool & valid : valid_flags) { + if (valid) { + *write++ = static_cast(*v); + } + ++v; + } + return out; + }()}; + constexpr static auto names {get_valueNames(std::make_integer_sequence {})}; + + constexpr static bool + is_valid(E value) noexcept + { + return std::binary_search(values.begin(), values.end(), value); + } + + constexpr static std::optional + parse(std::string_view name) noexcept + { + if (const auto itr = std::find(names.begin(), names.end(), name); itr != names.end()) { + return values[std::distance(names.begin(), itr)]; + } + return std::nullopt; + } + + constexpr static std::optional + to_string(E value) noexcept + { + if (const auto itr = std::find(values.begin(), values.end(), value); itr != values.end()) { + return names[std::distance(values.begin(), itr)]; + } + return std::nullopt; + } +}; -- cgit v1.2.3