1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
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
17 namespace folly {
18 namespace detail {
19
20 template <class I>
PolyVal(PolyVal && that)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>());
24 }
25
26 template <class I>
PolyVal(PolyOrNonesuch const & that)27 inline 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
33 template <class I>
~PolyVal()34 inline PolyVal<I>::~PolyVal() {
35 vptr_->ops_(Op::eNuke, this, nullptr);
36 }
37
38 template <class I>
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);
44 }
45
46 template <class I>
47 template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
PolyVal(T && t)48 inline 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
67 template <class I>
68 template <class I2, std::enable_if_t<ValueCompatible<I, I2>::value, int>>
PolyVal(Poly<I2> that)69 inline 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
81 template <class I>
82 template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
83 inline Poly<I>& PolyVal<I>::operator=(T&& t) {
84 *this = PolyVal(static_cast<T&&>(t));
85 return static_cast<Poly<I>&>(*this);
86 }
87
88 template <class I>
89 template <class I2, std::enable_if_t<ValueCompatible<I, I2>::value, int>>
90 inline Poly<I>& PolyVal<I>::operator=(Poly<I2> that) {
91 *this = PolyVal(std::move(that));
92 return static_cast<Poly<I>&>(*this);
93 }
94
95 template <class I>
swap(Poly<I> & that)96 inline 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
114 template <class I>
_polyRoot_()115 inline 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
120 template <class I>
refType()121 constexpr RefType PolyRef<I>::refType() noexcept {
122 using J = std::remove_reference_t<I>;
123 return std::is_rvalue_reference<I>::value ? RefType::eRvalue
124 : std::is_const<J>::value ? RefType::eConstLvalue
125 : RefType::eLvalue;
126 }
127
128 template <class I>
129 template <class That, class I2>
PolyRef(That && that,Type<I2>)130 inline 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
145 template <class I>
PolyRef(PolyRef const & that)146 inline PolyRef<I>::PolyRef(PolyRef const& that) noexcept {
147 _data_()->pobj_ = that._data_()->pobj_;
148 this->vptr_ = that.vptr_;
149 }
150
151 template <class I>
152 inline 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
158 template <class I>
159 template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
PolyRef(T && t)160 inline 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
166 template <class I>
167 template <
168 class I2,
169 std::enable_if_t<ReferenceCompatible<I, I2, I2&&>::value, int>>
PolyRef(Poly<I2> && that)170 inline 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
179 template <class I>
180 template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
181 inline Poly<I>& PolyRef<I>::operator=(T&& t) noexcept {
182 *this = PolyRef(static_cast<T&&>(t));
183 return static_cast<Poly<I>&>(*this);
184 }
185
186 template <class I>
187 template <
188 class I2,
189 std::enable_if_t<ReferenceCompatible<I, I2, I2&&>::value, int>>
noexcept(std::is_reference<I2>::value)190 inline 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
196 template <class I>
197 template <
198 class I2,
199 std::enable_if_t<ReferenceCompatible<I, I2, I2&>::value, int>>
noexcept(std::is_reference<I2>::value)200 inline 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
206 template <class I>
207 template <
208 class I2,
209 std::enable_if_t<ReferenceCompatible<I, I2, I2 const&>::value, int>>
noexcept(std::is_reference<I2>::value)210 inline 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
216 template <class I>
swap(Poly<I> & that)217 inline 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
222 template <class I>
get()223 inline 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