/* * 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 inline PolyVal::PolyVal(PolyVal&& that) noexcept { that.vptr_->ops_(Op::eMove, &that, static_cast(this)); vptr_ = std::exchange(that.vptr_, vtable()); } template inline PolyVal::PolyVal(PolyOrNonesuch const& that) { that.vptr_->ops_( Op::eCopy, const_cast(that._data_()), PolyAccess::data(*this)); vptr_ = that.vptr_; } template inline PolyVal::~PolyVal() { vptr_->ops_(Op::eNuke, this, nullptr); } template inline Poly& PolyVal::operator=(PolyVal that) noexcept { vptr_->ops_(Op::eNuke, _data_(), nullptr); that.vptr_->ops_(Op::eMove, that._data_(), _data_()); vptr_ = std::exchange(that.vptr_, vtable()); return static_cast&>(*this); } template template ::value, int>> inline PolyVal::PolyVal(T&& t) { using U = std::decay_t; static_assert( std::is_copy_constructible::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) || !"Dynamic and static exception types don't match. Object would " "be sliced when storing in Poly."); if (inSitu()) { auto const buff = static_cast(&_data_()->buff_); ::new (buff) U(static_cast(t)); } else { _data_()->pobj_ = new U(static_cast(t)); } vptr_ = vtableFor(); } template template ::value, int>> inline PolyVal::PolyVal(Poly that) { static_assert( !Copyable::value || std::is_copy_constructible>::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(*std::exchange(that_vptr, vtable>())); } } template template ::value, int>> inline Poly& PolyVal::operator=(T&& t) { *this = PolyVal(static_cast(t)); return static_cast&>(*this); } template template ::value, int>> inline Poly& PolyVal::operator=(Poly that) { *this = PolyVal(std::move(that)); return static_cast&>(*this); } template inline void PolyVal::swap(Poly& 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&>(that)); // NOTE: qualified, not ADL } } template inline AddCvrefOf, I>& PolyRef::_polyRoot_() const noexcept { return const_cast, I>&>( static_cast const&>(*this)); } template constexpr RefType PolyRef::refType() noexcept { using J = std::remove_reference_t; return std::is_rvalue_reference::value ? RefType::eRvalue : std::is_const::value ? RefType::eConstLvalue : RefType::eLvalue; } template template inline PolyRef::PolyRef(That&& that, Type) { 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(static_cast(&that_data->buff_)) : that_data->pobj_; this->vptr_ = &select>( *static_cast> const*>(that_vptr->ops_( Op::eRefr, nullptr, reinterpret_cast(refType())))); } template inline PolyRef::PolyRef(PolyRef const& that) noexcept { _data_()->pobj_ = that._data_()->pobj_; this->vptr_ = that.vptr_; } template inline Poly& PolyRef::operator=(PolyRef const& that) noexcept { _data_()->pobj_ = that._data_()->pobj_; this->vptr_ = that.vptr_; return static_cast&>(*this); } template template ::value, int>> inline PolyRef::PolyRef(T&& t) noexcept { _data_()->pobj_ = const_cast(static_cast(std::addressof(t))); this->vptr_ = vtableFor, AddCvrefOf, I>>(); } template template < class I2, std::enable_if_t::value, int>> inline PolyRef::PolyRef(Poly&& that) noexcept( std::is_reference::value) : PolyRef{that, Type{}} { static_assert( Disjunction, std::is_rvalue_reference>::value, "Attempting to construct a Poly that is a reference to a temporary. " "This is probably a mistake."); } template template ::value, int>> inline Poly& PolyRef::operator=(T&& t) noexcept { *this = PolyRef(static_cast(t)); return static_cast&>(*this); } template template < class I2, std::enable_if_t::value, int>> inline Poly& PolyRef::operator=(Poly&& that) noexcept( std::is_reference::value) { *this = PolyRef(std::move(that)); return static_cast&>(*this); } template template < class I2, std::enable_if_t::value, int>> inline Poly& PolyRef::operator=(Poly& that) noexcept( std::is_reference::value) { *this = PolyRef(that); return static_cast&>(*this); } template template < class I2, std::enable_if_t::value, int>> inline Poly& PolyRef::operator=(Poly const& that) noexcept( std::is_reference::value) { *this = PolyRef(that); return static_cast&>(*this); } template inline void PolyRef::swap(Poly& that) noexcept { std::swap(_data_()->pobj_, that._data_()->pobj_); std::swap(this->vptr_, that.vptr_); } template inline AddCvrefOf, I>& PolyRef::get() const noexcept { return const_cast, I>&>( static_cast const&>(*this)); } } // namespace detail } // namespace folly