aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/yson_pull/scalar.h
blob: 509fce8b5ec468db3d85e4e0b466c871549ba3da (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#pragma once

#include "cyson_enums.h"

#include <util/generic/strbuf.h>
#include <util/system/types.h>
#include <util/system/yassert.h>

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);
    }

}