The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

379 lines
14KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. The code included in this file is provided under the terms of the ISC license
  8. http://www.isc.org/downloads/software-support-policy/isc-license. Permission
  9. To use, copy, modify, and/or distribute this software for any purpose with or
  10. without fee is hereby granted provided that the above copyright notice and
  11. this permission notice appear in all copies.
  12. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  13. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  14. DISCLAIMED.
  15. ==============================================================================
  16. */
  17. #pragma once
  18. #include <utility>
  19. namespace juce
  20. {
  21. namespace detail
  22. {
  23. namespace adlSwap
  24. {
  25. using std::swap;
  26. template <typename T>
  27. constexpr auto isNothrowSwappable = noexcept (swap (std::declval<T&>(), std::declval<T&>()));
  28. } // namespace adlSwap
  29. } // namespace detail
  30. struct Nullopt {};
  31. constexpr Nullopt nullopt;
  32. // Without this, our tests can emit "unreachable code" warnings during
  33. // link time code generation.
  34. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4702)
  35. /* For internal use only!
  36. A simple optional type.
  37. Has similar (not necessarily identical!) semantics to std::optional.
  38. This isn't really intended to be used by JUCE clients. Instead, it's to be
  39. used internally in JUCE code, with an API close-enough to std::optional
  40. that the types can be swapped with fairly minor disruption at some point in
  41. the future, but *without breaking any public APIs*.
  42. */
  43. template <typename Value>
  44. class Optional
  45. {
  46. template <typename T, typename U>
  47. struct NotConstructibleFromSimilarType
  48. {
  49. static constexpr auto value = ! std::is_constructible<T, Optional<U>&>::value
  50. && ! std::is_constructible<T, const Optional<U>&>::value
  51. && ! std::is_constructible<T, Optional<U>&&>::value
  52. && ! std::is_constructible<T, const Optional<U>&&>::value
  53. && ! std::is_convertible<Optional<U>&, T>::value
  54. && ! std::is_convertible<const Optional<U>&, T>::value
  55. && ! std::is_convertible<Optional<U>&&, T>::value
  56. && ! std::is_convertible<const Optional<U>&&, T>::value;
  57. };
  58. template <typename T, typename U>
  59. using OptionalCopyConstructorEnabled = std::enable_if_t<std::is_constructible<T, const U&>::value && NotConstructibleFromSimilarType<T, U>::value>;
  60. template <typename T, typename U>
  61. using OptionalMoveConstructorEnabled = std::enable_if_t<std::is_constructible<T, U&&>::value && NotConstructibleFromSimilarType<T, U>::value>;
  62. template <typename T, typename U>
  63. static auto notAssignableFromSimilarType = NotConstructibleFromSimilarType<T, U>::value
  64. && ! std::is_assignable<T&, Optional<U>&>::value
  65. && ! std::is_assignable<T&, const Optional<U>&>::value
  66. && ! std::is_assignable<T&, Optional<U>&&>::value
  67. && ! std::is_assignable<T&, const Optional<U>&&>::value;
  68. template <typename T, typename U>
  69. using OptionalCopyAssignmentEnabled = std::enable_if_t<std::is_constructible<T, const U&>::value
  70. && std::is_assignable<T&, const U&>::value
  71. && NotConstructibleFromSimilarType<T, U>::value>;
  72. template <typename T, typename U>
  73. using OptionalMoveAssignmentEnabled = std::enable_if_t<std::is_constructible<T, U>::value
  74. && std::is_nothrow_assignable<T&, U>::value
  75. && NotConstructibleFromSimilarType<T, U>::value>;
  76. public:
  77. Optional() = default;
  78. Optional (Nullopt) noexcept {}
  79. template <typename U = Value,
  80. typename = std::enable_if_t<std::is_constructible<Value, U&&>::value
  81. && ! std::is_same<std::decay_t<U>, Optional>::value>>
  82. Optional (U&& value) noexcept (noexcept (Value (std::forward<U> (value))))
  83. : valid (true)
  84. {
  85. new (&storage) Value (std::forward<U> (value));
  86. }
  87. Optional (Optional&& other) noexcept (noexcept (std::declval<Optional>().constructFrom (other)))
  88. {
  89. constructFrom (other);
  90. }
  91. Optional (const Optional& other)
  92. : valid (other.valid)
  93. {
  94. if (valid)
  95. new (&storage) Value (*other);
  96. }
  97. template <typename Other, typename = OptionalMoveConstructorEnabled<Value, Other>>
  98. Optional (Optional<Other>&& other) noexcept (noexcept (std::declval<Optional>().constructFrom (other)))
  99. {
  100. constructFrom (other);
  101. }
  102. template <typename Other, typename = OptionalCopyConstructorEnabled<Value, Other>>
  103. Optional (const Optional<Other>& other)
  104. : valid (other.hasValue())
  105. {
  106. if (valid)
  107. new (&storage) Value (*other);
  108. }
  109. Optional& operator= (Nullopt) noexcept
  110. {
  111. reset();
  112. return *this;
  113. }
  114. template <typename U = Value,
  115. typename = std::enable_if_t<std::is_nothrow_move_constructible<U>::value
  116. && std::is_nothrow_move_assignable<U>::value>>
  117. Optional& operator= (Optional&& other) noexcept (noexcept (std::declval<Optional>().assign (std::declval<Optional&>())))
  118. {
  119. assign (other);
  120. return *this;
  121. }
  122. template <typename U = Value,
  123. typename = std::enable_if_t<! std::is_same<std::decay_t<U>, Optional>::value
  124. && std::is_constructible<Value, U>::value
  125. && std::is_assignable<Value&, U>::value
  126. && (! std::is_scalar<Value>::value || ! std::is_same<std::decay_t<U>, Value>::value)>>
  127. Optional& operator= (U&& value)
  128. {
  129. if (valid)
  130. **this = std::forward<U> (value);
  131. else
  132. new (&storage) Value (std::forward<U> (value));
  133. valid = true;
  134. return *this;
  135. }
  136. /* Maintains the strong exception safety guarantee. */
  137. Optional& operator= (const Optional& other)
  138. {
  139. auto copy = other;
  140. assign (copy);
  141. return *this;
  142. }
  143. template <typename Other, typename = OptionalMoveAssignmentEnabled<Value, Other>>
  144. Optional& operator= (Optional<Other>&& other) noexcept (noexcept (std::declval<Optional>().assign (other)))
  145. {
  146. assign (other);
  147. return *this;
  148. }
  149. /* Maintains the strong exception safety guarantee. */
  150. template <typename Other, typename = OptionalCopyAssignmentEnabled<Value, Other>>
  151. Optional& operator= (const Optional<Other>& other)
  152. {
  153. auto copy = other;
  154. assign (copy);
  155. return *this;
  156. }
  157. ~Optional() noexcept
  158. {
  159. reset();
  160. }
  161. Value* operator->() noexcept { return reinterpret_cast< Value*> (&storage); }
  162. const Value* operator->() const noexcept { return reinterpret_cast<const Value*> (&storage); }
  163. Value& operator*() noexcept { return *operator->(); }
  164. const Value& operator*() const noexcept { return *operator->(); }
  165. explicit operator bool() const noexcept { return valid; }
  166. bool hasValue() const noexcept { return valid; }
  167. void reset()
  168. {
  169. if (std::exchange (valid, false))
  170. operator*().~Value();
  171. }
  172. /* Like std::optional::value_or */
  173. template <typename U>
  174. Value orFallback (U&& fallback) const { return *this ? **this : std::forward<U> (fallback); }
  175. template <typename... Args>
  176. Value& emplace (Args&&... args)
  177. {
  178. reset();
  179. new (&storage) Value (std::forward<Args> (args)...);
  180. valid = true;
  181. return **this;
  182. }
  183. void swap (Optional& other) noexcept (std::is_nothrow_move_constructible<Value>::value
  184. && detail::adlSwap::isNothrowSwappable<Value>)
  185. {
  186. if (hasValue() && other.hasValue())
  187. {
  188. using std::swap;
  189. swap (**this, *other);
  190. }
  191. else if (hasValue() || other.hasValue())
  192. {
  193. (hasValue() ? other : *this).constructFrom (hasValue() ? *this : other);
  194. }
  195. }
  196. private:
  197. template <typename Other>
  198. void constructFrom (Optional<Other>& other) noexcept (noexcept (Value (std::move (*other))))
  199. {
  200. if (! other.hasValue())
  201. return;
  202. new (&storage) Value (std::move (*other));
  203. valid = true;
  204. other.reset();
  205. }
  206. template <typename Other>
  207. void assign (Optional<Other>& other) noexcept (noexcept (std::declval<Value&>() = std::move (*other)) && noexcept (std::declval<Optional>().constructFrom (other)))
  208. {
  209. if (valid)
  210. {
  211. if (other.hasValue())
  212. {
  213. **this = std::move (*other);
  214. other.reset();
  215. }
  216. else
  217. {
  218. reset();
  219. }
  220. }
  221. else
  222. {
  223. constructFrom (other);
  224. }
  225. }
  226. std::aligned_storage_t<sizeof (Value), alignof (Value)> storage;
  227. bool valid = false;
  228. };
  229. JUCE_END_IGNORE_WARNINGS_MSVC
  230. template <class T, class U>
  231. bool operator== (const Optional<T>& lhs, const Optional<U>& rhs)
  232. {
  233. if (lhs.hasValue() != rhs.hasValue()) return false;
  234. if (! lhs.hasValue()) return true;
  235. return *lhs == *rhs;
  236. }
  237. template <class T, class U>
  238. bool operator!= (const Optional<T>& lhs, const Optional<U>& rhs)
  239. {
  240. if (lhs.hasValue() != rhs.hasValue()) return true;
  241. if (! lhs.hasValue()) return false;
  242. return *lhs != *rhs;
  243. }
  244. template <class T, class U>
  245. bool operator< (const Optional<T>& lhs, const Optional<U>& rhs)
  246. {
  247. if (! rhs.hasValue()) return false;
  248. if (! lhs.hasValue()) return true;
  249. return *lhs < *rhs;
  250. }
  251. template <class T, class U>
  252. bool operator<= (const Optional<T>& lhs, const Optional<U>& rhs)
  253. {
  254. if (! lhs.hasValue()) return true;
  255. if (! rhs.hasValue()) return false;
  256. return *lhs <= *rhs;
  257. }
  258. template <class T, class U>
  259. bool operator> (const Optional<T>& lhs, const Optional<U>& rhs)
  260. {
  261. if (! lhs.hasValue()) return false;
  262. if (! rhs.hasValue()) return true;
  263. return *lhs > *rhs;
  264. }
  265. template <class T, class U>
  266. bool operator>= (const Optional<T>& lhs, const Optional<U>& rhs)
  267. {
  268. if (! rhs.hasValue()) return true;
  269. if (! lhs.hasValue()) return false;
  270. return *lhs >= *rhs;
  271. }
  272. template <class T>
  273. bool operator== (const Optional<T>& opt, Nullopt) noexcept { return ! opt.hasValue(); }
  274. template <class T>
  275. bool operator== (Nullopt, const Optional<T>& opt) noexcept { return ! opt.hasValue(); }
  276. template <class T>
  277. bool operator!= (const Optional<T>& opt, Nullopt) noexcept { return opt.hasValue(); }
  278. template <class T>
  279. bool operator!= (Nullopt, const Optional<T>& opt) noexcept { return opt.hasValue(); }
  280. template <class T>
  281. bool operator< (const Optional<T>&, Nullopt) noexcept { return false; }
  282. template <class T>
  283. bool operator< (Nullopt, const Optional<T>& opt) noexcept { return opt.hasValue(); }
  284. template <class T>
  285. bool operator<= (const Optional<T>& opt, Nullopt) noexcept { return ! opt.hasValue(); }
  286. template <class T>
  287. bool operator<= (Nullopt, const Optional<T>&) noexcept { return true; }
  288. template <class T>
  289. bool operator> (const Optional<T>& opt, Nullopt) noexcept { return opt.hasValue(); }
  290. template <class T>
  291. bool operator> (Nullopt, const Optional<T>&) noexcept { return false; }
  292. template <class T>
  293. bool operator>= (const Optional<T>&, Nullopt) noexcept { return true; }
  294. template <class T>
  295. bool operator>= (Nullopt, const Optional<T>& opt) noexcept { return ! opt.hasValue(); }
  296. template <class T, class U>
  297. bool operator== (const Optional<T>& opt, const U& value) { return opt.hasValue() ? *opt == value : false; }
  298. template <class T, class U>
  299. bool operator== (const T& value, const Optional<U>& opt) { return opt.hasValue() ? value == *opt : false; }
  300. template <class T, class U>
  301. bool operator!= (const Optional<T>& opt, const U& value) { return opt.hasValue() ? *opt != value : true; }
  302. template <class T, class U>
  303. bool operator!= (const T& value, const Optional<U>& opt) { return opt.hasValue() ? value != *opt : true; }
  304. template <class T, class U>
  305. bool operator< (const Optional<T>& opt, const U& value) { return opt.hasValue() ? *opt < value : true; }
  306. template <class T, class U>
  307. bool operator< (const T& value, const Optional<U>& opt) { return opt.hasValue() ? value < *opt : false; }
  308. template <class T, class U>
  309. bool operator<= (const Optional<T>& opt, const U& value) { return opt.hasValue() ? *opt <= value : true; }
  310. template <class T, class U>
  311. bool operator<= (const T& value, const Optional<U>& opt) { return opt.hasValue() ? value <= *opt : false; }
  312. template <class T, class U>
  313. bool operator> (const Optional<T>& opt, const U& value) { return opt.hasValue() ? *opt > value : false; }
  314. template <class T, class U>
  315. bool operator> (const T& value, const Optional<U>& opt) { return opt.hasValue() ? value > *opt : true; }
  316. template <class T, class U>
  317. bool operator>= (const Optional<T>& opt, const U& value) { return opt.hasValue() ? *opt >= value : false; }
  318. template <class T, class U>
  319. bool operator>= (const T& value, const Optional<U>& opt) { return opt.hasValue() ? value >= *opt : true; }
  320. } // namespace juce