proxygen
PolyDetail.h
Go to the documentation of this file.
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 #pragma once
18 
19 #include <functional>
20 #include <new>
21 #include <tuple>
22 #include <type_traits>
23 #include <typeinfo>
24 #include <utility>
25 
26 #include <folly/Traits.h>
27 #include <folly/Utility.h>
28 #include <folly/detail/TypeList.h>
30 #include <folly/lang/Exception.h>
31 
32 #include <folly/PolyException.h>
33 
34 namespace folly {
36 namespace detail {
37 template <class I>
38 struct PolyRoot;
39 
40 using RRef_ = MetaQuoteTrait<std::add_rvalue_reference>;
41 using LRef_ = MetaQuoteTrait<std::add_lvalue_reference>;
42 
43 template <typename T>
44 struct XRef_ : Type<MetaQuoteTrait<Type>> {};
45 template <typename T>
46 using XRef = _t<XRef_<T>>;
47 template <typename T>
48 struct XRef_<T&&> : Type<MetaCompose<RRef_, XRef<T>>> {};
49 template <typename T>
50 struct XRef_<T&> : Type<MetaCompose<LRef_, XRef<T>>> {};
51 template <typename T>
52 struct XRef_<T const> : Type<MetaQuoteTrait<std::add_const>> {};
53 
54 template <class A, class B>
55 using AddCvrefOf = MetaApply<XRef<B>, A>;
56 } // namespace detail
58 
59 template <class I>
60 struct Poly;
61 
62 template <class T, class I>
63 detail::AddCvrefOf<T, I>& poly_cast(detail::PolyRoot<I>&);
64 
65 template <class T, class I>
66 detail::AddCvrefOf<T, I> const& poly_cast(detail::PolyRoot<I> const&);
67 
68 #if !defined(__cpp_template_auto)
69 #define FOLLY_AUTO class
70 template <class... Ts>
72 #else
73 #define FOLLY_AUTO auto
74 template <auto...>
75 struct PolyMembers;
76 #endif
77 
79 namespace detail {
80 /* *****************************************************************************
81  * IMPLEMENTATION NOTES
82  *
83 
84 Building the Interface
85 ----------------------
86 
87 Here is a high-level description of how Poly works. Users write an interface
88 such as:
89 
90  struct Mine {
91  template <class Base>
92  struct Interface {
93  int Exec() const {
94  return folly::poly_call<0>(*this);
95  }
96  }
97  template <class T>
98  using Members = folly::PolyMembers<&T::Exec>;
99  };
100 
101 Then they instantiate Poly<Mine>, which will have an Exec member function
102 of the correct signature. The Exec member function comes from
103 Mine::Interface<PolyNode<Mine, PolyRoot<Mine>>>, from which Poly<Mine> inherits.
104 Here's what each piece means:
105 
106 - PolyRoot<I>: stores Data, which is a union of a void* (used when the Poly is
107  storing an object on the heap or a reference) and some aligned storage (used
108  when the Poly is storing an object in-situ). PolyRoot also stores a vtable
109  pointer for interface I, which is a pointer to a struct containing function
110  pointers. The function pointers are bound member functions (e.g.,
111  SomeType::Exec). More on the vtable pointer and how it is generated below.
112 
113 - PolyNode: provides the hooks used by folly::poly_call to dispatch to the
114 correctly bound member function for this interface. In the context of an
115 interface I, folly::poly_call<K>(*this, args...) will:
116  1. Fetch the vtable pointer from PolyRoot,
117  2. Select the I portion of that vtable (which, in the case of interface
118  extension, may only be a part of the total vtable),
119  3. Fetch the K-th function pointer from that vtable part,
120  4. Call through that function pointer, passing Data (from PolyRoot) and any
121  additional arguments in the folly::poly_call<K> invocation.
122 
123 In the case of interface extension -- for instance, if interface Mine extended
124 interface Yours by inheriting from PolyExtends<Yours> -- then interface Mine
125 will have a list of base interfaces in a typelist called "Subsumptions".
126 Poly<Mine> will fold all the subsumed interfaces together, linearly inheriting
127 from them. To take the example of an interface Mine that extends Yours,
128 Poly<Mine> would inherit from this type:
129 
130  Mine::Interface<
131  PolyNode<Mine,
132  Your::Interface<
133  PolyNode<Your, PolyRoot<Mine>>>>>
134 
135 Through linear inheritance, Poly<Mine> ends up with the public member functions
136 of both interfaces, Mine and Yours.
137 
138 VTables
139 -------
140 
141 As mentioned above, PolyRoot<I> stores a vtable pointer for interface I. The
142 vtable is a struct whose members are function pointers. How are the types of
143 those function pointers computed from the interface? A dummy type is created,
144 Archetype<I>, in much the same way that Poly<I>'s base type is computed. Instead
145 of PolyNode and PolyRoot, there is ArchetypeNode and ArchetypeRoot. These types
146 also provide hooks for folly::poly_call, but they are dummy hooks that do
147 nothing. (Actually, they call std::terminate; they will never be called.) Once
148 Archetype<I> has been constructed, it is a concrete type that has all the
149 member functions of the interface and its subsumed interfaces. That type is
150 passed to Mine::Members, which takes the address of Archetype<I>::Exec and
151 inspects the resulting member function type. This is done for each member in the
152 interface. From a list of [member] function pointers, it is a simple matter of
153 metaprogramming to build a struct of function pointers. std::tuple is used for
154 this.
155 
156 An extra field is added to the tuple for a function that handles all of the
157 "special" operations: destruction, copying, moving, getting the type
158 information, getting the address of the stored object, and fetching a fixed-up
159 vtable pointer for reference conversions (e.g., I -> I&, I& -> I const&, etc).
160 
161 Subsumed interfaces are handled by having VTable<IDerived> inherit from
162 BasePtr<IBase>, where BasePtr<IBase> has only one member of type
163 VTable<IBase> const*.
164 
165 Now that the type of VTable<I> is computed, how are the fields populated?
166 Poly<I> default-constructs to an empty state. Its vtable pointer points to a
167 vtable whose fields are initialized with the addresses of functions that do
168 nothing but throw a BadPolyAccess exception. That way, if you call a member
169 function on an empty Poly, you get an exception. The function pointer
170 corresponding to the "special" operations points to a no-op function; copying,
171 moving and destroying an empty Poly does nothing.
172 
173 On the other hand, when you pass an object of type T satisfying interface I to
174 Poly<I>'s constructor or assignment operator, a vtable for {I,T} is reified by
175 passing type T to I::Members, thereby creating a list of bindings for T's member
176 functions. The address of this vtable gets stored in the PolyRoot<I> subobject,
177 imbuing the Poly object with the behaviors of type T. The T object itself gets
178 stored either on the heap or in the aligned storage within the Poly object
179 itself, depending on the size of T and whether or not it has a noexcept move
180 constructor.
181 */
182 
183 template <class T>
184 using Uncvref = std::remove_cv_t<std::remove_reference_t<T>>;
185 
186 template <class T, template <class...> class U>
187 struct IsInstanceOf : std::false_type {};
188 
189 template <class... Ts, template <class...> class U>
190 struct IsInstanceOf<U<Ts...>, U> : std::true_type {};
191 
192 template <class T>
193 using Not = Bool<!T::value>;
194 
195 template <class T>
196 struct StaticConst {
197  static constexpr T value{};
198 };
199 
200 template <class T>
201 constexpr T StaticConst<T>::value;
202 
203 template <class Then>
204 decltype(auto) if_constexpr(std::true_type, Then then) {
205  return then(Identity{});
206 }
207 
208 template <class Then>
209 void if_constexpr(std::false_type, Then) {}
210 
211 template <class Then, class Else>
212 decltype(auto) if_constexpr(std::true_type, Then then, Else) {
213  return then(Identity{});
214 }
215 
216 template <class Then, class Else>
217 decltype(auto) if_constexpr(std::false_type, Then, Else else_) {
218  return else_(Identity{});
219 }
220 
221 enum class Op : short { eNuke, eMove, eCopy, eType, eAddr, eRefr };
222 
223 enum class RefType : std::uintptr_t { eRvalue, eLvalue, eConstLvalue };
224 
225 struct Data;
226 
227 template <class I>
228 struct PolyVal;
229 
230 template <class I>
231 struct PolyRef;
232 
233 struct PolyAccess;
234 
235 template <class T>
236 using IsPoly = IsInstanceOf<Uncvref<T>, Poly>;
237 
238 // Given an interface I and a concrete type T that satisfies the interface
239 // I, create a list of member function bindings from members of T to members
240 // of I.
241 template <class I, class T>
242 using MembersOf = typename I::template Members<Uncvref<T>>;
243 
244 // Given an interface I and a base type T, create a type that implements
245 // the interface I in terms of the capabilities of T.
246 template <class I, class T>
247 using InterfaceOf = typename I::template Interface<T>;
248 
249 #if !defined(__cpp_template_auto)
250 template <class T, T V>
251 using Member = std::integral_constant<T, V>;
252 
253 template <class M>
254 using MemberType = typename M::value_type;
255 
256 template <class M>
257 inline constexpr MemberType<M> memberValue() noexcept {
258  return M::value;
259 }
260 
261 template <class... Ts>
262 struct MakeMembers {
263  template <Ts... Vs>
264  using Members = PolyMembers<Member<Ts, Vs>...>;
265 };
266 
267 template <class... Ts>
268 MakeMembers<Ts...> deduceMembers(Ts...);
269 
270 template <class Member, class = MemberType<Member>>
271 struct MemberDef;
272 
273 template <class Member, class R, class D, class... As>
274 struct MemberDef<Member, R (D::*)(As...)> {
275  static R value(D& d, As... as) {
276  return folly::invoke(memberValue<Member>(), d, static_cast<As&&>(as)...);
277  }
278 };
279 
280 template <class Member, class R, class D, class... As>
281 struct MemberDef<Member, R (D::*)(As...) const> {
282  static R value(D const& d, As... as) {
283  return folly::invoke(memberValue<Member>(), d, static_cast<As&&>(as)...);
284  }
285 };
286 
287 #else
288 template <auto M>
289 using MemberType = decltype(M);
290 
291 template <auto M>
292 inline constexpr MemberType<M> memberValue() noexcept {
293  return M;
294 }
295 #endif
296 
297 struct PolyBase {};
298 
299 template <class I, class = void>
300 struct SubsumptionsOf_ {
301  using type = TypeList<>;
302 };
303 
304 template <class I>
305 using InclusiveSubsumptionsOf = TypePushFront<_t<SubsumptionsOf_<I>>, I>;
306 
307 template <class I>
308 struct SubsumptionsOf_<I, void_t<typename I::Subsumptions>> {
309  using type = TypeJoin<TypeTransform<
310  typename I::Subsumptions,
312 };
313 
314 template <class I>
315 using SubsumptionsOf = TypeReverseUnique<_t<SubsumptionsOf_<I>>>;
316 
317 struct Bottom {
318  template <class T>
319  [[noreturn]] /* implicit */ operator T &&() const {
320  std::terminate();
321  }
322 };
323 
324 using ArchetypeNode = MetaQuote<InterfaceOf>;
325 
326 template <class I>
327 struct ArchetypeRoot;
328 
329 template <class I>
330 using Archetype =
331  TypeFold<InclusiveSubsumptionsOf<I>, ArchetypeRoot<I>, ArchetypeNode>;
332 
333 struct ArchetypeBase : Bottom {
334  ArchetypeBase() = default;
335  template <class T>
336  /* implicit */ ArchetypeBase(T&&);
337  template <std::size_t, class... As>
338  [[noreturn]] Bottom _polyCall_(As&&...) const {
339  std::terminate();
340  }
341 
342  friend bool operator==(ArchetypeBase const&, ArchetypeBase const&);
343  friend bool operator!=(ArchetypeBase const&, ArchetypeBase const&);
344  friend bool operator<(ArchetypeBase const&, ArchetypeBase const&);
345  friend bool operator<=(ArchetypeBase const&, ArchetypeBase const&);
346  friend bool operator>(ArchetypeBase const&, ArchetypeBase const&);
347  friend bool operator>=(ArchetypeBase const&, ArchetypeBase const&);
348  friend Bottom operator++(ArchetypeBase const&);
349  friend Bottom operator++(ArchetypeBase const&, int);
350  friend Bottom operator--(ArchetypeBase const&);
351  friend Bottom operator--(ArchetypeBase const&, int);
352  friend Bottom operator+(ArchetypeBase const&, ArchetypeBase const&);
353  friend Bottom operator+=(ArchetypeBase const&, ArchetypeBase const&);
354  friend Bottom operator-(ArchetypeBase const&, ArchetypeBase const&);
355  friend Bottom operator-=(ArchetypeBase const&, ArchetypeBase const&);
356  friend Bottom operator*(ArchetypeBase const&, ArchetypeBase const&);
357  friend Bottom operator*=(ArchetypeBase const&, ArchetypeBase const&);
358  friend Bottom operator/(ArchetypeBase const&, ArchetypeBase const&);
359  friend Bottom operator/=(ArchetypeBase const&, ArchetypeBase const&);
360  friend Bottom operator%(ArchetypeBase const&, ArchetypeBase const&);
361  friend Bottom operator%=(ArchetypeBase const&, ArchetypeBase const&);
362  friend Bottom operator<<(ArchetypeBase const&, ArchetypeBase const&);
363  friend Bottom operator<<=(ArchetypeBase const&, ArchetypeBase const&);
364  friend Bottom operator>>(ArchetypeBase const&, ArchetypeBase const&);
365  friend Bottom operator>>=(ArchetypeBase const&, ArchetypeBase const&);
366 };
367 
368 template <class I>
369 struct ArchetypeRoot : ArchetypeBase {
370  template <class Node, class Tfx>
371  using _polySelf_ = Archetype<AddCvrefOf<MetaApply<Tfx, I>, Node>>;
372  using _polyInterface_ = I;
373 };
374 
375 struct Data {
376  Data() = default;
377  // Suppress compiler-generated copy ops to not copy anything:
378  Data(Data const&) {}
379  Data& operator=(Data const&) {
380  return *this;
381  }
382  union {
383  void* pobj_ = nullptr;
384  std::aligned_storage_t<sizeof(double[2])> buff_;
385  };
386 };
387 
388 template <class U, class I>
389 using Arg =
390  If<std::is_same<Uncvref<U>, Archetype<I>>::value,
392  U>;
393 
394 template <class U, class I>
395 using Ret =
396  If<std::is_same<Uncvref<U>, Archetype<I>>::value,
397  AddCvrefOf<Poly<I>, U>,
398  U>;
399 
400 template <class Member, class I>
401 struct SignatureOf_;
402 
403 template <class R, class C, class... As, class I>
404 struct SignatureOf_<R (C::*)(As...), I> {
405  using type = Ret<R, I> (*)(Data&, Arg<As, I>...);
406 };
407 
408 template <class R, class C, class... As, class I>
409 struct SignatureOf_<R (C::*)(As...) const, I> {
410  using type = Ret<R, I> (*)(Data const&, Arg<As, I>...);
411 };
412 
413 template <class R, class This, class... As, class I>
414 struct SignatureOf_<R (*)(This&, As...), I> {
415  using type = Ret<R, I> (*)(Data&, Arg<As, I>...);
416 };
417 
418 template <class R, class This, class... As, class I>
419 struct SignatureOf_<R (*)(This const&, As...), I> {
420  using type = Ret<R, I> (*)(Data const&, Arg<As, I>...);
421 };
422 
423 template <FOLLY_AUTO Arch, class I>
424 using SignatureOf = _t<SignatureOf_<MemberType<Arch>, I>>;
425 
426 template <FOLLY_AUTO User, class I, class Sig = SignatureOf<User, I>>
427 struct ArgTypes_;
428 
429 template <FOLLY_AUTO User, class I, class Ret, class Data, class... Args>
430 struct ArgTypes_<User, I, Ret (*)(Data, Args...)> {
431  using type = TypeList<Args...>;
432 };
433 
434 template <FOLLY_AUTO User, class I>
435 using ArgTypes = _t<ArgTypes_<User, I>>;
436 
437 template <class R, class... Args>
438 using FnPtr = R (*)(Args...);
439 
440 struct ThrowThunk {
441  template <class R, class... Args>
442  constexpr /* implicit */ operator FnPtr<R, Args...>() const noexcept {
443  struct _ {
444  static R call(Args...) {
445  throw_exception<BadPolyAccess>();
446  }
447  };
448  return &_::call;
449  }
450 };
451 
452 inline constexpr ThrowThunk throw_() noexcept {
453  return ThrowThunk{};
454 }
455 
456 template <class T>
457 inline constexpr bool inSitu() noexcept {
458  return !std::is_reference<T>::value &&
459  sizeof(std::decay_t<T>) <= sizeof(Data) &&
460  std::is_nothrow_move_constructible<std::decay_t<T>>::value;
461 }
462 
463 template <class T>
464 T& get(Data& d) noexcept {
465  if (inSitu<T>()) {
466  return *(std::add_pointer_t<T>)static_cast<void*>(&d.buff_);
467  } else {
468  return *static_cast<std::add_pointer_t<T>>(d.pobj_);
469  }
470 }
471 
472 template <class T>
473 T const& get(Data const& d) noexcept {
474  if (inSitu<T>()) {
475  return *(std::add_pointer_t<T const>)static_cast<void const*>(&d.buff_);
476  } else {
477  return *static_cast<std::add_pointer_t<T const>>(d.pobj_);
478  }
479 }
480 
481 enum class State : short { eEmpty, eInSitu, eOnHeap };
482 
483 template <class T>
484 struct IsPolyRef : std::false_type {};
485 
486 template <class T>
487 struct IsPolyRef<Poly<T&>> : std::true_type {};
488 
489 template <class Arg, class U>
490 decltype(auto) convert(U&& u) {
491  return detail::if_constexpr(
493  IsPolyRef<Uncvref<U>>,
494  Negation<std::is_convertible<U, Arg>>>(),
495  [&](auto id) -> decltype(auto) {
496  return poly_cast<Uncvref<Arg>>(id(u).get());
497  },
498  [&](auto id) -> U&& { return static_cast<U&&>(id(u)); });
499 }
500 
501 template <class Fun>
502 struct IsConstMember : std::false_type {};
503 
504 template <class R, class C, class... As>
505 struct IsConstMember<R (C::*)(As...) const> : std::true_type {};
506 
507 template <class R, class C, class... As>
508 struct IsConstMember<R (*)(C const&, As...)> : std::true_type {};
509 
510 template <
511  class T,
512  FOLLY_AUTO User,
513  class I,
514  class = ArgTypes<User, I>,
515  class = Bool<true>>
516 struct ThunkFn {
517  template <class R, class D, class... As>
518  constexpr /* implicit */ operator FnPtr<R, D&, As...>() const noexcept {
519  return nullptr;
520  }
521 };
522 
523 template <class T, FOLLY_AUTO User, class I, class... Args>
524 struct ThunkFn<
525  T,
526  User,
527  I,
528  TypeList<Args...>,
529  Bool<
530  !std::is_const<std::remove_reference_t<T>>::value ||
531  IsConstMember<MemberType<User>>::value>> {
532  template <class R, class D, class... As>
533  constexpr /* implicit */ operator FnPtr<R, D&, As...>() const noexcept {
534  struct _ {
535  static R call(D& d, As... as) {
536  return folly::invoke(
537  memberValue<User>(),
538  get<T>(d),
539  convert<Args>(static_cast<As&&>(as))...);
540  }
541  };
542  return &_::call;
543  }
544 };
545 
546 template <
547  class I,
548  class = MembersOf<I, Archetype<I>>,
549  class = SubsumptionsOf<I>>
550 struct VTable;
551 
552 template <class T, FOLLY_AUTO User, class I>
553 inline constexpr ThunkFn<T, User, I> thunk() noexcept {
554  return ThunkFn<T, User, I>{};
555 }
556 
557 template <class I>
558 constexpr VTable<I> const* vtable() noexcept {
559  return &StaticConst<VTable<I>>::value;
560 }
561 
562 template <class I, class T>
563 struct VTableFor : VTable<I> {
564  constexpr VTableFor() noexcept : VTable<I>{Type<T>{}} {}
565 };
566 
567 template <class I, class T>
568 constexpr VTable<I> const* vtableFor() noexcept {
569  return &StaticConst<VTableFor<I, T>>::value;
570 }
571 
572 template <class I, class T>
573 constexpr void* vtableForRef(RefType ref) {
574  switch (ref) {
575  case RefType::eRvalue:
576  return const_cast<VTable<I>*>(vtableFor<I, T&&>());
577  case RefType::eLvalue:
578  return const_cast<VTable<I>*>(vtableFor<I, T&>());
579  case RefType::eConstLvalue:
580  return const_cast<VTable<I>*>(vtableFor<I, T const&>());
581  }
582  return nullptr;
583 }
584 
585 template <
586  class I,
587  class T,
589 void* execOnHeap(Op op, Data* from, void* to) {
590  switch (op) {
591  case Op::eNuke:
592  break;
593  case Op::eMove:
594  case Op::eCopy:
595  static_cast<Data*>(to)->pobj_ = from->pobj_;
596  break;
597  case Op::eType:
598  return const_cast<void*>(static_cast<void const*>(&typeid(T)));
599  case Op::eAddr:
600  if (*static_cast<std::type_info const*>(to) == typeid(T)) {
601  return from->pobj_;
602  }
603  throw_exception<BadPolyCast>();
604  case Op::eRefr:
605  return vtableForRef<I, Uncvref<T>>(
606  static_cast<RefType>(reinterpret_cast<std::uintptr_t>(to)));
607  }
608  return nullptr;
609 }
610 
611 template <
612  class I,
613  class T,
614  std::enable_if_t<Not<std::is_reference<T>>::value, int> = 0>
615 void* execOnHeap(Op op, Data* from, void* to) {
616  switch (op) {
617  case Op::eNuke:
618  delete &get<T>(*from);
619  break;
620  case Op::eMove:
621  static_cast<Data*>(to)->pobj_ = std::exchange(from->pobj_, nullptr);
622  break;
623  case Op::eCopy:
624  detail::if_constexpr(std::is_copy_constructible<T>(), [&](auto id) {
625  static_cast<Data*>(to)->pobj_ = new T(id(get<T>(*from)));
626  });
627  break;
628  case Op::eType:
629  return const_cast<void*>(static_cast<void const*>(&typeid(T)));
630  case Op::eAddr:
631  if (*static_cast<std::type_info const*>(to) == typeid(T)) {
632  return from->pobj_;
633  }
634  throw_exception<BadPolyCast>();
635  case Op::eRefr:
636  return vtableForRef<I, Uncvref<T>>(
637  static_cast<RefType>(reinterpret_cast<std::uintptr_t>(to)));
638  }
639  return nullptr;
640 }
641 
642 template <class I, class T>
643 void* execInSitu(Op op, Data* from, void* to) {
644  switch (op) {
645  case Op::eNuke:
646  get<T>(*from).~T();
647  break;
648  case Op::eMove:
649  ::new (static_cast<void*>(&static_cast<Data*>(to)->buff_))
650  T(std::move(get<T>(*from)));
651  get<T>(*from).~T();
652  break;
653  case Op::eCopy:
654  detail::if_constexpr(std::is_copy_constructible<T>(), [&](auto id) {
655  ::new (static_cast<void*>(&static_cast<Data*>(to)->buff_))
656  T(id(get<T>(*from)));
657  });
658  break;
659  case Op::eType:
660  return const_cast<void*>(static_cast<void const*>(&typeid(T)));
661  case Op::eAddr:
662  if (*static_cast<std::type_info const*>(to) == typeid(T)) {
663  return &from->buff_;
664  }
665  throw_exception<BadPolyCast>();
666  case Op::eRefr:
667  return vtableForRef<I, Uncvref<T>>(
668  static_cast<RefType>(reinterpret_cast<std::uintptr_t>(to)));
669  }
670  return nullptr;
671 }
672 
673 inline void* noopExec(Op op, Data*, void*) {
674  if (op == Op::eAddr)
675  throw_exception<BadPolyAccess>();
676  return const_cast<void*>(static_cast<void const*>(&typeid(void)));
677 }
678 
679 template <class I>
680 struct BasePtr {
681  VTable<I> const* vptr_;
682 };
683 
684 template <class I, class T, std::enable_if_t<inSitu<T>(), int> = 0>
685 constexpr void* (*getOps() noexcept)(Op, Data*, void*) {
686  return &execInSitu<I, T>;
687 }
688 
689 template <class I, class T, std::enable_if_t<!inSitu<T>(), int> = 0>
690 constexpr void* (*getOps() noexcept)(Op, Data*, void*) {
691  return &execOnHeap<I, T>;
692 }
693 
694 template <class I, FOLLY_AUTO... Arch, class... S>
695 struct VTable<I, PolyMembers<Arch...>, TypeList<S...>>
696  : BasePtr<S>..., std::tuple<SignatureOf<Arch, I>...> {
697  private:
698  template <class T, FOLLY_AUTO... User>
699  constexpr VTable(Type<T>, PolyMembers<User...>) noexcept
700  : BasePtr<S>{vtableFor<S, T>()}...,
701  std::tuple<SignatureOf<Arch, I>...>{thunk<T, User, I>()...},
702  state_{inSitu<T>() ? State::eInSitu : State::eOnHeap},
703  ops_{getOps<I, T>()} {}
704 
705  public:
706  constexpr VTable() noexcept
707  : BasePtr<S>{vtable<S>()}...,
708  std::tuple<SignatureOf<Arch, I>...>{
709  static_cast<SignatureOf<Arch, I>>(throw_())...},
710  state_{State::eEmpty},
711  ops_{&noopExec} {}
712 
713  template <class T>
714  explicit constexpr VTable(Type<T>) noexcept
715  : VTable{Type<T>{}, MembersOf<I, T>{}} {}
716 
717  State state_;
718  void* (*ops_)(Op, Data*, void*);
719 };
720 
721 template <class I>
722 constexpr VTable<I> const& select(VTable<_t<Type<I>>> const& vtbl) noexcept {
723  return vtbl;
724 }
725 
726 template <class I>
727 constexpr VTable<I> const& select(BasePtr<_t<Type<I>>> const& base) noexcept {
728  return *base.vptr_;
729 }
730 
731 struct PolyAccess {
732  template <std::size_t N, typename This, typename... As>
733  static auto call(This&& _this, As&&... args)
734  -> decltype(static_cast<This&&>(_this).template _polyCall_<N>(
735  static_cast<As&&>(args)...)) {
736  static_assert(
737  !IsInstanceOf<std::decay_t<This>, Poly>::value,
738  "When passing a Poly<> object to call(), you must explicitly "
739  "say which Interface to dispatch to, as in "
740  "call<0, MyInterface>(self, args...)");
741  return static_cast<This&&>(_this).template _polyCall_<N>(
742  static_cast<As&&>(args)...);
743  }
744 
745  template <class Poly>
746  using Iface = typename Uncvref<Poly>::_polyInterface_;
747 
748  template <class Node, class Tfx = MetaIdentity>
749  static typename Uncvref<Node>::template _polySelf_<Node, Tfx> self_();
750 
751  template <class T, class Poly, class I = Iface<Poly>>
752  static decltype(auto) cast(Poly&& _this) {
753  using Ret = AddCvrefOf<AddCvrefOf<T, I>, Poly&&>;
754  return static_cast<Ret>(
755  *static_cast<std::add_pointer_t<Ret>>(_this.vptr_->ops_(
756  Op::eAddr,
757  const_cast<Data*>(static_cast<Data const*>(&_this)),
758  const_cast<void*>(static_cast<void const*>(&typeid(T))))));
759  }
760 
761  template <class Poly>
762  static decltype(auto) root(Poly&& _this) noexcept {
763  return static_cast<Poly&&>(_this)._polyRoot_();
764  }
765 
766  template <class I>
767  static std::type_info const& type(PolyRoot<I> const& _this) noexcept {
768  return *static_cast<std::type_info const*>(
769  _this.vptr_->ops_(Op::eType, nullptr, nullptr));
770  }
771 
772  template <class I>
773  static VTable<Uncvref<I>> const* vtable(PolyRoot<I> const& _this) noexcept {
774  return _this.vptr_;
775  }
776 
777  template <class I>
778  static Data* data(PolyRoot<I>& _this) noexcept {
779  return &_this;
780  }
781 
782  template <class I>
783  static Data const* data(PolyRoot<I> const& _this) noexcept {
784  return &_this;
785  }
786 
787  template <class I>
788  static Poly<I&&> move(PolyRoot<I&> const& _this) noexcept {
789  return Poly<I&&>{_this, Type<I&>{}};
790  }
791 
792  template <class I>
793  static Poly<I const&> move(PolyRoot<I const&> const& _this) noexcept {
794  return Poly<I const&>{_this, Type<I const&>{}};
795  }
796 };
797 
798 template <class I, class Tail>
799 struct PolyNode : Tail {
800  private:
801  friend PolyAccess;
802  using Tail::Tail;
803 
804  template <std::size_t K, typename... As>
805  decltype(auto) _polyCall_(As&&... as) {
806  return std::get<K>(select<I>(*PolyAccess::vtable(*this)))(
807  *PolyAccess::data(*this), static_cast<As&&>(as)...);
808  }
809  template <std::size_t K, typename... As>
810  decltype(auto) _polyCall_(As&&... as) const {
811  return std::get<K>(select<I>(*PolyAccess::vtable(*this)))(
812  *PolyAccess::data(*this), static_cast<As&&>(as)...);
813  }
814 };
815 
816 struct MakePolyNode {
817  template <class I, class State>
818  using apply = InterfaceOf<I, PolyNode<I, State>>;
819 };
820 
821 template <class I>
822 struct PolyRoot : private PolyBase, private Data {
823  friend PolyAccess;
824  friend Poly<I>;
825  friend PolyVal<I>;
826  friend PolyRef<I>;
827  template <class Node, class Tfx>
828  using _polySelf_ = Poly<AddCvrefOf<MetaApply<Tfx, I>, Node>>;
829  using _polyInterface_ = I;
830 
831  private:
832  PolyRoot& _polyRoot_() noexcept {
833  return *this;
834  }
835  PolyRoot const& _polyRoot_() const noexcept {
836  return *this;
837  }
838  VTable<std::decay_t<I>> const* vptr_ = vtable<std::decay_t<I>>();
839 };
840 
841 template <class I>
842 using PolyImpl =
843  TypeFold<InclusiveSubsumptionsOf<Uncvref<I>>, PolyRoot<I>, MakePolyNode>;
844 
845 // A const-qualified function type means the user is trying to disambiguate
846 // a member function pointer.
847 template <class Fun> // Fun = R(As...) const
848 struct Sig {
849  template <class T>
850  constexpr Fun T::*operator()(Fun T::*t) const /* nolint */ volatile noexcept {
851  return t;
852  }
853  template <class F, class T>
854  constexpr F T::*operator()(F T::*t) const /* nolint */ volatile noexcept {
855  return t;
856  }
857 };
858 
859 // A functon type with no arguments means the user is trying to disambiguate
860 // a member function pointer.
861 template <class R>
862 struct Sig<R()> : Sig<R() const> {
863  using Fun = R();
864  using Sig<R() const>::operator();
865 
866  template <class T>
867  constexpr Fun T::*operator()(Fun T::*t) const noexcept {
868  return t;
869  }
870 };
871 
872 template <class R, class... As>
873 struct SigImpl : Sig<R(As...) const> {
874  using Fun = R(As...);
875  using Sig<R(As...) const>::operator();
876 
877  template <class T>
878  constexpr Fun T::*operator()(Fun T::*t) const noexcept {
879  return t;
880  }
881  constexpr Fun* operator()(Fun* t) const noexcept {
882  return t;
883  }
884  template <class F>
885  constexpr F* operator()(F* t) const noexcept {
886  return t;
887  }
888 };
889 
890 // The user could be trying to disambiguate either a member or a free function.
891 template <class R, class... As>
892 struct Sig<R(As...)> : SigImpl<R, As...> {};
893 
894 // This case is like the one above, except we want to add an overload that
895 // handles the case of a free function where the first argument is more
896 // const-qualified than the user explicitly specified.
897 template <class R, class A, class... As>
898 struct Sig<R(A&, As...)> : SigImpl<R, A&, As...> {
899  using CCFun = R(A const&, As...);
900  using SigImpl<R, A&, As...>::operator();
901 
902  constexpr CCFun* operator()(CCFun* t) const /* nolint */ volatile noexcept {
903  return t;
904  }
905 };
906 
907 template <
908  class T,
909  class I,
910  class U = std::decay_t<T>,
911  std::enable_if_t<Not<std::is_base_of<PolyBase, U>>::value, int> = 0,
912  std::enable_if_t<std::is_constructible<AddCvrefOf<U, I>, T>::value, int> =
913  0,
914  class = MembersOf<std::decay_t<I>, U>>
915 std::true_type modelsInterface_(int);
916 template <class T, class I>
917 std::false_type modelsInterface_(long);
918 
919 template <class T, class I>
920 struct ModelsInterface : decltype(modelsInterface_<T, I>(0)) {};
921 
922 template <class I1, class I2>
923 struct ValueCompatible : std::is_base_of<I1, I2> {};
924 
925 // This prevents PolyRef's converting constructors and assignment operators
926 // from being considered as copy constructors and assignment operators:
927 template <class I1>
928 struct ValueCompatible<I1, I1> : std::false_type {};
929 
930 template <class I1, class I2, class I2Ref>
931 struct ReferenceCompatible : std::is_constructible<I1, I2Ref> {};
932 
933 // This prevents PolyRef's converting constructors and assignment operators
934 // from being considered as copy constructors and assignment operators:
935 template <class I1, class I2Ref>
936 struct ReferenceCompatible<I1, I1, I2Ref> : std::false_type {};
937 
938 } // namespace detail
940 } // namespace folly
941 
942 #undef FOLLY_AUTO
bool operator>(const Expected< Value, Error > &lhs, const Expected< Value, Error > &rhs)
Definition: Expected.h:1349
std::unique_ptr< int > A
MemberType
Definition: Base.h:575
PskType type
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
folly::std T
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
MetaApply< MetaApply< List, impl::FoldR_< Fn >>, State > TypeFold
Definition: TypeList.h:380
bool_constant< true > true_type
Definition: gtest-port.h:2210
ScopeGuardImpl< typename std::decay< FunctionType >::type, true > operator+(detail::ScopeGuardOnExit, FunctionType &&fn)
Definition: ScopeGuard.h:264
bool operator!=(const Unexpected< Error > &lhs, const Unexpected< Error > &rhs)
Definition: Expected.h:766
MetaApply< impl::If_< If_ >, Then, Else > If
Definition: TypeList.h:159
State
See Core for details.
Definition: Core.h:43
constexpr auto invoke(F &&f, Args &&...args) noexcept(noexcept(static_cast< F && >(f)(static_cast< Args && >(args)...))) -> decltype(static_cast< F && >(f)(static_cast< Args && >(args)...))
Definition: Invoke.h:49
MetaApply< List, MetaBindFront< MetaQuote< TypeList >, Ts... >> TypePushFront
Definition: TypeList.h:301
std::enable_if< detail::is_chrono_conversion< Tgt, Src >::value, Tgt >::type to(const Src &value)
Definition: Conv.h:677
#define D(name, bit)
Definition: CpuId.h:145
internal::NotMatcher< InnerMatcher > Not(InnerMatcher m)
typename T::type _t
Definition: Traits.h:171
detail::TypeList< Ts... > PolyMembers
Definition: PolyDetail.h:71
constexpr auto data(C &c) -> decltype(c.data())
Definition: Access.h:71
MetaApply< List, impl::TypeTransform_< Fn >> TypeTransform
Definition: TypeList.h:327
LogLevel & operator-=(LogLevel &level, uint32_t value)
Definition: LogLevel.h:122
#define C(name, bit)
Definition: CpuId.h:204
static const char *const value
Definition: Conv.cpp:50
PUSHMI_INLINE_VAR constexpr struct folly::pushmi::operators::from_fn from
**Optimized Holders **The template hazptr_array< M > provides most of the functionality *of M hazptr_holder s but with faster construction destruction *for M
Definition: Hazptr.h:104
bool operator>=(const Expected< Value, Error > &lhs, const Expected< Value, Error > &rhs)
Definition: Expected.h:1358
detail::AddCvrefOf< T, I > & poly_cast(detail::PolyRoot< I > &)
Definition: Poly.h:310
T exchange(T &obj, U &&new_value)
Definition: Utility.h:120
TypeReverseFold< List, TypeList<>, MetaFlip< impl::Unique_ >> TypeReverseUnique
Definition: TypeList.h:488
bool operator==(const Unexpected< Error > &lhs, const Unexpected< Error > &rhs)
Definition: Expected.h:758
bool operator<=(const Expected< Value, Error > &lhs, const Expected< Value, Error > &rhs)
Definition: Expected.h:1340
const
Definition: upload.py:398
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
bool_constant< false > false_type
Definition: gtest-port.h:2209
const internal::AnythingMatcher _
constexpr LogLevel operator-(LogLevel level, uint32_t value)
Definition: LogLevel.h:119
MetaApply< TypeFold< List, MetaQuote< TypeList >, impl::Join_ >> TypeJoin
Definition: TypeList.h:538
Collect as()
Definition: Base.h:811
#define FOLLY_AUTO
Definition: PolyDetail.h:69
decltype(auto) constexpr apply(F &&func, Tuple &&tuple)
Definition: ApplyTuple.h:87
static constexpr uint64_t data[1]
Definition: Fingerprint.cpp:43
LogLevel & operator+=(LogLevel &level, uint32_t value)
Definition: LogLevel.h:115
Future< bool > call(int depth, Executor *executor)
std::basic_istream< typename basic_fbstring< E, T, A, S >::value_type, typename basic_fbstring< E, T, A, S >::traits_type > & operator>>(std::basic_istream< typename basic_fbstring< E, T, A, S >::value_type, typename basic_fbstring< E, T, A, S >::traits_type > &is, basic_fbstring< E, T, A, S > &str)
Definition: FBString.h:2728
std::enable_if< IsLessThanComparable< Value >::value, bool >::type operator<(const Expected< Value, Error > &lhs, const Expected< Value, Error > &rhs)
Definition: Expected.h:1321
static bool is_const(T &&)
std::ostream & operator<<(std::ostream &out, dynamic const &d)
Definition: dynamic-inl.h:1158