aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/ref.hh
blob: d6bf53bb8d9ef812a3a34ee39594e9b9ac64dced (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
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
#pragma once

#include <memory>
#include <exception>
#include <stdexcept>

namespace nix {

/* A simple non-nullable reference-counted pointer. Actually a wrapper
   around std::shared_ptr that prevents non-null constructions. */
template<typename T>
class ref
{
private:

    std::shared_ptr<T> p;

public:

    ref<T>(const ref<T> & r)
        : p(r.p)
    { }

    explicit ref<T>(const std::shared_ptr<T> & p)
        : p(p)
    {
        if (!p)
            throw std::invalid_argument("null pointer cast to ref");
    }

    explicit ref<T>(T * p)
        : p(p)
    {
        if (!p)
            throw std::invalid_argument("null pointer cast to ref");
    }

    T* operator ->() const
    {
        return &*p;
    }

    T& operator *() const
    {
        return *p;
    }

    operator std::shared_ptr<T> () const
    {
        return p;
    }

    std::shared_ptr<T> get_ptr() const
    {
        return p;
    }

    template<typename T2>
    ref<T2> cast() const
    {
        return ref<T2>(std::dynamic_pointer_cast<T2>(p));
    }

    template<typename T2>
    std::shared_ptr<T2> dynamic_pointer_cast() const
    {
        return std::dynamic_pointer_cast<T2>(p);
    }

    template<typename T2>
    operator ref<T2> () const
    {
        return ref<T2>((std::shared_ptr<T2>) p);
    }

    bool operator == (const ref<T> & other) const
    {
        return p == other.p;
    }

    bool operator != (const ref<T> & other) const
    {
        return p != other.p;
    }

private:

    template<typename T2, typename... Args>
    friend ref<T2>
    make_ref(Args&&... args);

};

template<typename T, typename... Args>
inline ref<T>
make_ref(Args&&... args)
{
    auto p = std::make_shared<T>(std::forward<Args>(args)...);
    return ref<T>(p);
}


/* A non-nullable pointer.
   This is similar to a C++ "& reference", but mutable.
   This is similar to ref<T> but backed by a regular pointer instead of a smart pointer.
 */
template<typename T>
class ptr {
private:
    T * p;

public:
    ptr<T>(const ptr<T> & r)
        : p(r.p)
    { }

    explicit ptr<T>(T * p)
        : p(p)
    {
        if (!p)
            throw std::invalid_argument("null pointer cast to ptr");
    }

    T* operator ->() const
    {
        return &*p;
    }

    T& operator *() const
    {
        return *p;
    }

    bool operator == (const ptr<T> & other) const
    {
        return p == other.p;
    }

    bool operator != (const ptr<T> & other) const
    {
        return p != other.p;
    }
};

}