1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
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, "Func should not be a const-qualified type");
96 static_assert(
97 !std::is_reference<Func>::value, "Func should not be a reference type");
98
LazyLazy99 explicit Lazy(Func&& f) : func_(std::move(f)) {}
LazyLazy100 explicit Lazy(const Func& f) : func_(f) {}
101
LazyLazy102 Lazy(Lazy&& o) : value_(std::move(o.value_)), func_(std::move(o.func_)) {}
103
104 Lazy(const Lazy&) = delete;
105 Lazy& operator=(const Lazy&) = delete;
106 Lazy& operator=(Lazy&&) = delete;
107
operatorLazy108 const result_type& operator()() const {
109 ensure_initialized();
110
111 return *value_;
112 }
113
operatorLazy114 result_type& operator()() {
115 ensure_initialized();
116
117 return *value_;
118 }
119
120 private:
ensure_initializedLazy121 void ensure_initialized() const {
122 if (!value_) {
123 value_ = func_();
124 }
125 }
126
127 mutable Optional<result_type> value_;
128 mutable Func func_;
129 };
130
131 } // namespace detail
132
133 //////////////////////////////////////////////////////////////////////
134
135 template <class Func>
lazy(Func && fun)136 auto lazy(Func&& fun) {
137 return detail::Lazy<remove_cvref_t<Func>>(std::forward<Func>(fun));
138 }
139
140 //////////////////////////////////////////////////////////////////////
141
142 } // namespace folly
143