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.

521 lines
13KB

  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. // -----------------------------------------------------------------------
  22. // Define list_entry and list_entry_const
  23. #ifndef offsetof
  24. # define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
  25. #endif
  26. #if (defined(__GNUC__) || defined(__clang__)) && ! defined(__STRICT_ANSI__)
  27. # define container_of(ptr, type, member) ({ \
  28. typeof( ((type *)0)->member ) *__mptr = (ptr); \
  29. (type *)( (char *)__mptr - offsetof(type, member) );})
  30. # define container_of_const(ptr, type, member) ({ \
  31. const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  32. (const type *)( (const char *)__mptr - offsetof(type, member) );})
  33. # define list_entry(ptr, type, member) \
  34. container_of(ptr, type, member)
  35. # define list_entry_const(ptr, type, member) \
  36. container_of_const(ptr, type, member)
  37. #else
  38. # define list_entry(ptr, type, member) \
  39. ((type *)((char *)(ptr)-offsetof(type, member)))
  40. # define list_entry_const(ptr, type, member) \
  41. ((const type *)((const char *)(ptr)-offsetof(type, member)))
  42. #endif
  43. // -----------------------------------------------------------------------
  44. // Abstract Linked List class
  45. // _allocate() and _deallocate are virtual calls provided by subclasses
  46. // NOTE: data-type classes are not allowed to throw
  47. template<typename T>
  48. class AbstractLinkedList
  49. {
  50. protected:
  51. struct ListHead {
  52. ListHead* next;
  53. ListHead* prev;
  54. };
  55. struct Data {
  56. T value;
  57. ListHead siblings;
  58. };
  59. AbstractLinkedList(const bool isClass) noexcept
  60. : kIsClass(isClass),
  61. kDataSize(sizeof(Data)),
  62. fCount(0),
  63. fQueue({&fQueue, &fQueue}) {}
  64. public:
  65. virtual ~AbstractLinkedList() noexcept
  66. {
  67. CARLA_SAFE_ASSERT(fCount == 0);
  68. }
  69. class Itenerator {
  70. public:
  71. Itenerator(const ListHead& queue) noexcept
  72. : fData(nullptr),
  73. fEntry(queue.next),
  74. fEntry2(fEntry->next),
  75. kQueue(queue)
  76. {
  77. CARLA_SAFE_ASSERT(fEntry != nullptr);
  78. CARLA_SAFE_ASSERT(fEntry2 != nullptr);
  79. }
  80. bool valid() const noexcept
  81. {
  82. return (fEntry != nullptr && fEntry != &kQueue);
  83. }
  84. void next() noexcept
  85. {
  86. fEntry = fEntry2;
  87. fEntry2 = (fEntry != nullptr) ? fEntry->next : nullptr;
  88. }
  89. T& getValue() noexcept
  90. {
  91. fData = list_entry(fEntry, Data, siblings);
  92. return fData->value;
  93. }
  94. void setValue(const T& value) noexcept
  95. {
  96. fData = list_entry(fEntry, Data, siblings);
  97. fData->value = value;
  98. }
  99. private:
  100. Data* fData;
  101. ListHead* fEntry;
  102. ListHead* fEntry2;
  103. const ListHead& kQueue;
  104. friend class AbstractLinkedList;
  105. };
  106. Itenerator begin() const noexcept
  107. {
  108. return Itenerator(fQueue);
  109. }
  110. void clear() noexcept
  111. {
  112. if (fCount == 0)
  113. return;
  114. ListHead* entry;
  115. ListHead* entry2;
  116. for (entry = fQueue.next, entry2 = entry->next; entry != &fQueue; entry = entry2, entry2 = entry->next)
  117. {
  118. Data* const data = list_entry(entry, Data, siblings);
  119. CARLA_SAFE_ASSERT_CONTINUE(data != nullptr);
  120. if (kIsClass)
  121. data->~Data();
  122. _deallocate(data);
  123. }
  124. _init();
  125. }
  126. size_t count() const noexcept
  127. {
  128. return fCount;
  129. }
  130. bool isEmpty() const noexcept
  131. {
  132. return (fCount == 0);
  133. }
  134. bool append(const T& value) noexcept
  135. {
  136. return _add(value, true, &fQueue);
  137. }
  138. bool appendAt(const T& value, const Itenerator& it) noexcept
  139. {
  140. return _add(value, true, it.fEntry->next);
  141. }
  142. bool insert(const T& value) noexcept
  143. {
  144. return _add(value, false, &fQueue);
  145. }
  146. bool insertAt(const T& value, const Itenerator& it) noexcept
  147. {
  148. return _add(value, false, it.fEntry->prev);
  149. }
  150. const T& getAt(const size_t index, const T& fallback) const noexcept
  151. {
  152. CARLA_SAFE_ASSERT_RETURN(fCount > 0 && index < fCount, fallback);
  153. size_t i = 0;
  154. ListHead* entry;
  155. ListHead* entry2;
  156. for (entry = fQueue.next, entry2 = entry->next; entry != &fQueue; entry = entry2, entry2 = entry->next)
  157. {
  158. if (index != i++)
  159. continue;
  160. return _get(entry, fallback);
  161. }
  162. return fallback;
  163. }
  164. T& getAt(const size_t index, T& fallback) const noexcept
  165. {
  166. CARLA_SAFE_ASSERT_RETURN(fCount > 0 && index < fCount, fallback);
  167. size_t i = 0;
  168. ListHead* entry;
  169. ListHead* entry2;
  170. for (entry = fQueue.next, entry2 = entry->next; entry != &fQueue; entry = entry2, entry2 = entry->next)
  171. {
  172. if (index != i++)
  173. continue;
  174. return _get(entry, fallback);
  175. }
  176. return fallback;
  177. }
  178. T getAt(const size_t index, T& fallback, const bool removeObj) noexcept
  179. {
  180. CARLA_SAFE_ASSERT_RETURN(fCount > 0 && index < fCount, fallback);
  181. size_t i = 0;
  182. ListHead* entry;
  183. ListHead* entry2;
  184. for (entry = fQueue.next, entry2 = entry->next; entry != &fQueue; entry = entry2, entry2 = entry->next)
  185. {
  186. if (index != i++)
  187. continue;
  188. return _get(entry, fallback, removeObj);
  189. }
  190. return fallback;
  191. }
  192. const T& getFirst(const T& fallback) const noexcept
  193. {
  194. CARLA_SAFE_ASSERT_RETURN(fCount > 0, fallback);
  195. return _get(fQueue.next, fallback);
  196. }
  197. T& getFirst(T& fallback) const noexcept
  198. {
  199. CARLA_SAFE_ASSERT_RETURN(fCount > 0, fallback);
  200. return _get(fQueue.next, fallback);
  201. }
  202. T getFirst(T& fallback, const bool removeObj) noexcept
  203. {
  204. CARLA_SAFE_ASSERT_RETURN(fCount > 0, fallback);
  205. return _get(fQueue.next, fallback, removeObj);
  206. }
  207. const T& getLast(const T& fallback) const noexcept
  208. {
  209. CARLA_SAFE_ASSERT_RETURN(fCount > 0, fallback);
  210. return _get(fQueue.prev, fallback);
  211. }
  212. T& getLast(T& fallback) const noexcept
  213. {
  214. CARLA_SAFE_ASSERT_RETURN(fCount > 0, fallback);
  215. return _get(fQueue.prev, fallback);
  216. }
  217. T getLast(T& fallback, const bool removeObj) noexcept
  218. {
  219. CARLA_SAFE_ASSERT_RETURN(fCount > 0, fallback);
  220. return _get(fQueue.prev, fallback, removeObj);
  221. }
  222. void remove(Itenerator& it) noexcept
  223. {
  224. CARLA_SAFE_ASSERT_RETURN(it.fEntry != nullptr,);
  225. CARLA_SAFE_ASSERT_RETURN(it.fData != nullptr,);
  226. _delete(it.fEntry, it.fData);
  227. }
  228. bool removeOne(const T& value) noexcept
  229. {
  230. ListHead* entry;
  231. ListHead* entry2;
  232. for (entry = fQueue.next, entry2 = entry->next; entry != &fQueue; entry = entry2, entry2 = entry->next)
  233. {
  234. Data* const data = list_entry(entry, Data, siblings);
  235. CARLA_SAFE_ASSERT_CONTINUE(data != nullptr);
  236. if (data->value != value)
  237. continue;
  238. _delete(entry, data);
  239. return true;
  240. }
  241. return false;
  242. }
  243. void removeAll(const T& value) noexcept
  244. {
  245. ListHead* entry;
  246. ListHead* entry2;
  247. for (entry = fQueue.next, entry2 = entry->next; entry != &fQueue; entry = entry2, entry2 = entry->next)
  248. {
  249. Data* const data = list_entry(entry, Data, siblings);
  250. CARLA_SAFE_ASSERT_CONTINUE(data != nullptr);
  251. if (data->value != value)
  252. continue;
  253. _delete(entry, data);
  254. }
  255. }
  256. void spliceAppendTo(AbstractLinkedList<T>& list) noexcept
  257. {
  258. if (fQueue.next == &fQueue)
  259. return;
  260. __list_splice_tail(&fQueue, &list.fQueue);
  261. list.fCount += fCount;
  262. _init();
  263. }
  264. void spliceInsertInto(AbstractLinkedList<T>& list) noexcept
  265. {
  266. if (fQueue.next == &fQueue)
  267. return;
  268. __list_splice(&fQueue, &list.fQueue);
  269. list.fCount += fCount;
  270. _init();
  271. }
  272. protected:
  273. const bool kIsClass;
  274. const size_t kDataSize;
  275. size_t fCount;
  276. ListHead fQueue;
  277. virtual Data* _allocate() noexcept = 0;
  278. virtual void _deallocate(Data* const dataPtr) noexcept = 0;
  279. private:
  280. void _init() noexcept
  281. {
  282. fCount = 0;
  283. fQueue.next = &fQueue;
  284. fQueue.prev = &fQueue;
  285. }
  286. void _createData(Data* const data, const T& value) noexcept
  287. {
  288. if (kIsClass)
  289. new(data)Data({value, {nullptr, nullptr}});
  290. else
  291. data->value = value;
  292. ++fCount;
  293. }
  294. bool _add(const T& value, const bool inTail, ListHead* const queue) noexcept
  295. {
  296. if (Data* const data = _allocate())
  297. {
  298. _createData(data, value);
  299. if (inTail)
  300. __list_add(data->siblings, queue->prev, queue);
  301. else
  302. __list_add(data->siblings, queue, queue->next);
  303. return true;
  304. }
  305. return false;
  306. }
  307. void _delete(ListHead* const entry, Data* const data) noexcept
  308. {
  309. __list_del(entry->prev, entry->next);
  310. entry->next = nullptr;
  311. entry->prev = nullptr;
  312. --fCount;
  313. if (kIsClass)
  314. data->~Data();
  315. _deallocate(data);
  316. }
  317. const T& _get(ListHead* const entry, const T& fallback) const noexcept
  318. {
  319. const Data* const data = list_entry_const(entry, Data, siblings);
  320. CARLA_SAFE_ASSERT_RETURN(data != nullptr, fallback);
  321. return data->value;
  322. }
  323. T& _get(ListHead* const entry, T& fallback) const noexcept
  324. {
  325. Data* const data = list_entry(entry, Data, siblings);
  326. CARLA_SAFE_ASSERT_RETURN(data != nullptr, fallback);
  327. return data->value;
  328. }
  329. T _get(ListHead* const entry, T& fallback, const bool removeObj) noexcept
  330. {
  331. Data* const data = list_entry(entry, Data, siblings);
  332. CARLA_SAFE_ASSERT_RETURN(data != nullptr, fallback);
  333. if (! removeObj)
  334. return data->value;
  335. const T value(data->value);
  336. _delete(entry, data);
  337. return value;
  338. }
  339. /*
  340. * Insert a new entry between two known consecutive entries.
  341. */
  342. static void __list_add(ListHead& new_, ListHead* const prev, ListHead* const next) noexcept
  343. {
  344. next->prev = &new_;
  345. new_.next = next;
  346. new_.prev = prev;
  347. prev->next = &new_;
  348. }
  349. /*
  350. * Delete a list entry by making the prev/next entries
  351. * point to each other.
  352. */
  353. static void __list_del(ListHead* const prev, ListHead* const next) noexcept
  354. {
  355. next->prev = prev;
  356. prev->next = next;
  357. }
  358. static void __list_splice(ListHead* const list, ListHead* const head) noexcept
  359. {
  360. ListHead* const first = list->next;
  361. ListHead* const last = list->prev;
  362. ListHead* const at = head->next;
  363. first->prev = head;
  364. head->next = first;
  365. last->next = at;
  366. at->prev = last;
  367. }
  368. static void __list_splice_tail(ListHead* const list, ListHead* const head) noexcept
  369. {
  370. ListHead* const first = list->next;
  371. ListHead* const last = list->prev;
  372. ListHead* const at = head->prev;
  373. first->prev = at;
  374. at->next = first;
  375. last->next = head;
  376. head->prev = last;
  377. }
  378. template<typename> friend class RtLinkedList;
  379. CARLA_PREVENT_VIRTUAL_HEAP_ALLOCATION
  380. CARLA_DECLARE_NON_COPY_CLASS(AbstractLinkedList)
  381. };
  382. // -----------------------------------------------------------------------
  383. // LinkedList
  384. template<typename T>
  385. class LinkedList : public AbstractLinkedList<T>
  386. {
  387. public:
  388. LinkedList(const bool isClass = false) noexcept
  389. : AbstractLinkedList<T>(isClass) {}
  390. protected:
  391. typename AbstractLinkedList<T>::Data* _allocate() noexcept override
  392. {
  393. return (typename AbstractLinkedList<T>::Data*)std::malloc(this->kDataSize);
  394. }
  395. void _deallocate(typename AbstractLinkedList<T>::Data* const dataPtr) noexcept override
  396. {
  397. CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr,);
  398. std::free(dataPtr);
  399. }
  400. CARLA_PREVENT_VIRTUAL_HEAP_ALLOCATION
  401. CARLA_DECLARE_NON_COPY_CLASS(LinkedList)
  402. };
  403. // -----------------------------------------------------------------------
  404. #endif // LINKED_LIST_HPP_INCLUDED