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 | |
17 | namespace folly { |
18 | namespace detail { |
19 | |
20 | template <class I> |
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> |
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> |
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>> |
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>> |
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> |
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> |
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> |
121 | constexpr 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 | |
128 | template <class I> |
129 | template <class That, class 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> |
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>> |
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>> |
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>> |
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>> |
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>> |
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> |
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> |
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 | |