#pragma once
#include "preprocessor.h"
#include <util/generic/strbuf.h>
#include <stdexcept>
#include <type_traits>
#include <array>
#include <vector>
#include <library/cpp/yt/exception/exception.h>
namespace NYT {
////////////////////////////////////////////////////////////////////////////////
/*
* Smart enumerations augment C++ enum classes with a bunch of reflection
* capabilities accessible via TEnumTraits class specialization.
*
* Please refer to the unit test for an actual example of usage
* (unittests/enum_ut.cpp).
*/
// Actual overload must be provided with defines DEFINE_ENUM_XXX (see below).
template <class T>
void GetEnumTraitsImpl(T);
template <
class T,
bool = std::is_enum<T>::value &&
!std::is_convertible<T, int>::value &&
!std::is_same<void, decltype(GetEnumTraitsImpl(T()))>::value
>
struct TEnumTraits
{
static constexpr bool IsEnum = false;
static constexpr bool IsBitEnum = false;
static constexpr bool IsStringSerializableEnum = false;
};
template <class T>
struct TEnumTraits<T, true>
{
using TImpl = decltype(GetEnumTraitsImpl(T()));
using TType = T;
using TUnderlying = typename TImpl::TUnderlying;
static constexpr bool IsEnum = true;
static constexpr bool IsBitEnum = TImpl::IsBitEnum;
static constexpr bool IsStringSerializableEnum = TImpl::IsStringSerializableEnum;
static constexpr int DomainSize = TImpl::DomainSize;
static TStringBuf GetTypeName();
static const TStringBuf* FindLiteralByValue(TType value);
static bool FindValueByLiteral(TStringBuf literal, TType* result);
static const std::array<TStringBuf, DomainSize>& GetDomainNames();
static const std::array<TType, DomainSize>& GetDomainValues();
static TType FromString(TStringBuf str);
static TString ToString(TType value);
// For non-bit enums only.
static constexpr TType GetMinValue();
static constexpr TType GetMaxValue();
// For bit enums only.
static std::vector<TType> Decompose(TType value);
// LLVM SmallDenseMap interop.
// This should only be used for enums whose underlying type has big enough range
// (see getEmptyKey and getTombstoneKey functions).
struct TDenseMapInfo
{
static inline TType getEmptyKey()
{
return static_cast<TType>(-1);
}
static inline TType getTombstoneKey()
{
return static_cast<TType>(-2);
}
static unsigned getHashValue(const TType& key)
{
return static_cast<unsigned>(key) * 37U;
}
static bool isEqual(const TType& lhs, const TType& rhs)
{
return lhs == rhs;
}
};
};
////////////////////////////////////////////////////////////////////////////////
//! Defines a smart enumeration with a specific underlying type.
/*!
* \param name Enumeration name.
* \param seq Enumeration domain encoded as a <em>sequence</em>.
* \param underlyingType Underlying type.
*/
#define DEFINE_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \
ENUM__CLASS(name, underlyingType, seq) \
ENUM__BEGIN_TRAITS(name, underlyingType, false, false, seq) \
ENUM__MINMAX \
ENUM__VALIDATE_UNIQUE(name) \
ENUM__END_TRAITS(name)
//! Defines a smart enumeration with a specific underlying type.
//! Duplicate enumeration values are allowed.
#define DEFINE_AMBIGUOUS_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \
ENUM__CLASS(name, underlyingType, seq) \
ENUM__BEGIN_TRAITS(name, underlyingType, false, false, seq) \
ENUM__MINMAX \
ENUM__END_TRAITS(name)
//! Defines a smart enumeration with the default |int| underlying type.
#define DEFINE_ENUM(name, seq) \
DEFINE_ENUM_WITH_UNDERLYING_TYPE(name, int, seq)
//! Defines a smart enumeration with a specific underlying type.
/*!
* \param name Enumeration name.
* \param seq Enumeration domain encoded as a <em>sequence</em>.
* \param underlyingType Underlying type.
*/
#define DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \
ENUM__CLASS(name, underlyingType, seq) \
ENUM__BEGIN_TRAITS(name, underlyingType, true, false, seq) \
ENUM__DECOMPOSE \
ENUM__VALIDATE_UNIQUE(name) \
ENUM__END_TRAITS(name) \
ENUM__BITWISE_OPS(name)
//! Defines a smart enumeration with a specific underlying type.
//! Duplicate enumeration values are allowed.
/*!
* \param name Enumeration name.
* \param seq Enumeration domain encoded as a <em>sequence</em>.
* \param underlyingType Underlying type.
*/
#define DEFINE_AMBIGUOUS_BIT_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \
ENUM__CLASS(name, underlyingType, seq) \
ENUM__BEGIN_TRAITS(name, underlyingType, true, false, seq) \
ENUM__DECOMPOSE \
ENUM__END_TRAITS(name) \
ENUM__BITWISE_OPS(name)
//! Defines a smart enumeration with the default |unsigned| underlying type.
/*!
* \param name Enumeration name.
* \param seq Enumeration domain encoded as a <em>sequence</em>.
*/
#define DEFINE_BIT_ENUM(name, seq) \
DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(name, unsigned, seq)
//! Defines a smart enumeration with a specific underlying type and IsStringSerializable attribute.
/*!
* \param name Enumeration name.
* \param seq Enumeration domain encoded as a <em>sequence</em>.
* \param underlyingType Underlying type.
*/
#define DEFINE_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \
ENUM__CLASS(name, underlyingType, seq) \
ENUM__BEGIN_TRAITS(name, underlyingType, false, true, seq) \
ENUM__MINMAX \
ENUM__VALIDATE_UNIQUE(name) \
ENUM__END_TRAITS(name) \
//! Defines a smart enumeration with a specific underlying type and IsStringSerializable attribute.
//! Duplicate enumeration values are allowed.
#define DEFINE_AMBIGUOUS_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \
ENUM__CLASS(name, underlyingType, seq) \
ENUM__BEGIN_TRAITS(name, underlyingType, false, true, seq) \
ENUM__MINMAX \
ENUM__END_TRAITS(name)
//! Defines a smart enumeration with the default |int| underlying type and IsStringSerializable attribute.
#define DEFINE_STRING_SERIALIZABLE_ENUM(name, seq) \
DEFINE_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(name, int, seq)
////////////////////////////////////////////////////////////////////////////////
//! A statically sized vector with elements of type |T| indexed by
//! the items of enumeration type |E|.
/*!
* Items are value-initialized on construction.
*/
template <
class E,
class T,
E Min = TEnumTraits<E>::GetMinValue(),
E Max = TEnumTraits<E>::GetMaxValue()
>
class TEnumIndexedVector
{
public:
using TIndex = E;
using TValue = T;
TEnumIndexedVector();
TEnumIndexedVector(std::initializer_list<T> elements);
T& operator[] (E index);
const T& operator[] (E index) const;
// STL interop.
T* begin();
const T* begin() const;
T* end();
const T* end() const;
static bool IsDomainValue(E value);
private:
using TUnderlying = typename TEnumTraits<E>::TUnderlying;
static constexpr int N = static_cast<TUnderlying>(Max) - static_cast<TUnderlying>(Min) + 1;
std::array<T, N> Items_;
};
////////////////////////////////////////////////////////////////////////////////
//! Returns |true| iff the enumeration value is not bitwise zero.
template <typename E, typename = std::enable_if_t<NYT::TEnumTraits<E>::IsBitEnum, E>>
bool Any(E value);
//! Returns |true| iff the enumeration value is bitwise zero.
template <typename E, typename = std::enable_if_t<NYT::TEnumTraits<E>::IsBitEnum, E>>
bool None(E value);
////////////////////////////////////////////////////////////////////////////////
} // namespace NYT
#define ENUM_INL_H_
#include "enum-inl.h"
#undef ENUM_INL_H_