Commit d8ecccad authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

tweaks to DelayedInit

Summary:
Tweaks to `folly::DelayedInit`:
* No potential for ambiguity in placement-new by using `::new` and casting the address to `void*`.
* Helper functions `slot` and `store` simplify `try_emplace_with` and `try_emplace`.
* `try_emplace_with` and `try_emplace` are no longer `const`-qualified, removing the need for `mutable` qualifiers.

The emplacement members should not be `const`-qualified since they are not semantically non-modifying. The `const` qualifier signals semantic non-modification. While it is the case that there are customs around `const` qualifiers and concurrency, these customs are not the core meaning of `const`.

Reviewed By: praihan

Differential Revision: D25919779

fbshipit-source-id: 95e5c4b4abf5285fbb00dddda1192998baf6ee59
parent b9cc811a
...@@ -39,34 +39,38 @@ namespace folly { ...@@ -39,34 +39,38 @@ namespace folly {
* Otherwise, all design considerations from `folly::Lazy` are reflected here. * Otherwise, all design considerations from `folly::Lazy` are reflected here.
*/ */
template <class Func> template <class Ctor>
struct ConcurrentLazy { struct ConcurrentLazy {
using result_type = invoke_result_t<Func>; using result_type = invoke_result_t<Ctor>;
static_assert( static_assert(
!std::is_const<Func>::value, !std::is_const<Ctor>::value,
"Func should not be a const-qualified type"); "Func should not be a const-qualified type");
static_assert( static_assert(
!std::is_reference<Func>::value, !std::is_reference<Ctor>::value,
"Func should not be a reference type"); "Func should not be a reference type");
explicit ConcurrentLazy(Func&& f) : func_(std::move(f)) {} template <
explicit ConcurrentLazy(const Func& f) : func_(f) {} typename F,
std::enable_if_t<std::is_constructible_v<Ctor, F>, int> = 0>
explicit ConcurrentLazy(F&& f) noexcept(
std::is_nothrow_constructible_v<Ctor, F>)
: ctor_(static_cast<F&&>(f)) {}
const result_type& operator()() const { const result_type& operator()() const {
return value_.try_emplace_with(std::ref(func_)); return value_.try_emplace_with(std::ref(ctor_));
} }
result_type& operator()() { return value_.try_emplace_with(std::ref(func_)); } result_type& operator()() { return value_.try_emplace_with(std::ref(ctor_)); }
private: private:
folly::DelayedInit<result_type> value_; mutable folly::DelayedInit<result_type> value_;
mutable Func func_; mutable Ctor ctor_;
}; };
template <class Func> template <class Func>
auto concurrent_lazy(Func&& fun) { ConcurrentLazy<remove_cvref_t<Func>> concurrent_lazy(Func&& func) {
return ConcurrentLazy<remove_cvref_t<Func>>(std::forward<Func>(fun)); return ConcurrentLazy<remove_cvref_t<Func>>(static_cast<Func&&>(func));
} }
} // namespace folly } // namespace folly
...@@ -51,7 +51,8 @@ class SimpleObservable { ...@@ -51,7 +51,8 @@ class SimpleObservable {
struct Wrapper; struct Wrapper;
std::shared_ptr<Context> context_; std::shared_ptr<Context> context_;
folly::DelayedInit<Observer<typename observer_detail::Unwrap<T>::type>> mutable folly::DelayedInit<
Observer<typename observer_detail::Unwrap<T>::type>>
observer_; observer_;
}; };
} // namespace observer } // namespace observer
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#pragma once #pragma once
#include <initializer_list> #include <initializer_list>
#include <memory> #include <new>
#include <stdexcept> #include <stdexcept>
#include <type_traits> #include <type_traits>
...@@ -80,10 +80,8 @@ struct DelayedInit { ...@@ -80,10 +80,8 @@ struct DelayedInit {
* then the provided function is not called. * then the provided function is not called.
*/ */
template <typename Func> template <typename Func>
T& try_emplace_with(Func func) const { T& try_emplace_with(Func func) {
call_once(storage_.init, [&]() mutable { call_once(storage_.init, [&] { ::new (slot()) T(func()); });
new (std::addressof(storage_.value)) T(func());
});
return storage_.value; return storage_.value;
} }
...@@ -91,25 +89,19 @@ struct DelayedInit { ...@@ -91,25 +89,19 @@ struct DelayedInit {
* Gets the pre-existing value if already initialized or constructs the value * Gets the pre-existing value if already initialized or constructs the value
* in-place by direct-initializing with the provided arguments. * in-place by direct-initializing with the provided arguments.
*/ */
template <typename... Args> template <typename... A>
T& try_emplace(Args&&... args) const { T& try_emplace(A&&... a) {
call_once( call_once(storage_.init, [&] { store(static_cast<A&&>(a)...); });
storage_.init,
[this](Args&&... forwardedArgs) mutable {
new (std::addressof(storage_.value))
T(std::forward<Args>(forwardedArgs)...);
},
std::forward<Args>(args)...);
return storage_.value; return storage_.value;
} }
template < template <
typename U, typename U,
typename... Args, typename... A,
typename = std::enable_if_t< typename = std::enable_if_t<
std::is_constructible<T, std::initializer_list<U>, Args...>::value>> std::is_constructible<T, std::initializer_list<U>, A...>::value>>
T& try_emplace(std::initializer_list<U> ilist, Args&&... args) const { T& try_emplace(std::initializer_list<U> ilist, A&&... a) {
return try_emplace<std::initializer_list<U>, Args...>( call_once(storage_.init, [&] { store(ilist, static_cast<A&&>(a)...); });
std::move(ilist), std::forward<Args>(args)...); return storage_.value;
} }
bool has_value() const { return test_once(storage_.init); } bool has_value() const { return test_once(storage_.init); }
...@@ -182,7 +174,14 @@ struct DelayedInit { ...@@ -182,7 +174,14 @@ struct DelayedInit {
StorageTriviallyDestructible, StorageTriviallyDestructible,
StorageNonTriviallyDestructible>; StorageNonTriviallyDestructible>;
mutable Storage storage_; void* slot() { return static_cast<void*>(std::addressof(storage_.value)); }
template <typename... A>
void store(A&&... a) {
::new (slot()) T(static_cast<A&&>(a)...);
}
Storage storage_;
}; };
} // namespace folly } // namespace folly
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment