From 2a8650ca939ea47877b26b1f6bcf47fe86764a1a Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Tue, 28 Sep 2021 21:35:45 +0700 Subject: [PATCH] new value string functions + to_value_string + to_value_string_or_empty + to_value_string_or_throw + from_value_string + from_value_string_or_default + from_value_string_or_throw --- headers/enum.hpp/enum.hpp | 132 +++++++++++++++++++++++++++++++++----- untests/enum_tests.cpp | 97 ++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+), 15 deletions(-) diff --git a/headers/enum.hpp/enum.hpp b/headers/enum.hpp/enum.hpp index b1e67cb..02d57eb 100644 --- a/headers/enum.hpp/enum.hpp +++ b/headers/enum.hpp/enum.hpp @@ -54,6 +54,11 @@ namespace enum_hpp return traits_t::names; } + template < typename Enum > + constexpr const std::array()>& value_names() noexcept { + return traits_t::value_names; + } + template < typename Enum > constexpr typename traits_t::underlying_type to_underlying(Enum e) noexcept { return traits_t::to_underlying(e); @@ -74,6 +79,21 @@ namespace enum_hpp return traits_t::to_string_or_throw(e); } + template < typename Enum > + constexpr std::optional to_value_string(Enum e) noexcept { + return traits_t::to_value_string(e); + } + + template < typename Enum > + constexpr std::string_view to_value_string_or_empty(Enum e) noexcept { + return traits_t::to_value_string_or_empty(e); + } + + template < typename Enum > + std::string_view to_value_string_or_throw(Enum e) { + return traits_t::to_value_string_or_throw(e); + } + template < typename Enum > constexpr std::optional from_string(std::string_view name) noexcept { return traits_t::from_string(name); @@ -89,6 +109,21 @@ namespace enum_hpp return traits_t::from_string_or_throw(name); } + template < typename Enum > + constexpr std::optional from_value_string(std::string_view name) noexcept { + return traits_t::from_value_string(name); + } + + template < typename Enum > + constexpr Enum from_value_string_or_default(std::string_view name, Enum def) noexcept { + return traits_t::from_value_string_or_default(name, def); + } + + template < typename Enum > + Enum from_value_string_or_throw(std::string_view name) { + return traits_t::from_value_string_or_throw(name); + } + template < typename Enum > constexpr std::optional to_index(Enum e) noexcept { return traits_t::to_index(e); @@ -144,26 +179,32 @@ namespace enum_hpp::detail } }; - constexpr bool is_end_of_name(char ch) noexcept { - switch ( ch ) { - case ' ': - case '=': - case '\r': - case '\n': - case '\t': - return true; - default: - return false; + constexpr std::string_view trim_raw_name(std::string_view raw_name) noexcept { + // "none" -> "none" + // "color = 1 << 0" -> "color" + // "alpha = 1 << 1" -> "alpha" + // "all = color | alpha" -> "all" + + if ( const auto pos = raw_name.find_first_of(" =\f\n\r\t\v"); pos != std::string_view::npos ) { + return raw_name.substr(0, pos); } + + return raw_name; } - constexpr std::string_view trim_raw_name(std::string_view raw_name) noexcept { - for ( std::size_t i = 0; i < raw_name.size(); ++i ) { - if ( is_end_of_name(raw_name[i]) ) { - return raw_name.substr(0, i); + constexpr std::string_view trim_raw_value_name(std::string_view raw_name) noexcept { + // "none" -> "" + // "color = 1 << 0" -> "1 << 0" + // "alpha = 1 << 1" -> "1 << 1" + // "all = color | alpha" -> "color | alpha" + + if ( auto pos = raw_name.find('='); pos != std::string_view::npos ) { + if ( pos = raw_name.find_first_not_of(" \f\n\r\t\v", pos + 1); pos != std::string_view::npos ) { + return raw_name.substr(pos); } } - return raw_name; + + return std::string_view{}; } } @@ -197,6 +238,16 @@ namespace enum_hpp::detail #define ENUM_HPP_GENERATE_NAMES(Fields)\ ENUM_HPP_PP_SEQ_FOR_EACH(ENUM_HPP_GENERATE_NAMES_OP, _, Fields) +// +// ENUM_HPP_GENERATE_VALUE_NAMES +// + +#define ENUM_HPP_GENERATE_VALUE_NAMES_OP(d, i, x)\ + ::enum_hpp::detail::trim_raw_value_name(ENUM_HPP_PP_STRINGIZE(x)), + +#define ENUM_HPP_GENERATE_VALUE_NAMES(Fields)\ + ENUM_HPP_PP_SEQ_FOR_EACH(ENUM_HPP_GENERATE_VALUE_NAMES_OP, _, Fields) + // // ENUM_HPP_GENERATE_VALUE_TO_NAME_CASES // @@ -207,6 +258,16 @@ namespace enum_hpp::detail #define ENUM_HPP_GENERATE_VALUE_TO_NAME_CASES(Enum, Fields)\ ENUM_HPP_PP_SEQ_FOR_EACH(ENUM_HPP_GENERATE_VALUE_TO_NAME_CASES_OP, Enum, Fields) +// +// ENUM_HPP_GENERATE_VALUE_TO_VALUE_NAME_CASES +// + +#define ENUM_HPP_GENERATE_VALUE_TO_VALUE_NAME_CASES_OP(Enum, i, x)\ + case values[i]: return value_names[i]; + +#define ENUM_HPP_GENERATE_VALUE_TO_VALUE_NAME_CASES(Enum, Fields)\ + ENUM_HPP_PP_SEQ_FOR_EACH(ENUM_HPP_GENERATE_VALUE_TO_VALUE_NAME_CASES_OP, Enum, Fields) + // // ENUM_HPP_GENERATE_VALUE_TO_INDEX_CASES // @@ -259,6 +320,9 @@ namespace enum_hpp::detail static constexpr const std::array names = {\ { ENUM_HPP_GENERATE_NAMES(Fields) }\ };\ + static constexpr const std::array value_names = {\ + { ENUM_HPP_GENERATE_VALUE_NAMES(Fields) }\ + };\ public:\ [[maybe_unused]] static constexpr underlying_type to_underlying(enum_type e) noexcept {\ return static_cast(e);\ @@ -281,6 +345,24 @@ namespace enum_hpp::detail }\ ::enum_hpp::detail::throw_exception_with(#Enum "_traits::to_string_or_throw(): invalid argument");\ }\ + [[maybe_unused]] static constexpr std::optional to_value_string(enum_type e) noexcept {\ + switch ( e ) {\ + ENUM_HPP_GENERATE_VALUE_TO_VALUE_NAME_CASES(Enum, Fields)\ + default: return std::nullopt;\ + }\ + }\ + [[maybe_unused]] static constexpr std::string_view to_value_string_or_empty(enum_type e) noexcept {\ + if ( auto s = to_value_string(e) ) {\ + return *s;\ + }\ + return ::enum_hpp::empty_string;\ + }\ + [[maybe_unused]] static std::string_view to_value_string_or_throw(enum_type e) {\ + if ( auto s = to_value_string(e) ) {\ + return *s;\ + }\ + ::enum_hpp::detail::throw_exception_with(#Enum "_traits::to_value_string_or_throw(): invalid argument");\ + }\ [[maybe_unused]] static constexpr std::optional from_string(std::string_view name) noexcept {\ for ( std::size_t i = 0; i < size; ++i) {\ if ( name == names[i] ) {\ @@ -301,6 +383,26 @@ namespace enum_hpp::detail }\ ::enum_hpp::detail::throw_exception_with(#Enum "_traits::from_string_or_throw(): invalid argument");\ }\ + [[maybe_unused]] static constexpr std::optional from_value_string(std::string_view value_name) noexcept {\ + for ( std::size_t i = 0; i < size; ++i) {\ + if ( value_name == value_names[i] ) {\ + return values[i];\ + }\ + }\ + return std::nullopt;\ + }\ + [[maybe_unused]] static constexpr enum_type from_value_string_or_default(std::string_view value_name, enum_type def) noexcept {\ + if ( auto e = from_value_string(value_name) ) {\ + return *e;\ + }\ + return def;\ + }\ + [[maybe_unused]] static enum_type from_value_string_or_throw(std::string_view value_name) {\ + if ( auto e = from_value_string(value_name) ) {\ + return *e;\ + }\ + ::enum_hpp::detail::throw_exception_with(#Enum "_traits::from_value_string_or_throw(): invalid argument");\ + }\ [[maybe_unused]] static constexpr std::optional to_index(enum_type e) noexcept {\ switch ( e ) {\ ENUM_HPP_GENERATE_VALUE_TO_INDEX_CASES(Enum, Fields)\ diff --git a/untests/enum_tests.cpp b/untests/enum_tests.cpp index 2b1a5cf..2d82cb5 100644 --- a/untests/enum_tests.cpp +++ b/untests/enum_tests.cpp @@ -262,6 +262,63 @@ TEST_CASE("enum") { } } + SUBCASE("to_value_string") { + { + STATIC_CHECK(sn::color_traits::to_value_string(sn::color::red) == "2"); + STATIC_CHECK(sn::color_traits::to_value_string(sn::color::green) == ""); + STATIC_CHECK(sn::color_traits::to_value_string(sn::color::blue) == "red + 4"); + + STATIC_CHECK(sn::color_traits::to_value_string_or_empty(sn::color::red) == "2"); + STATIC_CHECK(sn::color_traits::to_value_string_or_empty(sn::color::green) == ""); + STATIC_CHECK(sn::color_traits::to_value_string_or_empty(sn::color::blue) == "red + 4"); + + CHECK(sn::color_traits::to_value_string_or_throw(sn::color::red) == "2"); + CHECK(sn::color_traits::to_value_string_or_throw(sn::color::green) == ""); + CHECK(sn::color_traits::to_value_string_or_throw(sn::color::blue) == "red + 4"); + + STATIC_CHECK_FALSE(sn::color_traits::to_value_string(sn::color(42))); + STATIC_CHECK(sn::color_traits::to_value_string_or_empty(sn::color(42)) == ""); + #ifndef ENUM_HPP_NO_EXCEPTIONS + CHECK_THROWS_AS(sn::color_traits::to_value_string_or_throw(sn::color(42)), enum_hpp::exception); + #endif + + STATIC_CHECK(enum_hpp::to_value_string(sn::color::red) == "2"); + STATIC_CHECK(enum_hpp::to_value_string(sn::color::green) == ""); + STATIC_CHECK(enum_hpp::to_value_string(sn::color::blue) == "red + 4"); + + STATIC_CHECK(enum_hpp::to_value_string_or_empty(sn::color::red) == "2"); + STATIC_CHECK(enum_hpp::to_value_string_or_empty(sn::color::green) == ""); + STATIC_CHECK(enum_hpp::to_value_string_or_empty(sn::color::blue) == "red + 4"); + + CHECK(enum_hpp::to_value_string_or_throw(sn::color::red) == "2"); + CHECK(enum_hpp::to_value_string_or_throw(sn::color::green) == ""); + CHECK(enum_hpp::to_value_string_or_throw(sn::color::blue) == "red + 4"); + + STATIC_CHECK_FALSE(enum_hpp::to_value_string(sn::color(42))); + STATIC_CHECK(enum_hpp::to_value_string_or_empty(sn::color(42)) == ""); + #ifndef ENUM_HPP_NO_EXCEPTIONS + CHECK_THROWS_AS(enum_hpp::to_value_string_or_throw(sn::color(42)), enum_hpp::exception); + #endif + } + + { + STATIC_CHECK(sn::render::mask_traits::to_value_string(sn::render::mask::none) == ""); + STATIC_CHECK(sn::render::mask_traits::to_value_string(sn::render::mask::color) == "1 << 0"); + STATIC_CHECK(sn::render::mask_traits::to_value_string(sn::render::mask::alpha) == "1 << 1"); + STATIC_CHECK(sn::render::mask_traits::to_value_string(sn::render::mask::all) == "color | alpha"); + + STATIC_CHECK(sn::render::mask_traits::to_value_string_or_empty(sn::render::mask::none) == ""); + STATIC_CHECK(sn::render::mask_traits::to_value_string_or_empty(sn::render::mask::color) == "1 << 0"); + STATIC_CHECK(sn::render::mask_traits::to_value_string_or_empty(sn::render::mask::alpha) == "1 << 1"); + STATIC_CHECK(sn::render::mask_traits::to_value_string_or_empty(sn::render::mask::all) == "color | alpha"); + + CHECK(sn::render::mask_traits::to_value_string_or_throw(sn::render::mask::none) == ""); + CHECK(sn::render::mask_traits::to_value_string_or_throw(sn::render::mask::color) == "1 << 0"); + CHECK(sn::render::mask_traits::to_value_string_or_throw(sn::render::mask::alpha) == "1 << 1"); + CHECK(sn::render::mask_traits::to_value_string_or_throw(sn::render::mask::all) == "color | alpha"); + } + } + SUBCASE("from_string") { { STATIC_CHECK(sn::color_traits::from_string("red") == sn::color::red); @@ -307,6 +364,46 @@ TEST_CASE("enum") { } } + SUBCASE("from_value_string") { + { + STATIC_CHECK(sn::render::mask_traits::from_value_string("") == sn::render::mask::none); + STATIC_CHECK(sn::render::mask_traits::from_value_string("1 << 0") == sn::render::mask::color); + STATIC_CHECK(sn::render::mask_traits::from_value_string("1 << 1") == sn::render::mask::alpha); + STATIC_CHECK(sn::render::mask_traits::from_value_string("color | alpha") == sn::render::mask::all); + + STATIC_CHECK(sn::color_traits::from_value_string_or_default("2", sn::color::green) == sn::color::red); + STATIC_CHECK(sn::color_traits::from_value_string_or_default("", sn::color::red) == sn::color::green); + STATIC_CHECK(sn::color_traits::from_value_string_or_default("red + 4", sn::color::red) == sn::color::blue); + + #ifndef ENUM_HPP_NO_EXCEPTIONS + CHECK(sn::color_traits::from_value_string_or_throw("2") == sn::color::red); + CHECK(sn::color_traits::from_value_string_or_throw("") == sn::color::green); + CHECK(sn::color_traits::from_value_string_or_throw("red + 4") == sn::color::blue); + #endif + + STATIC_CHECK_FALSE(sn::color_traits::from_value_string("42")); + STATIC_CHECK(sn::color_traits::from_value_string_or_default("42", sn::color::red) == sn::color::red); + #ifndef ENUM_HPP_NO_EXCEPTIONS + CHECK_THROWS_AS(sn::color_traits::from_value_string_or_throw("42"), enum_hpp::exception); + #endif + } + { + STATIC_CHECK(enum_hpp::from_value_string("") == sn::render::mask::none); + STATIC_CHECK(enum_hpp::from_value_string("1 << 0") == sn::render::mask::color); + STATIC_CHECK(enum_hpp::from_value_string("1 << 1") == sn::render::mask::alpha); + STATIC_CHECK(enum_hpp::from_value_string("color | alpha") == sn::render::mask::all); + STATIC_CHECK_FALSE(enum_hpp::from_value_string("42")); + + STATIC_CHECK(enum_hpp::from_value_string_or_default("2", sn::color::green) == sn::color::red); + STATIC_CHECK(enum_hpp::from_value_string_or_default("", sn::color::red) == sn::color::green); + STATIC_CHECK(enum_hpp::from_value_string_or_default("red + 4", sn::color::red) == sn::color::blue); + + CHECK(enum_hpp::from_value_string_or_throw("2") == sn::color::red); + CHECK(enum_hpp::from_value_string_or_throw("") == sn::color::green); + CHECK(enum_hpp::from_value_string_or_throw("red + 4") == sn::color::blue); + } + } + SUBCASE("to_index") { { STATIC_CHECK(sn::color_traits::to_index(sn::color::red) == 0u);