Lazy.h 4.0 KB

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