Code

fix reference maybes by separate specialization
[inkscape.git] / src / libnr / nr-maybe.h
1 #ifndef __NR_MAYBE_H__
2 #define __NR_MAYBE_H__
4 /*
5  * Nullable values for C++
6  *
7  * Copyright 2004, 2007  MenTaLguY <mental@rydia.net>
8  *
9  * This code is licensed under the GNU GPL; see COPYING for more information.
10  */
12 #if HAVE_CONFIG_H
13 #include "config.h"
14 #endif
16 #include <stdexcept>
17 #include <string>
19 namespace NR {
21 class IsNothing : public std::domain_error {
22 public:
23     IsNothing() : domain_error(std::string("Is nothing")) {}
24 };
26 struct Nothing {};
28 template <typename T>
29 class MaybeStorage {
30 public:
31     MaybeStorage() : _is_nothing(true) {}
32     MaybeStorage(T const &value)
33     : _value(value), _is_nothing(false) {}
35     bool is_nothing() const { return _is_nothing; }
36     T &value() { return _value; }
37     T const &value() const { return _value; }
39 private:
40     T _value;
41     bool _is_nothing;
42 };
44 template <typename T>
45 class Maybe {
46 public:
47     Maybe() {}
48     Maybe(Nothing) {}
49     Maybe(T const &t) : _storage(t) {}
50     Maybe(Maybe const &m) : _storage(m._storage) {}
52     template <typename T2>
53     Maybe(Maybe<T2> const &m) {
54         if (m) {
55             _storage = *m;
56         }
57     }
59     template <typename T2>
60     Maybe(Maybe<T2 const &> m) {
61         if (m) {
62             _storage = *m;
63         }
64     }
66     operator bool() const { return !_storage.is_nothing(); }
68     T const &operator*() const throw(IsNothing) {
69         if (_storage.is_nothing()) {
70             throw IsNothing();
71         } else {
72             return _storage.value();
73         }
74     }
75     T &operator*() throw(IsNothing) {
76         if (_storage.is_nothing()) {
77             throw IsNothing();
78         } else {
79             return _storage.value();
80         }
81     }
83     T const *operator->() const throw(IsNothing) {
84         if (_storage.is_nothing()) {
85             throw IsNothing();
86         } else {
87             return &_storage.value();
88         }
89     }
90     T *operator->() throw(IsNothing) {
91         if (_storage.is_nothing()) {
92             throw IsNothing();
93         } else {
94             return &_storage.value();
95         }
96     }
98     template <typename T2>
99     bool operator==(Maybe<T2> const &other) const {
100         bool is_nothing = _storage.is_nothing();
101         if ( is_nothing || !other ) {
102             return is_nothing && !other;
103         } else {
104             return _storage.value() == *other;
105         }
106     }
107     template <typename T2>
108     bool operator!=(Maybe<T2> const &other) const {
109         bool is_nothing = _storage.is_nothing();
110         if ( is_nothing || !other ) {
111             return !is_nothing || other;
112         } else {
113             return _storage.value() != *other;
114         }
115     }
117 private:
118     MaybeStorage<T> _storage;
119 };
121 template <typename T>
122 class Maybe<T &> {
123 public:
124     Maybe() : _ref(NULL) {}
125     Maybe(Nothing) : _ref(NULL) {}
126     Maybe(T &t) : _ref(&t) {}
128     template <typename T2>
129     Maybe(Maybe<T2> const &m) {
130         if (m) {
131             _ref = &*m;
132         } 
133     }
135     template <typename T2>
136     Maybe(Maybe<T2 &> m) {
137         if (m) {
138             _ref = *m;
139         }
140     }
142     template <typename T2>
143     Maybe(Maybe<T2 const &> m) {
144         if (m) {
145             _ref = *m;
146         }
147     }
149     operator bool() const { return _ref; }
151     T &operator*() const throw(IsNothing) {
152         if (!_ref) {
153             throw IsNothing();
154         } else {
155             return *_ref;
156         }
157     }
158     T *operator->() const throw(IsNothing) {
159         if (!_ref) {
160             throw IsNothing();
161         } else {
162             return _ref;
163         }
164     }
166     template <typename T2>
167     bool operator==(Maybe<T2> const &other) const {
168         if ( !_ref || !other ) {
169             return !_ref && !other;
170         } else {
171             return *_ref == *other;
172         }
173     }
174     template <typename T2>
175     bool operator!=(Maybe <T2> const &other) const {
176         if ( !_ref || !other ) {
177             return _ref || other;
178         } else {
179             return *_ref != *other;
180         }
181     }
183 private:
184     T *_ref;
185 };
187 } /* namespace NR */
189 #endif
191 /*
192   Local Variables:
193   mode:c++
194   c-file-style:"stroustrup"
195   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
196   indent-tabs-mode:nil
197   fill-column:99
198   End:
199 */
200 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :