Explicitly refer to the std::chrono namespace to avoid conflicts with the folly:...
[folly.git] / folly / Lazy.h
1 /*
2  * Copyright 2017 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
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 concurrent accesses by multiple
39  * threads, even if you declare it const.  See note below.
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  *    - Not thread safe for const accesses.  Many use cases for lazy
75  *      values are local variables on the stack, where multiple
76  *      threads shouldn't even be able to reach the value.  It still
77  *      is useful to indicate/check that the value doesn't change with
78  *      const, particularly when it is captured by a large family of
79  *      lambdas.  Adding internal synchronization seems like it would
80  *      pessimize the most common use case in favor of less likely use
81  *      cases.
82  *
83  */
84
85 //////////////////////////////////////////////////////////////////////
86
87 namespace detail {
88
89 template <class Func>
90 struct Lazy {
91   typedef typename std::result_of<Func()>::type result_type;
92
93   explicit Lazy(Func&& f) : func_(std::move(f)) {}
94   explicit Lazy(Func& f)  : func_(f) {}
95
96   Lazy(Lazy&& o)
97     : value_(std::move(o.value_))
98     , func_(std::move(o.func_))
99   {}
100
101   Lazy(const Lazy&) = delete;
102   Lazy& operator=(const Lazy&) = delete;
103   Lazy& operator=(Lazy&&) = delete;
104
105   const result_type& operator()() const {
106     return const_cast<Lazy&>(*this)();
107   }
108
109   result_type& operator()() {
110     if (!value_) {
111       value_ = func_();
112     }
113     return *value_;
114   }
115
116  private:
117   Optional<result_type> value_;
118   Func func_;
119 };
120
121 } // namespace detail
122
123 //////////////////////////////////////////////////////////////////////
124
125 template <class Func>
126 detail::Lazy<typename std::remove_reference<Func>::type>
127 lazy(Func&& fun) {
128   return detail::Lazy<typename std::remove_reference<Func>::type>(
129     std::forward<Func>(fun)
130   );
131 }
132
133 //////////////////////////////////////////////////////////////////////
134
135 } // namespace folly