230 lines
7.3 KiB
C++
230 lines
7.3 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
namespace folly {
|
|
namespace detail {
|
|
|
|
template <class I>
|
|
inline PolyVal<I>::PolyVal(PolyVal&& that) noexcept {
|
|
that.vptr_->ops_(Op::eMove, &that, static_cast<Data*>(this));
|
|
vptr_ = std::exchange(that.vptr_, vtable<I>());
|
|
}
|
|
|
|
template <class I>
|
|
inline PolyVal<I>::PolyVal(PolyOrNonesuch const& that) {
|
|
that.vptr_->ops_(
|
|
Op::eCopy, const_cast<Data*>(that._data_()), PolyAccess::data(*this));
|
|
vptr_ = that.vptr_;
|
|
}
|
|
|
|
template <class I>
|
|
inline PolyVal<I>::~PolyVal() {
|
|
vptr_->ops_(Op::eNuke, this, nullptr);
|
|
}
|
|
|
|
template <class I>
|
|
inline Poly<I>& PolyVal<I>::operator=(PolyVal that) noexcept {
|
|
vptr_->ops_(Op::eNuke, _data_(), nullptr);
|
|
that.vptr_->ops_(Op::eMove, that._data_(), _data_());
|
|
vptr_ = std::exchange(that.vptr_, vtable<I>());
|
|
return static_cast<Poly<I>&>(*this);
|
|
}
|
|
|
|
template <class I>
|
|
template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
|
|
inline PolyVal<I>::PolyVal(T&& t) {
|
|
using U = std::decay_t<T>;
|
|
static_assert(
|
|
std::is_copy_constructible<U>::value || !Copyable::value,
|
|
"This Poly<> requires copyability, and the source object is not "
|
|
"copyable");
|
|
// The static and dynamic types should match; otherwise, this will slice.
|
|
assert(typeid(t) == typeid(std::decay_t<T>) ||
|
|
!"Dynamic and static exception types don't match. Object would "
|
|
"be sliced when storing in Poly.");
|
|
if (inSitu<U>()) {
|
|
auto const buff = static_cast<void*>(&_data_()->buff_);
|
|
::new (buff) U(static_cast<T&&>(t));
|
|
} else {
|
|
_data_()->pobj_ = new U(static_cast<T&&>(t));
|
|
}
|
|
vptr_ = vtableFor<I, U>();
|
|
}
|
|
|
|
template <class I>
|
|
template <class I2, std::enable_if_t<ValueCompatible<I, I2>::value, int>>
|
|
inline PolyVal<I>::PolyVal(Poly<I2> that) {
|
|
static_assert(
|
|
!Copyable::value || std::is_copy_constructible<Poly<I2>>::value,
|
|
"This Poly<> requires copyability, and the source object is not "
|
|
"copyable");
|
|
auto* that_vptr = PolyAccess::vtable(that);
|
|
if (that_vptr->state_ != State::eEmpty) {
|
|
that_vptr->ops_(Op::eMove, PolyAccess::data(that), _data_());
|
|
vptr_ = &select<I>(*std::exchange(that_vptr, vtable<std::decay_t<I2>>()));
|
|
}
|
|
}
|
|
|
|
template <class I>
|
|
template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
|
|
inline Poly<I>& PolyVal<I>::operator=(T&& t) {
|
|
*this = PolyVal(static_cast<T&&>(t));
|
|
return static_cast<Poly<I>&>(*this);
|
|
}
|
|
|
|
template <class I>
|
|
template <class I2, std::enable_if_t<ValueCompatible<I, I2>::value, int>>
|
|
inline Poly<I>& PolyVal<I>::operator=(Poly<I2> that) {
|
|
*this = PolyVal(std::move(that));
|
|
return static_cast<Poly<I>&>(*this);
|
|
}
|
|
|
|
template <class I>
|
|
inline void PolyVal<I>::swap(Poly<I>& that) noexcept {
|
|
switch (vptr_->state_) {
|
|
case State::eEmpty:
|
|
*this = std::move(that);
|
|
break;
|
|
case State::eOnHeap:
|
|
if (State::eOnHeap == that.vptr_->state_) {
|
|
std::swap(_data_()->pobj_, that._data_()->pobj_);
|
|
std::swap(vptr_, that.vptr_);
|
|
return;
|
|
}
|
|
FOLLY_FALLTHROUGH;
|
|
case State::eInSitu:
|
|
std::swap(
|
|
*this, static_cast<PolyVal<I>&>(that)); // NOTE: qualified, not ADL
|
|
}
|
|
}
|
|
|
|
template <class I>
|
|
inline AddCvrefOf<PolyRoot<I>, I>& PolyRef<I>::_polyRoot_() const noexcept {
|
|
return const_cast<AddCvrefOf<PolyRoot<I>, I>&>(
|
|
static_cast<PolyRoot<I> const&>(*this));
|
|
}
|
|
|
|
template <class I>
|
|
constexpr RefType PolyRef<I>::refType() noexcept {
|
|
using J = std::remove_reference_t<I>;
|
|
return std::is_rvalue_reference<I>::value
|
|
? RefType::eRvalue
|
|
: std::is_const<J>::value ? RefType::eConstLvalue : RefType::eLvalue;
|
|
}
|
|
|
|
template <class I>
|
|
template <class That, class I2>
|
|
inline PolyRef<I>::PolyRef(That&& that, Type<I2>) {
|
|
auto* that_vptr = PolyAccess::vtable(PolyAccess::root(that));
|
|
detail::State const that_state = that_vptr->state_;
|
|
if (that_state == State::eEmpty) {
|
|
throw BadPolyAccess();
|
|
}
|
|
auto* that_data = PolyAccess::data(PolyAccess::root(that));
|
|
_data_()->pobj_ = that_state == State::eInSitu
|
|
? const_cast<void*>(static_cast<void const*>(&that_data->buff_))
|
|
: that_data->pobj_;
|
|
this->vptr_ = &select<std::decay_t<I>>(
|
|
*static_cast<VTable<std::decay_t<I2>> const*>(that_vptr->ops_(
|
|
Op::eRefr, nullptr, reinterpret_cast<void*>(refType()))));
|
|
}
|
|
|
|
template <class I>
|
|
inline PolyRef<I>::PolyRef(PolyRef const& that) noexcept {
|
|
_data_()->pobj_ = that._data_()->pobj_;
|
|
this->vptr_ = that.vptr_;
|
|
}
|
|
|
|
template <class I>
|
|
inline Poly<I>& PolyRef<I>::operator=(PolyRef const& that) noexcept {
|
|
_data_()->pobj_ = that._data_()->pobj_;
|
|
this->vptr_ = that.vptr_;
|
|
return static_cast<Poly<I>&>(*this);
|
|
}
|
|
|
|
template <class I>
|
|
template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
|
|
inline PolyRef<I>::PolyRef(T&& t) noexcept {
|
|
_data_()->pobj_ =
|
|
const_cast<void*>(static_cast<void const*>(std::addressof(t)));
|
|
this->vptr_ = vtableFor<std::decay_t<I>, AddCvrefOf<std::decay_t<T>, I>>();
|
|
}
|
|
|
|
template <class I>
|
|
template <
|
|
class I2,
|
|
std::enable_if_t<ReferenceCompatible<I, I2, I2&&>::value, int>>
|
|
inline PolyRef<I>::PolyRef(Poly<I2>&& that) noexcept(
|
|
std::is_reference<I2>::value)
|
|
: PolyRef{that, Type<I2>{}} {
|
|
static_assert(
|
|
Disjunction<std::is_reference<I2>, std::is_rvalue_reference<I>>::value,
|
|
"Attempting to construct a Poly that is a reference to a temporary. "
|
|
"This is probably a mistake.");
|
|
}
|
|
|
|
template <class I>
|
|
template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
|
|
inline Poly<I>& PolyRef<I>::operator=(T&& t) noexcept {
|
|
*this = PolyRef(static_cast<T&&>(t));
|
|
return static_cast<Poly<I>&>(*this);
|
|
}
|
|
|
|
template <class I>
|
|
template <
|
|
class I2,
|
|
std::enable_if_t<ReferenceCompatible<I, I2, I2&&>::value, int>>
|
|
inline Poly<I>& PolyRef<I>::operator=(Poly<I2>&& that) noexcept(
|
|
std::is_reference<I2>::value) {
|
|
*this = PolyRef(std::move(that));
|
|
return static_cast<Poly<I>&>(*this);
|
|
}
|
|
|
|
template <class I>
|
|
template <
|
|
class I2,
|
|
std::enable_if_t<ReferenceCompatible<I, I2, I2&>::value, int>>
|
|
inline Poly<I>& PolyRef<I>::operator=(Poly<I2>& that) noexcept(
|
|
std::is_reference<I2>::value) {
|
|
*this = PolyRef(that);
|
|
return static_cast<Poly<I>&>(*this);
|
|
}
|
|
|
|
template <class I>
|
|
template <
|
|
class I2,
|
|
std::enable_if_t<ReferenceCompatible<I, I2, I2 const&>::value, int>>
|
|
inline Poly<I>& PolyRef<I>::operator=(Poly<I2> const& that) noexcept(
|
|
std::is_reference<I2>::value) {
|
|
*this = PolyRef(that);
|
|
return static_cast<Poly<I>&>(*this);
|
|
}
|
|
|
|
template <class I>
|
|
inline void PolyRef<I>::swap(Poly<I>& that) noexcept {
|
|
std::swap(_data_()->pobj_, that._data_()->pobj_);
|
|
std::swap(this->vptr_, that.vptr_);
|
|
}
|
|
|
|
template <class I>
|
|
inline AddCvrefOf<PolyImpl<I>, I>& PolyRef<I>::get() const noexcept {
|
|
return const_cast<AddCvrefOf<PolyImpl<I>, I>&>(
|
|
static_cast<PolyImpl<I> const&>(*this));
|
|
}
|
|
|
|
} // namespace detail
|
|
} // namespace folly
|