Merge remote-tracking branch 'public/master' into vulkan
[mesa.git] / src / gallium / state_trackers / clover / util / lazy.hpp
1 //
2 // Copyright 2013 Francisco Jerez
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 // OTHER DEALINGS IN THE SOFTWARE.
21 //
22
23 #ifndef CLOVER_UTIL_LAZY_HPP
24 #define CLOVER_UTIL_LAZY_HPP
25
26 #include <type_traits>
27 #include <stdexcept>
28 #include <memory>
29
30 namespace clover {
31 namespace detail {
32 template<typename T>
33 class basic_lazy {
34 public:
35 virtual
36 ~basic_lazy() {
37 }
38
39 virtual basic_lazy *
40 clone() const = 0;
41
42 virtual
43 operator T() const = 0;
44 };
45
46 template<typename T, typename F>
47 class deferred_lazy : public basic_lazy<T> {
48 public:
49 template<typename G>
50 deferred_lazy(G &&f) : f(new F(std::forward<G>(f))) {
51 }
52
53 virtual basic_lazy<T> *
54 clone() const {
55 return new deferred_lazy(*this);
56 }
57
58 operator T() const {
59 if (f) {
60 x = (*f)();
61 f = {};
62 }
63
64 return x;
65 }
66
67 private:
68 mutable std::shared_ptr<F> f;
69 mutable T x;
70 };
71
72 template<typename T>
73 class strict_lazy : public basic_lazy<T> {
74 public:
75 template<typename S>
76 strict_lazy(S &&x) : x(std::forward<S>(x)) {
77 }
78
79 virtual basic_lazy<T> *
80 clone() const {
81 return new strict_lazy(*this);
82 }
83
84 operator T() const {
85 return x;
86 }
87
88 private:
89 T x;
90 };
91 }
92
93 ///
94 /// Object that represents a value of type \a T that is calculated
95 /// lazily as soon as it is required.
96 ///
97 template<typename T>
98 class lazy {
99 public:
100 class undefined_error : std::logic_error {
101 public:
102 undefined_error() : std::logic_error("") {
103 }
104 };
105
106 ///
107 /// Initialize to some fixed value \a x which isn't calculated
108 /// lazily.
109 ///
110 lazy(T x) : obj(new detail::strict_lazy<T>(x)) {
111 }
112
113 ///
114 /// Initialize by providing a functor \a f that will calculate
115 /// the value on-demand.
116 ///
117 template<typename F>
118 lazy(F &&f) : obj(new detail::deferred_lazy<
119 T, typename std::remove_reference<F>::type
120 >(std::forward<F>(f))) {
121 }
122
123 ///
124 /// Initialize to undefined.
125 ///
126 lazy() : lazy([]() {
127 throw undefined_error();
128 return T();
129 }) {
130 }
131
132 lazy(const lazy &other) : obj(obj->clone()) {
133 }
134
135 lazy(lazy &&other) : obj(NULL) {
136 std::swap(obj, other.obj);
137 }
138
139 ~lazy() {
140 delete obj;
141 }
142
143 lazy &
144 operator=(lazy other) {
145 std::swap(obj, other.obj);
146 return *this;
147 }
148
149 ///
150 /// Evaluate the value.
151 ///
152 operator T() const {
153 return *obj;
154 }
155
156 private:
157 detail::basic_lazy<T> *obj;
158 };
159 }
160
161 #endif