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
25namespace 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
88namespace detail {
89
90template <class Func>
91struct 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
137template <class Func>
138auto lazy(Func&& fun) {
139 return detail::Lazy<remove_cvref_t<Func>>(std::forward<Func>(fun));
140}
141
142//////////////////////////////////////////////////////////////////////
143
144} // namespace folly
145