summaryrefslogtreecommitdiff
path: root/src/value.hh
blob: 2b9e0d222e81f279c3d481d8505dc1f1f45e0ca3 (plain)
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
#ifndef value_hh_INCLUDED
#define value_hh_INCLUDED

#include "hash_map.hh"
#include "units.hh"
#include "meta.hh"

#include <type_traits>
#include <memory>

namespace Kakoune
{

struct bad_value_cast {};

struct Value
{
    Value() = default;

    template<typename T> requires (not std::is_same_v<Value, T>)
    Value(T&& val)
        : m_value{new Model<std::remove_cvref_t<T>>{std::forward<T>(val)}} {}

    template<typename T>
    Value(Meta::Type<T>, auto&&... args) :
        m_value(new Model<T>(std::forward<decltype(args)>(args)...)) {}

    Value(const Value& val) = delete;
    Value(Value&&) = default;

    Value& operator=(const Value& val) = delete;
    Value& operator=(Value&& val) = default;

    explicit operator bool() const { return (bool)m_value; }

    template<typename T>
    bool is_a() const
    {
        return m_value and m_value->type() == typeid(T);
    }

    template<typename T>
    T& as()
    {
        if (not is_a<T>())
            throw bad_value_cast{};
        return static_cast<Model<T>*>(m_value.get())->m_content;
    }

    template<typename T>
    const T& as() const
    {
        return const_cast<Value*>(this)->as<T>();
    }

private:
    struct Concept
    {
        virtual ~Concept() = default;
        virtual const std::type_info& type() const = 0;
    };

    template<typename T>
    struct Model : public Concept, public UseMemoryDomain<MemoryDomain::Values>
    {
        Model(auto&&... args) : m_content(std::forward<decltype(args)>(args)...) {}
        const std::type_info& type() const override { return typeid(T); }

        T m_content;
    };

    std::unique_ptr<Concept> m_value;
};

enum class ValueId : int {};

inline ValueId get_free_value_id()
{
    static int next = 0;
    return (ValueId)(next++);
}

using ValueMap = HashMap<ValueId, Value, MemoryDomain::Values>;

}

#endif // value_hh_INCLUDED