Add folly::lazy
[folly.git] / folly / Lazy.h
1 /*
2  * Copyright 2013 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #ifndef FOLLY_LAZY_H_
17 #define FOLLY_LAZY_H_
18
19 #include <utility>
20 #include <type_traits>
21
22 #include "folly/Optional.h"
23
24 namespace folly {
25
26 //////////////////////////////////////////////////////////////////////
27
28 /*
29  * Lazy -- for delayed initialization of a value.  The value's
30  * initialization will be computed on demand at its first use, but
31  * will not be recomputed if its value is requested again.  The value
32  * may still be mutated after its initialization if the lazy is not
33  * declared const.
34  *
35  * The value is created using folly::lazy, usually with a lambda, and
36  * its value is requested using operator().
37  *
38  * Note that the value is not safe for current accesses by multiple
39  * threads, even if you declare it const.
40  *
41  *
42  * Example Usage:
43  *
44  *   void foo() {
45  *     auto const val = folly::lazy([&]{
46  *       return something_expensive(blah());
47  *     });
48  *
49  *     if (condition1) {
50  *       use(val());
51  *     }
52  *     if (condition2) {
53  *       useMaybeAgain(val());
54  *     } else {
55  *       // Unneeded in this branch.
56  *     }
57  *   }
58  *
59  *
60  * Rationale:
61  *
62  *    - operator() is used to request the value instead of an implicit
63  *      conversion because the slight syntactic overhead in common
64  *      seems worth the increased clarity.
65  *
66  *    - Lazy values do not model CopyConstructible because it is
67  *      unclear what semantics would be desirable.  Either copies
68  *      should share the cached value (adding overhead to cases that
69  *      don't need to support copies), or they could recompute the
70  *      value unnecessarily.  Sharing with mutable lazies would also
71  *      leave them with non-value semantics despite looking
72  *      value-like.
73  */
74
75 //////////////////////////////////////////////////////////////////////
76
77 namespace detail {
78
79 template<class Func>
80 struct Lazy {
81   typedef typename std::result_of<Func()>::type result_type;
82
83   explicit Lazy(Func&& f) : func_(std::move(f)) {}
84   explicit Lazy(Func& f)  : func_(f) {}
85
86   Lazy(Lazy&& o)
87     : value_(std::move(o.value_))
88     , func_(std::move(o.func_))
89   {}
90
91   Lazy(const Lazy&) = delete;
92   Lazy& operator=(const Lazy&) = delete;
93   Lazy& operator=(Lazy&&) = delete;
94
95   const result_type& operator()() const {
96     return const_cast<Lazy&>(*this)();
97   }
98
99   result_type& operator()() {
100     if (!value_) value_ = func_();
101     return *value_;
102   }
103
104 private:
105   Optional<result_type> value_;
106   Func func_;
107 };
108
109 }
110
111 //////////////////////////////////////////////////////////////////////
112
113 template<class Func>
114 detail::Lazy<typename std::remove_reference<Func>::type>
115 lazy(Func&& fun) {
116   return detail::Lazy<typename std::remove_reference<Func>::type>(
117     std::forward<Func>(fun)
118   );
119 }
120
121 //////////////////////////////////////////////////////////////////////
122
123 }
124
125 #endif