in folly/Replaceable.h [396:628]
class alignas(T) Replaceable
: public replaceable_detail::dtor_mixin<T>,
public replaceable_detail::default_and_move_ctor_mixin<T>,
public replaceable_detail::copy_ctor_mixin<T>,
public replaceable_detail::move_assignment_mixin<T>,
public replaceable_detail::copy_assignment_mixin<T> {
using ctor_base = replaceable_detail::default_and_move_ctor_mixin<T>;
public:
using value_type = T;
/* Rule-of-zero default- copy- and move- constructors. The ugly code to make
* these work are above, in namespace folly::replaceable_detail.
*/
constexpr Replaceable() = default;
constexpr Replaceable(const Replaceable&) = default;
constexpr Replaceable(Replaceable&&) = default;
/* Rule-of-zero copy- and move- assignment operators. The ugly code to make
* these work are above, in namespace folly::replaceable_detail.
*
* Note - these destruct the `T` and then in-place construct a new one based
* on what is in the other replaceable; they do not invoke the assignment
* operator of `T`.
*/
Replaceable& operator=(const Replaceable&) = default;
Replaceable& operator=(Replaceable&&) = default;
/* Rule-of-zero destructor. The ugly code to make this work is above, in
* namespace folly::replaceable_detail.
*/
~Replaceable() = default;
/**
* Constructors; these are modeled very closely on the definition of
* `std::optional` in C++17.
*/
template <
class... Args,
std::enable_if_t<std::is_constructible<T, Args&&...>::value, int> = 0>
constexpr explicit Replaceable(in_place_t, Args&&... args)
// clang-format off
noexcept(std::is_nothrow_constructible<T, Args&&...>::value)
// clang-format on
: ctor_base(0) {
::new (storage_) T(std::forward<Args>(args)...);
}
template <
class U,
class... Args,
std::enable_if_t<
std::is_constructible<T, std::initializer_list<U>, Args&&...>::value,
int> = 0>
constexpr explicit Replaceable(
in_place_t, std::initializer_list<U> il, Args&&... args)
// clang-format off
noexcept(std::is_nothrow_constructible<
T,
std::initializer_list<U>,
Args&&...>::value)
// clang-format on
: ctor_base(0) {
::new (storage_) T(il, std::forward<Args>(args)...);
}
template <
class U = T,
std::enable_if_t<
std::is_constructible<T, U&&>::value &&
!std::is_same<std::decay_t<U>, in_place_t>::value &&
!std::is_same<Replaceable<T>, std::decay_t<U>>::value &&
std::is_convertible<U&&, T>::value,
int> = 0>
constexpr /* implicit */ Replaceable(U&& other)
// clang-format off
noexcept(std::is_nothrow_constructible<T, U&&>::value)
// clang-format on
: ctor_base(0) {
::new (storage_) T(std::forward<U>(other));
}
template <
class U = T,
std::enable_if_t<
std::is_constructible<T, U&&>::value &&
!std::is_same<std::decay_t<U>, in_place_t>::value &&
!std::is_same<Replaceable<T>, std::decay_t<U>>::value &&
!std::is_convertible<U&&, T>::value,
int> = 0>
constexpr explicit Replaceable(U&& other)
// clang-format off
noexcept(std::is_nothrow_constructible<T, U&&>::value)
// clang-format on
: ctor_base(0) {
::new (storage_) T(std::forward<U>(other));
}
template <
class U,
std::enable_if_t<
std::is_constructible<T, const U&>::value &&
!replaceable_detail::is_constructible_from_replaceable<
T>::value &&
!replaceable_detail::is_convertible_from_replaceable<T>::value &&
std::is_convertible<const U&, T>::value,
int> = 0>
/* implicit */ Replaceable(const Replaceable<U>& other)
// clang-format off
noexcept(std::is_nothrow_constructible<T, U const&>::value)
// clang-format on
: ctor_base(0) {
::new (storage_) T(*other);
}
template <
class U,
std::enable_if_t<
std::is_constructible<T, const U&>::value &&
!replaceable_detail::is_constructible_from_replaceable<
T>::value &&
!replaceable_detail::is_convertible_from_replaceable<T>::value &&
!std::is_convertible<const U&, T>::value,
int> = 0>
explicit Replaceable(const Replaceable<U>& other)
// clang-format off
noexcept(std::is_nothrow_constructible<T, U const&>::value)
// clang-format on
: ctor_base(0) {
::new (storage_) T(*other);
}
template <
class U,
std::enable_if_t<
std::is_constructible<T, U&&>::value &&
!replaceable_detail::is_constructible_from_replaceable<
T>::value &&
!replaceable_detail::is_convertible_from_replaceable<T>::value &&
std::is_convertible<U&&, T>::value,
int> = 0>
/* implicit */ Replaceable(Replaceable<U>&& other)
// clang-format off
noexcept(std::is_nothrow_constructible<T, U&&>::value)
// clang-format on
: ctor_base(0) {
::new (storage_) T(std::move(*other));
}
template <
class U,
std::enable_if_t<
std::is_constructible<T, U&&>::value &&
!replaceable_detail::is_constructible_from_replaceable<
T>::value &&
!replaceable_detail::is_convertible_from_replaceable<T>::value &&
!std::is_convertible<U&&, T>::value,
int> = 0>
explicit Replaceable(Replaceable<U>&& other)
// clang-format off
noexcept(std::is_nothrow_constructible<T, U&&>::value)
// clang-format on
: ctor_base(0) {
::new (storage_) T(std::move(*other));
}
/**
* `emplace` destructs the contained object and in-place constructs the
* replacement.
*
* The destructor must not throw (as usual). The constructor must not throw
* because that would violate the invariant that a `Replaceable<T>` always
* contains a T instance.
*
* As these methods are `noexcept` the program will be terminated if an
* exception is thrown. If you are encountering this issue you should look at
* using `Optional` instead.
*/
template <class... Args>
T& emplace(Args&&... args) noexcept {
T* destruct_ptr = launder(reinterpret_cast<T*>(storage_));
destruct_ptr->~T();
return *::new (storage_) T(std::forward<Args>(args)...);
}
template <class U, class... Args>
T& emplace(std::initializer_list<U> il, Args&&... args) noexcept {
T* destruct_ptr = launder(reinterpret_cast<T*>(storage_));
destruct_ptr->~T();
return *::new (storage_) T(il, std::forward<Args>(args)...);
}
/**
* `swap` just calls `swap(T&, T&)`.
*/
void swap(Replaceable& other) noexcept(IsNothrowSwappable<Replaceable>{}) {
using std::swap;
swap(*(*this), *other);
}
/**
* Methods to access the contained object. Intended to be very unsurprising.
*/
constexpr const T* operator->() const {
return launder(reinterpret_cast<T const*>(storage_));
}
constexpr T* operator->() { return launder(reinterpret_cast<T*>(storage_)); }
constexpr const T& operator*() const& {
return *launder(reinterpret_cast<T const*>(storage_));
}
constexpr T& operator*() & {
return *launder(reinterpret_cast<T*>(storage_));
}
constexpr T&& operator*() && {
return std::move(*launder(reinterpret_cast<T*>(storage_)));
}
constexpr const T&& operator*() const&& {
return std::move(*launder(reinterpret_cast<T const*>(storage_)));
}
private:
friend struct replaceable_detail::dtor_mixin<T>;
friend struct replaceable_detail::default_and_move_ctor_mixin<T>;
friend struct replaceable_detail::copy_ctor_mixin<T>;
friend struct replaceable_detail::move_assignment_mixin<T>;
friend struct replaceable_detail::copy_assignment_mixin<T>;
aligned_storage_for_t<T> storage_[1];
};