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.

529 lines
18KB

  1. //
  2. // ██████ ██  ██  ██████  ██████
  3. // ██      ██  ██ ██    ██ ██       ** Clean Header-Only Classes **
  4. // ██  ███████ ██  ██ ██
  5. // ██  ██   ██ ██  ██ ██ https://github.com/Tracktion/choc
  6. //  ██████ ██  ██  ██████   ██████
  7. //
  8. // CHOC is (C)2021 Tracktion Corporation, and is offered under the terms of the ISC license:
  9. //
  10. // Permission to use, copy, modify, and/or distribute this software for any purpose with or
  11. // without fee is hereby granted, provided that the above copyright notice and this permission
  12. // notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  13. // WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  14. // AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
  15. // CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  16. // WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  17. // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  18. #ifndef CHOC_SMALLVECTOR_HEADER_INCLUDED
  19. #define CHOC_SMALLVECTOR_HEADER_INCLUDED
  20. #include <algorithm>
  21. #include "choc_Span.h"
  22. namespace choc
  23. {
  24. /**
  25. A std::vector-style container class, which uses some pre-allocated storage
  26. to avoid heap allocation when the number of elements is small.
  27. Inspired by LLVM's SmallVector, I've found this to be handy in many situations
  28. where you know there's only likely to be a small or fixed number of elements,
  29. and where performance is important.
  30. It retains most of the same basic methods as std::vector, but without some of
  31. the more exotic tricks that the std library uses, just to avoid things getting
  32. too complicated.
  33. */
  34. template <typename ElementType, size_t numPreallocatedElements>
  35. struct SmallVector
  36. {
  37. using value_type = ElementType;
  38. using reference = ElementType&;
  39. using const_reference = const ElementType&;
  40. using iterator = ElementType*;
  41. using const_iterator = const ElementType*;
  42. using size_type = size_t;
  43. SmallVector() noexcept;
  44. ~SmallVector() noexcept;
  45. SmallVector (SmallVector&&) noexcept;
  46. SmallVector (const SmallVector&);
  47. SmallVector& operator= (SmallVector&&) noexcept;
  48. SmallVector& operator= (const SmallVector&);
  49. /// Creates a SmallVector as a copy of some kind of iterable container.
  50. template <typename VectorType>
  51. SmallVector (const VectorType& initialContent);
  52. /// Replaces the contents of this vector with a copy of some kind of iterable container.
  53. template <typename VectorType>
  54. SmallVector& operator= (const VectorType&);
  55. reference operator[] (size_type index);
  56. const_reference operator[] (size_type index) const;
  57. value_type* data() const noexcept;
  58. const_iterator begin() const noexcept;
  59. const_iterator end() const noexcept;
  60. const_iterator cbegin() const noexcept;
  61. const_iterator cend() const noexcept;
  62. iterator begin() noexcept;
  63. iterator end() noexcept;
  64. const_reference front() const;
  65. reference front();
  66. const_reference back() const;
  67. reference back();
  68. bool empty() const noexcept;
  69. size_type size() const noexcept;
  70. size_type length() const noexcept;
  71. size_type capacity() const noexcept;
  72. bool contains (const ElementType&) const;
  73. void clear() noexcept;
  74. void resize (size_type newSize);
  75. void reserve (size_type requiredNumElements);
  76. void push_back (const value_type&);
  77. void push_back (value_type&&);
  78. /// Handy method to add multiple elements with a single push_back call.
  79. template <typename... Others>
  80. void push_back (const value_type& first, Others&&... others);
  81. template <typename... ConstructorArgs>
  82. void emplace_back (ConstructorArgs&&... args);
  83. void pop_back();
  84. void insert (iterator insertPosition, const value_type& valueToInsert);
  85. void insert (iterator insertPosition, value_type&& valueToInsert);
  86. void erase (iterator startPosition);
  87. void erase (iterator startPosition, iterator endPosition);
  88. bool operator== (span<value_type>) const;
  89. bool operator!= (span<value_type>) const;
  90. private:
  91. value_type* elements;
  92. size_type numElements = 0, numAllocated = numPreallocatedElements;
  93. uint64_t internalStorage[(numPreallocatedElements * sizeof (value_type) + sizeof (uint64_t) - 1) / sizeof (uint64_t)];
  94. void shrink (size_type);
  95. value_type* getInternalStorage() noexcept { return reinterpret_cast<value_type*> (internalStorage); }
  96. bool isUsingInternalStorage() const noexcept { return numAllocated <= numPreallocatedElements; }
  97. void resetToInternalStorage() noexcept;
  98. void freeHeapAndResetToInternalStorage() noexcept;
  99. static inline ElementType& _nullValue() noexcept { static ElementType e = {}; return e; }
  100. };
  101. //==============================================================================
  102. // _ _ _ _
  103. // __| | ___ | |_ __ _ (_)| | ___
  104. // / _` | / _ \| __| / _` || || |/ __|
  105. // | (_| || __/| |_ | (_| || || |\__ \ _ _ _
  106. // \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_)
  107. //
  108. // Code beyond this point is implementation detail...
  109. //
  110. //==============================================================================
  111. template <typename ElementType, size_t preSize>
  112. SmallVector<ElementType, preSize>::SmallVector() noexcept : elements (getInternalStorage())
  113. {
  114. }
  115. template <typename ElementType, size_t preSize>
  116. SmallVector<ElementType, preSize>::~SmallVector() noexcept
  117. {
  118. clear();
  119. }
  120. template <typename ElementType, size_t preSize>
  121. SmallVector<ElementType, preSize>::SmallVector (const SmallVector& other) : SmallVector()
  122. {
  123. operator= (other);
  124. }
  125. template <typename ElementType, size_t preSize>
  126. template <typename VectorType>
  127. SmallVector<ElementType, preSize>::SmallVector (const VectorType& initialContent) : SmallVector()
  128. {
  129. reserve (initialContent.size());
  130. for (auto& i : initialContent)
  131. emplace_back (i);
  132. }
  133. template <typename ElementType, size_t preSize>
  134. SmallVector<ElementType, preSize>::SmallVector (SmallVector&& other) noexcept
  135. {
  136. if (other.isUsingInternalStorage())
  137. {
  138. elements = getInternalStorage();
  139. numElements = other.numElements;
  140. for (size_type i = 0; i < numElements; ++i)
  141. new (elements + i) value_type (std::move (other.elements[i]));
  142. }
  143. else
  144. {
  145. elements = other.elements;
  146. numElements = other.numElements;
  147. numAllocated = other.numAllocated;
  148. other.resetToInternalStorage();
  149. other.numElements = 0;
  150. }
  151. }
  152. template <typename ElementType, size_t preSize>
  153. SmallVector<ElementType, preSize>& SmallVector<ElementType, preSize>::operator= (SmallVector&& other) noexcept
  154. {
  155. clear();
  156. if (other.isUsingInternalStorage())
  157. {
  158. numElements = other.numElements;
  159. for (size_type i = 0; i < numElements; ++i)
  160. new (elements + i) value_type (std::move (other.elements[i]));
  161. }
  162. else
  163. {
  164. elements = other.elements;
  165. numElements = other.numElements;
  166. numAllocated = other.numAllocated;
  167. other.resetToInternalStorage();
  168. other.numElements = 0;
  169. }
  170. return *this;
  171. }
  172. template <typename ElementType, size_t preSize>
  173. SmallVector<ElementType, preSize>& SmallVector<ElementType, preSize>::operator= (const SmallVector& other)
  174. {
  175. if (other.size() > numElements)
  176. {
  177. reserve (other.size());
  178. for (size_type i = 0; i < numElements; ++i)
  179. elements[i] = other.elements[i];
  180. for (size_type i = numElements; i < other.size(); ++i)
  181. new (elements + i) value_type (other.elements[i]);
  182. numElements = other.size();
  183. }
  184. else
  185. {
  186. shrink (other.size());
  187. for (size_type i = 0; i < numElements; ++i)
  188. elements[i] = other.elements[i];
  189. }
  190. return *this;
  191. }
  192. template <typename ElementType, size_t preSize>
  193. template <typename VectorType>
  194. SmallVector<ElementType, preSize>& SmallVector<ElementType, preSize>::operator= (const VectorType& other)
  195. {
  196. if (other.size() > numElements)
  197. {
  198. reserve (other.size());
  199. for (size_type i = 0; i < numElements; ++i)
  200. elements[i] = other[i];
  201. for (size_type i = numElements; i < other.size(); ++i)
  202. new (elements + i) value_type (other[i]);
  203. numElements = other.size();
  204. }
  205. else
  206. {
  207. shrink (other.size());
  208. for (size_type i = 0; i < numElements; ++i)
  209. elements[i] = other[i];
  210. }
  211. return *this;
  212. }
  213. template <typename ElementType, size_t preSize>
  214. void SmallVector<ElementType, preSize>::resetToInternalStorage() noexcept
  215. {
  216. elements = getInternalStorage();
  217. numAllocated = preSize;
  218. }
  219. template <typename ElementType, size_t preSize>
  220. void SmallVector<ElementType, preSize>::freeHeapAndResetToInternalStorage() noexcept
  221. {
  222. if (! isUsingInternalStorage())
  223. {
  224. delete[] reinterpret_cast<char*> (elements);
  225. resetToInternalStorage();
  226. }
  227. }
  228. template <typename ElementType, size_t preSize>
  229. typename SmallVector<ElementType, preSize>::reference SmallVector<ElementType, preSize>::operator[] (size_type index)
  230. {
  231. DISTRHO_SAFE_ASSERT_RETURN (index < numElements, _nullValue());
  232. return elements[index];
  233. }
  234. template <typename ElementType, size_t preSize>
  235. typename SmallVector<ElementType, preSize>::const_reference SmallVector<ElementType, preSize>::operator[] (size_type index) const
  236. {
  237. DISTRHO_SAFE_ASSERT_RETURN (index < numElements, _nullValue());
  238. return elements[index];
  239. }
  240. template <typename ElementType, size_t preSize>
  241. typename SmallVector<ElementType, preSize>::value_type* SmallVector<ElementType, preSize>::data() const noexcept { return elements; }
  242. template <typename ElementType, size_t preSize>
  243. typename SmallVector<ElementType, preSize>::const_iterator SmallVector<ElementType, preSize>::begin() const noexcept { return elements; }
  244. template <typename ElementType, size_t preSize>
  245. typename SmallVector<ElementType, preSize>::const_iterator SmallVector<ElementType, preSize>::end() const noexcept { return elements + numElements; }
  246. template <typename ElementType, size_t preSize>
  247. typename SmallVector<ElementType, preSize>::const_iterator SmallVector<ElementType, preSize>::cbegin() const noexcept { return elements; }
  248. template <typename ElementType, size_t preSize>
  249. typename SmallVector<ElementType, preSize>::const_iterator SmallVector<ElementType, preSize>::cend() const noexcept { return elements + numElements; }
  250. template <typename ElementType, size_t preSize>
  251. typename SmallVector<ElementType, preSize>::iterator SmallVector<ElementType, preSize>::begin() noexcept { return elements; }
  252. template <typename ElementType, size_t preSize>
  253. typename SmallVector<ElementType, preSize>::iterator SmallVector<ElementType, preSize>::end() noexcept { return elements + numElements; }
  254. template <typename ElementType, size_t preSize>
  255. typename SmallVector<ElementType, preSize>::reference SmallVector<ElementType, preSize>::front()
  256. {
  257. DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue());
  258. return elements[0];
  259. }
  260. template <typename ElementType, size_t preSize>
  261. typename SmallVector<ElementType, preSize>::const_reference SmallVector<ElementType, preSize>::front() const
  262. {
  263. DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue());
  264. return elements[0];
  265. }
  266. template <typename ElementType, size_t preSize>
  267. typename SmallVector<ElementType, preSize>::reference SmallVector<ElementType, preSize>::back()
  268. {
  269. DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue());
  270. return elements[numElements - 1];
  271. }
  272. template <typename ElementType, size_t preSize>
  273. typename SmallVector<ElementType, preSize>::const_reference SmallVector<ElementType, preSize>::back() const
  274. {
  275. DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue());
  276. return elements[numElements - 1];
  277. }
  278. template <typename ElementType, size_t preSize>
  279. typename SmallVector<ElementType, preSize>::size_type SmallVector<ElementType, preSize>::size() const noexcept { return numElements; }
  280. template <typename ElementType, size_t preSize>
  281. typename SmallVector<ElementType, preSize>::size_type SmallVector<ElementType, preSize>::length() const noexcept { return numElements; }
  282. template <typename ElementType, size_t preSize>
  283. typename SmallVector<ElementType, preSize>::size_type SmallVector<ElementType, preSize>::capacity() const noexcept { return numAllocated; }
  284. template <typename ElementType, size_t preSize>
  285. bool SmallVector<ElementType, preSize>::empty() const noexcept { return numElements == 0; }
  286. template <typename ElementType, size_t preSize>
  287. bool SmallVector<ElementType, preSize>::contains (const ElementType& target) const
  288. {
  289. for (size_t i = 0; i < numElements; ++i)
  290. if (elements[i] == target)
  291. return true;
  292. return false;
  293. }
  294. template <typename ElementType, size_t preSize>
  295. bool SmallVector<ElementType, preSize>::operator== (span<value_type> other) const { return span<value_type> (*this) == other; }
  296. template <typename ElementType, size_t preSize>
  297. bool SmallVector<ElementType, preSize>::operator!= (span<value_type> other) const { return span<value_type> (*this) != other; }
  298. template <typename ElementType, size_t preSize>
  299. void SmallVector<ElementType, preSize>::push_back (const value_type& item)
  300. {
  301. reserve (numElements + 1);
  302. new (elements + numElements) value_type (item);
  303. ++numElements;
  304. }
  305. template <typename ElementType, size_t preSize>
  306. void SmallVector<ElementType, preSize>::push_back (value_type&& item)
  307. {
  308. reserve (numElements + 1);
  309. new (elements + numElements) value_type (std::move (item));
  310. ++numElements;
  311. }
  312. template <typename ElementType, size_t preSize>
  313. template <typename... Others>
  314. void SmallVector<ElementType, preSize>::push_back (const value_type& first, Others&&... others)
  315. {
  316. reserve (numElements + 1 + sizeof... (others));
  317. push_back (first);
  318. push_back (std::forward<Others> (others)...);
  319. }
  320. template <typename ElementType, size_t preSize>
  321. template <typename... ConstructorArgs>
  322. void SmallVector<ElementType, preSize>::emplace_back (ConstructorArgs&&... args)
  323. {
  324. reserve (numElements + 1);
  325. new (elements + numElements) value_type (std::forward<ConstructorArgs> (args)...);
  326. ++numElements;
  327. }
  328. template <typename ElementType, size_t preSize>
  329. void SmallVector<ElementType, preSize>::insert (iterator insertPos, const value_type& item)
  330. {
  331. DISTRHO_SAFE_ASSERT_RETURN (insertPos != nullptr && insertPos >= begin() && insertPos <= end(),);
  332. auto index = insertPos - begin();
  333. push_back (item);
  334. std::rotate (begin() + index, end() - 1, end());
  335. }
  336. template <typename ElementType, size_t preSize>
  337. void SmallVector<ElementType, preSize>::insert (iterator insertPos, value_type&& item)
  338. {
  339. DISTRHO_SAFE_ASSERT_RETURN (insertPos != nullptr && insertPos >= begin() && insertPos <= end(),);
  340. auto index = insertPos - begin();
  341. push_back (std::move (item));
  342. std::rotate (begin() + index, end() - 1, end());
  343. }
  344. template <typename ElementType, size_t preSize>
  345. void SmallVector<ElementType, preSize>::pop_back()
  346. {
  347. if (numElements == 1)
  348. {
  349. clear();
  350. }
  351. else
  352. {
  353. DISTRHO_SAFE_ASSERT_RETURN (numElements > 0,);
  354. elements[--numElements].~value_type();
  355. }
  356. }
  357. template <typename ElementType, size_t preSize>
  358. void SmallVector<ElementType, preSize>::clear() noexcept
  359. {
  360. for (size_type i = 0; i < numElements; ++i)
  361. elements[i].~value_type();
  362. numElements = 0;
  363. freeHeapAndResetToInternalStorage();
  364. }
  365. template <typename ElementType, size_t preSize>
  366. void SmallVector<ElementType, preSize>::resize (size_type newSize)
  367. {
  368. if (newSize > numElements)
  369. {
  370. reserve (newSize);
  371. while (numElements < newSize)
  372. new (elements + numElements++) value_type (value_type());
  373. }
  374. else
  375. {
  376. shrink (newSize);
  377. }
  378. }
  379. template <typename ElementType, size_t preSize>
  380. void SmallVector<ElementType, preSize>::shrink (size_type newSize)
  381. {
  382. if (newSize == 0)
  383. return clear();
  384. DISTRHO_SAFE_ASSERT_RETURN (newSize <= numElements,);
  385. while (newSize < numElements && numElements > 0)
  386. elements[--numElements].~value_type();
  387. }
  388. template <typename ElementType, size_t preSize>
  389. void SmallVector<ElementType, preSize>::reserve (size_type requiredNumElements)
  390. {
  391. if (requiredNumElements > numAllocated)
  392. {
  393. requiredNumElements = static_cast<size_type> ((requiredNumElements + 15u) & ~(size_type) 15u);
  394. if (requiredNumElements > preSize)
  395. {
  396. auto* newBuffer = reinterpret_cast<value_type*> (new char[requiredNumElements * sizeof (value_type)]);
  397. for (size_type i = 0; i < numElements; ++i)
  398. {
  399. new (newBuffer + i) value_type (std::move (elements[i]));
  400. elements[i].~value_type();
  401. }
  402. freeHeapAndResetToInternalStorage();
  403. elements = newBuffer;
  404. }
  405. numAllocated = requiredNumElements;
  406. }
  407. }
  408. template <typename ElementType, size_t preSize>
  409. void SmallVector<ElementType, preSize>::erase (iterator startElement)
  410. {
  411. erase (startElement, startElement + 1);
  412. }
  413. template <typename ElementType, size_t preSize>
  414. void SmallVector<ElementType, preSize>::erase (iterator startElement, iterator endElement)
  415. {
  416. DISTRHO_SAFE_ASSERT_RETURN (startElement != nullptr && startElement >= begin() && startElement <= end(),);
  417. DISTRHO_SAFE_ASSERT_RETURN (endElement != nullptr && endElement >= begin() && endElement <= end(),);
  418. if (startElement != endElement)
  419. {
  420. DISTRHO_SAFE_ASSERT_RETURN (startElement < endElement,);
  421. if (endElement == end())
  422. return shrink (static_cast<size_type> (startElement - begin()));
  423. auto dest = startElement;
  424. for (auto src = endElement; src < end(); ++dest, ++src)
  425. *dest = std::move (*src);
  426. shrink (size() - static_cast<size_type> (endElement - startElement));
  427. }
  428. }
  429. }
  430. #endif // CHOC_SMALLVECTOR_HEADER_INCLUDED