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 Maybe {
30 public:
31 Maybe(Nothing) : _is_nothing(true) {}
32 Maybe(T const &t) : _t(t), _is_nothing(false) {}
33 Maybe(Maybe const &m) : _t(m._t), _is_nothing(m._is_nothing) {}
35 template <typename T2> Maybe(Maybe<T2> const &m)
36 : _is_nothing(!m)
37 {
38 if (m) {
39 _t = *m;
40 }
41 }
43 template <typename T2> Maybe(T2 const &t)
44 : _t(t), _is_nothing(false) {}
46 operator bool() const { return !_is_nothing; }
48 T const &operator*() const throw(IsNothing) {
49 if (_is_nothing) {
50 throw IsNothing();
51 } else {
52 return _t;
53 }
54 }
55 T &operator*() throw(IsNothing) {
56 if (_is_nothing) {
57 throw IsNothing();
58 } else {
59 return _t;
60 }
61 }
63 T const *operator->() const throw(IsNothing) {
64 if (_is_nothing) {
65 throw IsNothing();
66 } else {
67 return &_t;
68 }
69 }
70 T *operator->() throw(IsNothing) {
71 if (_is_nothing) {
72 throw IsNothing();
73 } else {
74 return &_t;
75 }
76 }
78 template <typename T2>
79 bool operator==(NR::Maybe<T2> const &other) const {
80 if ( _is_nothing || !other ) {
81 return _is_nothing && !other;
82 } else {
83 return _t == *other;
84 }
85 }
86 template <typename T2>
87 bool operator!=(NR::Maybe<T2> const &other) const {
88 if ( _is_nothing || !other ) {
89 return !_is_nothing || other;
90 } else {
91 return _t != *other;
92 }
93 }
95 private:
96 T _t;
97 bool _is_nothing;
98 };
100 template <typename T>
101 class Maybe<T const> {
102 public:
103 Maybe(Nothing) : _is_nothing(true) {}
104 Maybe(T const &t) : _t(t), _is_nothing(false) {}
105 Maybe(Maybe const &m) : _t(m._t), _is_nothing(m._is_nothing) {}
107 template <typename T2> Maybe(Maybe<T2> const &m)
108 : _is_nothing(!m)
109 {
110 if (m) {
111 _t = *m;
112 }
113 }
115 template <typename T2> Maybe(T2 const &t)
116 : _t(t), _is_nothing(false) {}
118 operator bool() const { return !_is_nothing; }
120 T const &operator*() const throw(IsNothing) {
121 if (_is_nothing) {
122 throw IsNothing();
123 } else {
124 return _t;
125 }
126 }
128 T const *operator->() const throw(IsNothing) {
129 if (_is_nothing) {
130 throw IsNothing();
131 } else {
132 return &_t;
133 }
134 }
136 template <typename T2>
137 bool operator==(NR::Maybe<T2> const &other) const {
138 if ( _is_nothing || !other ) {
139 return _is_nothing && !other;
140 } else {
141 return _t == *other;
142 }
143 }
144 template <typename T2>
145 bool operator!=(NR::Maybe<T2> const &other) const {
146 if ( _is_nothing || !other ) {
147 return !_is_nothing || other;
148 } else {
149 return _t != *other;
150 }
151 }
153 private:
154 T const _t;
155 bool _is_nothing;
156 };
158 template <typename T>
159 class Maybe<T &> {
160 public:
161 Maybe(Nothing) : _ref(NULL) {}
162 Maybe(T &t) : _ref(&t) {}
163 Maybe(Maybe const &m) : _ref(m._ref) {}
165 template <typename T2> Maybe(Maybe<T2> const &m)
166 : _ref( m ? &*m : NULL ) {}
167 template <typename T2> Maybe(T2 &t) : _ref(&t) {}
169 operator bool() const { return _ref; }
171 T &operator*() const throw(IsNothing) {
172 if (_ref) {
173 throw IsNothing();
174 } else {
175 return *_ref;
176 }
177 }
179 T *operator->() const throw(IsNothing) {
180 if (_ref) {
181 throw IsNothing();
182 } else {
183 return _ref;
184 }
185 }
187 template <typename T2>
188 bool operator==(NR::Maybe<T2> const &other) const {
189 if ( !_ref || !other ) {
190 return !_ref && !other;
191 } else {
192 return *_ref == *other;
193 }
194 }
195 template <typename T2>
196 bool operator!=(NR::Maybe<T2> const &other) const {
197 if ( !_ref || !other ) {
198 return _ref || other;
199 } else {
200 return *_ref != *other;
201 }
202 }
204 private:
205 void operator=(Maybe const &); // no assign
207 T *_ref;
208 };
210 } /* namespace NR */
212 #endif
214 /*
215 Local Variables:
216 mode:c++
217 c-file-style:"stroustrup"
218 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
219 indent-tabs-mode:nil
220 fill-column:99
221 End:
222 */
223 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :