Commit 6229600d authored by Ian Petersen's avatar Ian Petersen Committed by Facebook Github Bot

Remove some undefined behaviour from const Lazy.

Summary:
operator()() const uses const_cast to forward its implementation
to operator()(), which invokes UB when writing to the internal state.
This change marks the internal state mutable, which means we can delete
the const_cast.

Reviewed By: yfeldblum

Differential Revision: D7089568

fbshipit-source-id: 09f726e6399a95987075d6170ce6fb8103189552
parent 35970f56
...@@ -90,8 +90,15 @@ template <class Func> ...@@ -90,8 +90,15 @@ template <class Func>
struct Lazy { struct Lazy {
typedef typename std::result_of<Func()>::type result_type; typedef typename std::result_of<Func()>::type result_type;
static_assert(
!std::is_const<Func>::value,
"Func should not be a const-qualified type");
static_assert(
!std::is_reference<Func>::value,
"Func should not be a reference type");
explicit Lazy(Func&& f) : func_(std::move(f)) {} explicit Lazy(Func&& f) : func_(std::move(f)) {}
explicit Lazy(Func& f) : func_(f) {} explicit Lazy(const Func& f) : func_(f) {}
Lazy(Lazy&& o) Lazy(Lazy&& o)
: value_(std::move(o.value_)) : value_(std::move(o.value_))
...@@ -103,19 +110,26 @@ struct Lazy { ...@@ -103,19 +110,26 @@ struct Lazy {
Lazy& operator=(Lazy&&) = delete; Lazy& operator=(Lazy&&) = delete;
const result_type& operator()() const { const result_type& operator()() const {
return const_cast<Lazy&>(*this)(); ensure_initialized();
return *value_;
} }
result_type& operator()() { result_type& operator()() {
ensure_initialized();
return *value_;
}
private:
void ensure_initialized() const {
if (!value_) { if (!value_) {
value_ = func_(); value_ = func_();
} }
return *value_;
} }
private: mutable Optional<result_type> value_;
Optional<result_type> value_; mutable Func func_;
Func func_;
}; };
} // namespace detail } // namespace detail
...@@ -123,11 +137,8 @@ struct Lazy { ...@@ -123,11 +137,8 @@ struct Lazy {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
template <class Func> template <class Func>
detail::Lazy<typename std::remove_reference<Func>::type> auto lazy(Func&& fun) {
lazy(Func&& fun) { return detail::Lazy<remove_cvref_t<Func>>(std::forward<Func>(fun));
return detail::Lazy<typename std::remove_reference<Func>::type>(
std::forward<Func>(fun)
);
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
......
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