diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/yt/misc/enum-inl.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/yt/misc/enum-inl.h')
-rw-r--r-- | library/cpp/yt/misc/enum-inl.h | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/library/cpp/yt/misc/enum-inl.h b/library/cpp/yt/misc/enum-inl.h new file mode 100644 index 00000000000..59ef7047753 --- /dev/null +++ b/library/cpp/yt/misc/enum-inl.h @@ -0,0 +1,385 @@ +#pragma once +#ifndef ENUM_INL_H_ +#error "Direct inclusion of this file is not allowed, include enum.h" +// For the sake of sane code completion. +#include "enum.h" +#endif + +#include <util/string/printf.h> +#include <util/string/cast.h> + +#include <algorithm> +#include <stdexcept> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +#define ENUM__CLASS(name, underlyingType, seq) \ + enum class name : underlyingType \ + { \ + PP_FOR_EACH(ENUM__DOMAIN_ITEM, seq) \ + }; + +#define ENUM__DOMAIN_ITEM(item) \ + PP_IF( \ + PP_IS_SEQUENCE(item), \ + ENUM__DOMAIN_ITEM_SEQ, \ + ENUM__DOMAIN_ITEM_ATOMIC \ + )(item)() + +#define ENUM__DOMAIN_ITEM_ATOMIC(item) \ + item PP_COMMA + +#define ENUM__DOMAIN_ITEM_SEQ(seq) \ + PP_ELEMENT(seq, 0) = PP_ELEMENT(seq, 1) PP_COMMA + +//////////////////////////////////////////////////////////////////////////////// + +namespace NDetail { + +template <typename TValues> +static constexpr bool AreValuesDistinct(const TValues& values) +{ + for (int i = 0; i < static_cast<int>(values.size()); ++i) { + for (int j = i + 1; j < static_cast<int>(values.size()); ++j) { + if (values[i] == values[j]) { + return false; + } + } + } + return true; +} + +} // namespace NDetail + +//////////////////////////////////////////////////////////////////////////////// + +#define ENUM__BEGIN_TRAITS(name, underlyingType, isBit, isStringSerializable, seq) \ + struct TEnumTraitsImpl_##name \ + { \ + using TType = name; \ + using TUnderlying = underlyingType; \ + [[maybe_unused]] static constexpr bool IsBitEnum = isBit; \ + [[maybe_unused]] static constexpr bool IsStringSerializableEnum = isStringSerializable; \ + [[maybe_unused]] static constexpr int DomainSize = PP_COUNT(seq); \ + \ + static constexpr std::array<TStringBuf, DomainSize> Names{{ \ + PP_FOR_EACH(ENUM__GET_DOMAIN_NAMES_ITEM, seq) \ + }}; \ + static constexpr std::array<TType, DomainSize> Values{{ \ + PP_FOR_EACH(ENUM__GET_DOMAIN_VALUES_ITEM, seq) \ + }}; \ + \ + static TStringBuf GetTypeName() \ + { \ + static constexpr TStringBuf typeName = PP_STRINGIZE(name); \ + return typeName; \ + } \ + \ + static const TStringBuf* FindLiteralByValue(TType value) \ + { \ + for (int i = 0; i < DomainSize; ++i) { \ + if (Values[i] == value) { \ + return &Names[i]; \ + } \ + } \ + return nullptr; \ + } \ + \ + static bool FindValueByLiteral(TStringBuf literal, TType* result) \ + { \ + for (int i = 0; i < DomainSize; ++i) { \ + if (Names[i] == literal) { \ + *result = Values[i]; \ + return true; \ + } \ + } \ + return false; \ + } \ + \ + static const std::array<TStringBuf, DomainSize>& GetDomainNames() \ + { \ + return Names; \ + } \ + \ + static const std::array<TType, DomainSize>& GetDomainValues() \ + { \ + return Values; \ + } \ + \ + static TType FromString(TStringBuf str) \ + { \ + TType value; \ + if (!FindValueByLiteral(str, &value)) { \ + throw ::NYT::TSimpleException(Sprintf("Error parsing %s value %s", \ + PP_STRINGIZE(name), \ + TString(str).Quote().c_str()).c_str()); \ + } \ + return value; \ + } + +#define ENUM__GET_DOMAIN_VALUES_ITEM(item) \ + PP_IF( \ + PP_IS_SEQUENCE(item), \ + ENUM__GET_DOMAIN_VALUES_ITEM_SEQ, \ + ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC \ + )(item) + +#define ENUM__GET_DOMAIN_VALUES_ITEM_SEQ(seq) \ + ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC(PP_ELEMENT(seq, 0)) + +#define ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC(item) \ + TType::item, + +#define ENUM__GET_DOMAIN_NAMES_ITEM(item) \ + PP_IF( \ + PP_IS_SEQUENCE(item), \ + ENUM__GET_DOMAIN_NAMES_ITEM_SEQ, \ + ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC \ + )(item) + +#define ENUM__GET_DOMAIN_NAMES_ITEM_SEQ(seq) \ + ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC(PP_ELEMENT(seq, 0)) + +#define ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC(item) \ + TStringBuf(PP_STRINGIZE(item)), + +#define ENUM__DECOMPOSE \ + static std::vector<TType> Decompose(TType value) \ + { \ + std::vector<TType> result; \ + for (int i = 0; i < DomainSize; ++i) { \ + if (static_cast<TUnderlying>(value) & static_cast<TUnderlying>(Values[i])) { \ + result.push_back(Values[i]); \ + } \ + } \ + return result; \ + } + +#define ENUM__MINMAX \ + static constexpr TType GetMinValue() \ + { \ + static_assert(!Values.empty()); \ + return *std::min_element(std::begin(Values), std::end(Values)); \ + } \ + \ + static constexpr TType GetMaxValue() \ + { \ + static_assert(!Values.empty()); \ + return *std::max_element(std::begin(Values), std::end(Values)); \ + } + +#define ENUM__VALIDATE_UNIQUE(name) \ + static_assert(::NYT::NDetail::AreValuesDistinct(Values), \ + "Enumeration " #name " contains duplicate values"); + +#define ENUM__END_TRAITS(name) \ + }; \ + \ + [[maybe_unused]] inline TEnumTraitsImpl_##name GetEnumTraitsImpl(name) \ + { \ + return TEnumTraitsImpl_##name(); \ + } \ + \ + using ::ToString; \ + [[maybe_unused]] inline TString ToString(name value) \ + { \ + return ::NYT::TEnumTraits<name>::ToString(value); \ + } + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +std::vector<T> TEnumTraits<T, true>::Decompose(T value) +{ + return TImpl::Decompose(value); +} + +template <class T> +T TEnumTraits<T, true>::FromString(TStringBuf str) +{ + return TImpl::FromString(str); +} + +template <class T> +TString TEnumTraits<T, true>::ToString(TType value) +{ + TString result; + const auto* literal = FindLiteralByValue(value); + if (literal) { + result = *literal; + } else { + result = GetTypeName(); + result += "("; + result += ::ToString(static_cast<TUnderlying>(value)); + result += ")"; + } + return result; +} + +template <class T> +auto TEnumTraits<T, true>::GetDomainValues() -> const std::array<T, DomainSize>& +{ + return TImpl::GetDomainValues(); +} + +template <class T> +auto TEnumTraits<T, true>::GetDomainNames() -> const std::array<TStringBuf, DomainSize>& +{ + return TImpl::GetDomainNames(); +} + +template <class T> +constexpr T TEnumTraits<T, true>::GetMaxValue() +{ + return TImpl::GetMaxValue(); +} + +template <class T> +constexpr T TEnumTraits<T, true>::GetMinValue() +{ + return TImpl::GetMinValue(); +} + +template <class T> +bool TEnumTraits<T, true>::FindValueByLiteral(TStringBuf literal, TType* result) +{ + return TImpl::FindValueByLiteral(literal, result); +} + +template <class T> +const TStringBuf* TEnumTraits<T, true>::FindLiteralByValue(TType value) +{ + return TImpl::FindLiteralByValue(value); +} + +template <class T> +TStringBuf TEnumTraits<T, true>::GetTypeName() +{ + return TImpl::GetTypeName(); +} + +//////////////////////////////////////////////////////////////////////////////// + +template <class E, class T, E Min, E Max> +TEnumIndexedVector<E, T, Min, Max>::TEnumIndexedVector() + : Items_{} +{ } + +template <class E, class T, E Min, E Max> +TEnumIndexedVector<E, T, Min, Max>::TEnumIndexedVector(std::initializer_list<T> elements) + : Items_{} +{ + Y_ASSERT(std::distance(elements.begin(), elements.end()) <= N); + size_t index = 0; + for (const auto& element : elements) { + Items_[index++] = element; + } +} + +template <class E, class T, E Min, E Max> +T& TEnumIndexedVector<E, T, Min, Max>::operator[] (E index) +{ + Y_ASSERT(index >= Min && index <= Max); + return Items_[static_cast<TUnderlying>(index) - static_cast<TUnderlying>(Min)]; +} + +template <class E, class T, E Min, E Max> +const T& TEnumIndexedVector<E, T, Min, Max>::operator[] (E index) const +{ + return const_cast<TEnumIndexedVector&>(*this)[index]; +} + +template <class E, class T, E Min, E Max> +T* TEnumIndexedVector<E, T, Min, Max>::begin() +{ + return Items_.data(); +} + +template <class E, class T, E Min, E Max> +const T* TEnumIndexedVector<E, T, Min, Max>::begin() const +{ + return Items_.data(); +} + +template <class E, class T, E Min, E Max> +T* TEnumIndexedVector<E, T, Min, Max>::end() +{ + return begin() + N; +} + +template <class E, class T, E Min, E Max> +const T* TEnumIndexedVector<E, T, Min, Max>::end() const +{ + return begin() + N; +} + +template <class E, class T, E Min, E Max> +bool TEnumIndexedVector<E, T, Min, Max>::IsDomainValue(E value) +{ + return value >= Min && value <= Max; +} + +//////////////////////////////////////////////////////////////////////////////// + +#define ENUM__BINARY_BITWISE_OPERATOR(T, assignOp, op) \ + [[maybe_unused]] inline constexpr T operator op (T lhs, T rhs) \ + { \ + using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ + return T(static_cast<TUnderlying>(lhs) op static_cast<TUnderlying>(rhs)); \ + } \ + \ + [[maybe_unused]] inline T& operator assignOp (T& lhs, T rhs) \ + { \ + using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ + lhs = T(static_cast<TUnderlying>(lhs) op static_cast<TUnderlying>(rhs)); \ + return lhs; \ + } + +#define ENUM__UNARY_BITWISE_OPERATOR(T, op) \ + [[maybe_unused]] inline constexpr T operator op (T value) \ + { \ + using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ + return T(op static_cast<TUnderlying>(value)); \ + } + +#define ENUM__BIT_SHIFT_OPERATOR(T, assignOp, op) \ + [[maybe_unused]] inline constexpr T operator op (T lhs, size_t rhs) \ + { \ + using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ + return T(static_cast<TUnderlying>(lhs) op rhs); \ + } \ + \ + [[maybe_unused]] inline T& operator assignOp (T& lhs, size_t rhs) \ + { \ + using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ + lhs = T(static_cast<TUnderlying>(lhs) op rhs); \ + return lhs; \ + } + +#define ENUM__BITWISE_OPS(name) \ + ENUM__BINARY_BITWISE_OPERATOR(name, &=, &) \ + ENUM__BINARY_BITWISE_OPERATOR(name, |=, | ) \ + ENUM__BINARY_BITWISE_OPERATOR(name, ^=, ^) \ + ENUM__UNARY_BITWISE_OPERATOR(name, ~) \ + ENUM__BIT_SHIFT_OPERATOR(name, <<=, << ) \ + ENUM__BIT_SHIFT_OPERATOR(name, >>=, >> ) + +//////////////////////////////////////////////////////////////////////////////// + +template <typename E, typename> +bool Any(E value) +{ + return static_cast<typename TEnumTraits<E>::TUnderlying>(value) != 0; +} + +template <class E, typename> +bool None(E value) +{ + return static_cast<typename TEnumTraits<E>::TUnderlying>(value) == 0; +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT |