2 * Copyright 2017-present Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
21 inline PolyVal<I>::PolyVal(PolyVal&& that) noexcept {
22 that.vptr_->ops_(Op::eMove, &that, static_cast<Data*>(this));
23 vptr_ = std::exchange(that.vptr_, vtable<I>());
27 inline PolyVal<I>::PolyVal(PolyOrNonesuch const& that) {
29 Op::eCopy, const_cast<Data*>(that._data_()), PolyAccess::data(*this));
34 inline PolyVal<I>::~PolyVal() {
35 vptr_->ops_(Op::eNuke, this, nullptr);
39 inline Poly<I>& PolyVal<I>::operator=(PolyVal that) noexcept {
40 vptr_->ops_(Op::eNuke, _data_(), nullptr);
41 that.vptr_->ops_(Op::eMove, that._data_(), _data_());
42 vptr_ = std::exchange(that.vptr_, vtable<I>());
43 return static_cast<Poly<I>&>(*this);
47 template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
48 inline PolyVal<I>::PolyVal(T&& t) {
49 using U = std::decay_t<T>;
51 std::is_copy_constructible<U>::value || !Copyable::value,
52 "This Poly<> requires copyability, and the source object is not "
54 // The static and dynamic types should match; otherwise, this will slice.
55 assert(typeid(t) == typeid(_t<std::decay<T>>) ||
56 !"Dynamic and static exception types don't match. Object would "
57 "be sliced when storing in Poly.");
59 ::new (static_cast<void*>(&_data_()->buff_)) U(static_cast<T&&>(t));
61 _data_()->pobj_ = new U(static_cast<T&&>(t));
63 vptr_ = vtableFor<I, U>();
67 template <class I2, std::enable_if_t<ValueCompatible<I, I2>::value, int>>
68 inline PolyVal<I>::PolyVal(Poly<I2> that) {
70 !Copyable::value || std::is_copy_constructible<Poly<I2>>::value,
71 "This Poly<> requires copyability, and the source object is not "
73 auto* that_vptr = PolyAccess::vtable(that);
74 if (that_vptr->state_ != State::eEmpty) {
75 that_vptr->ops_(Op::eMove, PolyAccess::data(that), _data_());
76 vptr_ = &select<I>(*std::exchange(that_vptr, vtable<std::decay_t<I2>>()));
81 template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
82 inline Poly<I>& PolyVal<I>::operator=(T&& t) {
83 *this = PolyVal(static_cast<T&&>(t));
84 return static_cast<Poly<I>&>(*this);
88 template <class I2, std::enable_if_t<ValueCompatible<I, I2>::value, int>>
89 inline Poly<I>& PolyVal<I>::operator=(Poly<I2> that) {
90 *this = PolyVal(std::move(that));
91 return static_cast<Poly<I>&>(*this);
95 inline void PolyVal<I>::swap(Poly<I>& that) noexcept {
96 switch (vptr_->state_) {
98 *this = std::move(that);
101 if (State::eOnHeap == that.vptr_->state_) {
102 std::swap(_data_()->pobj_, _data_()->pobj_);
103 std::swap(vptr_, that.vptr_);
107 std::swap(*this, that); // NOTE: qualified, not ADL
112 inline AddCvrefOf<PolyRoot<I>, I>& PolyRef<I>::_polyRoot_() const noexcept {
113 return const_cast<AddCvrefOf<PolyRoot<I>, I>&>(
114 static_cast<PolyRoot<I> const&>(*this));
118 constexpr RefType PolyRef<I>::refType() noexcept {
119 using J = std::remove_reference_t<I>;
120 return std::is_rvalue_reference<I>::value
122 : std::is_const<J>::value ? RefType::eConstLvalue : RefType::eLvalue;
126 template <class That, class I2>
127 inline PolyRef<I>::PolyRef(That&& that, Type<I2>) {
128 auto* that_vptr = PolyAccess::vtable(PolyAccess::root(that));
129 detail::State const that_state = that_vptr->state_;
130 if (that_state == State::eEmpty) {
131 throw BadPolyAccess();
133 auto* that_data = PolyAccess::data(PolyAccess::root(that));
134 _data_()->pobj_ = that_state == State::eInSitu
135 ? const_cast<void*>(static_cast<void const*>(&that_data->buff_))
137 this->vptr_ = &select<std::decay_t<I>>(
138 *static_cast<VTable<std::decay_t<I2>> const*>(that_vptr->ops_(
139 Op::eRefr, nullptr, reinterpret_cast<void*>(refType()))));
143 inline PolyRef<I>::PolyRef(PolyRef const& that) noexcept {
144 _data_()->pobj_ = that._data_()->pobj_;
145 this->vptr_ = that.vptr_;
149 inline Poly<I>& PolyRef<I>::operator=(PolyRef const& that) noexcept {
150 _data_()->pobj_ = that._data_()->pobj_;
151 this->vptr_ = that.vptr_;
152 return static_cast<Poly<I>&>(*this);
156 template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
157 inline PolyRef<I>::PolyRef(T&& t) noexcept {
159 const_cast<void*>(static_cast<void const*>(std::addressof(t)));
160 this->vptr_ = vtableFor<std::decay_t<I>, AddCvrefOf<std::decay_t<T>, I>>();
166 std::enable_if_t<ReferenceCompatible<I, I2, I2&&>::value, int>>
167 inline PolyRef<I>::PolyRef(Poly<I2>&& that) noexcept(
168 std::is_reference<I2>::value)
169 : PolyRef{that, Type<I2>{}} {
171 Disjunction<std::is_reference<I2>, std::is_rvalue_reference<I>>::value,
172 "Attempting to construct a Poly that is a reference to a temporary. "
173 "This is probably a mistake.");
177 template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
178 inline Poly<I>& PolyRef<I>::operator=(T&& t) noexcept {
179 *this = PolyRef(static_cast<T&&>(t));
180 return static_cast<Poly<I>&>(*this);
186 std::enable_if_t<ReferenceCompatible<I, I2, I2&&>::value, int>>
187 inline Poly<I>& PolyRef<I>::operator=(Poly<I2>&& that) noexcept(
188 std::is_reference<I2>::value) {
189 *this = PolyRef(std::move(that));
190 return static_cast<Poly<I>&>(*this);
196 std::enable_if_t<ReferenceCompatible<I, I2, I2&>::value, int>>
197 inline Poly<I>& PolyRef<I>::operator=(Poly<I2>& that) noexcept(
198 std::is_reference<I2>::value) {
199 *this = PolyRef(that);
200 return static_cast<Poly<I>&>(*this);
206 std::enable_if_t<ReferenceCompatible<I, I2, I2 const&>::value, int>>
207 inline Poly<I>& PolyRef<I>::operator=(Poly<I2> const& that) noexcept(
208 std::is_reference<I2>::value) {
209 *this = PolyRef(that);
210 return static_cast<Poly<I>&>(*this);
214 inline void PolyRef<I>::swap(Poly<I>& that) noexcept {
215 std::swap(_data_()->pobj_, that._data_()->pobj_);
216 std::swap(this->vptr_, that.vptr_);
220 inline AddCvrefOf<PolyImpl<I>, I>& PolyRef<I>::get() const noexcept {
221 return const_cast<AddCvrefOf<PolyImpl<I>, I>&>(
222 static_cast<PolyImpl<I> const&>(*this));
225 } // namespace detail