functional.hpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*************************************************************************
  2. *
  3. * Copyright 2021 Realm Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. **************************************************************************/
  18. #ifndef REALM_UTIL_FUNCTIONAL
  19. #define REALM_UTIL_FUNCTIONAL
  20. #include <realm/util/assert.hpp>
  21. #include <realm/util/type_traits.hpp>
  22. #include <functional>
  23. #include <memory>
  24. #include <type_traits>
  25. namespace realm::util {
  26. template <typename Function>
  27. class UniqueFunction;
  28. /**
  29. * A `UniqueFunction` is a move-only, type-erased functor object similar to `std::function`.
  30. * It is useful in situations where a functor cannot be wrapped in `std::function` objects because
  31. * it is incapable of being copied. Often this happens with C++14 or later lambdas which capture a
  32. * `std::unique_ptr` by move. The interface of `UniqueFunction` is nearly identical to
  33. * `std::function`, except that it is not copyable.
  34. */
  35. template <typename RetType, typename... Args>
  36. class UniqueFunction<RetType(Args...)> {
  37. private:
  38. template <typename Functor>
  39. using EnableIfCallable =
  40. std::enable_if_t<std::conjunction_v<std::is_invocable_r<RetType, Functor, Args...>,
  41. std::negation<std::is_same<std::decay_t<Functor>, UniqueFunction>>>,
  42. int>;
  43. struct Impl {
  44. virtual ~Impl() noexcept = default;
  45. virtual RetType call(Args&&... args) = 0;
  46. };
  47. public:
  48. using result_type = RetType;
  49. ~UniqueFunction() noexcept = default;
  50. UniqueFunction() = default;
  51. UniqueFunction(const UniqueFunction&) = delete;
  52. UniqueFunction& operator=(const UniqueFunction&) = delete;
  53. UniqueFunction(UniqueFunction&&) noexcept = default;
  54. UniqueFunction& operator=(UniqueFunction&&) noexcept = default;
  55. void swap(UniqueFunction& that) noexcept
  56. {
  57. using std::swap;
  58. swap(this->impl, that.impl);
  59. }
  60. friend void swap(UniqueFunction& a, UniqueFunction& b) noexcept
  61. {
  62. a.swap(b);
  63. }
  64. template <typename Functor, EnableIfCallable<Functor> = 0>
  65. /* implicit */
  66. UniqueFunction(Functor&& functor)
  67. // This does not use make_unique() because
  68. // std::unique_ptr<Base>(std::make_unique<Derived>()) results in
  69. // std::unique_ptr<Derived> being instantiated, which can have
  70. // surprisingly negative effects on debug build performance.
  71. : impl(new SpecificImpl<std::decay_t<Functor>>(std::forward<Functor>(functor)))
  72. {
  73. }
  74. UniqueFunction(std::nullptr_t) noexcept {}
  75. RetType operator()(Args... args) const
  76. {
  77. REALM_ASSERT(static_cast<bool>(*this));
  78. return impl->call(std::forward<Args>(args)...);
  79. }
  80. explicit operator bool() const noexcept
  81. {
  82. return static_cast<bool>(this->impl);
  83. }
  84. template <typename T>
  85. const T* target() const noexcept
  86. {
  87. if (impl && typeid(*impl) == typeid(SpecificImpl<T>)) {
  88. return &static_cast<SpecificImpl<T>*>(impl.get())->f;
  89. }
  90. return nullptr;
  91. }
  92. /// Release ownership of the owned implementation pointer, if any.
  93. ///
  94. /// If not null, the returned pointer _must_ be used at a later point to
  95. /// construct a new UniqueFunction. This can be used to move UniqueFunction
  96. /// instances over API boundaries which do not support C++ move semantics.
  97. Impl* release()
  98. {
  99. return impl.release();
  100. }
  101. /// Construct a UniqueFunction using a pointer returned by release().
  102. ///
  103. /// This takes ownership of the passed pointer.
  104. UniqueFunction(Impl* impl)
  105. : impl(impl)
  106. {
  107. }
  108. // Needed to make `std::is_convertible<util::UniqueFunction<...>, std::function<...>>` be
  109. // `std::false_type`. `UniqueFunction` objects are not convertible to any kind of
  110. // `std::function` object, since the latter requires a copy constructor, which the former does
  111. // not provide. If you see a compiler error which references this line, you have tried to
  112. // assign a `UniqueFunction` object to a `std::function` object which is impossible -- please
  113. // check your variables and function signatures.
  114. template <typename Signature>
  115. operator std::function<Signature>() = delete;
  116. template <typename Signature>
  117. operator std::function<Signature>() const = delete;
  118. private:
  119. // These overload helpers are needed to squelch problems in the `T ()` -> `void ()` case.
  120. template <typename Functor>
  121. static void call_regular_void(const std::true_type is_void, Functor& f, Args&&... args)
  122. {
  123. // The result of this call is not cast to void, to help preserve detection of
  124. // `[[nodiscard]]` violations.
  125. static_cast<void>(is_void);
  126. f(std::forward<Args>(args)...);
  127. }
  128. template <typename Functor>
  129. static RetType call_regular_void(const std::false_type is_not_void, Functor& f, Args&&... args)
  130. {
  131. static_cast<void>(is_not_void);
  132. return f(std::forward<Args>(args)...);
  133. }
  134. template <typename Functor>
  135. struct SpecificImpl : Impl {
  136. template <typename F>
  137. explicit SpecificImpl(F&& func)
  138. : f(std::forward<F>(func))
  139. {
  140. }
  141. RetType call(Args&&... args) override
  142. {
  143. return call_regular_void(std::is_void<RetType>(), f, std::forward<Args>(args)...);
  144. }
  145. Functor f;
  146. };
  147. std::unique_ptr<Impl> impl;
  148. };
  149. /**
  150. * Helper to pattern-match the signatures for all combinations of const and l-value-qualifed member
  151. * function pointers. We don't currently support r-value-qualified call operators.
  152. */
  153. template <typename>
  154. struct UFDeductionHelper {
  155. };
  156. template <typename Class, typename Ret, typename... Args>
  157. struct UFDeductionHelper<Ret (Class::*)(Args...)> : TypeIdentity<Ret(Args...)> {
  158. };
  159. template <typename Class, typename Ret, typename... Args>
  160. struct UFDeductionHelper<Ret (Class::*)(Args...)&> : TypeIdentity<Ret(Args...)> {
  161. };
  162. template <typename Class, typename Ret, typename... Args>
  163. struct UFDeductionHelper<Ret (Class::*)(Args...) const> : TypeIdentity<Ret(Args...)> {
  164. };
  165. template <typename Class, typename Ret, typename... Args>
  166. struct UFDeductionHelper<Ret (Class::*)(Args...) const&> : TypeIdentity<Ret(Args...)> {
  167. };
  168. /**
  169. * Deduction guides for UniqueFunction<Sig> that pluck the signature off of function pointers and
  170. * non-overloaded, non-generic function objects such as lambdas that don't use `auto` arguments.
  171. */
  172. template <typename Ret, typename... Args>
  173. UniqueFunction(Ret (*)(Args...)) -> UniqueFunction<Ret(Args...)>;
  174. template <typename T, typename Sig = typename UFDeductionHelper<decltype(&T::operator())>::type>
  175. UniqueFunction(T) -> UniqueFunction<Sig>;
  176. template <typename Signature>
  177. bool operator==(const UniqueFunction<Signature>& lhs, std::nullptr_t) noexcept
  178. {
  179. return !lhs;
  180. }
  181. template <typename Signature>
  182. bool operator!=(const UniqueFunction<Signature>& lhs, std::nullptr_t) noexcept
  183. {
  184. return static_cast<bool>(lhs);
  185. }
  186. template <typename Signature>
  187. bool operator==(std::nullptr_t, const UniqueFunction<Signature>& rhs) noexcept
  188. {
  189. return !rhs;
  190. }
  191. template <typename Signature>
  192. bool operator!=(std::nullptr_t, const UniqueFunction<Signature>& rhs) noexcept
  193. {
  194. return static_cast<bool>(rhs);
  195. }
  196. } // namespace realm::util
  197. #endif // REALM_UTIL_FUNCTIONAL