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.

428 lines
16KB

  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. template <typename T, typename = void>
  22. constexpr auto canPreDecrement = false;
  23. template <typename T>
  24. constexpr auto canPreDecrement<T, std::void_t<decltype (--std::declval<T>())>> = true;
  25. template <typename T, typename I, typename = void>
  26. constexpr auto canAddAssign = false;
  27. template <typename T, typename I>
  28. constexpr auto canAddAssign<T, I, std::void_t<decltype (std::declval<T>() += std::declval<I>())>> = true;
  29. template <typename T, typename I, typename = void>
  30. constexpr auto canSubAssign = false;
  31. template <typename T, typename I>
  32. constexpr auto canSubAssign<T, I, std::void_t<decltype (std::declval<T>() -= std::declval<I>())>> = true;
  33. template <typename T, typename I, typename = void>
  34. constexpr auto canAdd = false;
  35. template <typename T, typename I>
  36. constexpr auto canAdd<T, I, std::void_t<decltype (std::declval<T>() + std::declval<I>())>> = true;
  37. template <typename T, typename I, typename = void>
  38. constexpr auto canSub = false;
  39. template <typename T, typename I>
  40. constexpr auto canSub<T, I, std::void_t<decltype (std::declval<T>() - std::declval<I>())>> = true;
  41. template <typename T, typename I, typename = void>
  42. constexpr auto canLessThan = false;
  43. template <typename T, typename I>
  44. constexpr auto canLessThan<T, I, std::void_t<decltype (std::declval<T>() < std::declval<I>())>> = true;
  45. template <typename T, typename I, typename = void>
  46. constexpr auto canLessThanEqual = false;
  47. template <typename T, typename I>
  48. constexpr auto canLessThanEqual<T, I, std::void_t<decltype (std::declval<T>() <= std::declval<I>())>> = true;
  49. template <typename T, typename I, typename = void>
  50. constexpr auto canGreaterThan = false;
  51. template <typename T, typename I>
  52. constexpr auto canGreaterThan<T, I, std::void_t<decltype (std::declval<T>() > std::declval<I>())>> = true;
  53. template <typename T, typename I, typename = void>
  54. constexpr auto canGreaterThanEqual = false;
  55. template <typename T, typename I>
  56. constexpr auto canGreaterThanEqual<T, I, std::void_t<decltype (std::declval<T>() >= std::declval<I>())>> = true;
  57. namespace withAdlSize
  58. {
  59. using std::size;
  60. template <typename Range>
  61. using AdlSize = decltype (size (std::declval<Range>()));
  62. template <typename Range>
  63. using AdlSignedSize = std::common_type_t<std::ptrdiff_t, std::make_signed_t<AdlSize<Range>>>;
  64. }
  65. } // namespace detail
  66. /**
  67. Returned when dereferencing an EnumerateIterator.
  68. Allows querying the index associated with an element, along with a reference to the element
  69. itself.
  70. You should never need to construct an instance of this type yourself. Instead, use the
  71. enumerate() function to construct a range that can be enumerated.
  72. @see enumerate()
  73. @tags{Core}
  74. */
  75. template <typename Index, typename Value>
  76. struct Enumerated
  77. {
  78. Index index;
  79. Value value;
  80. };
  81. /**
  82. An iterator that wraps some other iterator, keeping track of the relative position of that
  83. iterator based on calls to arithmetic operators such as
  84. operator++(), operator--(), operator+(), and operator-().
  85. You should never need to construct an instance of this type yourself. Instead, use the
  86. enumerate() function to construct a range that can be enumerated.
  87. @see enumerate()
  88. @tags{Core}
  89. */
  90. template <typename Iter, typename Index = ptrdiff_t>
  91. class EnumerateIterator
  92. {
  93. public:
  94. /** Default constructor. */
  95. constexpr EnumerateIterator() = default;
  96. /** Wraps the provided iterator, and sets the internal count to 0. */
  97. constexpr explicit EnumerateIterator (Iter iter)
  98. : EnumerateIterator (std::move (iter), Index{}) {}
  99. /** Wraps the provided iterator, and sets the internal count to the provided value. */
  100. constexpr EnumerateIterator (Iter iter, Index ind)
  101. : iterator (std::move (iter)), index (ind) {}
  102. /** Two EnumerateIterators are considered equal if the wrapped iterators are equal. */
  103. template <typename OtherIter, typename OtherInd>
  104. [[nodiscard]] constexpr bool operator== (const EnumerateIterator<OtherIter, OtherInd>& other) const
  105. {
  106. return iterator == other.iterator;
  107. }
  108. /** @see operator==() */
  109. template <typename OtherIter, typename OtherInd>
  110. [[nodiscard]] constexpr bool operator!= (const EnumerateIterator<OtherIter, OtherInd>& other) const
  111. {
  112. return ! operator== (other);
  113. }
  114. /** Dereferencing the iterator produces an Enumerated instance *by value*. This type holds
  115. a copy of the iterator's current index, along with the result of dereferencing the
  116. wrapped iterator (normally a reference type).
  117. */
  118. [[nodiscard]] constexpr Enumerated<Index, decltype (*std::declval<Iter>())> operator*() const
  119. {
  120. return { index, *iterator };
  121. }
  122. /** Increments the iterator and the index. */
  123. constexpr EnumerateIterator& operator++()
  124. {
  125. ++iterator;
  126. ++index;
  127. return *this;
  128. }
  129. /** Increments the iterator and the index. */
  130. constexpr EnumerateIterator operator++ (int)
  131. {
  132. auto copy = *this;
  133. operator++();
  134. return copy;
  135. }
  136. /** Decrements the iterator and the index.
  137. Only participates in overload resolution if the iterator can be pre-decremented.
  138. */
  139. template <typename T = Iter, std::enable_if_t<detail::canPreDecrement<T>, int> = 0>
  140. constexpr EnumerateIterator& operator--()
  141. {
  142. --iterator;
  143. --index;
  144. return *this;
  145. }
  146. /** Decrements the iterator and the index.
  147. Only participates in overload resolution if the iterator can be pre-decremented.
  148. */
  149. template <typename T = Iter, std::enable_if_t<detail::canPreDecrement<T>, int> = 0>
  150. constexpr EnumerateIterator operator-- (int)
  151. {
  152. auto copy = *this;
  153. operator--();
  154. return copy;
  155. }
  156. /** Adds an integral value to both the iterator and the index.
  157. Only participates in overload resolution if the iterator can be add-assigned.
  158. */
  159. template <typename I, std::enable_if_t<detail::canAddAssign<Iter&, I>, int> = 0>
  160. constexpr EnumerateIterator& operator+= (I diff)
  161. {
  162. iterator += diff;
  163. index += static_cast<Index> (diff);
  164. return *this;
  165. }
  166. /** Subtracts an integral value from both the iterator and the index.
  167. Only participates in overload resolution if the iterator can be sub-assigned.
  168. */
  169. template <typename I, std::enable_if_t<detail::canSubAssign<Iter&, I>, int> = 0>
  170. constexpr EnumerateIterator& operator-= (I diff)
  171. {
  172. iterator -= diff;
  173. index -= static_cast<Index> (diff);
  174. return *this;
  175. }
  176. /** Subtracts another enumerate iterator from this one, producing the same result as
  177. subtracting the two wrapped iterators. For random-access iterators, this will normally
  178. return the distance between the two iterators.
  179. Only participates in overload resolution if the wrapped iterators can be subtracted.
  180. */
  181. template <typename OtherIter, typename OtherInd, std::enable_if_t<detail::canSub<Iter, OtherIter>, int> = 0>
  182. [[nodiscard]] constexpr auto operator- (const EnumerateIterator<OtherIter, OtherInd>& other) const
  183. {
  184. return iterator - other.iterator;
  185. }
  186. /** Indexes into this iterator, equivalent to adding an integral value to this iterator and
  187. then dereferencing the result.
  188. Only participates in overload resolution if the wrapped iterator allows addition of
  189. integral values.
  190. */
  191. template <typename I, std::enable_if_t<detail::canAdd<EnumerateIterator, I>, int> = 0>
  192. [[nodiscard]] constexpr auto operator[] (I diff) const
  193. {
  194. return *(*this + diff);
  195. }
  196. /** Returns the result of comparing the two wrapped iterators.
  197. Only participates in overload resolution if the wrapped iterators are comparable.
  198. */
  199. template <typename OtherIter, typename OtherInd, std::enable_if_t<detail::canLessThan<Iter, OtherIter>, int> = 0>
  200. [[nodiscard]] constexpr bool operator< (const EnumerateIterator<OtherIter, OtherInd>& other) const
  201. {
  202. return iterator < other.iterator;
  203. }
  204. /** Returns the result of comparing the two wrapped iterators.
  205. Only participates in overload resolution if the wrapped iterators are comparable.
  206. */
  207. template <typename OtherIter, typename OtherInd, std::enable_if_t<detail::canLessThanEqual<Iter, OtherIter>, int> = 0>
  208. [[nodiscard]] constexpr bool operator<= (const EnumerateIterator<OtherIter, OtherInd>& other) const
  209. {
  210. return iterator <= other.iterator;
  211. }
  212. /** Returns the result of comparing the two wrapped iterators.
  213. Only participates in overload resolution if the wrapped iterators are comparable.
  214. */
  215. template <typename OtherIter, typename OtherInd, std::enable_if_t<detail::canGreaterThan<Iter, OtherIter>, int> = 0>
  216. [[nodiscard]] constexpr bool operator> (const EnumerateIterator<OtherIter, OtherInd>& other) const
  217. {
  218. return iterator > other.iterator;
  219. }
  220. /** Returns the result of comparing the two wrapped iterators.
  221. Only participates in overload resolution if the wrapped iterators are comparable.
  222. */
  223. template <typename OtherIter, typename OtherInd, std::enable_if_t<detail::canGreaterThanEqual<Iter, OtherIter>, int> = 0>
  224. [[nodiscard]] constexpr bool operator>= (const EnumerateIterator<OtherIter, OtherInd>& other) const
  225. {
  226. return iterator >= other.iterator;
  227. }
  228. /** Returns the result of adding an integral value to this iterator.
  229. Only participates in overload resolution if addition is supported by the wrapped iterator.
  230. */
  231. template <typename I, std::enable_if_t<detail::canAddAssign<EnumerateIterator&, I>, int> = 0>
  232. constexpr friend auto operator+ (EnumerateIterator iter, I ind)
  233. {
  234. return iter += ind;
  235. }
  236. /** Returns the result of adding an integral value to this iterator.
  237. Only participates in overload resolution if addition is supported by the wrapped iterator.
  238. */
  239. template <typename I, std::enable_if_t<detail::canAddAssign<EnumerateIterator&, I>, int> = 0>
  240. constexpr friend auto operator+ (I ind, EnumerateIterator iter)
  241. {
  242. return iter += ind;
  243. }
  244. /** Returns the result of subtracting an integral value from this iterator.
  245. Only participates in overload resolution if subtraction is supported by the wrapped iterator.
  246. */
  247. template <typename I, std::enable_if_t<detail::canSubAssign<EnumerateIterator&, I>, int> = 0>
  248. constexpr friend auto operator- (EnumerateIterator iter, I ind)
  249. {
  250. return iter -= ind;
  251. }
  252. private:
  253. Iter iterator{};
  254. Index index = 0;
  255. };
  256. //==============================================================================
  257. /**
  258. Wraps a pair of iterators, providing member begin() and end() functions that return
  259. those iterators.
  260. This is useful in situations where you have an iterator pair, but want to use that
  261. pair somewhere that requires an iterable range, such as in a ranged-for loop.
  262. @see makeRange()
  263. @tags{Core}
  264. */
  265. template <typename Begin, typename End>
  266. class IteratorPair
  267. {
  268. public:
  269. /** Constructs a pair from a begin and end iterator.
  270. Instead of calling this directly, use makeRange().
  271. */
  272. constexpr IteratorPair (Begin bIn, End eIn)
  273. : b (std::move (bIn)), e (std::move (eIn)) {}
  274. /** Returns the begin iterator. */
  275. constexpr auto begin() const { return b; }
  276. /** Returns the end iterator. */
  277. constexpr auto end() const { return e; }
  278. private:
  279. Begin b;
  280. End e;
  281. };
  282. /**
  283. Given two iterators "begin" and "end", returns an IteratorPair with a member
  284. begin() and end() function. This pair can be used in contexts that expect an
  285. iterable range, the most significant of which is ranged-for loops.
  286. This automatically deduces the Begin and End types, so it is more concise to use than
  287. directly calling the IteratorPair constructor.
  288. */
  289. template <typename Begin, typename End = Begin>
  290. [[nodiscard]] constexpr auto makeRange (Begin begin, End end)
  291. {
  292. return IteratorPair<Begin, End> { std::move (begin), std::move (end) };
  293. }
  294. //==============================================================================
  295. /**
  296. Given a range and an optional starting offset, returns an IteratorPair that
  297. holds EnumerateIterators wrapping the begin() and end() of the range.
  298. This is useful in situations where you need to iterate some range, but also query
  299. the position of each item in the range.
  300. A simple usage might look like this:
  301. @code
  302. std::list<int> elements { 10, 20, 30, 40, 50 };
  303. for (const auto pair : enumerate (elements))
  304. std::cout << pair.index << ' ' << pair.value << ' ';
  305. // output: 0 10 1 20 2 30 3 40 4 50
  306. @endcode
  307. You can also use structured bindings to concisely destructure each Enumerated instance:
  308. @code
  309. for (const auto [index, value] : enumerate (elements))
  310. std::cout << index << ' ' << value << ' ';
  311. @endcode
  312. Note that the Enumerated instance is returned by value. This is because each Enumerated
  313. instance is created on-demand when the iterator is dereferenced. As a result, the following
  314. will result in a dangling reference, and will probably trigger a compiler warning:
  315. @code
  316. // BAD IDEA: creating a reference to a temporary Enumerated instance
  317. for (auto& [index, value] : enumerate (elements))
  318. ...
  319. @endcode
  320. The 'value' member of Enumerated automatically assumes the same type as dereferencing the
  321. wrapped iterator, which is normally a reference to an element of a container.
  322. In the following snippet, the type of '[index, value]' is 'const Enumerated<ptrdiff_t, int&>',
  323. the type of 'index' is 'ptrdiff_t', and the type of 'value' is 'int&'.
  324. @code
  325. std::vector<int> elements { 10, 20, 30, 40, 50 };
  326. for (const auto [index, value] : enumerate (elements))
  327. ...
  328. @endcode
  329. By default, the constness of pair.value will match the constness of the range passed to
  330. enumerate. If you pass a mutable lvalue reference to enumerate, then each value will also
  331. be mutable. If you pass a constant lvalue reference to enumerate, then each value will be
  332. const. If you know that you don't need the iterated elements to be mutable, it's good
  333. practice to wrap the range with std::as_const before passing it to enumerate:
  334. @code
  335. for (const auto [index, value] : enumerate (std::as_const (elements)))
  336. {
  337. // value is immutable here
  338. }
  339. @endcode
  340. */
  341. template <typename Range, typename Index = detail::withAdlSize::AdlSignedSize<Range>>
  342. [[nodiscard]] constexpr auto enumerate (Range&& range, Index startingValue = {})
  343. {
  344. // This ensures argument-dependent lookup works properly for user-defined non-member begin/end
  345. using std::begin, std::end;
  346. return makeRange (EnumerateIterator { begin (range), startingValue },
  347. EnumerateIterator { end (range), startingValue });
  348. }
  349. } // namespace juce