/* * 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