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 MaybeStorage<T &> {
46 public:
47 MaybeStorage() : _ref(NULL) {}
48 MaybeStorage(T &value) : _ref(&value) {}
50 bool is_nothing() const { return !_ref; }
51 T &value() const { return *_ref; }
53 private:
54 T *_ref;
55 };
57 template <typename T>
58 class Maybe {
59 public:
60 Maybe() {}
62 Maybe(Nothing) {}
64 Maybe(T &t) : _storage(t) {}
65 Maybe(T const &t) : _storage(t) {}
67 Maybe(Maybe &m) : _storage(m._storage) {}
68 Maybe(Maybe const &m) : _storage(m._storage) {}
70 template <typename T2>
71 Maybe(Maybe<T2> &m) {
72 if (m) {
73 _storage = *m;
74 }
75 }
76 template <typename T2>
77 Maybe(Maybe<T2> const &m) {
78 if (m) {
79 _storage = *m;
80 }
81 }
83 template <typename T2>
84 Maybe(Maybe<T2 &> m) {
85 if (m) {
86 _storage = *m;
87 }
88 }
89 template <typename T2>
90 Maybe(Maybe<T2 const &> m) {
91 if (m) {
92 _storage = *m;
93 }
94 }
96 operator bool() const { return !_storage.is_nothing(); }
98 T const &operator*() const throw(IsNothing) {
99 if (_storage.is_nothing()) {
100 throw IsNothing();
101 } else {
102 return _storage.value();
103 }
104 }
105 T &operator*() throw(IsNothing) {
106 if (_storage.is_nothing()) {
107 throw IsNothing();
108 } else {
109 return _storage.value();
110 }
111 }
113 T const *operator->() const throw(IsNothing) {
114 if (_storage.is_nothing()) {
115 throw IsNothing();
116 } else {
117 return &_storage.value();
118 }
119 }
120 T *operator->() throw(IsNothing) {
121 if (_storage.is_nothing()) {
122 throw IsNothing();
123 } else {
124 return &_storage.value();
125 }
126 }
128 template <typename T2>
129 bool operator==(NR::Maybe<T2> const &other) const {
130 bool is_nothing = _storage.is_nothing();
131 if ( is_nothing || !other ) {
132 return is_nothing && !other;
133 } else {
134 return _storage.value() == *other;
135 }
136 }
137 template <typename T2>
138 bool operator!=(NR::Maybe<T2> const &other) const {
139 bool is_nothing = _storage.is_nothing();
140 if ( is_nothing || !other ) {
141 return !is_nothing || other;
142 } else {
143 return _storage.value() != *other;
144 }
145 }
147 private:
148 MaybeStorage<T> _storage;
149 };
151 } /* namespace NR */
153 #endif
155 /*
156 Local Variables:
157 mode:c++
158 c-file-style:"stroustrup"
159 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
160 indent-tabs-mode:nil
161 fill-column:99
162 End:
163 */
164 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :