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.

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