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.

402 lines
15KB

  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. namespace juce
  18. {
  19. namespace detail
  20. {
  21. namespace adlSwap
  22. {
  23. using std::swap;
  24. template <typename T>
  25. constexpr auto isNothrowSwappable = noexcept (swap (std::declval<T&>(), std::declval<T&>()));
  26. } // namespace adlSwap
  27. } // namespace detail
  28. /** A type representing the null state of an Optional.
  29. Similar to std::nullopt_t.
  30. */
  31. struct Nullopt
  32. {
  33. explicit constexpr Nullopt (int) {}
  34. };
  35. /** An object that can be used when constructing and comparing Optional instances.
  36. Similar to std::nullopt.
  37. */
  38. constexpr Nullopt nullopt { 0 };
  39. // Without this, our tests can emit "unreachable code" warnings during
  40. // link time code generation.
  41. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4702)
  42. /**
  43. A simple optional type.
  44. Has similar (not necessarily identical!) semantics to std::optional.
  45. This is intended to stand-in for std::optional while JUCE's minimum
  46. supported language standard is lower than C++17. When the minimum language
  47. standard moves to C++17, this class will probably be deprecated, in much
  48. the same way that juce::ScopedPointer was deprecated in favour of
  49. std::unique_ptr after C++11.
  50. This isn't really intended to be used by JUCE clients. Instead, it's to be
  51. used internally in JUCE code, with an API close-enough to std::optional
  52. that the types can be swapped with fairly minor disruption at some point in
  53. the future, but *without breaking any public APIs*.
  54. @tags{Core}
  55. */
  56. template <typename Value>
  57. class Optional
  58. {
  59. template <typename T, typename U>
  60. struct NotConstructibleFromSimilarType
  61. {
  62. static constexpr auto value = ! std::is_constructible<T, Optional<U>&>::value
  63. && ! std::is_constructible<T, const Optional<U>&>::value
  64. && ! std::is_constructible<T, Optional<U>&&>::value
  65. && ! std::is_constructible<T, const Optional<U>&&>::value
  66. && ! std::is_convertible<Optional<U>&, T>::value
  67. && ! std::is_convertible<const Optional<U>&, T>::value
  68. && ! std::is_convertible<Optional<U>&&, T>::value
  69. && ! std::is_convertible<const Optional<U>&&, T>::value;
  70. };
  71. template <typename T, typename U>
  72. using OptionalCopyConstructorEnabled = std::enable_if_t<std::is_constructible<T, const U&>::value && NotConstructibleFromSimilarType<T, U>::value>;
  73. template <typename T, typename U>
  74. using OptionalMoveConstructorEnabled = std::enable_if_t<std::is_constructible<T, U&&>::value && NotConstructibleFromSimilarType<T, U>::value>;
  75. template <typename T, typename U>
  76. static auto notAssignableFromSimilarType = NotConstructibleFromSimilarType<T, U>::value
  77. && ! std::is_assignable<T&, Optional<U>&>::value
  78. && ! std::is_assignable<T&, const Optional<U>&>::value
  79. && ! std::is_assignable<T&, Optional<U>&&>::value
  80. && ! std::is_assignable<T&, const Optional<U>&&>::value;
  81. template <typename T, typename U>
  82. using OptionalCopyAssignmentEnabled = std::enable_if_t<std::is_constructible<T, const U&>::value
  83. && std::is_assignable<T&, const U&>::value
  84. && NotConstructibleFromSimilarType<T, U>::value>;
  85. template <typename T, typename U>
  86. using OptionalMoveAssignmentEnabled = std::enable_if_t<std::is_constructible<T, U>::value
  87. && std::is_nothrow_assignable<T&, U>::value
  88. && NotConstructibleFromSimilarType<T, U>::value>;
  89. public:
  90. Optional() : placeholder() {}
  91. Optional (Nullopt) noexcept : placeholder() {}
  92. template <typename U = Value,
  93. typename = std::enable_if_t<std::is_constructible<Value, U&&>::value
  94. && ! std::is_same<std::decay_t<U>, Optional>::value>>
  95. Optional (U&& value) noexcept (noexcept (Value (std::forward<U> (value))))
  96. : storage (std::forward<U> (value)), valid (true)
  97. {
  98. }
  99. Optional (Optional&& other) noexcept (noexcept (std::declval<Optional>().constructFrom (other)))
  100. : placeholder()
  101. {
  102. constructFrom (other);
  103. }
  104. Optional (const Optional& other)
  105. : placeholder(), valid (other.valid)
  106. {
  107. if (valid)
  108. new (&storage) Value (*other);
  109. }
  110. template <typename Other, typename = OptionalMoveConstructorEnabled<Value, Other>>
  111. Optional (Optional<Other>&& other) noexcept (noexcept (std::declval<Optional>().constructFrom (other)))
  112. : placeholder()
  113. {
  114. constructFrom (other);
  115. }
  116. template <typename Other, typename = OptionalCopyConstructorEnabled<Value, Other>>
  117. Optional (const Optional<Other>& other)
  118. : placeholder(), valid (other.hasValue())
  119. {
  120. if (valid)
  121. new (&storage) Value (*other);
  122. }
  123. Optional& operator= (Nullopt) noexcept
  124. {
  125. reset();
  126. return *this;
  127. }
  128. template <typename U = Value,
  129. typename = std::enable_if_t<std::is_nothrow_move_constructible<U>::value
  130. && std::is_nothrow_move_assignable<U>::value>>
  131. Optional& operator= (Optional&& other) noexcept (noexcept (std::declval<Optional>().assign (std::declval<Optional&>())))
  132. {
  133. assign (other);
  134. return *this;
  135. }
  136. template <typename U = Value,
  137. typename = std::enable_if_t<! std::is_same<std::decay_t<U>, Optional>::value
  138. && std::is_constructible<Value, U>::value
  139. && std::is_assignable<Value&, U>::value
  140. && (! std::is_scalar<Value>::value || ! std::is_same<std::decay_t<U>, Value>::value)>>
  141. Optional& operator= (U&& value)
  142. {
  143. if (valid)
  144. **this = std::forward<U> (value);
  145. else
  146. new (&storage) Value (std::forward<U> (value));
  147. valid = true;
  148. return *this;
  149. }
  150. /** Maintains the strong exception safety guarantee. */
  151. Optional& operator= (const Optional& other)
  152. {
  153. auto copy = other;
  154. assign (copy);
  155. return *this;
  156. }
  157. template <typename Other, typename = OptionalMoveAssignmentEnabled<Value, Other>>
  158. Optional& operator= (Optional<Other>&& other) noexcept (noexcept (std::declval<Optional>().assign (other)))
  159. {
  160. assign (other);
  161. return *this;
  162. }
  163. /** Maintains the strong exception safety guarantee. */
  164. template <typename Other, typename = OptionalCopyAssignmentEnabled<Value, Other>>
  165. Optional& operator= (const Optional<Other>& other)
  166. {
  167. auto copy = other;
  168. assign (copy);
  169. return *this;
  170. }
  171. ~Optional() noexcept
  172. {
  173. reset();
  174. }
  175. Value* operator->() noexcept { return reinterpret_cast< Value*> (&storage); }
  176. const Value* operator->() const noexcept { return reinterpret_cast<const Value*> (&storage); }
  177. Value& operator*() noexcept { return *operator->(); }
  178. const Value& operator*() const noexcept { return *operator->(); }
  179. explicit operator bool() const noexcept { return valid; }
  180. bool hasValue() const noexcept { return valid; }
  181. void reset()
  182. {
  183. if (std::exchange (valid, false))
  184. operator*().~Value();
  185. }
  186. /** Like std::optional::value_or */
  187. template <typename U>
  188. Value orFallback (U&& fallback) const { return *this ? **this : std::forward<U> (fallback); }
  189. template <typename... Args>
  190. Value& emplace (Args&&... args)
  191. {
  192. reset();
  193. new (&storage) Value (std::forward<Args> (args)...);
  194. valid = true;
  195. return **this;
  196. }
  197. void swap (Optional& other) noexcept (std::is_nothrow_move_constructible<Value>::value
  198. && detail::adlSwap::isNothrowSwappable<Value>)
  199. {
  200. if (hasValue() && other.hasValue())
  201. {
  202. using std::swap;
  203. swap (**this, *other);
  204. }
  205. else if (hasValue() || other.hasValue())
  206. {
  207. (hasValue() ? other : *this).constructFrom (hasValue() ? *this : other);
  208. }
  209. }
  210. private:
  211. template <typename Other>
  212. void constructFrom (Optional<Other>& other) noexcept (noexcept (Value (std::move (*other))))
  213. {
  214. if (! other.hasValue())
  215. return;
  216. new (&storage) Value (std::move (*other));
  217. valid = true;
  218. other.reset();
  219. }
  220. template <typename Other>
  221. void assign (Optional<Other>& other) noexcept (noexcept (std::declval<Value&>() = std::move (*other)) && noexcept (std::declval<Optional>().constructFrom (other)))
  222. {
  223. if (valid)
  224. {
  225. if (other.hasValue())
  226. {
  227. **this = std::move (*other);
  228. other.reset();
  229. }
  230. else
  231. {
  232. reset();
  233. }
  234. }
  235. else
  236. {
  237. constructFrom (other);
  238. }
  239. }
  240. union
  241. {
  242. char placeholder;
  243. Value storage;
  244. };
  245. bool valid = false;
  246. };
  247. JUCE_END_IGNORE_WARNINGS_MSVC
  248. template <typename Value>
  249. Optional<std::decay_t<Value>> makeOptional (Value&& v)
  250. {
  251. return std::forward<Value> (v);
  252. }
  253. template <class T, class U>
  254. bool operator== (const Optional<T>& lhs, const Optional<U>& rhs)
  255. {
  256. if (lhs.hasValue() != rhs.hasValue()) return false;
  257. if (! lhs.hasValue()) return true;
  258. return *lhs == *rhs;
  259. }
  260. template <class T, class U>
  261. bool operator!= (const Optional<T>& lhs, const Optional<U>& rhs)
  262. {
  263. if (lhs.hasValue() != rhs.hasValue()) return true;
  264. if (! lhs.hasValue()) return false;
  265. return *lhs != *rhs;
  266. }
  267. template <class T, class U>
  268. bool operator< (const Optional<T>& lhs, const Optional<U>& rhs)
  269. {
  270. if (! rhs.hasValue()) return false;
  271. if (! lhs.hasValue()) return true;
  272. return *lhs < *rhs;
  273. }
  274. template <class T, class U>
  275. bool operator<= (const Optional<T>& lhs, const Optional<U>& rhs)
  276. {
  277. if (! lhs.hasValue()) return true;
  278. if (! rhs.hasValue()) return false;
  279. return *lhs <= *rhs;
  280. }
  281. template <class T, class U>
  282. bool operator> (const Optional<T>& lhs, const Optional<U>& rhs)
  283. {
  284. if (! lhs.hasValue()) return false;
  285. if (! rhs.hasValue()) return true;
  286. return *lhs > *rhs;
  287. }
  288. template <class T, class U>
  289. bool operator>= (const Optional<T>& lhs, const Optional<U>& rhs)
  290. {
  291. if (! rhs.hasValue()) return true;
  292. if (! lhs.hasValue()) return false;
  293. return *lhs >= *rhs;
  294. }
  295. template <class T>
  296. bool operator== (const Optional<T>& opt, Nullopt) noexcept { return ! opt.hasValue(); }
  297. template <class T>
  298. bool operator== (Nullopt, const Optional<T>& opt) noexcept { return ! opt.hasValue(); }
  299. template <class T>
  300. bool operator!= (const Optional<T>& opt, Nullopt) noexcept { return opt.hasValue(); }
  301. template <class T>
  302. bool operator!= (Nullopt, const Optional<T>& opt) noexcept { return opt.hasValue(); }
  303. template <class T>
  304. bool operator< (const Optional<T>&, Nullopt) noexcept { return false; }
  305. template <class T>
  306. bool operator< (Nullopt, const Optional<T>& opt) noexcept { return opt.hasValue(); }
  307. template <class T>
  308. bool operator<= (const Optional<T>& opt, Nullopt) noexcept { return ! opt.hasValue(); }
  309. template <class T>
  310. bool operator<= (Nullopt, const Optional<T>&) noexcept { return true; }
  311. template <class T>
  312. bool operator> (const Optional<T>& opt, Nullopt) noexcept { return opt.hasValue(); }
  313. template <class T>
  314. bool operator> (Nullopt, const Optional<T>&) noexcept { return false; }
  315. template <class T>
  316. bool operator>= (const Optional<T>&, Nullopt) noexcept { return true; }
  317. template <class T>
  318. bool operator>= (Nullopt, const Optional<T>& opt) noexcept { return ! opt.hasValue(); }
  319. template <class T, class U>
  320. bool operator== (const Optional<T>& opt, const U& value) { return opt.hasValue() ? *opt == value : false; }
  321. template <class T, class U>
  322. bool operator== (const T& value, const Optional<U>& opt) { return opt.hasValue() ? value == *opt : false; }
  323. template <class T, class U>
  324. bool operator!= (const Optional<T>& opt, const U& value) { return opt.hasValue() ? *opt != value : true; }
  325. template <class T, class U>
  326. bool operator!= (const T& value, const Optional<U>& opt) { return opt.hasValue() ? value != *opt : true; }
  327. template <class T, class U>
  328. bool operator< (const Optional<T>& opt, const U& value) { return opt.hasValue() ? *opt < value : true; }
  329. template <class T, class U>
  330. bool operator< (const T& value, const Optional<U>& opt) { return opt.hasValue() ? value < *opt : false; }
  331. template <class T, class U>
  332. bool operator<= (const Optional<T>& opt, const U& value) { return opt.hasValue() ? *opt <= value : true; }
  333. template <class T, class U>
  334. bool operator<= (const T& value, const Optional<U>& opt) { return opt.hasValue() ? value <= *opt : false; }
  335. template <class T, class U>
  336. bool operator> (const Optional<T>& opt, const U& value) { return opt.hasValue() ? *opt > value : false; }
  337. template <class T, class U>
  338. bool operator> (const T& value, const Optional<U>& opt) { return opt.hasValue() ? value > *opt : true; }
  339. template <class T, class U>
  340. bool operator>= (const Optional<T>& opt, const U& value) { return opt.hasValue() ? *opt >= value : false; }
  341. template <class T, class U>
  342. bool operator>= (const T& value, const Optional<U>& opt) { return opt.hasValue() ? value >= *opt : true; }
  343. } // namespace juce