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 ~basic_lazy()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> deferred_lazy(G && f)50 deferred_lazy(G &&f) : f(new F(std::forward<G>(f))) { 51 } 52 53 virtual basic_lazy<T> * clone() const54 clone() const { 55 return new deferred_lazy(*this); 56 } 57 operator T() const58 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> strict_lazy(S && x)76 strict_lazy(S &&x) : x(std::forward<S>(x)) { 77 } 78 79 virtual basic_lazy<T> * clone() const80 clone() const { 81 return new strict_lazy(*this); 82 } 83 operator T() const84 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: undefined_error()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 /// lazy(T x)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> lazy(F && 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 /// lazy()126 lazy() : lazy([]() { 127 throw undefined_error(); 128 return T(); 129 }) { 130 } 131 lazy(const lazy & other)132 lazy(const lazy &other) : obj(obj->clone()) { 133 } 134 lazy(lazy && other)135 lazy(lazy &&other) : obj(NULL) { 136 std::swap(obj, other.obj); 137 } 138 ~lazy()139 ~lazy() { 140 delete obj; 141 } 142 143 lazy & operator =(lazy other)144 operator=(lazy other) { 145 std::swap(obj, other.obj); 146 return *this; 147 } 148 149 /// 150 /// Evaluate the value. 151 /// operator T() const152 operator T() const { 153 return *obj; 154 } 155 156 private: 157 detail::basic_lazy<T> *obj; 158 }; 159 } 160 161 #endif 162