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.

443 lines
9.9KB

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