diff options
author | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/draft/enum.h |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/draft/enum.h')
-rw-r--r-- | util/draft/enum.h | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/util/draft/enum.h b/util/draft/enum.h new file mode 100644 index 00000000000..18002b7df20 --- /dev/null +++ b/util/draft/enum.h @@ -0,0 +1,136 @@ +#pragma once + +#include <bitset> + +#include <util/generic/strbuf.h> +#include <util/stream/str.h> +#include <util/string/cast.h> +#include <util/string/split.h> +#include <utility> + +class TEnumNotFoundException: public yexception { +}; + +#define EnumFromString(key, entries) EnumFromStringImpl(key, entries, Y_ARRAY_SIZE(entries)) +#define EnumFromStringWithSize(key, entries, size) EnumFromStringImpl(key, entries, size) +#define FindEnumFromString(key, entries) FindEnumFromStringImpl(key, entries, Y_ARRAY_SIZE(entries)) +#define FindEnumFromStringWithSize(key, entries, size) FindEnumFromStringImpl(key, entries, size) +#define EnumToString(key, entries) EnumToStringImpl(key, entries, Y_ARRAY_SIZE(entries)) +#define EnumToStringWithSize(key, entries, size) EnumToStringImpl(key, entries, size) +#define PrintEnumItems(entries) PrintEnumItemsImpl(entries, Y_ARRAY_SIZE(entries)) + +template <class K1, class K2, class V> +const V* FindEnumFromStringImpl(K1 key, const std::pair<K2, V>* entries, size_t arraySize) { + for (size_t i = 0; i < arraySize; i++) + if (entries[i].first == key) + return &entries[i].second; + return nullptr; +} + +// special version for const char* +template <class V> +const V* FindEnumFromStringImpl(const char* key, const std::pair<const char*, V>* entries, size_t arraySize) { + for (size_t i = 0; i < arraySize; i++) + if (entries[i].first && key && !strcmp(entries[i].first, key)) + return &entries[i].second; + return nullptr; +} + +template <class K, class V> +TString PrintEnumItemsImpl(const std::pair<K, V>* entries, size_t arraySize) { + TString result; + TStringOutput out(result); + for (size_t i = 0; i < arraySize; i++) + out << (i ? ", " : "") << "'" << entries[i].first << "'"; + return result; +} + +// special version for const char* +template <class V> +TString PrintEnumItemsImpl(const std::pair<const char*, V>* entries, size_t arraySize) { + TString result; + TStringOutput out(result); + for (size_t i = 0; i < arraySize; i++) + out << (i ? ", " : "") << "'" << (entries[i].first ? entries[i].first : "<null>") << "'"; + return result; +} + +template <class K1, class K2, class V> +const V* EnumFromStringImpl(K1 key, const std::pair<K2, V>* entries, size_t arraySize) { + const V* res = FindEnumFromStringImpl(key, entries, arraySize); + if (res) + return res; + + ythrow TEnumNotFoundException() << "Key '" << key << "' not found in enum. Valid options are: " << PrintEnumItemsImpl(entries, arraySize) << ". "; +} + +template <class K, class V> +const K* EnumToStringImpl(V value, const std::pair<K, V>* entries, size_t arraySize) { + for (size_t i = 0; i < arraySize; i++) + if (entries[i].second == value) + return &entries[i].first; + + TEnumNotFoundException exc; + exc << "Value '" << int(value) << "' not found in enum. Valid values are: "; + for (size_t i = 0; i < arraySize; i++) + exc << (i ? ", " : "") << int(entries[i].second); + exc << ". "; + ythrow exc; +} + +/////////////////////////////////// + +template <class B> +inline void SetEnumFlagsForEmptySpec(B& flags, bool allIfEmpty) { + if (allIfEmpty) { + flags.set(); + } else { + flags.reset(); + } +} + +// all set by default +template <class E, size_t N, size_t B> +inline void SetEnumFlags(const std::pair<const char*, E> (&str2Enum)[N], TStringBuf optSpec, + std::bitset<B>& flags, bool allIfEmpty = true) { + if (optSpec.empty()) { + SetEnumFlagsForEmptySpec(flags, allIfEmpty); + } else { + flags.reset(); + for (const auto& it : StringSplitter(optSpec).Split(',')) { + E e = *EnumFromStringImpl(ToString(it.Token()).data(), str2Enum, N); + flags.set(e); + } + } +} + +template <class E, size_t B> +inline void SetEnumFlags(const std::pair<const char*, E>* str2Enum, TStringBuf optSpec, + std::bitset<B>& flags, const size_t size, + bool allIfEmpty = true) { + if (optSpec.empty()) { + SetEnumFlagsForEmptySpec(flags, allIfEmpty); + } else { + flags.reset(); + for (const auto& it : StringSplitter(optSpec).Split(',')) { + E e = *EnumFromStringImpl(ToString(it.Token()).data(), str2Enum, size); + flags.set(e); + } + } +} + +// for enums generated with GENERATE_ENUM_SERIALIZATION +template <class E, size_t B> +inline void SetEnumFlags(TStringBuf optSpec, std::bitset<B>& flags, bool allIfEmpty = true) { + if (optSpec.empty()) { + SetEnumFlagsForEmptySpec(flags, allIfEmpty); + } else { + flags.reset(); + for (const auto& it : StringSplitter(optSpec).Split(',')) { + E e; + if (!TryFromString(it.Token(), e)) + ythrow yexception() << "Unknown enum value '" << it.Token() << "'"; + flags.set((size_t)e); + } + } +} |