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>
18 #include <algorithm>
20 namespace NR {
22 class IsNothing : public std::domain_error {
23 public:
24 IsNothing() : domain_error(std::string("Is nothing")) {}
25 };
27 struct Nothing {};
29 template <typename T>
30 class MaybeStorage {
31 public:
32 MaybeStorage() : _is_nothing(true) {}
33 MaybeStorage(T const &value)
34 : _value(value), _is_nothing(false) {}
36 bool is_nothing() const { return _is_nothing; }
37 T &value() { return _value; }
38 T const &value() const { return _value; }
40 private:
41 T _value;
42 bool _is_nothing;
43 };
45 template <typename T>
46 class Maybe {
47 public:
48 Maybe() {}
49 Maybe(Nothing) {}
50 Maybe(T const &t) : _storage(t) {}
51 Maybe(Maybe const &m) : _storage(m._storage) {}
53 template <typename T2>
54 Maybe(Maybe<T2> const &m) {
55 if (m) {
56 _storage = *m;
57 }
58 }
60 template <typename T2>
61 Maybe(Maybe<T2 const &> m) {
62 if (m) {
63 _storage = *m;
64 }
65 }
67 operator bool() const { return !_storage.is_nothing(); }
69 T const &operator*() const throw(IsNothing) {
70 if (_storage.is_nothing()) {
71 throw IsNothing();
72 } else {
73 return _storage.value();
74 }
75 }
76 T &operator*() throw(IsNothing) {
77 if (_storage.is_nothing()) {
78 throw IsNothing();
79 } else {
80 return _storage.value();
81 }
82 }
84 T const *operator->() const throw(IsNothing) {
85 if (_storage.is_nothing()) {
86 throw IsNothing();
87 } else {
88 return &_storage.value();
89 }
90 }
91 T *operator->() throw(IsNothing) {
92 if (_storage.is_nothing()) {
93 throw IsNothing();
94 } else {
95 return &_storage.value();
96 }
97 }
99 template <typename T2>
100 bool operator==(Maybe<T2> const &other) const {
101 bool is_nothing = _storage.is_nothing();
102 if ( is_nothing || !other ) {
103 return is_nothing && !other;
104 } else {
105 return _storage.value() == *other;
106 }
107 }
108 template <typename T2>
109 bool operator!=(Maybe<T2> const &other) const {
110 bool is_nothing = _storage.is_nothing();
111 if ( is_nothing || !other ) {
112 return !is_nothing || other;
113 } else {
114 return _storage.value() != *other;
115 }
116 }
118 private:
119 MaybeStorage<T> _storage;
120 };
122 template <typename T>
123 class Maybe<T &> {
124 public:
125 Maybe() : _ref(NULL) {}
126 Maybe(Nothing) : _ref(NULL) {}
127 Maybe(T &t) : _ref(&t) {}
129 template <typename T2>
130 Maybe(Maybe<T2> const &m) {
131 if (m) {
132 _ref = &*m;
133 }
134 }
136 template <typename T2>
137 Maybe(Maybe<T2 &> m) {
138 if (m) {
139 _ref = *m;
140 }
141 }
143 template <typename T2>
144 Maybe(Maybe<T2 const &> m) {
145 if (m) {
146 _ref = *m;
147 }
148 }
150 operator bool() const { return _ref; }
152 T &operator*() const throw(IsNothing) {
153 if (!_ref) {
154 throw IsNothing();
155 } else {
156 return *_ref;
157 }
158 }
159 T *operator->() const throw(IsNothing) {
160 if (!_ref) {
161 throw IsNothing();
162 } else {
163 return _ref;
164 }
165 }
167 template <typename T2>
168 bool operator==(Maybe<T2> const &other) const {
169 if ( !_ref || !other ) {
170 return !_ref && !other;
171 } else {
172 return *_ref == *other;
173 }
174 }
175 template <typename T2>
176 bool operator!=(Maybe <T2> const &other) const {
177 if ( !_ref || !other ) {
178 return _ref || other;
179 } else {
180 return *_ref != *other;
181 }
182 }
184 private:
185 T *_ref;
186 };
188 } /* namespace NR */
190 #endif
192 /*
193 Local Variables:
194 mode:c++
195 c-file-style:"stroustrup"
196 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
197 indent-tabs-mode:nil
198 fill-column:99
199 End:
200 */
201 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :