unique_any.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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 <any>
  9. namespace base {
  10. namespace details {
  11. template <typename Value>
  12. struct moveable_as_copyable_wrap {
  13. moveable_as_copyable_wrap(Value &&other)
  14. : value(std::move(other)) {
  15. }
  16. moveable_as_copyable_wrap &operator=(Value &&other) {
  17. value = std::move(other);
  18. return *this;
  19. }
  20. moveable_as_copyable_wrap(moveable_as_copyable_wrap &&other)
  21. : value(std::move(other.value)) {
  22. }
  23. moveable_as_copyable_wrap(
  24. const moveable_as_copyable_wrap &other) {
  25. Unexpected("Attempt to copy-construct a move-only type.");
  26. }
  27. moveable_as_copyable_wrap &operator=(
  28. moveable_as_copyable_wrap &&other) {
  29. value = std::move(other.value);
  30. return *this;
  31. }
  32. moveable_as_copyable_wrap &operator=(
  33. const moveable_as_copyable_wrap &other) {
  34. Unexpected("Attempt to copy-assign a move-only type.");
  35. }
  36. Value value;
  37. };
  38. template <
  39. typename Value,
  40. typename = std::enable_if_t<
  41. std::is_move_constructible_v<std::decay_t<Value>>
  42. && !std::is_lvalue_reference_v<Value>>>
  43. auto wrap_moveable_as_copyable(Value &&value) {
  44. return moveable_as_copyable_wrap<Value>(std::move(value));
  45. }
  46. } // namespace details
  47. class unique_any;
  48. template <typename Value>
  49. Value *any_cast(unique_any *value) noexcept;
  50. template <typename Value>
  51. const Value *any_cast(const unique_any *value) noexcept;
  52. class unique_any final {
  53. public:
  54. // Construction and destruction [any.cons]
  55. constexpr unique_any() noexcept {
  56. }
  57. unique_any(const unique_any &other) = delete;
  58. unique_any &operator=(const unique_any &other) = delete;
  59. unique_any(unique_any &&other) noexcept
  60. : _impl(std::move(other._impl)) {
  61. }
  62. unique_any &operator=(unique_any &&other) noexcept {
  63. _impl = std::move(other._impl);
  64. return *this;
  65. }
  66. template <
  67. typename Value,
  68. typename = std::enable_if_t<
  69. !std::is_same_v<std::decay_t<Value>, unique_any>>>
  70. unique_any(Value &&other)
  71. : unique_any(
  72. std::forward<Value>(other),
  73. std::is_copy_constructible<std::decay_t<Value>>()) {
  74. }
  75. template <
  76. typename Value,
  77. typename = std::enable_if_t<
  78. !std::is_same_v<std::decay_t<Value>, unique_any>>>
  79. unique_any &operator=(Value &&other) {
  80. if constexpr (std::is_copy_constructible_v<std::decay_t<Value>>) {
  81. _impl = std::forward<Value>(other);
  82. } else if constexpr (std::is_move_constructible_v<std::decay_t<Value>>
  83. && !std::is_lvalue_reference_v<Value>) {
  84. _impl = details::wrap_moveable_as_copyable(std::move(other));
  85. } else {
  86. static_assert(
  87. false_t(Value{}),
  88. "Bad value for base::unique_any.");
  89. }
  90. return *this;
  91. }
  92. template <
  93. typename Value,
  94. typename ...Args,
  95. typename = std::enable_if_t<
  96. std::is_constructible_v<std::decay_t<Value>, Args...>
  97. && std::is_copy_constructible_v<decay_t<Value>>>>
  98. std::decay_t<Value> &emplace(Args &&...args) {
  99. return _impl.emplace<Value>(std::forward<Args>(args)...);
  100. }
  101. void reset() noexcept {
  102. _impl.reset();
  103. }
  104. void swap(unique_any &other) noexcept {
  105. _impl.swap(other._impl);
  106. }
  107. bool has_value() const noexcept {
  108. return _impl.has_value();
  109. }
  110. // Should check if it is a moveable_only wrap first.
  111. //const std::type_info &type() const noexcept {
  112. // return _impl.type();
  113. //}
  114. private:
  115. template <
  116. typename Value,
  117. typename = std::enable_if_t<
  118. !std::is_same_v<std::decay_t<Value>, unique_any>
  119. && std::is_copy_constructible_v<std::decay_t<Value>>>>
  120. unique_any(Value &&other, std::true_type)
  121. : _impl(std::forward<Value>(other)) {
  122. }
  123. template <
  124. typename Value,
  125. typename = std::enable_if_t<
  126. !std::is_same_v<std::decay_t<Value>, unique_any>
  127. && !std::is_copy_constructible_v<std::decay_t<Value>>
  128. && std::is_move_constructible_v<std::decay_t<Value>>
  129. && !std::is_lvalue_reference_v<Value>>>
  130. unique_any(Value &&other, std::false_type)
  131. : _impl(details::wrap_moveable_as_copyable(std::move(other))) {
  132. }
  133. template <
  134. typename Value,
  135. typename ...Args>
  136. friend unique_any make_any(Args &&...args);
  137. template <typename Value>
  138. friend const Value *any_cast(const unique_any *value) noexcept;
  139. template <typename Value>
  140. friend Value *any_cast(unique_any *value) noexcept;
  141. std::any _impl;
  142. };
  143. inline void swap(unique_any &a, unique_any &b) noexcept {
  144. a.swap(b);
  145. }
  146. template <
  147. typename Value,
  148. typename ...Args>
  149. inline auto make_any(Args &&...args)
  150. -> std::enable_if_t<
  151. std::is_copy_constructible_v<std::decay_t<Value>>,
  152. unique_any> {
  153. return std::make_any<Value>(std::forward<Args>(args)...);
  154. }
  155. template <
  156. typename Value,
  157. typename ...Args>
  158. inline auto make_any(Args &&...args)
  159. -> std::enable_if_t<
  160. !std::is_copy_constructible_v<std::decay_t<Value>>
  161. && std::is_move_constructible_v<std::decay_t<Value>>,
  162. unique_any> {
  163. return Value(std::forward<Args>(args)...);
  164. }
  165. template <typename Value>
  166. inline Value *any_cast(unique_any *value) noexcept {
  167. if constexpr (std::is_copy_constructible_v<Value>) {
  168. return std::any_cast<Value>(&value->_impl);
  169. } else if constexpr (std::is_move_constructible_v<Value>) {
  170. auto wrap = std::any_cast<
  171. details::moveable_as_copyable_wrap<Value>
  172. >(&value->_impl);
  173. return wrap ? &wrap->value : nullptr;
  174. } else {
  175. static_assert(
  176. false_t(Value{}),
  177. "Bad type for base::any_cast.");
  178. }
  179. }
  180. template <typename Value>
  181. inline const Value *any_cast(const unique_any *value) noexcept {
  182. if constexpr (std::is_copy_constructible_v<Value>) {
  183. return std::any_cast<Value>(&value->_impl);
  184. } else if constexpr (std::is_move_constructible_v<Value>) {
  185. auto wrap = std::any_cast<
  186. details::moveable_as_copyable_wrap<Value>
  187. >(&value->_impl);
  188. return wrap ? &wrap->value : nullptr;
  189. } else {
  190. static_assert(
  191. false_t(Value{}),
  192. "Bad type for base::any_cast.");
  193. }
  194. }
  195. } // namespace base