function_ref.h 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. #include <iosfwd>
  5. #include <memory> // IWYU pragma: keep
  6. #include <type_traits>
  7. #include <utility>
  8. #include "opentelemetry/version.h"
  9. OPENTELEMETRY_BEGIN_NAMESPACE
  10. namespace nostd
  11. {
  12. template <class Sig>
  13. class function_ref; // IWYU pragma: keep
  14. /**
  15. * Non-owning function reference that can be used as a more performant
  16. * replacement for std::function when ownership sematics aren't needed.
  17. *
  18. * See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0792r0.html
  19. *
  20. * Based off of https://stackoverflow.com/a/39087660/4447365
  21. */
  22. template <class R, class... Args>
  23. class function_ref<R(Args...)>
  24. {
  25. void *callable_ = nullptr;
  26. R (*invoker_)(void *, Args...) = nullptr;
  27. template <class F>
  28. using FunctionPointer = decltype(std::addressof(std::declval<F &>()));
  29. template <class F>
  30. void BindTo(F &f) noexcept
  31. {
  32. callable_ = static_cast<void *>(std::addressof(f));
  33. invoker_ = [](void *callable, Args... args) -> R {
  34. return (*static_cast<FunctionPointer<F>>(callable))(std::forward<Args>(args)...);
  35. };
  36. }
  37. template <class R_in, class... Args_in>
  38. void BindTo(R_in (*f)(Args_in...)) noexcept
  39. {
  40. using F = decltype(f);
  41. if (f == nullptr)
  42. {
  43. return BindTo(nullptr);
  44. }
  45. callable_ = reinterpret_cast<void *>(f);
  46. invoker_ = [](void *callable, Args... args) -> R {
  47. return (F(callable))(std::forward<Args>(args)...);
  48. };
  49. }
  50. void BindTo(std::nullptr_t) noexcept
  51. {
  52. callable_ = nullptr;
  53. invoker_ = nullptr;
  54. }
  55. public:
  56. template <
  57. class F,
  58. typename std::enable_if<!std::is_same<function_ref, typename std::decay<F>::type>::value,
  59. int>::type = 0,
  60. typename std::enable_if<
  61. #if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && (_MSVC_LANG > 201402))
  62. // std::result_of deprecated in C++17, removed in C++20
  63. std::is_convertible<typename std::invoke_result<F, Args...>::type, R>::value,
  64. #else
  65. // std::result_of since C++11
  66. std::is_convertible<typename std::result_of<F &(Args...)>::type, R>::value,
  67. #endif
  68. int>::type = 0>
  69. function_ref(F &&f)
  70. {
  71. BindTo(f); // not forward
  72. }
  73. function_ref(std::nullptr_t) {}
  74. function_ref(const function_ref &) noexcept = default;
  75. function_ref(function_ref &&) noexcept = default;
  76. R operator()(Args... args) const { return invoker_(callable_, std::forward<Args>(args)...); }
  77. explicit operator bool() const { return invoker_; }
  78. };
  79. } // namespace nostd
  80. OPENTELEMETRY_END_NAMESPACE