From 9b19f037264ed9ede1729201ff6396fd7c97373f Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Wed, 6 Dec 2023 11:25:58 +0000 Subject: [PATCH 1/2] Correct name of inner detail namespace --- ACore/src/ecflow/core/Converter.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ACore/src/ecflow/core/Converter.hpp b/ACore/src/ecflow/core/Converter.hpp index 4ef865d09..ffdb0e7e6 100644 --- a/ACore/src/ecflow/core/Converter.hpp +++ b/ACore/src/ecflow/core/Converter.hpp @@ -24,7 +24,7 @@ struct bad_conversion : public std::runtime_error explicit bad_conversion(const std::string& m) : std::runtime_error(m) {} }; -namespace details { +namespace detail { template inline static auto try_lexical_convert(From&& v) { @@ -36,12 +36,12 @@ inline static auto try_lexical_convert(From&& v) { } } -} // namespace details +} // namespace detail template struct converter_traits { - inline static auto convert(From&& v) { return details::try_lexical_convert(std::forward(v)); } + inline static auto convert(From&& v) { return detail::try_lexical_convert(std::forward(v)); } }; template <> @@ -64,7 +64,7 @@ struct converter_traits || std::is template inline auto convert_to(From&& v) { - using namespace ecf::details; + using namespace ecf::detail; return converter_traits::convert(std::forward(v)); } From 88e9f3e29de3fcb95956fb8849b80edb8c00d783 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Wed, 6 Dec 2023 14:01:13 +0000 Subject: [PATCH 2/2] Avoid repeated code to map enum values to designations The goals behind these changes is to create a structure that holds the mapping between enum value and the corresponding designation, and then use it to make conversions. This approach avoids needless source code repetition (including repeated designation values), and allows to easily support new enum values/designation, by simply adding new entries to the mapping table. Re ECFLOW-1931 --- ACore/src/ecflow/core/Enumerate.hpp | 124 ++++++ Base/src/ecflow/base/cts/user/AlterCmd.cpp | 416 ++++++--------------- Base/src/ecflow/base/cts/user/AlterCmd.hpp | 6 +- 3 files changed, 247 insertions(+), 299 deletions(-) create mode 100644 ACore/src/ecflow/core/Enumerate.hpp diff --git a/ACore/src/ecflow/core/Enumerate.hpp b/ACore/src/ecflow/core/Enumerate.hpp new file mode 100644 index 000000000..2adc3d0ff --- /dev/null +++ b/ACore/src/ecflow/core/Enumerate.hpp @@ -0,0 +1,124 @@ +/* + * Copyright 2009- ECMWF. + * + * This software is licensed under the terms of the Apache Licence version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#ifndef ecflow_core_Enumerate_HPP +#define ecflow_core_Enumerate_HPP + +#include +#include + +#include + +namespace ecf { + +namespace detail { + +/** + * EnumTraits defines the mapping between a set of enum values and their designation. + * + * EnumTraits must define: + * - the mapping `map`, provided as an std::array composes of an std::pair for each enum value + * - the `size`, holding the number os entries in `map` + * + * @tparam E + */ + +template +struct EnumTraits +{ +}; + +} // namespace detail + +template > +struct Enumerate +{ +public: + using enum_t = E; + using string_t = std::string_view; + + /** + * Convert the given enum value to its designation + * + * @param e the enum value + * @return the designation, in case it exists; an empty optional, otherwise + */ + static constexpr inline std::optional to_string(enum_t e) noexcept { + auto found = std::find_if( + std::begin(TRAITS::map), std::end(TRAITS::map), [&](const auto& item) { return item.first == e; }); + if (found == std::end(TRAITS::map)) { + return std::nullopt; + } + return std::make_optional(found->second); + } + + /** + * Convert the given designation to the related enum value + * + * @param s the designation + * @return the enum value, in case it exists; an empty optional, otherwise + */ + static constexpr inline std::optional to_enum(string_t s) noexcept { + auto found = std::find_if( + std::begin(TRAITS::map), std::end(TRAITS::map), [&](const auto& item) { return item.second == s; }); + if (found == std::end(TRAITS::map)) { + return std::nullopt; + } + return std::make_optional(found->first); + } + + /** + * Checks if the given designation is valid (i.e. has a related enum value) + * + * @param s the designation + * @return true, if valid; false, otherwise + */ + static bool inline is_valid(string_t s) { + auto found = std::find_if( + std::begin(TRAITS::map), std::end(TRAITS::map), [&](const auto& item) { return item.second == s; }); + return found != std::end(TRAITS::map); + } + + /** + * The number of mapped enum values + */ + static const size_t size = TRAITS::size; + + /** + * The vector of mapped enum values + */ + static auto enums() { + std::vector result; + result.reserve(TRAITS::size); + std::transform(std::begin(TRAITS::map), + std::end(TRAITS::map), + std::back_inserter(result), + [](const auto& item) { return item.first; }); + return result; + } + + /** + * The vector of mapped designations + */ + static auto designations() { + std::vector result; + result.reserve(TRAITS::size); + std::transform(std::begin(TRAITS::map), + std::end(TRAITS::map), + std::back_inserter(result), + [](const auto& item) { return item.second; }); + + return result; + } +}; + +} // namespace ecf + +#endif /* ecflow_core_Enumerate_HPP */ diff --git a/Base/src/ecflow/base/cts/user/AlterCmd.cpp b/Base/src/ecflow/base/cts/user/AlterCmd.cpp index de1fab151..1c6180db8 100644 --- a/Base/src/ecflow/base/cts/user/AlterCmd.cpp +++ b/Base/src/ecflow/base/cts/user/AlterCmd.cpp @@ -19,6 +19,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/core/Converter.hpp" +#include "ecflow/core/Enumerate.hpp" #include "ecflow/core/Extract.hpp" #include "ecflow/core/Log.hpp" #include "ecflow/core/Str.hpp" @@ -47,327 +48,150 @@ static std::string dump_args(const std::vector& options, const std: return the_args; } +namespace ecf::detail { + +template <> +struct EnumTraits +{ + using underlying_t = std::underlying_type_t; + + static constexpr std::array map = std::array{ + // clang-format off + std::make_pair(AlterCmd::DEL_VARIABLE, "variable"), + std::make_pair(AlterCmd::DEL_TIME, "time"), + std::make_pair(AlterCmd::DEL_TODAY, "today"), + std::make_pair(AlterCmd::DEL_DATE, "date"), + std::make_pair(AlterCmd::DEL_DAY, "day"), + std::make_pair(AlterCmd::DEL_CRON, "cron"), + std::make_pair(AlterCmd::DEL_EVENT, "event"), + std::make_pair(AlterCmd::DEL_METER, "meter"), + std::make_pair(AlterCmd::DEL_LABEL, "label"), + std::make_pair(AlterCmd::DEL_TRIGGER, "trigger"), + std::make_pair(AlterCmd::DEL_COMPLETE, "complete"), + std::make_pair(AlterCmd::DEL_REPEAT, "repeat"), + std::make_pair(AlterCmd::DEL_LIMIT, "limit"), + std::make_pair(AlterCmd::DEL_LIMIT_PATH, "limit_path"), + std::make_pair(AlterCmd::DEL_INLIMIT, "inlimit"), + std::make_pair(AlterCmd::DEL_ZOMBIE, "zombie"), + std::make_pair(AlterCmd::DEL_LATE, "late"), + std::make_pair(AlterCmd::DEL_QUEUE, "queue"), + std::make_pair(AlterCmd::DEL_GENERIC, "generic") + // clang-format on + }; + static constexpr size_t size = map.size(); + + static_assert(EnumTraits::size == map.back().first); +}; + +template <> +struct EnumTraits +{ + using underlying_t = std::underlying_type_t; + + static constexpr std::array map = std::array{ + // clang-format off + std::make_pair(AlterCmd::ADD_TIME, "time"), + std::make_pair(AlterCmd::ADD_TODAY, "today"), + std::make_pair(AlterCmd::ADD_DATE, "date"), + std::make_pair(AlterCmd::ADD_DAY, "day"), + std::make_pair(AlterCmd::ADD_ZOMBIE, "zombie"), + std::make_pair(AlterCmd::ADD_VARIABLE, "variable"), + std::make_pair(AlterCmd::ADD_LATE, "late"), + std::make_pair(AlterCmd::ADD_LIMIT, "limit"), + std::make_pair(AlterCmd::ADD_INLIMIT, "inlimit"), + std::make_pair(AlterCmd::ADD_LABEL, "label") + // clang-format on + }; + static constexpr size_t size = map.size(); + + static_assert(EnumTraits::size == map.back().first); +}; + +template <> +struct EnumTraits +{ + using underlying_t = std::underlying_type_t; + + static constexpr std::array map = std::array{ + // clang-format off + std::make_pair(AlterCmd::VARIABLE, "variable"), + std::make_pair(AlterCmd::CLOCK_TYPE, "clock_type"), + std::make_pair(AlterCmd::CLOCK_DATE, "clock_date"), + std::make_pair(AlterCmd::CLOCK_GAIN, "clock_gain"), + std::make_pair(AlterCmd::CLOCK_SYNC, "clock_sync"), + std::make_pair(AlterCmd::EVENT, "event"), + std::make_pair(AlterCmd::METER, "meter"), + std::make_pair(AlterCmd::LABEL, "label"), + std::make_pair(AlterCmd::TRIGGER, "trigger"), + std::make_pair(AlterCmd::COMPLETE, "complete"), + std::make_pair(AlterCmd::REPEAT, "repeat"), + std::make_pair(AlterCmd::LIMIT_MAX, "limit_max"), + std::make_pair(AlterCmd::LIMIT_VAL, "limit_value"), + std::make_pair(AlterCmd::DEFSTATUS, "defstatus"), + std::make_pair(AlterCmd::LATE, "late"), + std::make_pair(AlterCmd::TIME, "time"), + std::make_pair(AlterCmd::TODAY, "today") + // clang-format on + }; + static constexpr size_t size = map.size(); + + static_assert(EnumTraits::size == map.back().first); +}; + +} // namespace ecf::detail + static AlterCmd::Delete_attr_type deleteAttrType(const std::string& s) { - if (s == "variable") - return AlterCmd::DEL_VARIABLE; - if (s == "time") - return AlterCmd::DEL_TIME; - if (s == "today") - return AlterCmd::DEL_TODAY; - if (s == "date") - return AlterCmd::DEL_DATE; - if (s == "day") - return AlterCmd::DEL_DAY; - if (s == "cron") - return AlterCmd::DEL_CRON; - if (s == "event") - return AlterCmd::DEL_EVENT; - if (s == "meter") - return AlterCmd::DEL_METER; - if (s == "label") - return AlterCmd::DEL_LABEL; - if (s == "trigger") - return AlterCmd::DEL_TRIGGER; - if (s == "complete") - return AlterCmd::DEL_COMPLETE; - if (s == "repeat") - return AlterCmd::DEL_REPEAT; - if (s == "limit") - return AlterCmd::DEL_LIMIT; - if (s == "limit_path") - return AlterCmd::DEL_LIMIT_PATH; - if (s == "inlimit") - return AlterCmd::DEL_INLIMIT; - if (s == "zombie") - return AlterCmd::DEL_ZOMBIE; - if (s == "late") - return AlterCmd::DEL_LATE; - if (s == "queue") - return AlterCmd::DEL_QUEUE; - if (s == "generic") - return AlterCmd::DEL_GENERIC; + if (auto found = ecf::Enumerate::to_enum(s); found) { + return found.value(); + } return AlterCmd::DELETE_ATTR_ND; } + static std::string to_string(AlterCmd::Delete_attr_type d) { - switch (d) { - case AlterCmd::DEL_VARIABLE: - return "variable"; - break; - case AlterCmd::DEL_TIME: - return "time"; - break; - case AlterCmd::DEL_TODAY: - return "today"; - break; - case AlterCmd::DEL_DATE: - return "date"; - break; - case AlterCmd::DEL_DAY: - return "day"; - break; - case AlterCmd::DEL_CRON: - return "cron"; - break; - case AlterCmd::DEL_EVENT: - return "event"; - break; - case AlterCmd::DEL_METER: - return "meter"; - break; - case AlterCmd::DEL_LABEL: - return "label"; - break; - case AlterCmd::DEL_TRIGGER: - return "trigger"; - break; - case AlterCmd::DEL_COMPLETE: - return "complete"; - break; - case AlterCmd::DEL_REPEAT: - return "repeat"; - break; - case AlterCmd::DEL_LIMIT: - return "limit"; - break; - case AlterCmd::DEL_LIMIT_PATH: - return "limit_path"; - break; - case AlterCmd::DEL_INLIMIT: - return "inlimit"; - break; - case AlterCmd::DEL_ZOMBIE: - return "zombie"; - break; - case AlterCmd::DEL_LATE: - return "late"; - break; - case AlterCmd::DEL_QUEUE: - return "queue"; - break; - case AlterCmd::DEL_GENERIC: - return "generic"; - break; - case AlterCmd::DELETE_ATTR_ND: - break; - default: - break; + if (auto found = ecf::Enumerate::to_string(d); found) { + return std::string{found.value()}; } - return string(); + return {}; } + static void validDeleteAttr(std::vector& vec) { - vec.reserve(19); - vec.emplace_back("variable"); - vec.emplace_back("time"); - vec.emplace_back("today"); - vec.emplace_back("date"); - vec.emplace_back("day"); - vec.emplace_back("cron"); - vec.emplace_back("event"); - vec.emplace_back("meter"); - vec.emplace_back("label"); - vec.emplace_back("trigger"); - vec.emplace_back("complete"); - vec.emplace_back("repeat"); - vec.emplace_back("limit"); - vec.emplace_back("limit_path"); - vec.emplace_back("inlimit"); - vec.emplace_back("zombie"); - vec.emplace_back("late"); - vec.emplace_back("queue"); - vec.emplace_back("generic"); + vec = ecf::Enumerate::designations(); } static AlterCmd::Add_attr_type addAttrType(const std::string& s) { - if (s == "time") - return AlterCmd::ADD_TIME; - if (s == "today") - return AlterCmd::ADD_TODAY; - if (s == "date") - return AlterCmd::ADD_DATE; - if (s == "day") - return AlterCmd::ADD_DAY; - if (s == "zombie") - return AlterCmd::ADD_ZOMBIE; - if (s == "variable") - return AlterCmd::ADD_VARIABLE; - if (s == "late") - return AlterCmd::ADD_LATE; - if (s == "limit") - return AlterCmd::ADD_LIMIT; - if (s == "inlimit") - return AlterCmd::ADD_INLIMIT; - if (s == "label") - return AlterCmd::ADD_LABEL; + if (auto found = ecf::Enumerate::to_enum(s); found) { + return found.value(); + } return AlterCmd::ADD_ATTR_ND; } + static std::string to_string(AlterCmd::Add_attr_type a) { - switch (a) { - case AlterCmd::ADD_TIME: - return "time;"; - break; - case AlterCmd::ADD_TODAY: - return "today"; - break; - case AlterCmd::ADD_DATE: - return "date"; - break; - case AlterCmd::ADD_DAY: - return "day"; - break; - case AlterCmd::ADD_ZOMBIE: - return "zombie"; - break; - case AlterCmd::ADD_VARIABLE: - return "variable"; - break; - case AlterCmd::ADD_LATE: - return "late"; - break; - case AlterCmd::ADD_LIMIT: - return "limit"; - break; - case AlterCmd::ADD_INLIMIT: - return "inlimit"; - break; - case AlterCmd::ADD_LABEL: - return "label"; - break; - case AlterCmd::ADD_ATTR_ND: - break; + if (auto found = ecf::Enumerate::to_string(a); found) { + return std::string{found.value()}; } - return string(); + return {}; } + static void validAddAttr(std::vector& vec) { - vec.reserve(10); - vec.emplace_back("time"); - vec.emplace_back("today"); - vec.emplace_back("date"); - vec.emplace_back("day"); - vec.emplace_back("zombie"); - vec.emplace_back("variable"); - vec.emplace_back("late"); - vec.emplace_back("limit"); - vec.emplace_back("inlimit"); - vec.emplace_back("label"); + vec = Enumerate::designations(); } static AlterCmd::Change_attr_type changeAttrType(const std::string& s) { - if (s == "variable") - return AlterCmd::VARIABLE; - if (s == "clock_type") - return AlterCmd::CLOCK_TYPE; - if (s == "clock_date") - return AlterCmd::CLOCK_DATE; - if (s == "clock_gain") - return AlterCmd::CLOCK_GAIN; - if (s == "clock_sync") - return AlterCmd::CLOCK_SYNC; - if (s == "event") - return AlterCmd::EVENT; - if (s == "meter") - return AlterCmd::METER; - if (s == "label") - return AlterCmd::LABEL; - if (s == "trigger") - return AlterCmd::TRIGGER; - if (s == "complete") - return AlterCmd::COMPLETE; - if (s == "repeat") - return AlterCmd::REPEAT; - if (s == "limit_max") - return AlterCmd::LIMIT_MAX; - if (s == "limit_value") - return AlterCmd::LIMIT_VAL; - if (s == "defstatus") - return AlterCmd::DEFSTATUS; - if (s == "late") - return AlterCmd::LATE; - if (s == "time") - return AlterCmd::TIME; - if (s == "today") - return AlterCmd::TODAY; + if (auto found = Enumerate::to_enum(s); found) { + return found.value(); + } return AlterCmd::CHANGE_ATTR_ND; } + static std::string to_string(AlterCmd::Change_attr_type c) { - switch (c) { - case AlterCmd::VARIABLE: - return "variable"; - break; - case AlterCmd::CLOCK_TYPE: - return "clock_type"; - break; - case AlterCmd::CLOCK_DATE: - return "clock_date"; - break; - case AlterCmd::CLOCK_GAIN: - return "clock_gain"; - break; - case AlterCmd::CLOCK_SYNC: - return "clock_sync"; - break; - case AlterCmd::EVENT: - return "event"; - break; - case AlterCmd::METER: - return "meter"; - break; - case AlterCmd::LABEL: - return "label"; - break; - case AlterCmd::TRIGGER: - return "trigger"; - break; - case AlterCmd::COMPLETE: - return "complete"; - break; - case AlterCmd::REPEAT: - return "repeat"; - break; - case AlterCmd::LIMIT_MAX: - return "limit_max"; - break; - case AlterCmd::LIMIT_VAL: - return "limit_value"; - break; - case AlterCmd::DEFSTATUS: - return "defstatus"; - break; - case AlterCmd::LATE: - return "late"; - break; - case AlterCmd::TIME: - return "time"; - break; - case AlterCmd::TODAY: - return "today"; - break; - case AlterCmd::CHANGE_ATTR_ND: - break; - default: - break; + if (auto found = Enumerate::to_string(c); found) { + return std::string{found.value()}; } - return string(); + return {}; } + static void validChangeAttr(std::vector& vec) { - vec.reserve(18); - vec.emplace_back("variable"); - vec.emplace_back("clock_type"); - vec.emplace_back("clock_gain"); - vec.emplace_back("clock_date"); - vec.emplace_back("clock_sync"); - vec.emplace_back("event"); - vec.emplace_back("meter"); - vec.emplace_back("label"); - vec.emplace_back("trigger"); - vec.emplace_back("complete"); - vec.emplace_back("repeat"); - vec.emplace_back("limit_max"); - vec.emplace_back("limit_value"); - vec.emplace_back("defstatus"); - vec.emplace_back("free_password"); - vec.emplace_back("late"); - vec.emplace_back("time"); - vec.emplace_back("today"); + vec = ecf::Enumerate::designations(); } //======================================================================================= diff --git a/Base/src/ecflow/base/cts/user/AlterCmd.hpp b/Base/src/ecflow/base/cts/user/AlterCmd.hpp index 44874953d..38632e78a 100644 --- a/Base/src/ecflow/base/cts/user/AlterCmd.hpp +++ b/Base/src/ecflow/base/cts/user/AlterCmd.hpp @@ -36,7 +36,7 @@ class AlterCmd final : public UserCmd { DELETE_ATTR_ND, DEL_LATE, DEL_QUEUE, - DEL_GENERIC + DEL_GENERIC, }; enum Change_attr_type { @@ -57,7 +57,7 @@ class AlterCmd final : public UserCmd { CLOCK_SYNC, LATE, TIME, - TODAY + TODAY, }; enum Add_attr_type { @@ -71,7 +71,7 @@ class AlterCmd final : public UserCmd { ADD_LATE, ADD_LIMIT, ADD_INLIMIT, - ADD_LABEL + ADD_LABEL, }; // Python