Audio plugin host https://kx.studio/carla
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.

451 lines
10KB

  1. /*
  2. * High-level, templated, C++ doubly-linked list
  3. * Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #ifndef LINKED_LIST_HPP_INCLUDED
  18. #define LINKED_LIST_HPP_INCLUDED
  19. #include "CarlaUtils.hpp"
  20. #include <new>
  21. extern "C" {
  22. #include "rtmempool/list.h"
  23. }
  24. // Declare non copyable and prevent heap allocation
  25. #ifdef CARLA_PROPER_CPP11_SUPPORT
  26. # define LINKED_LIST_DECLARATIONS(ClassName) \
  27. ClassName(ClassName&) = delete; \
  28. ClassName(const ClassName&) = delete; \
  29. ClassName& operator=(const ClassName&) = delete; \
  30. static void* operator new(size_t) = delete;
  31. #else
  32. # define LINKED_LIST_DECLARATIONS(ClassName) \
  33. ClassName(ClassName&); \
  34. ClassName(const ClassName&); \
  35. ClassName& operator=(const ClassName&);
  36. #endif
  37. typedef struct list_head k_list_head;
  38. // -----------------------------------------------------------------------
  39. // Abstract Linked List class
  40. // _allocate() and _deallocate are virtual calls provided by subclasses
  41. // NOTE: data-type classes are allowed to throw on creation, but NOT on deletion!
  42. template<typename T>
  43. class AbstractLinkedList
  44. {
  45. protected:
  46. struct Data {
  47. T value;
  48. k_list_head siblings;
  49. };
  50. AbstractLinkedList(const bool needsCopyCtr) noexcept
  51. : fDataSize(sizeof(Data)),
  52. fCount(0),
  53. fNeedsCopyCtr(needsCopyCtr)
  54. {
  55. _init();
  56. }
  57. public:
  58. virtual ~AbstractLinkedList() noexcept
  59. {
  60. CARLA_SAFE_ASSERT(fCount == 0);
  61. }
  62. class Itenerator {
  63. public:
  64. Itenerator(const k_list_head* queue) noexcept
  65. : fData(nullptr),
  66. fEntry(queue->next),
  67. fEntry2(fEntry->next),
  68. fQueue(queue)
  69. {
  70. CARLA_SAFE_ASSERT(fEntry != nullptr);
  71. CARLA_SAFE_ASSERT(fEntry2 != nullptr);
  72. CARLA_SAFE_ASSERT(fQueue != nullptr);
  73. }
  74. bool valid() const noexcept
  75. {
  76. return (fEntry != fQueue);
  77. }
  78. void next() noexcept
  79. {
  80. fEntry = fEntry2;
  81. fEntry2 = fEntry->next;
  82. }
  83. T& getValue() noexcept
  84. {
  85. fData = list_entry(fEntry, Data, siblings);
  86. return fData->value;
  87. }
  88. private:
  89. Data* fData;
  90. k_list_head* fEntry;
  91. k_list_head* fEntry2;
  92. const k_list_head* const fQueue;
  93. friend class AbstractLinkedList;
  94. };
  95. Itenerator begin() const noexcept
  96. {
  97. return Itenerator(&fQueue);
  98. }
  99. void clear() noexcept
  100. {
  101. if (fCount != 0)
  102. {
  103. k_list_head* entry;
  104. k_list_head* entry2;
  105. list_for_each_safe(entry, entry2, &fQueue)
  106. {
  107. if (Data* data = list_entry(entry, Data, siblings))
  108. {
  109. data->~Data();
  110. _deallocate(data);
  111. }
  112. }
  113. }
  114. _init();
  115. }
  116. size_t count() const noexcept
  117. {
  118. return fCount;
  119. }
  120. bool isEmpty() const noexcept
  121. {
  122. return (fCount == 0);
  123. }
  124. bool append(const T& value) noexcept
  125. {
  126. return _add(value, true, &fQueue);
  127. }
  128. bool appendAt(const T& value, const Itenerator& it) noexcept
  129. {
  130. return _add(value, true, it.fEntry->next);
  131. }
  132. bool insert(const T& value) noexcept
  133. {
  134. return _add(value, false, &fQueue);
  135. }
  136. bool insertAt(const T& value, const Itenerator& it) noexcept
  137. {
  138. return _add(value, false, it.fEntry->prev);
  139. }
  140. T& getAt(const size_t index) const noexcept
  141. {
  142. if (fCount == 0 || index >= fCount)
  143. return fRetValue;
  144. size_t i = 0;
  145. Data* data = nullptr;
  146. k_list_head* entry;
  147. k_list_head* entry2;
  148. list_for_each_safe(entry, entry2, &fQueue)
  149. {
  150. if (index != i++)
  151. continue;
  152. data = list_entry(entry, Data, siblings);
  153. if (data != nullptr)
  154. fRetValue = data->value;
  155. break;
  156. }
  157. return fRetValue;
  158. }
  159. T& getAt(const size_t index, const bool removeObj) noexcept
  160. {
  161. if (fCount == 0 || index >= fCount)
  162. return fRetValue;
  163. size_t i = 0;
  164. Data* data = nullptr;
  165. k_list_head* entry;
  166. k_list_head* entry2;
  167. list_for_each_safe(entry, entry2, &fQueue)
  168. {
  169. if (index != i++)
  170. continue;
  171. data = list_entry(entry, Data, siblings);
  172. if (data != nullptr)
  173. fRetValue = data->value;
  174. if (removeObj)
  175. {
  176. --fCount;
  177. list_del(entry);
  178. if (data != nullptr)
  179. {
  180. data->~Data();
  181. _deallocate(data);
  182. }
  183. }
  184. break;
  185. }
  186. return fRetValue;
  187. }
  188. T& getFirst(const bool removeObj = false) noexcept
  189. {
  190. return _getFirstOrLast(true, removeObj);
  191. }
  192. T& getLast(const bool removeObj = false) noexcept
  193. {
  194. return _getFirstOrLast(false, removeObj);
  195. }
  196. void remove(Itenerator& it) noexcept
  197. {
  198. CARLA_SAFE_ASSERT_RETURN(it.fEntry != nullptr,);
  199. --fCount;
  200. list_del(it.fEntry);
  201. CARLA_SAFE_ASSERT_RETURN(it.fData != nullptr,);
  202. it.fData->~Data();
  203. _deallocate(it.fData);
  204. }
  205. bool removeOne(const T& value) noexcept
  206. {
  207. Data* data = nullptr;
  208. k_list_head* entry;
  209. k_list_head* entry2;
  210. list_for_each_safe(entry, entry2, &fQueue)
  211. {
  212. data = list_entry(entry, Data, siblings);
  213. CARLA_SAFE_ASSERT_CONTINUE(data != nullptr);
  214. if (data->value == value)
  215. {
  216. --fCount;
  217. list_del(entry);
  218. data->~Data();
  219. _deallocate(data);
  220. break;
  221. }
  222. }
  223. return (data != nullptr);
  224. }
  225. void removeAll(const T& value) noexcept
  226. {
  227. Data* data;
  228. k_list_head* entry;
  229. k_list_head* entry2;
  230. list_for_each_safe(entry, entry2, &fQueue)
  231. {
  232. data = list_entry(entry, Data, siblings);
  233. CARLA_SAFE_ASSERT_CONTINUE(data != nullptr);
  234. if (data->value == value)
  235. {
  236. --fCount;
  237. list_del(entry);
  238. data->~Data();
  239. _deallocate(data);
  240. }
  241. }
  242. }
  243. void spliceAppend(AbstractLinkedList& list, const bool init = true) noexcept
  244. {
  245. if (init)
  246. {
  247. list_splice_tail_init(&fQueue, &list.fQueue);
  248. list.fCount += fCount;
  249. fCount = 0;
  250. }
  251. else
  252. {
  253. list_splice_tail(&fQueue, &list.fQueue);
  254. list.fCount += fCount;
  255. }
  256. }
  257. void spliceInsert(AbstractLinkedList& list, const bool init = true) noexcept
  258. {
  259. if (init)
  260. {
  261. list_splice_init(&fQueue, &list.fQueue);
  262. list.fCount += fCount;
  263. fCount = 0;
  264. }
  265. else
  266. {
  267. list_splice(&fQueue, &list.fQueue);
  268. list.fCount += fCount;
  269. }
  270. }
  271. protected:
  272. const size_t fDataSize;
  273. size_t fCount;
  274. k_list_head fQueue;
  275. const bool fNeedsCopyCtr;
  276. virtual Data* _allocate() noexcept = 0;
  277. virtual void _deallocate(Data* const dataPtr) noexcept = 0;
  278. private:
  279. mutable T fRetValue;
  280. void _init() noexcept
  281. {
  282. fCount = 0;
  283. INIT_LIST_HEAD(&fQueue);
  284. }
  285. bool _add(const T& value, const bool inTail, k_list_head* const queue) noexcept
  286. {
  287. if (Data* const data = _allocate())
  288. {
  289. if (fNeedsCopyCtr)
  290. {
  291. try {
  292. new(data)Data();
  293. }
  294. catch(...) {
  295. _deallocate(data);
  296. return false;
  297. }
  298. try {
  299. data->value = value;
  300. }
  301. catch(...) {
  302. data->~Data();
  303. _deallocate(data);
  304. return false;
  305. }
  306. }
  307. else
  308. {
  309. std::memcpy(&data->value, &value, fDataSize);
  310. }
  311. if (inTail)
  312. list_add_tail(&data->siblings, queue);
  313. else
  314. list_add(&data->siblings, queue);
  315. ++fCount;
  316. return true;
  317. }
  318. return false;
  319. }
  320. T& _getFirstOrLast(const bool first, const bool removeObj) noexcept
  321. {
  322. if (fCount == 0)
  323. return fRetValue;
  324. k_list_head* const entry = first ? fQueue.next : fQueue.prev;
  325. Data* data = list_entry(entry, Data, siblings);
  326. if (data != nullptr)
  327. fRetValue = data->value;
  328. if (removeObj)
  329. {
  330. --fCount;
  331. list_del(entry);
  332. if (data != nullptr)
  333. {
  334. data->~Data();
  335. _deallocate(data);
  336. }
  337. }
  338. return fRetValue;
  339. }
  340. LINKED_LIST_DECLARATIONS(AbstractLinkedList)
  341. };
  342. // -----------------------------------------------------------------------
  343. // LinkedList
  344. template<typename T>
  345. class LinkedList : public AbstractLinkedList<T>
  346. {
  347. public:
  348. LinkedList(const bool needsCopyCtr = false) noexcept
  349. : AbstractLinkedList<T>(needsCopyCtr) {}
  350. private:
  351. typename AbstractLinkedList<T>::Data* _allocate() noexcept override
  352. {
  353. return (typename AbstractLinkedList<T>::Data*)std::malloc(this->fDataSize);
  354. }
  355. void _deallocate(typename AbstractLinkedList<T>::Data* const dataPtr) noexcept override
  356. {
  357. CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr,);
  358. std::free(dataPtr);
  359. }
  360. LINKED_LIST_DECLARATIONS(LinkedList)
  361. };
  362. // -----------------------------------------------------------------------
  363. #endif // LINKED_LIST_HPP_INCLUDED