1 | /* |
2 | * Copyright 2013-present 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 | |
17 | #pragma once |
18 | |
19 | #include <type_traits> |
20 | #include <utility> |
21 | |
22 | #include <folly/Optional.h> |
23 | #include <folly/functional/Invoke.h> |
24 | |
25 | namespace folly { |
26 | |
27 | ////////////////////////////////////////////////////////////////////// |
28 | |
29 | /* |
30 | * Lazy -- for delayed initialization of a value. The value's |
31 | * initialization will be computed on demand at its first use, but |
32 | * will not be recomputed if its value is requested again. The value |
33 | * may still be mutated after its initialization if the lazy is not |
34 | * declared const. |
35 | * |
36 | * The value is created using folly::lazy, usually with a lambda, and |
37 | * its value is requested using operator(). |
38 | * |
39 | * Note that the value is not safe for concurrent accesses by multiple |
40 | * threads, even if you declare it const. See note below. |
41 | * |
42 | * |
43 | * Example Usage: |
44 | * |
45 | * void foo() { |
46 | * auto const val = folly::lazy([&]{ |
47 | * return something_expensive(blah()); |
48 | * }); |
49 | * |
50 | * if (condition1) { |
51 | * use(val()); |
52 | * } |
53 | * if (condition2) { |
54 | * useMaybeAgain(val()); |
55 | * } else { |
56 | * // Unneeded in this branch. |
57 | * } |
58 | * } |
59 | * |
60 | * |
61 | * Rationale: |
62 | * |
63 | * - operator() is used to request the value instead of an implicit |
64 | * conversion because the slight syntactic overhead in common |
65 | * seems worth the increased clarity. |
66 | * |
67 | * - Lazy values do not model CopyConstructible because it is |
68 | * unclear what semantics would be desirable. Either copies |
69 | * should share the cached value (adding overhead to cases that |
70 | * don't need to support copies), or they could recompute the |
71 | * value unnecessarily. Sharing with mutable lazies would also |
72 | * leave them with non-value semantics despite looking |
73 | * value-like. |
74 | * |
75 | * - Not thread safe for const accesses. Many use cases for lazy |
76 | * values are local variables on the stack, where multiple |
77 | * threads shouldn't even be able to reach the value. It still |
78 | * is useful to indicate/check that the value doesn't change with |
79 | * const, particularly when it is captured by a large family of |
80 | * lambdas. Adding internal synchronization seems like it would |
81 | * pessimize the most common use case in favor of less likely use |
82 | * cases. |
83 | * |
84 | */ |
85 | |
86 | ////////////////////////////////////////////////////////////////////// |
87 | |
88 | namespace detail { |
89 | |
90 | template <class Func> |
91 | struct Lazy { |
92 | typedef invoke_result_t<Func> result_type; |
93 | |
94 | static_assert( |
95 | !std::is_const<Func>::value, |
96 | "Func should not be a const-qualified type" ); |
97 | static_assert( |
98 | !std::is_reference<Func>::value, |
99 | "Func should not be a reference type" ); |
100 | |
101 | explicit Lazy(Func&& f) : func_(std::move(f)) {} |
102 | explicit Lazy(const Func& f) : func_(f) {} |
103 | |
104 | Lazy(Lazy&& o) : value_(std::move(o.value_)), func_(std::move(o.func_)) {} |
105 | |
106 | Lazy(const Lazy&) = delete; |
107 | Lazy& operator=(const Lazy&) = delete; |
108 | Lazy& operator=(Lazy&&) = delete; |
109 | |
110 | const result_type& operator()() const { |
111 | ensure_initialized(); |
112 | |
113 | return *value_; |
114 | } |
115 | |
116 | result_type& operator()() { |
117 | ensure_initialized(); |
118 | |
119 | return *value_; |
120 | } |
121 | |
122 | private: |
123 | void ensure_initialized() const { |
124 | if (!value_) { |
125 | value_ = func_(); |
126 | } |
127 | } |
128 | |
129 | mutable Optional<result_type> value_; |
130 | mutable Func func_; |
131 | }; |
132 | |
133 | } // namespace detail |
134 | |
135 | ////////////////////////////////////////////////////////////////////// |
136 | |
137 | template <class Func> |
138 | auto lazy(Func&& fun) { |
139 | return detail::Lazy<remove_cvref_t<Func>>(std::forward<Func>(fun)); |
140 | } |
141 | |
142 | ////////////////////////////////////////////////////////////////////// |
143 | |
144 | } // namespace folly |
145 | |