From fdcf0d649dd3496592d91e6eda1e45b747e31e4e Mon Sep 17 00:00:00 2001 From: Felix Weiglhofer <weiglhofer@fias.uni-frankfurt.de> Date: Fri, 2 Jun 2023 09:39:14 +0000 Subject: [PATCH] algo: Add support for Enum / String conversion. --- algo/base/Types.h | 67 +++++++++++++++++++ algo/base/util/SerializableEnum.h | 105 ++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 algo/base/Types.h create mode 100644 algo/base/util/SerializableEnum.h diff --git a/algo/base/Types.h b/algo/base/Types.h new file mode 100644 index 0000000000..6ef3ee98b7 --- /dev/null +++ b/algo/base/Types.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ +#ifndef CBM_BASE_TYPES_H +#define CBM_BASE_TYPES_H + +#include "util/SerializableEnum.h" + +namespace cbm::algo +{ + + enum class Detector + { + STS, + TOF, + }; + + template<> + struct EnumIsSerializable<Detector> : std::true_type { + }; + + template<> + const EnumDict_t<Detector> EnumDict<Detector> = { + {"STS", Detector::STS}, + {"TOF", Detector::TOF}, + }; + + enum class Step + { + Unpack, + DigiTrigger, + LocalReco, + }; + + template<> + struct EnumIsSerializable<Step> : std::true_type { + }; + + template<> + const EnumDict_t<Step> EnumDict<Step> = { + {"Unpack", Step::Unpack}, + {"Digitrigger", Step::DigiTrigger}, + {"Localreco", Step::LocalReco}, + }; + + enum class RecoData + { + Digi, + Cluster, + Hit, + }; + + template<> + struct EnumIsSerializable<RecoData> : std::true_type { + }; + + template<> + const EnumDict_t<RecoData> EnumDict<RecoData> = { + {"Digi", RecoData::Digi}, + {"Cluster", RecoData::Cluster}, + {"Hit", RecoData::Hit}, + }; + +} // namespace cbm::algo + + +#endif diff --git a/algo/base/util/SerializableEnum.h b/algo/base/util/SerializableEnum.h new file mode 100644 index 0000000000..8921b3ef79 --- /dev/null +++ b/algo/base/util/SerializableEnum.h @@ -0,0 +1,105 @@ +/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ +#ifndef CBM_ALGO_BASE_UTIL_SERIALIZABLEENUM_H +#define CBM_ALGO_BASE_UTIL_SERIALIZABLEENUM_H + +#include <algorithm> +#include <iostream> +#include <optional> +#include <set> +#include <stdexcept> +#include <string_view> + +#include <fmt/format.h> + +namespace cbm::algo +{ + /** + * @brief Helper class to serialize enums to strings and back. + * + * @tparam T The enum type. + * + * To use this class, you need to specialize EnumIsSerializable<T> and EnumStringMap<T>. + * Used to indicate that an enum can be converted to / from a string. + * + * Example: + * @code{.cpp} + * enum class Detector { + * STS, + * TOF, + * }; + * + * // Set to true to indicate that the enum is serializable. + * template<> + * struct EnumIsSerializable<Detector> : std::true_type {}; + * + * // Create dictionary to convert enum to string and back. + * template<> + * const EnumDict_t<Detector> EnumDict<Detector> = { + * {"sts", Detector::STS}, + * {"tof", Detector::TOF}, + * }; + * + * // Use it like this: + * L_(info) << ToString(Detector::STS); // Prints "sts" + * + * std::optional<Detector> d = FromString<Detector>("tof"); // *d == Detector::TOF + * std::optional<Detector> d2 = FromString<Detector>("invalid"); // d2 == std::nullopt + * @endcode + */ + template<typename T> + struct EnumIsSerializable : std::false_type { + }; + + template<typename T> + using EnumDict_t = std::set<std::pair<std::string_view, T>>; + + template<typename T> + inline const EnumDict_t<T> EnumDict; + + template<typename T, typename = std::enable_if_t<EnumIsSerializable<T>::value>> + std::optional<T> FromString(std::string_view str) + { + const auto& set = EnumDict<T>; + auto it = std::find_if(set.begin(), set.end(), [str](const auto& pair) { return pair.first == str; }); + if (it == set.end()) return std::nullopt; + return it->second; + } + + template<typename T, typename = std::enable_if_t<EnumIsSerializable<T>::value>> + std::string_view ToString(T t) + { + const auto& set = EnumDict<T>; + auto it = std::find_if(set.begin(), set.end(), [t](const auto& pair) { return pair.second == t; }); + if (it == set.end()) throw std::runtime_error(fmt::format("Entry {} for enum missing!", static_cast<int>(t))); + return it->first; + } +} // namespace cbm::algo + +// Stream operators for enums +// Placed in global namespace to be found by ADL e.g. for std::ostream_iterator +namespace std +{ + template<typename T, typename = std::enable_if_t<cbm::algo::EnumIsSerializable<T>::value>> + std::ostream& operator<<(std::ostream& os, T t) + { + os << cbm::algo::ToString(t); + return os; + } + + template<typename T, typename = std::enable_if_t<cbm::algo::EnumIsSerializable<T>::value>> + std::istream& operator>>(std::istream& is, T& t) + { + std::string str; + is >> str; + auto maybet = cbm::algo::FromString<T>(str); + + if (!maybet) throw std::invalid_argument("Could not parse " + str + " as Enum"); + t = *maybet; + + return is; + } +} // namespace std + +#endif //CBM_ALGO_BASE_UTIL_SERIALIZABLEENUM_H -- GitLab