unique_function.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #pragma once
  8. #include <functional>
  9. #ifndef Unexpected
  10. #define Unexpected(message) std::abort()
  11. #define UniqueFunctionUnexpected
  12. #endif // Unexpected
  13. namespace base {
  14. namespace details {
  15. template <typename Callable>
  16. class moveable_callable_wrap {
  17. public:
  18. static_assert(
  19. std::is_move_constructible_v<Callable>,
  20. "Should be at least moveable.");
  21. moveable_callable_wrap(Callable &&other)
  22. : _value(std::move(other)) {
  23. }
  24. moveable_callable_wrap &operator=(Callable &&other) {
  25. _value = std::move(other);
  26. return *this;
  27. }
  28. moveable_callable_wrap(moveable_callable_wrap &&other)
  29. : _value(std::move(other._value)) {
  30. }
  31. moveable_callable_wrap(
  32. const moveable_callable_wrap &other)
  33. : _value(fail_construct()) {
  34. }
  35. moveable_callable_wrap &operator=(
  36. moveable_callable_wrap &&other) {
  37. _value = std::move(other._value);
  38. return *this;
  39. }
  40. moveable_callable_wrap &operator=(
  41. const moveable_callable_wrap &other) {
  42. return fail_assign();
  43. }
  44. template <typename ...Args>
  45. decltype(auto) operator()(Args &&...args) {
  46. return _value(std::forward<Args>(args)...);
  47. }
  48. private:
  49. [[noreturn]] Callable fail_construct() {
  50. Unexpected("Attempt to copy-construct a move-only type.");
  51. }
  52. [[noreturn]] moveable_callable_wrap &fail_assign() {
  53. Unexpected("Attempt to copy-assign a move-only type.");
  54. }
  55. Callable _value;
  56. };
  57. } // namespace details
  58. template <typename Function>
  59. class unique_function;
  60. template <typename Return, typename ...Args>
  61. class unique_function<Return(Args...)> final {
  62. public:
  63. unique_function(std::nullptr_t = nullptr) noexcept {
  64. }
  65. unique_function(const unique_function &other) = delete;
  66. unique_function &operator=(const unique_function &other) = delete;
  67. // Move construct / assign from the same type.
  68. unique_function(unique_function &&other)
  69. : _impl(std::move(other._impl)) {
  70. }
  71. unique_function &operator=(unique_function &&other) {
  72. _impl = std::move(other._impl);
  73. return *this;
  74. }
  75. template <
  76. typename Callable,
  77. typename = std::enable_if_t<
  78. std::is_convertible_v<
  79. decltype(std::declval<Callable>()(
  80. std::declval<Args>()...)),
  81. Return>>>
  82. unique_function(Callable &&other)
  83. : unique_function(
  84. std::forward<Callable>(other),
  85. std::is_copy_constructible<std::decay_t<Callable>>{}) {
  86. }
  87. template <
  88. typename Callable,
  89. typename = std::enable_if_t<
  90. std::is_convertible_v<
  91. decltype(std::declval<Callable>()(
  92. std::declval<Args>()...)),
  93. Return>>>
  94. unique_function &operator=(Callable &&other) {
  95. using Decayed = std::decay_t<Callable>;
  96. if constexpr (std::is_copy_constructible_v<Decayed>) {
  97. _impl = std::forward<Callable>(other);
  98. } else if constexpr (std::is_move_constructible_v<Decayed>) {
  99. _impl = details::moveable_callable_wrap<Decayed>(
  100. std::forward<Callable>(other));
  101. } else {
  102. static_assert(false_t(other), "Should be moveable.");
  103. }
  104. return *this;
  105. }
  106. void swap(unique_function &other) {
  107. _impl.swap(other._impl);
  108. }
  109. Return operator()(Args ...args) {
  110. return _impl(std::forward<Args>(args)...);
  111. }
  112. explicit operator bool() const {
  113. return _impl.operator bool();
  114. }
  115. friend inline bool operator==(
  116. const unique_function &value,
  117. std::nullptr_t) noexcept {
  118. return value._impl == nullptr;
  119. }
  120. friend inline bool operator==(
  121. std::nullptr_t,
  122. const unique_function &value) noexcept {
  123. return value._impl == nullptr;
  124. }
  125. friend inline bool operator!=(
  126. const unique_function &value,
  127. std::nullptr_t) noexcept {
  128. return value._impl != nullptr;
  129. }
  130. friend inline bool operator!=(
  131. std::nullptr_t,
  132. const unique_function &value) noexcept {
  133. return value._impl != nullptr;
  134. }
  135. private:
  136. template <typename Callable>
  137. unique_function(Callable &&other, std::true_type)
  138. : _impl(std::forward<Callable>(other)) {
  139. }
  140. template <typename Callable>
  141. unique_function(Callable &&other, std::false_type)
  142. : _impl(details::moveable_callable_wrap<std::decay_t<Callable>>(
  143. std::forward<Callable>(other))) {
  144. }
  145. std::function<Return(Args...)> _impl;
  146. };
  147. } // namespace base
  148. #ifdef UniqueFunctionUnexpected
  149. #undef UniqueFunctionUnexpected
  150. #undef Unexpected
  151. #endif // UniqueFunctionUnexpectedb