diff --git a/src/libnr/nr-maybe.h b/src/libnr/nr-maybe.h
index 6eed01ec18f8944eef3c808a0653f2da0f4512d7..1413f69d2ce8ec533bc4e3de280a09fe5d477fdd 100644 (file)
--- a/src/libnr/nr-maybe.h
+++ b/src/libnr/nr-maybe.h
#define __NR_MAYBE_H__
/*
- * Functionalesque "Maybe" class
+ * Nullable values for C++
*
- * Copyright 2004 MenTaLguY
- *
- * Authors:
- * MenTaLguY <mental@rydia.net>
+ * Copyright 2004, 2007 MenTaLguY <mental@rydia.net>
*
* This code is licensed under the GNU GPL; see COPYING for more information.
*/
#endif
#include <stdexcept>
-#include <typeinfo>
#include <string>
+#include <algorithm>
namespace NR {
-/** An exception class for run-time type errors */
-template <typename T>
-class IsNot : public std::domain_error {
+class IsNothing : public std::domain_error {
public:
- IsNot() : domain_error(std::string("Is not ") + typeid(T).name()) {}
+ IsNothing() : domain_error(std::string("Is nothing")) {}
};
-/** A type with only one value, which (in principle) is only equal to itself.
- *
- * Types that may (at runtime) pretend to be Nothing need only provide an
- * operator bool operator==(Type, Nothing); the rest of the operator
- * definitions will be taken care of automatically.
- *
- * Such types should also provide a casting operator to Nothing, obviously.
- */
-struct Nothing {
- bool operator==(Nothing n) { return true; }
- bool operator!=(Nothing n) { return false; }
- template <typename T>
- bool operator==(T t) { return t == *this; }
- template <typename T>
- bool operator!=(T t) { return t != *this; }
-};
+struct Nothing {};
template <typename T>
-bool operator==(T t, Nothing n) { return false; }
-template <typename T>
-bool operator!=(T t, Nothing n) { return !( t == n ); }
+class MaybeStorage {
+public:
+ MaybeStorage() : _is_nothing(true) {}
+ MaybeStorage(T const &value)
+ : _value(value), _is_nothing(false) {}
-template <typename T>
-struct MaybeTraits;
+ bool is_nothing() const { return _is_nothing; }
+ T &value() { return _value; }
+ T const &value() const { return _value; }
+
+private:
+ T _value;
+ bool _is_nothing;
+};
template <typename T>
class Maybe {
public:
- typedef MaybeTraits<T> traits;
- typedef typename traits::storage storage;
- typedef typename traits::reference reference;
-
- Maybe(Nothing n) : _is_nothing(true), _t() {}
-
- Maybe(const Maybe<T> &m) : _is_nothing(m._is_nothing), _t(m._t) {}
+ Maybe() {}
+ Maybe(Nothing) {}
+ Maybe(T const &t) : _storage(t) {}
+ Maybe(Maybe const &m) : _storage(m._storage) {}
template <typename T2>
- Maybe(const Maybe<T2> &m)
- : _is_nothing(m._is_nothing),
- _t(traits::to_storage(MaybeTraits<T2>::from_storage(m._t))) {}
+ Maybe(Maybe<T2> const &m) {
+ if (m) {
+ _storage = *m;
+ }
+ }
template <typename T2>
- Maybe(T2 t) : _is_nothing(false), _t(traits::to_storage(t)) {}
+ Maybe(Maybe<T2 const &> m) {
+ if (m) {
+ _storage = *m;
+ }
+ }
+
+ operator bool() const { return !_storage.is_nothing(); }
- reference assume() const throw(IsNot<T>) {
- if (_is_nothing) {
- throw IsNot<T>();
+ T const &operator*() const throw(IsNothing) {
+ if (_storage.is_nothing()) {
+ throw IsNothing();
} else {
- return traits::from_storage(_t);
+ return _storage.value();
+ }
+ }
+ T &operator*() throw(IsNothing) {
+ if (_storage.is_nothing()) {
+ throw IsNothing();
+ } else {
+ return _storage.value();
}
}
- operator reference() const throw(IsNot<T>) {
- if (_is_nothing) {
- throw IsNot<T>();
+ T const *operator->() const throw(IsNothing) {
+ if (_storage.is_nothing()) {
+ throw IsNothing();
} else {
- return traits::from_storage(_t);
+ return &_storage.value();
}
}
- operator Nothing() const throw(IsNot<Nothing>) {
- if (!_is_nothing) {
- throw IsNot<Nothing>();
+ T *operator->() throw(IsNothing) {
+ if (_storage.is_nothing()) {
+ throw IsNothing();
} else {
- return Nothing();
+ return &_storage.value();
}
}
- bool operator==(Nothing n) { return _is_nothing; }
- bool operator==(reference r) {
- return traits::from_storage(_t) == r;
+ template <typename T2>
+ bool operator==(Maybe<T2> const &other) const {
+ bool is_nothing = _storage.is_nothing();
+ if ( is_nothing || !other ) {
+ return is_nothing && !other;
+ } else {
+ return _storage.value() == *other;
+ }
+ }
+ template <typename T2>
+ bool operator!=(Maybe<T2> const &other) const {
+ bool is_nothing = _storage.is_nothing();
+ if ( is_nothing || !other ) {
+ return !is_nothing || other;
+ } else {
+ return _storage.value() != *other;
+ }
}
private:
- bool _is_nothing;
- storage _t;
+ MaybeStorage<T> _storage;
};
-/* traits classes used by Maybe */
-
template <typename T>
-struct MaybeTraits {
- typedef T const storage;
- typedef T const &reference;
- static reference to_storage(reference t) { return t; }
- static reference from_storage(reference t) { return t; }
-};
+class Maybe<T &> {
+public:
+ Maybe() : _ref(NULL) {}
+ Maybe(Nothing) : _ref(NULL) {}
+ Maybe(T &t) : _ref(&t) {}
-template <typename T>
-struct MaybeTraits<T&> {
- typedef T *storage;
- typedef T &reference;
- static storage to_storage(reference t) { return &t; }
- static reference from_storage(storage t) { return *t; }
+ template <typename T2>
+ Maybe(Maybe<T2> const &m) {
+ if (m) {
+ _ref = &*m;
+ }
+ }
+
+ template <typename T2>
+ Maybe(Maybe<T2 &> m) {
+ if (m) {
+ _ref = *m;
+ }
+ }
+
+ template <typename T2>
+ Maybe(Maybe<T2 const &> m) {
+ if (m) {
+ _ref = *m;
+ }
+ }
+
+ operator bool() const { return _ref; }
+
+ T &operator*() const throw(IsNothing) {
+ if (!_ref) {
+ throw IsNothing();
+ } else {
+ return *_ref;
+ }
+ }
+ T *operator->() const throw(IsNothing) {
+ if (!_ref) {
+ throw IsNothing();
+ } else {
+ return _ref;
+ }
+ }
+
+ template <typename T2>
+ bool operator==(Maybe<T2> const &other) const {
+ if ( !_ref || !other ) {
+ return !_ref && !other;
+ } else {
+ return *_ref == *other;
+ }
+ }
+ template <typename T2>
+ bool operator!=(Maybe <T2> const &other) const {
+ if ( !_ref || !other ) {
+ return _ref || other;
+ } else {
+ return *_ref != *other;
+ }
+ }
+
+private:
+ T *_ref;
};
} /* namespace NR */
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :