1 #ifndef __NR_MAYBE_H__
2 #define __NR_MAYBE_H__
4 /*
5 * Functionalesque "Maybe" class
6 *
7 * Copyright 2004 MenTaLguY
8 *
9 * Authors:
10 * MenTaLguY <mental@rydia.net>
11 *
12 * This code is licensed under the GNU GPL; see COPYING for more information.
13 */
15 #if HAVE_CONFIG_H
16 #include "config.h"
17 #endif
19 #include <stdexcept>
20 #include <typeinfo>
21 #include <string>
23 namespace NR {
25 /** An exception class for run-time type errors */
26 template <typename T>
27 class IsNot : public std::domain_error {
28 public:
29 IsNot() : domain_error(std::string("Is not ") + typeid(T).name()) {}
30 };
32 /** A type with only one value, which (in principle) is only equal to itself.
33 *
34 * Types that may (at runtime) pretend to be Nothing need only provide an
35 * operator bool operator==(Type, Nothing); the rest of the operator
36 * definitions will be taken care of automatically.
37 *
38 * Such types should also provide a casting operator to Nothing, obviously.
39 */
40 struct Nothing {
41 bool operator==(Nothing n) { return true; }
42 bool operator!=(Nothing n) { return false; }
43 template <typename T>
44 bool operator==(T t) { return t == *this; }
45 template <typename T>
46 bool operator!=(T t) { return t != *this; }
47 };
49 template <typename T>
50 bool operator==(T t, Nothing n) { return false; }
51 template <typename T>
52 bool operator!=(T t, Nothing n) { return !( t == n ); }
54 template <typename T>
55 struct MaybeTraits;
57 template <typename T>
58 class Maybe {
59 public:
60 typedef MaybeTraits<T> traits;
61 typedef typename traits::storage storage;
62 typedef typename traits::reference reference;
64 Maybe(Nothing n) : _is_nothing(true), _t() {}
66 Maybe(const Maybe<T> &m) : _is_nothing(m._is_nothing), _t(m._t) {}
68 template <typename T2>
69 Maybe(const Maybe<T2> &m)
70 : _is_nothing(m._is_nothing),
71 _t(traits::to_storage(MaybeTraits<T2>::from_storage(m._t))) {}
73 template <typename T2>
74 Maybe(T2 t) : _is_nothing(false), _t(traits::to_storage(t)) {}
76 reference assume() const throw(IsNot<T>) {
77 if (_is_nothing) {
78 throw IsNot<T>();
79 } else {
80 return traits::from_storage(_t);
81 }
82 }
84 operator reference() const throw(IsNot<T>) {
85 if (_is_nothing) {
86 throw IsNot<T>();
87 } else {
88 return traits::from_storage(_t);
89 }
90 }
91 operator Nothing() const throw(IsNot<Nothing>) {
92 if (!_is_nothing) {
93 throw IsNot<Nothing>();
94 } else {
95 return Nothing();
96 }
97 }
99 bool operator==(Nothing n) { return _is_nothing; }
100 bool operator==(reference r) {
101 return traits::from_storage(_t) == r;
102 }
104 private:
105 bool _is_nothing;
106 storage _t;
107 };
109 /* traits classes used by Maybe */
111 template <typename T>
112 struct MaybeTraits {
113 typedef T const storage;
114 typedef T const &reference;
115 static reference to_storage(reference t) { return t; }
116 static reference from_storage(reference t) { return t; }
117 };
119 template <typename T>
120 struct MaybeTraits<T&> {
121 typedef T *storage;
122 typedef T &reference;
123 static storage to_storage(reference t) { return &t; }
124 static reference from_storage(storage t) { return *t; }
125 };
127 } /* namespace NR */
129 #endif
131 /*
132 Local Variables:
133 mode:c++
134 c-file-style:"stroustrup"
135 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
136 indent-tabs-mode:nil
137 fill-column:99
138 End:
139 */
140 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :