function_view.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #pragma once
  2. #include <library/cpp/yt/misc/concepts.h>
  3. namespace NYT {
  4. ////////////////////////////////////////////////////////////////////////////////
  5. // Non-owning type-erasure container.
  6. /*
  7. Example:
  8. template <class T>
  9. class TSerializedObject
  10. {
  11. public:
  12. explicit TSerializedObject(T value)
  13. : Object_(value)
  14. { }
  15. void Lock(TFunctionView<void(const T&)> callback)
  16. {
  17. auto guard = Guard(SpinLock_);
  18. callback(Object_);
  19. }
  20. private:
  21. TSpinLock SpinLock_;
  22. T Object_;
  23. };
  24. int main()
  25. {
  26. TSerializedObject<int> object(42);
  27. // object.Lock([] (const int& value) {
  28. // fmt::println("Value is {}", value);
  29. // });
  30. // ^ CE -- cannot pass rvalue.
  31. auto callback = [] (const int& value) {
  32. fmt::println("Value is {}", value);
  33. };
  34. object.Lock(callback); // <- prints "Value is 42".
  35. }
  36. */
  37. template <class TSignature>
  38. class TFunctionView;
  39. ////////////////////////////////////////////////////////////////////////////////
  40. // TODO(arkady-e1ppa): Support pointer-to-member-function?
  41. template <class T, class TSignature>
  42. concept CTypeErasable =
  43. CInvocable<T, TSignature> &&
  44. (!std::same_as<T, TFunctionView<TSignature>>);
  45. ////////////////////////////////////////////////////////////////////////////////
  46. template <class TResult, bool NoExcept, class... TArgs>
  47. class TFunctionView<TResult(TArgs...) noexcept(NoExcept)>
  48. {
  49. public:
  50. using TSignature = TResult(TArgs...) noexcept(NoExcept);
  51. TFunctionView() = default;
  52. template <CTypeErasable<TSignature> TConcrete>
  53. TFunctionView(TConcrete& concreteRef) noexcept;
  54. template <CTypeErasable<TSignature> TConcrete>
  55. TFunctionView(TConcrete* concretePtr) noexcept;
  56. TResult operator()(TArgs... args) noexcept(NoExcept);
  57. explicit operator bool() const noexcept;
  58. TFunctionView Release() noexcept;
  59. bool IsValid() const noexcept;
  60. void Reset() noexcept;
  61. bool operator==(const TFunctionView& other) const & = default;
  62. private:
  63. // NB: Technically, this is UB according to C standard, which
  64. // was not changed for C++ standard.
  65. // This is so because it is allowed to have
  66. // function pointers to be modelled by entities
  67. // different from object pointers.
  68. // No reasonable system architecture (e.g. x86 or ARM
  69. // or any other POSIX compliant one) does this.
  70. // No reasonable compiler (clang/gcc) does anything with this.
  71. // Accounting for such requirement would cause this class
  72. // to have std::variant-like storage which would make this class
  73. // weight more. Thus, we have decided to keep it this way,
  74. // since we are safe on x86 or ARM + clang.
  75. using TErasedPtr = void*;
  76. using TErasedInvoke = TResult(*)(TArgs..., TErasedPtr);
  77. TErasedPtr Ptr_ = nullptr;
  78. TErasedInvoke Invoke_ = nullptr;
  79. template <class TConcrete>
  80. static TResult ConcreteInvoke(TArgs... args, TErasedPtr ptr) noexcept(NoExcept);
  81. };
  82. ////////////////////////////////////////////////////////////////////////////////
  83. } // namespace NYT
  84. #define FUNCTION_VIEW_INL_H_
  85. #include "function_view-inl.h"
  86. #undef FUNCTION_VIEW_INL_H_