Commit d77b369f authored by Andrey Kashin's avatar Andrey Kashin Committed by Sara Golemon

Enabling folly::Synchronized for non-default constructible objects

Summary:
Currently folly::Synchronized can't be used with non-default
constructible types because copy and move constructors require
creation of datum_ before it's assignment.
To fix this we can initialize them in initializer-list and
handle guard creation using helper constructor

Test Plan:
fbconfig -r folly && fbmake runtests
Fixes compilation error: Synchronized started working for non-default
constructible types in my project(rfe).

Reviewed By: yuri@fb.com

Subscribers: dhruvbird

FB internal diff: D1502110
parent 7ec1fc0e
...@@ -198,36 +198,55 @@ struct Synchronized { ...@@ -198,36 +198,55 @@ struct Synchronized {
*/ */
Synchronized() = default; Synchronized() = default;
private:
static constexpr bool nxCopyCtor{
std::is_nothrow_copy_constructible<T>::value};
static constexpr bool nxMoveCtor{
std::is_nothrow_move_constructible<T>::value};
/**
* Helper constructors to enable Synchronized for
* non-default constructible types T.
* Guards are created in actual public constructors and are alive
* for the time required to construct the object
*/
template <typename Guard>
Synchronized(const Synchronized& rhs,
const Guard& /*guard*/) noexcept(nxCopyCtor)
: datum_(rhs.datum_) {}
template <typename Guard>
Synchronized(Synchronized&& rhs, const Guard& /*guard*/) noexcept(nxMoveCtor)
: datum_(std::move(rhs.datum_)) {}
public:
/** /**
* Copy constructor copies the data (with locking the source and * Copy constructor copies the data (with locking the source and
* all) but does NOT copy the mutex. Doing so would result in * all) but does NOT copy the mutex. Doing so would result in
* deadlocks. * deadlocks.
*/ */
Synchronized(const Synchronized& rhs) { Synchronized(const Synchronized& rhs) noexcept(nxCopyCtor)
auto guard = rhs.operator->(); : Synchronized(rhs, rhs.operator->()) {}
datum_ = rhs.datum_;
}
/** /**
* Move constructor moves the data (with locking the source and all) * Move constructor moves the data (with locking the source and all)
* but does not move the mutex. * but does not move the mutex.
*/ */
Synchronized(Synchronized&& rhs) { Synchronized(Synchronized&& rhs) noexcept(nxMoveCtor)
auto guard = rhs.operator->(); : Synchronized(std::move(rhs), rhs.operator->()) {}
datum_ = std::move(rhs.datum_);
}
/** /**
* Constructor taking a datum as argument copies it. There is no * Constructor taking a datum as argument copies it. There is no
* need to lock the constructing object. * need to lock the constructing object.
*/ */
explicit Synchronized(const T& rhs) : datum_(rhs) {} explicit Synchronized(const T& rhs) noexcept(nxCopyCtor) : datum_(rhs) {}
/** /**
* Constructor taking a datum rvalue as argument moves it. Again, * Constructor taking a datum rvalue as argument moves it. Again,
* there is no need to lock the constructing object. * there is no need to lock the constructing object.
*/ */
explicit Synchronized(T&& rhs) : datum_(std::move(rhs)) {} explicit Synchronized(T&& rhs) noexcept(nxMoveCtor)
: datum_(std::move(rhs)) {}
/** /**
* The canonical assignment operator only assigns the data, NOT the * The canonical assignment operator only assigns the data, NOT the
......
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