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.

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