From 5a0b3927a33807cca4c77c40eb873f8a3b51b0b0 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 29 Apr 2023 19:07:11 +0100 Subject: Drop .hpp for header only things Half of them acquired a .cpp part anyway --- lib/enumDetails.h | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 lib/enumDetails.h (limited to 'lib/enumDetails.h') diff --git a/lib/enumDetails.h b/lib/enumDetails.h new file mode 100644 index 0000000..5966be2 --- /dev/null +++ b/lib/enumDetails.h @@ -0,0 +1,143 @@ +#pragma once + +#include +#include +#include +#include +#include + +/// EnumDetailsBase +// Shared helpers +struct EnumDetailsBase { + template + constexpr static auto + strArr(auto input, auto start, auto end) + { + std::array out; + input.copy(out.begin(), end - start, start); + return out; + } +}; + +/// EnumTypeDetails +// Extracts the fully qualified name of the enumeration +template struct EnumTypeDetails : EnumDetailsBase { +#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 {strArr(typeraw(), typeNameStart, typeNameEnd)}; + +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 {EnumValueDetails::template strArr(raw(), nameStart, nameEnd)}; + +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}; +}; + +/// EnumValueCollection +// Customisation point for specifying the range of underlying values your enum can have +template struct EnumValueCollection { + using Vs = std::make_integer_sequence; +}; + +/// EnumDetails +// Interface for lookups/checks/etc at runtime +template struct EnumDetails { +#ifndef ENUM_PROBE +private: +#endif + template + constexpr static auto + get_valids(std::integer_sequence) + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" + return std::array {EnumValueDetails(n)>::valid...}; +#pragma GCC diagnostic pop + } + 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...}; + } + + using EVC = EnumValueCollection; + 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 {})}; + + constexpr static auto + lookup(const auto key, const auto & search, const auto & out) + -> std::optional::value_type> + { + if (const auto itr = std::find(search.begin(), search.end(), key); itr != search.end()) { + return out[static_cast(std::distance(search.begin(), itr))]; + } + return std::nullopt; + } + +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; + std::copy_if(values.begin(), values.end(), out.begin(), [valid = valid_flags.begin()](auto) mutable { + return *valid++; + }); + 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 + { + return lookup(name, names, values); + } + + constexpr static std::optional + to_string(E value) noexcept + { + return lookup(value, values, names); + } +}; -- cgit v1.2.3