1/*
2 * Copyright 2017-present Facebook, Inc.
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17namespace folly {
18namespace detail {
19
20template <class I>
21inline 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>());
24}
25
26template <class I>
27inline PolyVal<I>::PolyVal(PolyOrNonesuch const& that) {
28 that.vptr_->ops_(
29 Op::eCopy, const_cast<Data*>(that._data_()), PolyAccess::data(*this));
30 vptr_ = that.vptr_;
31}
32
33template <class I>
34inline PolyVal<I>::~PolyVal() {
35 vptr_->ops_(Op::eNuke, this, nullptr);
36}
37
38template <class I>
39inline 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);
44}
45
46template <class I>
47template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
48inline PolyVal<I>::PolyVal(T&& t) {
49 using U = std::decay_t<T>;
50 static_assert(
51 std::is_copy_constructible<U>::value || !Copyable::value,
52 "This Poly<> requires copyability, and the source object is not "
53 "copyable");
54 // The static and dynamic types should match; otherwise, this will slice.
55 assert(typeid(t) == typeid(std::decay_t<T>) ||
56 !"Dynamic and static exception types don't match. Object would "
57 "be sliced when storing in Poly.");
58 if (inSitu<U>()) {
59 auto const buff = static_cast<void*>(&_data_()->buff_);
60 ::new (buff) U(static_cast<T&&>(t));
61 } else {
62 _data_()->pobj_ = new U(static_cast<T&&>(t));
63 }
64 vptr_ = vtableFor<I, U>();
65}
66
67template <class I>
68template <class I2, std::enable_if_t<ValueCompatible<I, I2>::value, int>>
69inline PolyVal<I>::PolyVal(Poly<I2> that) {
70 static_assert(
71 !Copyable::value || std::is_copy_constructible<Poly<I2>>::value,
72 "This Poly<> requires copyability, and the source object is not "
73 "copyable");
74 auto* that_vptr = PolyAccess::vtable(that);
75 if (that_vptr->state_ != State::eEmpty) {
76 that_vptr->ops_(Op::eMove, PolyAccess::data(that), _data_());
77 vptr_ = &select<I>(*std::exchange(that_vptr, vtable<std::decay_t<I2>>()));
78 }
79}
80
81template <class I>
82template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
83inline Poly<I>& PolyVal<I>::operator=(T&& t) {
84 *this = PolyVal(static_cast<T&&>(t));
85 return static_cast<Poly<I>&>(*this);
86}
87
88template <class I>
89template <class I2, std::enable_if_t<ValueCompatible<I, I2>::value, int>>
90inline Poly<I>& PolyVal<I>::operator=(Poly<I2> that) {
91 *this = PolyVal(std::move(that));
92 return static_cast<Poly<I>&>(*this);
93}
94
95template <class I>
96inline void PolyVal<I>::swap(Poly<I>& that) noexcept {
97 switch (vptr_->state_) {
98 case State::eEmpty:
99 *this = std::move(that);
100 break;
101 case State::eOnHeap:
102 if (State::eOnHeap == that.vptr_->state_) {
103 std::swap(_data_()->pobj_, that._data_()->pobj_);
104 std::swap(vptr_, that.vptr_);
105 return;
106 }
107 FOLLY_FALLTHROUGH;
108 case State::eInSitu:
109 std::swap(
110 *this, static_cast<PolyVal<I>&>(that)); // NOTE: qualified, not ADL
111 }
112}
113
114template <class I>
115inline AddCvrefOf<PolyRoot<I>, I>& PolyRef<I>::_polyRoot_() const noexcept {
116 return const_cast<AddCvrefOf<PolyRoot<I>, I>&>(
117 static_cast<PolyRoot<I> const&>(*this));
118}
119
120template <class I>
121constexpr RefType PolyRef<I>::refType() noexcept {
122 using J = std::remove_reference_t<I>;
123 return std::is_rvalue_reference<I>::value
124 ? RefType::eRvalue
125 : std::is_const<J>::value ? RefType::eConstLvalue : RefType::eLvalue;
126}
127
128template <class I>
129template <class That, class I2>
130inline PolyRef<I>::PolyRef(That&& that, Type<I2>) {
131 auto* that_vptr = PolyAccess::vtable(PolyAccess::root(that));
132 detail::State const that_state = that_vptr->state_;
133 if (that_state == State::eEmpty) {
134 throw BadPolyAccess();
135 }
136 auto* that_data = PolyAccess::data(PolyAccess::root(that));
137 _data_()->pobj_ = that_state == State::eInSitu
138 ? const_cast<void*>(static_cast<void const*>(&that_data->buff_))
139 : that_data->pobj_;
140 this->vptr_ = &select<std::decay_t<I>>(
141 *static_cast<VTable<std::decay_t<I2>> const*>(that_vptr->ops_(
142 Op::eRefr, nullptr, reinterpret_cast<void*>(refType()))));
143}
144
145template <class I>
146inline PolyRef<I>::PolyRef(PolyRef const& that) noexcept {
147 _data_()->pobj_ = that._data_()->pobj_;
148 this->vptr_ = that.vptr_;
149}
150
151template <class I>
152inline Poly<I>& PolyRef<I>::operator=(PolyRef const& that) noexcept {
153 _data_()->pobj_ = that._data_()->pobj_;
154 this->vptr_ = that.vptr_;
155 return static_cast<Poly<I>&>(*this);
156}
157
158template <class I>
159template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
160inline PolyRef<I>::PolyRef(T&& t) noexcept {
161 _data_()->pobj_ =
162 const_cast<void*>(static_cast<void const*>(std::addressof(t)));
163 this->vptr_ = vtableFor<std::decay_t<I>, AddCvrefOf<std::decay_t<T>, I>>();
164}
165
166template <class I>
167template <
168 class I2,
169 std::enable_if_t<ReferenceCompatible<I, I2, I2&&>::value, int>>
170inline PolyRef<I>::PolyRef(Poly<I2>&& that) noexcept(
171 std::is_reference<I2>::value)
172 : PolyRef{that, Type<I2>{}} {
173 static_assert(
174 Disjunction<std::is_reference<I2>, std::is_rvalue_reference<I>>::value,
175 "Attempting to construct a Poly that is a reference to a temporary. "
176 "This is probably a mistake.");
177}
178
179template <class I>
180template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
181inline Poly<I>& PolyRef<I>::operator=(T&& t) noexcept {
182 *this = PolyRef(static_cast<T&&>(t));
183 return static_cast<Poly<I>&>(*this);
184}
185
186template <class I>
187template <
188 class I2,
189 std::enable_if_t<ReferenceCompatible<I, I2, I2&&>::value, int>>
190inline Poly<I>& PolyRef<I>::operator=(Poly<I2>&& that) noexcept(
191 std::is_reference<I2>::value) {
192 *this = PolyRef(std::move(that));
193 return static_cast<Poly<I>&>(*this);
194}
195
196template <class I>
197template <
198 class I2,
199 std::enable_if_t<ReferenceCompatible<I, I2, I2&>::value, int>>
200inline Poly<I>& PolyRef<I>::operator=(Poly<I2>& that) noexcept(
201 std::is_reference<I2>::value) {
202 *this = PolyRef(that);
203 return static_cast<Poly<I>&>(*this);
204}
205
206template <class I>
207template <
208 class I2,
209 std::enable_if_t<ReferenceCompatible<I, I2, I2 const&>::value, int>>
210inline Poly<I>& PolyRef<I>::operator=(Poly<I2> const& that) noexcept(
211 std::is_reference<I2>::value) {
212 *this = PolyRef(that);
213 return static_cast<Poly<I>&>(*this);
214}
215
216template <class I>
217inline void PolyRef<I>::swap(Poly<I>& that) noexcept {
218 std::swap(_data_()->pobj_, that._data_()->pobj_);
219 std::swap(this->vptr_, that.vptr_);
220}
221
222template <class I>
223inline AddCvrefOf<PolyImpl<I>, I>& PolyRef<I>::get() const noexcept {
224 return const_cast<AddCvrefOf<PolyImpl<I>, I>&>(
225 static_cast<PolyImpl<I> const&>(*this));
226}
227
228} // namespace detail
229} // namespace folly
230