Poly-inl.h 7.2 KB

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