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.

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