Commit e03e7630 authored by Joe Loser's avatar Joe Loser Committed by Facebook Github Bot

Cut backport of std::exchange (#1021)

Summary:
- Backporting `std:exchange` is no longer needed as Folly requires C++14
  support and C++14-compliant vendors have `std::exchange` in their
  standard library, notably including GCC 4.9.
- Cut backport of `std::exchange` and fix call sites to explicitly use
  `std::exchange` where they were previously relying on `exchange` being
  found in the `folly` namespace.
Pull Request resolved: https://github.com/facebook/folly/pull/1021

Reviewed By: Orvid

Differential Revision: D14119875

Pulled By: yfeldblum

fbshipit-source-id: 686a8e812f6728281b432eae1586de28d21da9dd
parent 6e296e64
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <cassert> #include <cassert>
#include <climits> #include <climits>
#include <utility>
#include <folly/Function.h> #include <folly/Function.h>
#include <folly/Utility.h> #include <folly/Utility.h>
...@@ -59,7 +60,8 @@ class Executor { ...@@ -59,7 +60,8 @@ class Executor {
} }
KeepAlive(KeepAlive&& other) noexcept KeepAlive(KeepAlive&& other) noexcept
: executorAndDummyFlag_(exchange(other.executorAndDummyFlag_, 0)) {} : executorAndDummyFlag_(std::exchange(other.executorAndDummyFlag_, 0)) {
}
KeepAlive(const KeepAlive& other) noexcept KeepAlive(const KeepAlive& other) noexcept
: KeepAlive(getKeepAliveToken(other.get())) {} : KeepAlive(getKeepAliveToken(other.get())) {}
...@@ -86,7 +88,7 @@ class Executor { ...@@ -86,7 +88,7 @@ class Executor {
KeepAlive& operator=(KeepAlive&& other) { KeepAlive& operator=(KeepAlive&& other) {
reset(); reset();
executorAndDummyFlag_ = exchange(other.executorAndDummyFlag_, 0); executorAndDummyFlag_ = std::exchange(other.executorAndDummyFlag_, 0);
return *this; return *this;
} }
...@@ -108,7 +110,7 @@ class Executor { ...@@ -108,7 +110,7 @@ class Executor {
void reset() { void reset() {
if (Executor* executor = get()) { if (Executor* executor = get()) {
if (exchange(executorAndDummyFlag_, 0) & kDummyFlag) { if (std::exchange(executorAndDummyFlag_, 0) & kDummyFlag) {
return; return;
} }
executor->keepAliveRelease(); executor->keepAliveRelease();
......
...@@ -90,7 +90,7 @@ class ScopeGuardImpl : public ScopeGuardImplBase { ...@@ -90,7 +90,7 @@ class ScopeGuardImpl : public ScopeGuardImplBase {
// on the value of other.dismissed_. The following lines only execute // on the value of other.dismissed_. The following lines only execute
// if the move/copy succeeded, in which case *this assumes ownership of // if the move/copy succeeded, in which case *this assumes ownership of
// the cleanup action and dismisses other. // the cleanup action and dismisses other.
dismissed_ = exchange(other.dismissed_, true); dismissed_ = std::exchange(other.dismissed_, true);
} }
~ScopeGuardImpl() noexcept(InvokeNoexcept) { ~ScopeGuardImpl() noexcept(InvokeNoexcept) {
......
...@@ -1086,7 +1086,7 @@ class LockedPtrBase { ...@@ -1086,7 +1086,7 @@ class LockedPtrBase {
} }
} }
LockedPtrBase(LockedPtrBase&& rhs) noexcept LockedPtrBase(LockedPtrBase&& rhs) noexcept
: parent_{exchange(rhs.parent_, nullptr)} {} : parent_{std::exchange(rhs.parent_, nullptr)} {}
LockedPtrBase& operator=(LockedPtrBase&& rhs) noexcept { LockedPtrBase& operator=(LockedPtrBase&& rhs) noexcept {
assignImpl(*this, rhs); assignImpl(*this, rhs);
return *this; return *this;
...@@ -1107,7 +1107,7 @@ class LockedPtrBase { ...@@ -1107,7 +1107,7 @@ class LockedPtrBase {
template <typename LockPolicyType> template <typename LockPolicyType>
LockedPtrBase( LockedPtrBase(
LockedPtrBase<SynchronizedType, Mutex, LockPolicyType>&& rhs) noexcept LockedPtrBase<SynchronizedType, Mutex, LockPolicyType>&& rhs) noexcept
: parent_{exchange(rhs.parent_, nullptr)} {} : parent_{std::exchange(rhs.parent_, nullptr)} {}
template <typename LockPolicyType> template <typename LockPolicyType>
LockedPtrBase& operator=( LockedPtrBase& operator=(
LockedPtrBase<SynchronizedType, Mutex, LockPolicyType>&& rhs) noexcept { LockedPtrBase<SynchronizedType, Mutex, LockPolicyType>&& rhs) noexcept {
...@@ -1126,7 +1126,7 @@ class LockedPtrBase { ...@@ -1126,7 +1126,7 @@ class LockedPtrBase {
LockPolicy::unlock(lhs.parent_->mutex_); LockPolicy::unlock(lhs.parent_->mutex_);
} }
lhs.parent_ = exchange(rhs.parent_, nullptr); lhs.parent_ = std::exchange(rhs.parent_, nullptr);
} }
using UnlockerData = SynchronizedType*; using UnlockerData = SynchronizedType*;
...@@ -1188,7 +1188,8 @@ class LockedPtrBase<SynchronizedType, std::mutex, LockPolicy> { ...@@ -1188,7 +1188,8 @@ class LockedPtrBase<SynchronizedType, std::mutex, LockPolicy> {
} }
LockedPtrBase(LockedPtrBase&& rhs) noexcept LockedPtrBase(LockedPtrBase&& rhs) noexcept
: lock_{std::move(rhs.lock_)}, parent_{exchange(rhs.parent_, nullptr)} {} : lock_{std::move(rhs.lock_)},
parent_{std::exchange(rhs.parent_, nullptr)} {}
LockedPtrBase& operator=(LockedPtrBase&& rhs) noexcept { LockedPtrBase& operator=(LockedPtrBase&& rhs) noexcept {
assignImpl(*this, rhs); assignImpl(*this, rhs);
return *this; return *this;
...@@ -1204,7 +1205,7 @@ class LockedPtrBase<SynchronizedType, std::mutex, LockPolicy> { ...@@ -1204,7 +1205,7 @@ class LockedPtrBase<SynchronizedType, std::mutex, LockPolicy> {
LockedPtrBase(LockedPtrBase<SynchronizedType, std::mutex, LockPolicyType>&& LockedPtrBase(LockedPtrBase<SynchronizedType, std::mutex, LockPolicyType>&&
other) noexcept other) noexcept
: lock_{std::move(other.lock_)}, : lock_{std::move(other.lock_)},
parent_{exchange(other.parent_, nullptr)} {} parent_{std::exchange(other.parent_, nullptr)} {}
template <typename LockPolicyType> template <typename LockPolicyType>
LockedPtrBase& operator=( LockedPtrBase& operator=(
LockedPtrBase<SynchronizedType, std::mutex, LockPolicyType>&& LockedPtrBase<SynchronizedType, std::mutex, LockPolicyType>&&
...@@ -1222,7 +1223,7 @@ class LockedPtrBase<SynchronizedType, std::mutex, LockPolicy> { ...@@ -1222,7 +1223,7 @@ class LockedPtrBase<SynchronizedType, std::mutex, LockPolicy> {
LockedPtrBase<SynchronizedType, std::mutex, LockPolicyRhs>& LockedPtrBase<SynchronizedType, std::mutex, LockPolicyRhs>&
rhs) noexcept { rhs) noexcept {
lhs.lock_ = std::move(rhs.lock_); lhs.lock_ = std::move(rhs.lock_);
lhs.parent_ = exchange(rhs.parent_, nullptr); lhs.parent_ = std::exchange(rhs.parent_, nullptr);
} }
/** /**
...@@ -1301,7 +1302,8 @@ class ScopedUnlocker { ...@@ -1301,7 +1302,8 @@ class ScopedUnlocker {
ScopedUnlocker(const ScopedUnlocker&) = delete; ScopedUnlocker(const ScopedUnlocker&) = delete;
ScopedUnlocker& operator=(const ScopedUnlocker&) = delete; ScopedUnlocker& operator=(const ScopedUnlocker&) = delete;
ScopedUnlocker(ScopedUnlocker&& other) noexcept ScopedUnlocker(ScopedUnlocker&& other) noexcept
: ptr_(exchange(other.ptr_, nullptr)), data_(std::move(other.data_)) {} : ptr_(std::exchange(other.ptr_, nullptr)),
data_(std::move(other.data_)) {}
ScopedUnlocker& operator=(ScopedUnlocker&& other) = delete; ScopedUnlocker& operator=(ScopedUnlocker&& other) = delete;
~ScopedUnlocker() { ~ScopedUnlocker() {
...@@ -1521,7 +1523,7 @@ class LockedPtr : public LockedPtrBase< ...@@ -1521,7 +1523,7 @@ class LockedPtr : public LockedPtrBase<
LockedPtr<SynchronizedType, LockPolicyFromUpgradeToExclusive> LockedPtr<SynchronizedType, LockPolicyFromUpgradeToExclusive>
moveFromUpgradeToWrite() { moveFromUpgradeToWrite() {
return LockedPtr<SynchronizedType, LockPolicyFromUpgradeToExclusive>( return LockedPtr<SynchronizedType, LockPolicyFromUpgradeToExclusive>(
exchange(this->parent_, nullptr)); std::exchange(this->parent_, nullptr));
} }
/** /**
...@@ -1535,7 +1537,7 @@ class LockedPtr : public LockedPtrBase< ...@@ -1535,7 +1537,7 @@ class LockedPtr : public LockedPtrBase<
LockedPtr<SynchronizedType, LockPolicyFromExclusiveToUpgrade> LockedPtr<SynchronizedType, LockPolicyFromExclusiveToUpgrade>
moveFromWriteToUpgrade() { moveFromWriteToUpgrade() {
return LockedPtr<SynchronizedType, LockPolicyFromExclusiveToUpgrade>( return LockedPtr<SynchronizedType, LockPolicyFromExclusiveToUpgrade>(
exchange(this->parent_, nullptr)); std::exchange(this->parent_, nullptr));
} }
/** /**
...@@ -1549,7 +1551,7 @@ class LockedPtr : public LockedPtrBase< ...@@ -1549,7 +1551,7 @@ class LockedPtr : public LockedPtrBase<
LockedPtr<SynchronizedType, LockPolicyFromUpgradeToShared> LockedPtr<SynchronizedType, LockPolicyFromUpgradeToShared>
moveFromUpgradeToRead() { moveFromUpgradeToRead() {
return LockedPtr<SynchronizedType, LockPolicyFromUpgradeToShared>( return LockedPtr<SynchronizedType, LockPolicyFromUpgradeToShared>(
exchange(this->parent_, nullptr)); std::exchange(this->parent_, nullptr));
} }
/** /**
...@@ -1563,7 +1565,7 @@ class LockedPtr : public LockedPtrBase< ...@@ -1563,7 +1565,7 @@ class LockedPtr : public LockedPtrBase<
LockedPtr<SynchronizedType, LockPolicyFromExclusiveToShared> LockedPtr<SynchronizedType, LockPolicyFromExclusiveToShared>
moveFromWriteToRead() { moveFromWriteToRead() {
return LockedPtr<SynchronizedType, LockPolicyFromExclusiveToShared>( return LockedPtr<SynchronizedType, LockPolicyFromExclusiveToShared>(
exchange(this->parent_, nullptr)); std::exchange(this->parent_, nullptr));
} }
}; };
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <stdexcept> #include <stdexcept>
#include <tuple> #include <tuple>
#include <utility>
namespace folly { namespace folly {
...@@ -174,7 +175,7 @@ void Try<T>::throwIfFailed() const { ...@@ -174,7 +175,7 @@ void Try<T>::throwIfFailed() const {
template <class T> template <class T>
void Try<T>::destroy() noexcept { void Try<T>::destroy() noexcept {
auto oldContains = folly::exchange(contains_, Contains::NOTHING); auto oldContains = std::exchange(contains_, Contains::NOTHING);
if (LIKELY(oldContains == Contains::VALUE)) { if (LIKELY(oldContains == Contains::VALUE)) {
value_.~T(); value_.~T();
} else if (UNLIKELY(oldContains == Contains::EXCEPTION)) { } else if (UNLIKELY(oldContains == Contains::EXCEPTION)) {
......
...@@ -108,23 +108,6 @@ constexpr like_t<Src, Dst>&& forward_like(Dst&& dst) noexcept { ...@@ -108,23 +108,6 @@ constexpr like_t<Src, Dst>&& forward_like(Dst&& dst) noexcept {
return static_cast<like_t<Src, Dst>&&>(std::forward<Dst>(dst)); return static_cast<like_t<Src, Dst>&&>(std::forward<Dst>(dst));
} }
#if __cpp_lib_exchange_function || _LIBCPP_STD_VER > 11 || _MSC_VER
/* using override */ using std::exchange;
#else
// mimic: std::exchange, C++14
// from: http://en.cppreference.com/w/cpp/utility/exchange, CC-BY-SA
template <class T, class U = T>
T exchange(T& obj, U&& new_value) {
T old_value = std::move(obj);
obj = std::forward<U>(new_value);
return old_value;
}
#endif
namespace utility_detail { namespace utility_detail {
template <typename...> template <typename...>
struct make_seq_cat; struct make_seq_cat;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <cassert> #include <cassert>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <utility>
#include <folly/Optional.h> #include <folly/Optional.h>
#include <folly/executors/ExecutorWithPriority.h> #include <folly/executors/ExecutorWithPriority.h>
...@@ -167,7 +168,7 @@ FutureBase<T>::FutureBase(in_place_t, Args&&... args) ...@@ -167,7 +168,7 @@ FutureBase<T>::FutureBase(in_place_t, Args&&... args)
template <class T> template <class T>
void FutureBase<T>::assign(FutureBase<T>&& other) noexcept { void FutureBase<T>::assign(FutureBase<T>&& other) noexcept {
detach(); detach();
core_ = exchange(other.core_, nullptr); core_ = std::exchange(other.core_, nullptr);
} }
template <class T> template <class T>
...@@ -1963,7 +1964,7 @@ Future<T> unorderedReduce(It first, It last, T initial, F func) { ...@@ -1963,7 +1964,7 @@ Future<T> unorderedReduce(It first, It last, T initial, F func) {
auto f = p.getFuture(); auto f = p.getFuture();
{ {
folly::MSLGuard lock(ctx->lock_); folly::MSLGuard lock(ctx->lock_);
f = exchange(ctx->memo_, std::move(f)); f = std::exchange(ctx->memo_, std::move(f));
if (++ctx->numThens_ == ctx->numFutures_) { if (++ctx->numThens_ == ctx->numFutures_) {
// After reducing the value of the last Future, fulfill the Promise // After reducing the value of the last Future, fulfill the Promise
ctx->memo_.setCallback_( ctx->memo_.setCallback_(
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <atomic> #include <atomic>
#include <thread> #include <thread>
#include <utility>
#include <folly/executors/InlineExecutor.h> #include <folly/executors/InlineExecutor.h>
#include <folly/futures/detail/Core.h> #include <folly/futures/detail/Core.h>
...@@ -47,14 +48,14 @@ Promise<T>::Promise() : retrieved_(false), core_(Core::make()) {} ...@@ -47,14 +48,14 @@ Promise<T>::Promise() : retrieved_(false), core_(Core::make()) {}
template <class T> template <class T>
Promise<T>::Promise(Promise<T>&& other) noexcept Promise<T>::Promise(Promise<T>&& other) noexcept
: retrieved_(exchange(other.retrieved_, false)), : retrieved_(std::exchange(other.retrieved_, false)),
core_(exchange(other.core_, nullptr)) {} core_(std::exchange(other.core_, nullptr)) {}
template <class T> template <class T>
Promise<T>& Promise<T>::operator=(Promise<T>&& other) noexcept { Promise<T>& Promise<T>::operator=(Promise<T>&& other) noexcept {
detach(); detach();
retrieved_ = exchange(other.retrieved_, false); retrieved_ = std::exchange(other.retrieved_, false);
core_ = exchange(other.core_, nullptr); core_ = std::exchange(other.core_, nullptr);
return *this; return *this;
} }
......
...@@ -538,7 +538,7 @@ class Core final { ...@@ -538,7 +538,7 @@ class Core final {
CoreAndCallbackReference& operator=(CoreAndCallbackReference&&) = delete; CoreAndCallbackReference& operator=(CoreAndCallbackReference&&) = delete;
CoreAndCallbackReference(CoreAndCallbackReference&& o) noexcept CoreAndCallbackReference(CoreAndCallbackReference&& o) noexcept
: core_(exchange(o.core_, nullptr)) {} : core_(std::exchange(o.core_, nullptr)) {}
Core* getCore() const noexcept { Core* getCore() const noexcept {
return core_; return core_;
...@@ -560,7 +560,7 @@ class Core final { ...@@ -560,7 +560,7 @@ class Core final {
DCHECK(state_ == State::Done); DCHECK(state_ == State::Done);
if (executor_) { if (executor_) {
auto x = exchange(executor_, Executor::KeepAlive<>()); auto x = std::exchange(executor_, Executor::KeepAlive<>());
exception_wrapper ew; exception_wrapper ew;
// We need to reset `callback_` after it was executed (which can happen // We need to reset `callback_` after it was executed (which can happen
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <limits> #include <limits>
#include <stdexcept> #include <stdexcept>
#include <thread> #include <thread>
#include <utility>
namespace folly { namespace folly {
namespace detail { namespace detail {
...@@ -238,11 +239,11 @@ class DistributedMutex<Atomic, TimePublishing>::DistributedMutexStateProxy { ...@@ -238,11 +239,11 @@ class DistributedMutex<Atomic, TimePublishing>::DistributedMutexStateProxy {
DistributedMutexStateProxy& operator=(DistributedMutexStateProxy&& other) { DistributedMutexStateProxy& operator=(DistributedMutexStateProxy&& other) {
DCHECK(!(*this)) << "Cannot move into a valid DistributedMutexStateProxy"; DCHECK(!(*this)) << "Cannot move into a valid DistributedMutexStateProxy";
next_ = exchange(other.next_, nullptr); next_ = std::exchange(other.next_, nullptr);
expected_ = exchange(other.expected_, 0); expected_ = std::exchange(other.expected_, 0);
wakerMetadata_ = exchange(other.wakerMetadata_, {}); wakerMetadata_ = std::exchange(other.wakerMetadata_, {});
waiters_ = exchange(other.waiters_, nullptr); waiters_ = std::exchange(other.waiters_, nullptr);
ready_ = exchange(other.ready_, nullptr); ready_ = std::exchange(other.ready_, nullptr);
return *this; return *this;
} }
...@@ -415,7 +416,7 @@ bool doFutexWait(Waiter* waiter, Waiter*& next) { ...@@ -415,7 +416,7 @@ bool doFutexWait(Waiter* waiter, Waiter*& next) {
while (pre != kWake) { while (pre != kWake) {
// before enqueueing on the futex, we wake any waiters that we were // before enqueueing on the futex, we wake any waiters that we were
// possibly responsible for // possibly responsible for
doFutexWake(exchange(next, nullptr)); doFutexWake(std::exchange(next, nullptr));
// then we wait on the futex // then we wait on the futex
// //
...@@ -765,7 +766,11 @@ void DistributedMutex<Atomic, Publish>::unlock( ...@@ -765,7 +766,11 @@ void DistributedMutex<Atomic, Publish>::unlock(
recordTimedWaiterAndClearTimedBit(proxy.timedWaiters_, head); recordTimedWaiterAndClearTimedBit(proxy.timedWaiters_, head);
auto next = extractAddress<CachelinePadded<Waiter<Atomic>>>(head); auto next = extractAddress<CachelinePadded<Waiter<Atomic>>>(head);
DCHECK((head & kLocked) && (head != kLocked)) << "incorrect state " << head; DCHECK((head & kLocked) && (head != kLocked)) << "incorrect state " << head;
if (wake(Publish, *next, {exchange(proxy.expected_, kLocked)}, sleepers)) { if (wake(
Publish,
*next,
{std::exchange(proxy.expected_, kLocked)},
sleepers)) {
break; break;
} }
} }
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <stdexcept> #include <stdexcept>
#include <utility>
namespace folly { namespace folly {
namespace detail { namespace detail {
...@@ -75,7 +76,7 @@ template <typename Mutex> ...@@ -75,7 +76,7 @@ template <typename Mutex>
ProxyLockableUniqueLock<Mutex>& ProxyLockableUniqueLock<Mutex>::operator=( ProxyLockableUniqueLock<Mutex>& ProxyLockableUniqueLock<Mutex>::operator=(
ProxyLockableUniqueLock&& other) noexcept { ProxyLockableUniqueLock&& other) noexcept {
proxy_ = std::move(other.proxy_); proxy_ = std::move(other.proxy_);
mutex_ = exchange(other.mutex_, nullptr); mutex_ = std::exchange(other.mutex_, nullptr);
return *this; return *this;
} }
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include <folly/Utility.h> #include <folly/Utility.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#include <utility>
namespace folly { namespace folly {
namespace { namespace {
...@@ -104,13 +106,13 @@ class Atomic { ...@@ -104,13 +106,13 @@ class Atomic {
Integer value, Integer value,
std::memory_order = std::memory_order_seq_cst) { std::memory_order = std::memory_order_seq_cst) {
onFetchOr_(); onFetchOr_();
return exchange(integer_, integer_ | value); return std::exchange(integer_, integer_ | value);
} }
Integer fetch_and( Integer fetch_and(
Integer value, Integer value,
std::memory_order = std::memory_order_seq_cst) { std::memory_order = std::memory_order_seq_cst) {
onFetchAnd_(); onFetchAnd_();
return exchange(integer_, integer_ & value); return std::exchange(integer_, integer_ & value);
} }
Integer load(std::memory_order = std::memory_order_seq_cst) { Integer load(std::memory_order = std::memory_order_seq_cst) {
......
...@@ -90,13 +90,6 @@ TEST_F(UtilityTest, forward_like) { ...@@ -90,13 +90,6 @@ TEST_F(UtilityTest, forward_like) {
EXPECT_EQ(&x, std::addressof(as_mutable(folly::forward_like<char const>(x)))); EXPECT_EQ(&x, std::addressof(as_mutable(folly::forward_like<char const>(x))));
} }
TEST_F(UtilityTest, exchange) {
auto obj = std::map<std::string, int>{{"hello", 3}};
auto old = exchange(obj, {{"world", 4}});
EXPECT_EQ((std::map<std::string, int>{{"world", 4}}), obj);
EXPECT_EQ((std::map<std::string, int>{{"hello", 3}}), old);
}
TEST(FollyIntegerSequence, core) { TEST(FollyIntegerSequence, core) {
constexpr auto seq = folly::integer_sequence<int, 0, 3, 2>(); constexpr auto seq = folly::integer_sequence<int, 0, 3, 2>();
static_assert(seq.size() == 3, ""); static_assert(seq.size() == 3, "");
......
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