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 :