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.

463 lines
11KB

  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. void setValue(const T& value) noexcept
  89. {
  90. fData = list_entry(fEntry, Data, siblings);
  91. fData->value = value;
  92. }
  93. private:
  94. Data* fData;
  95. k_list_head* fEntry;
  96. k_list_head* fEntry2;
  97. const k_list_head* const fQueue;
  98. friend class AbstractLinkedList;
  99. };
  100. Itenerator begin() const noexcept
  101. {
  102. return Itenerator(&fQueue);
  103. }
  104. void clear() noexcept
  105. {
  106. if (fCount != 0)
  107. {
  108. k_list_head* entry;
  109. k_list_head* entry2;
  110. list_for_each_safe(entry, entry2, &fQueue)
  111. {
  112. if (Data* data = list_entry(entry, Data, siblings))
  113. {
  114. if (fNeedsCopyCtr)
  115. data->~Data();
  116. _deallocate(data);
  117. }
  118. }
  119. }
  120. _init();
  121. }
  122. size_t count() const noexcept
  123. {
  124. return fCount;
  125. }
  126. bool isEmpty() const noexcept
  127. {
  128. return (fCount == 0);
  129. }
  130. bool append(const T& value) noexcept
  131. {
  132. return _add(value, true, &fQueue);
  133. }
  134. bool appendAt(const T& value, const Itenerator& it) noexcept
  135. {
  136. return _add(value, true, it.fEntry->next);
  137. }
  138. bool insert(const T& value) noexcept
  139. {
  140. return _add(value, false, &fQueue);
  141. }
  142. bool insertAt(const T& value, const Itenerator& it) noexcept
  143. {
  144. return _add(value, false, it.fEntry->prev);
  145. }
  146. T& getAt(const size_t index) const noexcept
  147. {
  148. if (fCount == 0 || index >= fCount)
  149. return fRetValue;
  150. size_t i = 0;
  151. Data* data = nullptr;
  152. k_list_head* entry;
  153. k_list_head* entry2;
  154. list_for_each_safe(entry, entry2, &fQueue)
  155. {
  156. if (index != i++)
  157. continue;
  158. data = list_entry(entry, Data, siblings);
  159. if (data != nullptr)
  160. fRetValue = data->value;
  161. break;
  162. }
  163. return fRetValue;
  164. }
  165. T& getAt(const size_t index, const bool removeObj) noexcept
  166. {
  167. if (fCount == 0 || index >= fCount)
  168. return fRetValue;
  169. size_t i = 0;
  170. Data* data = nullptr;
  171. k_list_head* entry;
  172. k_list_head* entry2;
  173. list_for_each_safe(entry, entry2, &fQueue)
  174. {
  175. if (index != i++)
  176. continue;
  177. data = list_entry(entry, Data, siblings);
  178. if (data != nullptr)
  179. fRetValue = data->value;
  180. if (removeObj)
  181. {
  182. --fCount;
  183. list_del(entry);
  184. if (data != nullptr)
  185. {
  186. if (fNeedsCopyCtr)
  187. data->~Data();
  188. _deallocate(data);
  189. }
  190. }
  191. break;
  192. }
  193. return fRetValue;
  194. }
  195. T& getFirst(const bool removeObj = false) noexcept
  196. {
  197. return _getFirstOrLast(true, removeObj);
  198. }
  199. T& getLast(const bool removeObj = false) noexcept
  200. {
  201. return _getFirstOrLast(false, removeObj);
  202. }
  203. void remove(Itenerator& it) noexcept
  204. {
  205. CARLA_SAFE_ASSERT_RETURN(it.fEntry != nullptr,);
  206. --fCount;
  207. list_del(it.fEntry);
  208. CARLA_SAFE_ASSERT_RETURN(it.fData != nullptr,);
  209. if (fNeedsCopyCtr)
  210. it.fData->~Data();
  211. _deallocate(it.fData);
  212. }
  213. bool removeOne(const T& value) noexcept
  214. {
  215. Data* data = nullptr;
  216. k_list_head* entry;
  217. k_list_head* entry2;
  218. list_for_each_safe(entry, entry2, &fQueue)
  219. {
  220. data = list_entry(entry, Data, siblings);
  221. CARLA_SAFE_ASSERT_CONTINUE(data != nullptr);
  222. if (data->value == value)
  223. {
  224. --fCount;
  225. list_del(entry);
  226. if (fNeedsCopyCtr)
  227. data->~Data();
  228. _deallocate(data);
  229. break;
  230. }
  231. }
  232. return (data != nullptr);
  233. }
  234. void removeAll(const T& value) noexcept
  235. {
  236. Data* data;
  237. k_list_head* entry;
  238. k_list_head* entry2;
  239. list_for_each_safe(entry, entry2, &fQueue)
  240. {
  241. data = list_entry(entry, Data, siblings);
  242. CARLA_SAFE_ASSERT_CONTINUE(data != nullptr);
  243. if (data->value == value)
  244. {
  245. --fCount;
  246. list_del(entry);
  247. if (fNeedsCopyCtr)
  248. data->~Data();
  249. _deallocate(data);
  250. }
  251. }
  252. }
  253. void spliceAppend(AbstractLinkedList& list, const bool init = true) noexcept
  254. {
  255. if (init)
  256. {
  257. list_splice_tail_init(&fQueue, &list.fQueue);
  258. list.fCount += fCount;
  259. fCount = 0;
  260. }
  261. else
  262. {
  263. list_splice_tail(&fQueue, &list.fQueue);
  264. list.fCount += fCount;
  265. }
  266. }
  267. void spliceInsert(AbstractLinkedList& list, const bool init = true) noexcept
  268. {
  269. if (init)
  270. {
  271. list_splice_init(&fQueue, &list.fQueue);
  272. list.fCount += fCount;
  273. fCount = 0;
  274. }
  275. else
  276. {
  277. list_splice(&fQueue, &list.fQueue);
  278. list.fCount += fCount;
  279. }
  280. }
  281. protected:
  282. const size_t fDataSize;
  283. size_t fCount;
  284. k_list_head fQueue;
  285. const bool fNeedsCopyCtr;
  286. virtual Data* _allocate() noexcept = 0;
  287. virtual void _deallocate(Data* const dataPtr) noexcept = 0;
  288. private:
  289. mutable T fRetValue;
  290. void _init() noexcept
  291. {
  292. fCount = 0;
  293. INIT_LIST_HEAD(&fQueue);
  294. }
  295. bool _add(const T& value, const bool inTail, k_list_head* const queue) noexcept
  296. {
  297. if (Data* const data = _allocate())
  298. {
  299. if (fNeedsCopyCtr)
  300. {
  301. try {
  302. new(data)Data();
  303. }
  304. catch(...) {
  305. _deallocate(data);
  306. return false;
  307. }
  308. try {
  309. data->value = value;
  310. }
  311. catch(...) {
  312. data->~Data();
  313. _deallocate(data);
  314. return false;
  315. }
  316. }
  317. else
  318. {
  319. std::memcpy(&data->value, &value, fDataSize);
  320. }
  321. if (inTail)
  322. list_add_tail(&data->siblings, queue);
  323. else
  324. list_add(&data->siblings, queue);
  325. ++fCount;
  326. return true;
  327. }
  328. return false;
  329. }
  330. T& _getFirstOrLast(const bool first, const bool removeObj) noexcept
  331. {
  332. if (fCount == 0)
  333. return fRetValue;
  334. k_list_head* const entry = first ? fQueue.next : fQueue.prev;
  335. Data* data = list_entry(entry, Data, siblings);
  336. if (data != nullptr)
  337. fRetValue = data->value;
  338. if (removeObj)
  339. {
  340. --fCount;
  341. list_del(entry);
  342. if (data != nullptr)
  343. {
  344. if (fNeedsCopyCtr)
  345. data->~Data();
  346. _deallocate(data);
  347. }
  348. }
  349. return fRetValue;
  350. }
  351. LINKED_LIST_DECLARATIONS(AbstractLinkedList)
  352. };
  353. // -----------------------------------------------------------------------
  354. // LinkedList
  355. template<typename T>
  356. class LinkedList : public AbstractLinkedList<T>
  357. {
  358. public:
  359. LinkedList(const bool needsCopyCtr = false) noexcept
  360. : AbstractLinkedList<T>(needsCopyCtr) {}
  361. protected:
  362. typename AbstractLinkedList<T>::Data* _allocate() noexcept override
  363. {
  364. return (typename AbstractLinkedList<T>::Data*)std::malloc(this->fDataSize);
  365. }
  366. void _deallocate(typename AbstractLinkedList<T>::Data* const dataPtr) noexcept override
  367. {
  368. CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr,);
  369. std::free(dataPtr);
  370. }
  371. LINKED_LIST_DECLARATIONS(LinkedList)
  372. };
  373. // -----------------------------------------------------------------------
  374. #endif // LINKED_LIST_HPP_INCLUDED