aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/config/value.h
blob: 9617d064b9c766dd7f708bff7765c4ead46bad53 (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
#pragma once

#include <typeinfo>

#include <util/generic/ptr.h>
#include <util/generic/cast.h>
#include <util/generic/string.h>
#include <util/generic/typetraits.h>

class IOutputStream;

namespace NConfig {
    class IValue: public TAtomicRefCount<IValue> {
    public:
        virtual ~IValue() = default;

        virtual bool IsA(const std::type_info& info) const = 0;
        virtual TString TypeName() const = 0;
        virtual void* Ptr() const = 0;

        virtual ui64 AsUInt() const = 0;
        virtual i64 AsInt() const = 0;
        virtual double AsDouble() const = 0;
        virtual bool AsBool() const = 0;
        virtual TString AsString() const = 0;

        virtual void ToJson(IOutputStream& out) const = 0;
    };

    namespace NCfgPrivate {
        struct TDummy {
        };

        template <class T>
        inline IValue* ConstructValueImpl(const T& t, ...) {
            extern IValue* ConstructValueImpl(const T& t);

            return ConstructValueImpl(t);
        }

        template <class T, std::enable_if_t<std::is_floating_point<T>::value>* = nullptr>
        inline IValue* ConstructValueImpl(const T& t, TDummy) {
            extern IValue* ConstructValueImpl(const double& t);

            return ConstructValueImpl(t);
        }

        template <class T, std::enable_if_t<std::is_integral<T>::value>* = nullptr>
        inline IValue* ConstructValueImpl(const T& t, TDummy) {
            typedef std::conditional_t<std::is_signed<T>::value, i64, ui64> Type;
            extern IValue* ConstructValueImpl(const Type& t);

            return ConstructValueImpl(t);
        }

        template <class T, std::enable_if_t<std::is_convertible<T, TString>::value>* = nullptr>
        inline IValue* ConstructValueImpl(const T& t, TDummy) {
            extern IValue* ConstructValueImpl(const TString& t);

            return ConstructValueImpl(t);
        }

        inline IValue* ConstructValueImpl(const bool& t, TDummy) {
            extern IValue* ConstructValueImpl(const bool& t);

            return ConstructValueImpl(t);
        }
    }

    template <class T>
    inline IValue* ConstructValue(const T& t) {
        return NCfgPrivate::ConstructValueImpl(t, NCfgPrivate::TDummy());
    }

    IValue* Null();

    namespace NCfgPrivate {
        template <bool Unsigned>
        struct TSelector {
            static inline ui64 Cvt(const IValue* v) {
                return v->AsUInt();
            }
        };

        template <>
        struct TSelector<false> {
            static inline i64 Cvt(const IValue* v) {
                return v->AsInt();
            }
        };

        [[noreturn]] void ReportTypeMismatch(TStringBuf realType, TStringBuf expectedType);
    }

    template <class T>
    inline T ValueAs(const IValue* val) {
        typedef NCfgPrivate::TSelector<std::is_unsigned<T>::value> TCvt;

        return SafeIntegerCast<T>(TCvt::Cvt(val));
    }

    template <>
    inline double ValueAs(const IValue* val) {
        return val->AsDouble();
    }

    template <>
    inline float ValueAs(const IValue* val) {
        return (float)val->AsDouble();
    }

    template <>
    inline bool ValueAs(const IValue* val) {
        return val->AsBool();
    }

    template <>
    inline TString ValueAs(const IValue* val) {
        return val->AsString();
    }
}