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.

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