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.

513 lines
17KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  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. template <class ElementType, class TypeOfCriticalSectionToUse>
  20. class ArrayBase : public TypeOfCriticalSectionToUse
  21. {
  22. private:
  23. using ParameterType = typename TypeHelpers::ParameterType<ElementType>::type;
  24. public:
  25. //==============================================================================
  26. ArrayBase() = default;
  27. ~ArrayBase()
  28. {
  29. clear();
  30. }
  31. ArrayBase (ArrayBase&& other) noexcept
  32. : elements (std::move (other.elements)),
  33. numAllocated (other.numAllocated),
  34. numUsed (other.numUsed)
  35. {
  36. other.numAllocated = 0;
  37. other.numUsed = 0;
  38. }
  39. ArrayBase& operator= (ArrayBase&& other) noexcept
  40. {
  41. if (this != &other)
  42. {
  43. auto tmp (std::move (other));
  44. swapWith (tmp);
  45. }
  46. return *this;
  47. }
  48. //==============================================================================
  49. template <class OtherArrayType>
  50. bool operator== (const OtherArrayType& other) const noexcept
  51. {
  52. if (size() != (int) other.size())
  53. return false;
  54. auto* e = begin();
  55. for (auto& o : other)
  56. if (! (*e++ == o))
  57. return false;
  58. return true;
  59. }
  60. template <class OtherArrayType>
  61. bool operator!= (const OtherArrayType& other) const noexcept
  62. {
  63. return ! operator== (other);
  64. }
  65. //==============================================================================
  66. inline ElementType& operator[] (const int index) const noexcept
  67. {
  68. jassert (elements != nullptr);
  69. jassert (isPositiveAndBelow (index, numUsed));
  70. return elements[index];
  71. }
  72. inline ElementType getValueWithDefault (const int index) const noexcept
  73. {
  74. return isPositiveAndBelow (index, numUsed) ? elements[index] : ElementType();
  75. }
  76. inline ElementType getFirst() const noexcept
  77. {
  78. return numUsed > 0 ? elements[0] : ElementType();
  79. }
  80. inline ElementType getLast() const noexcept
  81. {
  82. return numUsed > 0 ? elements[numUsed - 1] : ElementType();
  83. }
  84. //==============================================================================
  85. inline ElementType* begin() const noexcept
  86. {
  87. return elements;
  88. }
  89. inline ElementType* end() const noexcept
  90. {
  91. return elements + numUsed;
  92. }
  93. inline ElementType* data() const noexcept
  94. {
  95. return elements;
  96. }
  97. inline int size() const noexcept
  98. {
  99. return numUsed;
  100. }
  101. inline int capacity() const noexcept
  102. {
  103. return numAllocated;
  104. }
  105. //==============================================================================
  106. void setAllocatedSize (int numElements)
  107. {
  108. jassert (numElements >= numUsed);
  109. if (numAllocated != numElements)
  110. {
  111. if (numElements > 0)
  112. setAllocatedSizeInternal (numElements);
  113. else
  114. elements.free();
  115. }
  116. numAllocated = numElements;
  117. }
  118. void ensureAllocatedSize (int minNumElements)
  119. {
  120. if (minNumElements > numAllocated)
  121. setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
  122. jassert (numAllocated <= 0 || elements != nullptr);
  123. }
  124. void shrinkToNoMoreThan (int maxNumElements)
  125. {
  126. if (maxNumElements < numAllocated)
  127. setAllocatedSize (maxNumElements);
  128. }
  129. void clear()
  130. {
  131. for (int i = 0; i < numUsed; ++i)
  132. elements[i].~ElementType();
  133. numUsed = 0;
  134. }
  135. //==============================================================================
  136. void swapWith (ArrayBase& other) noexcept
  137. {
  138. elements.swapWith (other.elements);
  139. std::swap (numAllocated, other.numAllocated);
  140. std::swap (numUsed, other.numUsed);
  141. }
  142. //==============================================================================
  143. void add (const ElementType& newElement)
  144. {
  145. ensureAllocatedSize (numUsed + 1);
  146. addAssumingCapacityIsReady (newElement);
  147. }
  148. void add (ElementType&& newElement)
  149. {
  150. ensureAllocatedSize (numUsed + 1);
  151. addAssumingCapacityIsReady (std::move (newElement));
  152. }
  153. template <typename... OtherElements>
  154. void add (const ElementType& firstNewElement, OtherElements... otherElements)
  155. {
  156. ensureAllocatedSize (numUsed + 1 + (int) sizeof... (otherElements));
  157. addAssumingCapacityIsReady (firstNewElement, otherElements...);
  158. }
  159. template <typename... OtherElements>
  160. void add (ElementType&& firstNewElement, OtherElements... otherElements)
  161. {
  162. ensureAllocatedSize (numUsed + 1 + (int) sizeof... (otherElements));
  163. addAssumingCapacityIsReady (std::move (firstNewElement), otherElements...);
  164. }
  165. //==============================================================================
  166. template <typename Type>
  167. void addArray (const Type* elementsToAdd, int numElementsToAdd)
  168. {
  169. ensureAllocatedSize (numUsed + numElementsToAdd);
  170. addArrayInternal (elementsToAdd, numElementsToAdd);
  171. numUsed += numElementsToAdd;
  172. }
  173. template <typename TypeToCreateFrom>
  174. void addArray (const std::initializer_list<TypeToCreateFrom>& items)
  175. {
  176. ensureAllocatedSize (numUsed + (int) items.size());
  177. for (auto& item : items)
  178. new (elements + numUsed++) ElementType (item);
  179. }
  180. template <class OtherArrayType>
  181. void addArray (const OtherArrayType& arrayToAddFrom)
  182. {
  183. ensureAllocatedSize (numUsed + (int) arrayToAddFrom.size());
  184. for (auto& e : arrayToAddFrom)
  185. addAssumingCapacityIsReady (e);
  186. }
  187. template <class OtherArrayType>
  188. typename std::enable_if<! std::is_pointer<OtherArrayType>::value, int>::type
  189. addArray (const OtherArrayType& arrayToAddFrom,
  190. int startIndex, int numElementsToAdd = -1)
  191. {
  192. if (startIndex < 0)
  193. {
  194. jassertfalse;
  195. startIndex = 0;
  196. }
  197. if (numElementsToAdd < 0 || startIndex + numElementsToAdd > (int) arrayToAddFrom.size())
  198. numElementsToAdd = (int) arrayToAddFrom.size() - startIndex;
  199. addArray (arrayToAddFrom.data() + startIndex, numElementsToAdd);
  200. return numElementsToAdd;
  201. }
  202. //==============================================================================
  203. void insert (int indexToInsertAt, ParameterType newElement, int numberOfTimesToInsertIt)
  204. {
  205. auto* space = createInsertSpace (indexToInsertAt, numberOfTimesToInsertIt);
  206. for (int i = 0; i < numberOfTimesToInsertIt; ++i)
  207. new (space++) ElementType (newElement);
  208. numUsed += numberOfTimesToInsertIt;
  209. }
  210. void insertArray (int indexToInsertAt, const ElementType* newElements, int numberOfElements)
  211. {
  212. auto* space = createInsertSpace (indexToInsertAt, numberOfElements);
  213. for (int i = 0; i < numberOfElements; ++i)
  214. new (space++) ElementType (*(newElements++));
  215. numUsed += numberOfElements;
  216. }
  217. //==============================================================================
  218. void removeElements (int indexToRemoveAt, int numElementsToRemove)
  219. {
  220. jassert (indexToRemoveAt >= 0);
  221. jassert (numElementsToRemove >= 0);
  222. jassert (indexToRemoveAt + numElementsToRemove <= numUsed);
  223. if (numElementsToRemove > 0)
  224. {
  225. removeElementsInternal (indexToRemoveAt, numElementsToRemove);
  226. numUsed -= numElementsToRemove;
  227. }
  228. }
  229. //==============================================================================
  230. void swap (int index1, int index2)
  231. {
  232. if (isPositiveAndBelow (index1, numUsed)
  233. && isPositiveAndBelow (index2, numUsed))
  234. {
  235. std::swap (elements[index1],
  236. elements[index2]);
  237. }
  238. }
  239. //==============================================================================
  240. void move (int currentIndex, int newIndex) noexcept
  241. {
  242. if (isPositiveAndBelow (currentIndex, numUsed))
  243. {
  244. if (! isPositiveAndBelow (newIndex, numUsed))
  245. newIndex = numUsed - 1;
  246. moveInternal (currentIndex, newIndex);
  247. }
  248. }
  249. private:
  250. //==============================================================================
  251. template <typename T>
  252. using TriviallyCopyableVoid = typename std::enable_if<std::is_trivially_copyable<T>::value, void>::type;
  253. template <typename T>
  254. using NonTriviallyCopyableVoid = typename std::enable_if<! std::is_trivially_copyable<T>::value, void>::type;
  255. //==============================================================================
  256. template <typename T = ElementType>
  257. TriviallyCopyableVoid<T> addArrayInternal (const ElementType* otherElements, int numElements)
  258. {
  259. memcpy (elements + numUsed, otherElements, (size_t) numElements * sizeof (ElementType));
  260. }
  261. template <typename Type, typename T = ElementType>
  262. TriviallyCopyableVoid<T> addArrayInternal (const Type* otherElements, int numElements)
  263. {
  264. auto* start = elements + numUsed;
  265. while (--numElements >= 0)
  266. new (start++) ElementType (*(otherElements++));
  267. }
  268. template <typename Type, typename T = ElementType>
  269. NonTriviallyCopyableVoid<T> addArrayInternal (const Type* otherElements, int numElements)
  270. {
  271. auto* start = elements + numUsed;
  272. while (--numElements >= 0)
  273. new (start++) ElementType (*(otherElements++));
  274. }
  275. //==============================================================================
  276. template <typename T = ElementType>
  277. TriviallyCopyableVoid<T> setAllocatedSizeInternal (int numElements)
  278. {
  279. elements.realloc ((size_t) numElements);
  280. }
  281. template <typename T = ElementType>
  282. NonTriviallyCopyableVoid<T> setAllocatedSizeInternal (int numElements)
  283. {
  284. HeapBlock<ElementType> newElements (numElements);
  285. for (int i = 0; i < numUsed; ++i)
  286. {
  287. new (newElements + i) ElementType (std::move (elements[i]));
  288. elements[i].~ElementType();
  289. }
  290. elements = std::move (newElements);
  291. }
  292. //==============================================================================
  293. ElementType* createInsertSpace (int indexToInsertAt, int numElements)
  294. {
  295. ensureAllocatedSize (numUsed + numElements);
  296. if (! isPositiveAndBelow (indexToInsertAt, numUsed))
  297. return elements + numUsed;
  298. createInsertSpaceInternal (indexToInsertAt, numElements);
  299. return elements + indexToInsertAt;
  300. }
  301. template <typename T = ElementType>
  302. TriviallyCopyableVoid<T> createInsertSpaceInternal (int indexToInsertAt, int numElements)
  303. {
  304. auto* start = elements + indexToInsertAt;
  305. auto numElementsToShift = numUsed - indexToInsertAt;
  306. memmove (start + numElements, start, (size_t) numElementsToShift * sizeof (ElementType));
  307. }
  308. template <typename T = ElementType>
  309. NonTriviallyCopyableVoid<T> createInsertSpaceInternal (int indexToInsertAt, int numElements)
  310. {
  311. auto* end = elements + numUsed;
  312. auto* newEnd = end + numElements;
  313. auto numElementsToShift = numUsed - indexToInsertAt;
  314. for (int i = 0; i < numElementsToShift; ++i)
  315. {
  316. new (--newEnd) ElementType (std::move (*(--end)));
  317. end->~ElementType();
  318. }
  319. }
  320. //==============================================================================
  321. template <typename T = ElementType>
  322. TriviallyCopyableVoid<T> removeElementsInternal (int indexToRemoveAt, int numElementsToRemove)
  323. {
  324. auto* start = elements + indexToRemoveAt;
  325. auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
  326. memmove (start, start + numElementsToRemove, (size_t) numElementsToShift * sizeof (ElementType));
  327. }
  328. template <typename T = ElementType>
  329. NonTriviallyCopyableVoid<T> removeElementsInternal (int indexToRemoveAt, int numElementsToRemove)
  330. {
  331. auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
  332. auto* destination = elements + indexToRemoveAt;
  333. auto* source = destination + numElementsToRemove;
  334. for (int i = 0; i < numElementsToShift; ++i)
  335. moveAssignElement (destination++, std::move (*(source++)));
  336. for (int i = 0; i < numElementsToRemove; ++i)
  337. (destination++)->~ElementType();
  338. }
  339. //==============================================================================
  340. template <typename T = ElementType>
  341. TriviallyCopyableVoid<T> moveInternal (int currentIndex, int newIndex) noexcept
  342. {
  343. char tempCopy[sizeof (ElementType)];
  344. memcpy (tempCopy, elements + currentIndex, sizeof (ElementType));
  345. if (newIndex > currentIndex)
  346. {
  347. memmove (elements + currentIndex,
  348. elements + currentIndex + 1,
  349. sizeof (ElementType) * (size_t) (newIndex - currentIndex));
  350. }
  351. else
  352. {
  353. memmove (elements + newIndex + 1,
  354. elements + newIndex,
  355. sizeof (ElementType) * (size_t) (currentIndex - newIndex));
  356. }
  357. memcpy (elements + newIndex, tempCopy, sizeof (ElementType));
  358. }
  359. template <typename T = ElementType>
  360. NonTriviallyCopyableVoid<T> moveInternal (int currentIndex, int newIndex) noexcept
  361. {
  362. auto* e = elements + currentIndex;
  363. ElementType tempCopy (std::move (*e));
  364. auto delta = newIndex - currentIndex;
  365. if (delta > 0)
  366. {
  367. for (int i = 0; i < delta; ++i)
  368. {
  369. moveAssignElement (e, std::move (*(e + 1)));
  370. ++e;
  371. }
  372. }
  373. else
  374. {
  375. for (int i = 0; i < -delta; ++i)
  376. {
  377. moveAssignElement (e, std::move (*(e - 1)));
  378. --e;
  379. }
  380. }
  381. moveAssignElement (e, std::move (tempCopy));
  382. }
  383. //==============================================================================
  384. void addAssumingCapacityIsReady (const ElementType& element) { new (elements + numUsed++) ElementType (element); }
  385. void addAssumingCapacityIsReady (ElementType&& element) { new (elements + numUsed++) ElementType (std::move (element)); }
  386. template <typename... OtherElements>
  387. void addAssumingCapacityIsReady (const ElementType& firstNewElement, OtherElements... otherElements)
  388. {
  389. addAssumingCapacityIsReady (firstNewElement);
  390. addAssumingCapacityIsReady (otherElements...);
  391. }
  392. template <typename... OtherElements>
  393. void addAssumingCapacityIsReady (ElementType&& firstNewElement, OtherElements... otherElements)
  394. {
  395. addAssumingCapacityIsReady (std::move (firstNewElement));
  396. addAssumingCapacityIsReady (otherElements...);
  397. }
  398. //==============================================================================
  399. template <typename T = ElementType>
  400. typename std::enable_if<std::is_move_assignable<T>::value, void>::type
  401. moveAssignElement (ElementType* destination, ElementType&& source)
  402. {
  403. *destination = std::move (source);
  404. }
  405. template <typename T = ElementType>
  406. typename std::enable_if<! std::is_move_assignable<T>::value, void>::type
  407. moveAssignElement (ElementType* destination, ElementType&& source)
  408. {
  409. destination->~ElementType();
  410. new (destination) ElementType (std::move (source));
  411. }
  412. //==============================================================================
  413. HeapBlock<ElementType> elements;
  414. int numAllocated = 0, numUsed = 0;
  415. JUCE_DECLARE_NON_COPYABLE (ArrayBase)
  416. };
  417. } // namespace juce