-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmaybe.hpp
73 lines (55 loc) · 1.32 KB
/
maybe.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#ifndef MAYBE_HPP
#define MAYBE_HPP
#include <type_traits>
#include <cassert>
#include <new>
// maybe monad
template<class T>
class maybe {
using storage_type = typename std::aligned_union<0, T>::type;
storage_type storage;
const bool set;
public:
using value_type = T;
// monadic return (none/just)
maybe(): set(false) {}
maybe(T value): set(true) { new(&storage) T{std::move(value)}; }
maybe(maybe&& other): set(other.set) {
if(set) {
new(&storage) T{std::move(other.get())};
}
}
maybe(const maybe& other): set(other.set) {
if(set) {
new(&storage) T{other.get()};
}
}
explicit operator bool() const { return set; }
// unclear whether we actually need these at all
maybe& operator=(maybe&& other) = delete;
maybe& operator=(const maybe& other) = delete;
~maybe() {
if(set) {
get().~T();
}
}
const T& get() const {
assert(set);
return *reinterpret_cast<const T*>(&storage);
}
T& get() {
assert(set);
return *reinterpret_cast<T*>(&storage);
}
};
template<class T>
static maybe<T> some(const T& value) { return value; }
template<class A, class F>
static auto map(const maybe<A>& self, F f) {
using result_type = decltype(f(self.get()));
if(!self) {
return maybe<result_type>{};
}
return some(f(self.get()));
}
#endif