#pragma once #include "cyson_enums.h" #include #include #include namespace NYsonPull { //! \brief YSON TScalar value type tag enum class EScalarType { Entity = YSON_SCALAR_ENTITY, Boolean = YSON_SCALAR_BOOLEAN, Int64 = YSON_SCALAR_INT64, UInt64 = YSON_SCALAR_UINT64, Float64 = YSON_SCALAR_FLOAT64, String = YSON_SCALAR_STRING, }; //! \brief YSON TScalar value variant class TScalar { //! \internal \brief YSON TScalar value underlying representation union TScalarValue { struct TScalarStringRef { const char* Data; size_t Size; }; ui8 AsNothing[1]; bool AsBoolean; i64 AsInt64; ui64 AsUInt64; double AsFloat64; TScalarStringRef AsString; constexpr TScalarValue() : AsNothing{} { } explicit constexpr TScalarValue(bool value) : AsBoolean{value} { } explicit constexpr TScalarValue(i64 value) : AsInt64{value} { } explicit constexpr TScalarValue(ui64 value) : AsUInt64{value} { } explicit constexpr TScalarValue(double value) : AsFloat64{value} { } explicit constexpr TScalarValue(TStringBuf value) : AsString{value.data(), value.size()} { } }; static_assert( sizeof(TScalarValue) == sizeof(TStringBuf), "bad scalar_value size"); EScalarType Type_; TScalarValue Value_; public: constexpr TScalar() : Type_{EScalarType::Entity} { } explicit constexpr TScalar(bool value) : Type_{EScalarType::Boolean} , Value_{value} { } explicit constexpr TScalar(i64 value) : Type_{EScalarType::Int64} , Value_{value} { } explicit constexpr TScalar(ui64 value) : Type_{EScalarType::UInt64} , Value_{value} { } explicit constexpr TScalar(double value) : Type_{EScalarType::Float64} , Value_{value} { } explicit constexpr TScalar(TStringBuf value) : Type_{EScalarType::String} , Value_{value} { } // Disambiguation for literal constants // In the absence of this constructor, // they get implicitly converted to bool (yikes!) explicit TScalar(const char* value) : Type_{EScalarType::String} , Value_{TStringBuf{value}} { } EScalarType Type() const { return Type_; } #define CAST_TO(Type) \ Y_ASSERT(Type_ == EScalarType::Type); \ return Value_.As##Type bool AsBoolean() const { CAST_TO(Boolean); } i64 AsInt64() const { CAST_TO(Int64); } ui64 AsUInt64() const { CAST_TO(UInt64); } double AsFloat64() const { CAST_TO(Float64); } #undef CAST_TO TStringBuf AsString() const { Y_ASSERT(Type_ == EScalarType::String); return TStringBuf{ Value_.AsString.Data, Value_.AsString.Size, }; } const TScalarValue& AsUnsafeValue() const { return Value_; } }; bool operator==(const TScalar& left, const TScalar& right) noexcept; inline bool operator!=(const TScalar& left, const TScalar& right) noexcept { return !(left == right); } }