Fix RequestContext held too long issue in EventBase
[folly.git] / folly / Poly-inl.h
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(_t<std::decay<T>>) ||
56        !"Dynamic and static exception types don't match. Object would "
57         "be sliced when storing in Poly.");
58   if (inSitu<U>()) {
59     ::new (static_cast<void*>(&_data_()->buff_)) U(static_cast<T&&>(t));
60   } else {
61     _data_()->pobj_ = new U(static_cast<T&&>(t));
62   }
63   vptr_ = vtableFor<I, U>();
64 }
65
66 template <class I>
67 template <class I2, std::enable_if_t<ValueCompatible<I, I2>::value, int>>
68 inline PolyVal<I>::PolyVal(Poly<I2> that) {
69   static_assert(
70       !Copyable::value || std::is_copy_constructible<Poly<I2>>::value,
71       "This Poly<> requires copyability, and the source object is not "
72       "copyable");
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>>()));
77   }
78 }
79
80 template <class I>
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);
85 }
86
87 template <class I>
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);
92 }
93
94 template <class I>
95 inline void PolyVal<I>::swap(Poly<I>& that) noexcept {
96   switch (vptr_->state_) {
97     case State::eEmpty:
98       *this = std::move(that);
99       break;
100     case State::eOnHeap:
101       if (State::eOnHeap == that.vptr_->state_) {
102         std::swap(_data_()->pobj_, _data_()->pobj_);
103         std::swap(vptr_, that.vptr_);
104       }
105       FOLLY_FALLTHROUGH;
106     case State::eInSitu:
107       std::swap(*this, that); // NOTE: qualified, not ADL
108   }
109 }
110
111 template <class I>
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));
115 }
116
117 template <class I>
118 constexpr RefType PolyRef<I>::refType() noexcept {
119   using J = std::remove_reference_t<I>;
120   return std::is_rvalue_reference<I>::value
121       ? RefType::eRvalue
122       : std::is_const<J>::value ? RefType::eConstLvalue : RefType::eLvalue;
123 }
124
125 template <class I>
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();
132   }
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_))
136       : that_data->pobj_;
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()))));
140 }
141
142 template <class I>
143 inline PolyRef<I>::PolyRef(PolyRef const& that) noexcept {
144   _data_()->pobj_ = that._data_()->pobj_;
145   this->vptr_ = that.vptr_;
146 }
147
148 template <class I>
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);
153 }
154
155 template <class I>
156 template <class T, std::enable_if_t<ModelsInterface<T, I>::value, int>>
157 inline PolyRef<I>::PolyRef(T&& t) noexcept {
158   _data_()->pobj_ =
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>>();
161 }
162
163 template <class I>
164 template <
165     class I2,
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>{}} {
170   static_assert(
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.");
174 }
175
176 template <class I>
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);
181 }
182
183 template <class I>
184 template <
185     class I2,
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);
191 }
192
193 template <class I>
194 template <
195     class I2,
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);
201 }
202
203 template <class I>
204 template <
205     class I2,
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);
211 }
212
213 template <class I>
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_);
217 }
218
219 template <class I>
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));
223 }
224
225 } // namespace detail
226 } // namespace folly