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.

List.hpp 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. /*
  2. * High-level, templated, C++ doubly-linked list
  3. * Copyright (C) 2013 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 LIST_HPP_INCLUDED
  18. #define 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 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 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 List class
  40. // _allocate() and _deallocate are virtual calls provided by subclasses
  41. template<typename T>
  42. class AbstractList
  43. {
  44. protected:
  45. struct Data {
  46. T value;
  47. k_list_head siblings;
  48. };
  49. AbstractList()
  50. : fDataSize(sizeof(Data)),
  51. fCount(0)
  52. {
  53. _init();
  54. }
  55. virtual ~AbstractList()
  56. {
  57. CARLA_ASSERT(fCount == 0);
  58. }
  59. public:
  60. class Itenerator {
  61. public:
  62. Itenerator(const k_list_head* queue)
  63. : fEntry(queue->next),
  64. fEntry2(fEntry->next),
  65. fQueue(queue),
  66. fData(nullptr)
  67. {
  68. CARLA_ASSERT(fEntry != nullptr);
  69. CARLA_ASSERT(fEntry2 != nullptr);
  70. CARLA_ASSERT(fQueue != nullptr);
  71. }
  72. bool valid() const noexcept
  73. {
  74. return (fEntry != fQueue);
  75. }
  76. void next() noexcept
  77. {
  78. fEntry = fEntry2;
  79. fEntry2 = fEntry->next;
  80. }
  81. T& getValue()
  82. {
  83. fData = list_entry(fEntry, Data, siblings);
  84. CARLA_ASSERT(fData != nullptr);
  85. return fData->value;
  86. }
  87. const T& getConstValue()
  88. {
  89. fConstData = list_entry_const(fEntry, Data, siblings);
  90. CARLA_ASSERT(fConstData != nullptr);
  91. return fConstData->value;
  92. }
  93. #if 0
  94. T& operator*() const
  95. {
  96. return getValue();
  97. }
  98. #endif
  99. private:
  100. k_list_head* fEntry;
  101. k_list_head* fEntry2;
  102. const k_list_head* const fQueue;
  103. union {
  104. Data* fData;
  105. const Data* fConstData;
  106. };
  107. friend class AbstractList;
  108. };
  109. Itenerator begin() const
  110. {
  111. return Itenerator(&fQueue);
  112. }
  113. void clear()
  114. {
  115. if (fCount != 0)
  116. {
  117. k_list_head* entry;
  118. k_list_head* entry2;
  119. list_for_each_safe(entry, entry2, &fQueue)
  120. {
  121. if (Data* data = list_entry(entry, Data, siblings))
  122. {
  123. data->~Data();
  124. _deallocate(data);
  125. }
  126. }
  127. }
  128. _init();
  129. }
  130. // temporary fix for some const issue in midi-base.hpp
  131. void clear_const()
  132. {
  133. if (fCount != 0)
  134. {
  135. k_list_head* entry;
  136. k_list_head* entry2;
  137. list_for_each_safe(entry, entry2, &fQueue)
  138. {
  139. if (const Data* data = list_entry_const(entry, Data, siblings))
  140. {
  141. data->~Data();
  142. union CData {
  143. const Data* cdata;
  144. Data* data;
  145. };
  146. CData d;
  147. d.cdata = data;
  148. _deallocate(d.data);
  149. }
  150. }
  151. }
  152. _init();
  153. }
  154. size_t count() const noexcept
  155. {
  156. return fCount;
  157. }
  158. bool isEmpty() const noexcept
  159. {
  160. return (fCount == 0);
  161. }
  162. bool append(const T& value)
  163. {
  164. if (Data* const data = _allocate())
  165. {
  166. new(data)Data();
  167. data->value = value;
  168. list_add_tail(&data->siblings, &fQueue);
  169. ++fCount;
  170. return true;
  171. }
  172. return false;
  173. }
  174. bool appendAt(const T& value, const Itenerator& it)
  175. {
  176. if (Data* const data = _allocate())
  177. {
  178. new(data)Data();
  179. data->value = value;
  180. list_add_tail(&data->siblings, it.fEntry->next);
  181. ++fCount;
  182. return true;
  183. }
  184. return false;
  185. }
  186. bool insert(const T& value)
  187. {
  188. if (Data* const data = _allocate())
  189. {
  190. new(data)Data();
  191. data->value = value;
  192. list_add(&data->siblings, &fQueue);
  193. ++fCount;
  194. return true;
  195. }
  196. return false;
  197. }
  198. bool insertAt(const T& value, const Itenerator& it)
  199. {
  200. if (Data* const data = _allocate())
  201. {
  202. new(data)Data();
  203. data->value = value;
  204. list_add(&data->siblings, it.fEntry->prev);
  205. ++fCount;
  206. return true;
  207. }
  208. return false;
  209. }
  210. T& getAt(const size_t index, const bool remove = false)
  211. {
  212. if (fCount == 0 || index >= fCount)
  213. return fRetValue;
  214. size_t i = 0;
  215. Data* data = nullptr;
  216. k_list_head* entry;
  217. k_list_head* entry2;
  218. list_for_each_safe(entry, entry2, &fQueue)
  219. {
  220. if (index != i++)
  221. continue;
  222. data = list_entry(entry, Data, siblings);
  223. if (data != nullptr)
  224. fRetValue = data->value;
  225. if (remove)
  226. {
  227. --fCount;
  228. list_del(entry);
  229. if (data != nullptr)
  230. {
  231. data->~Data();
  232. _deallocate(data);
  233. }
  234. }
  235. break;
  236. }
  237. return fRetValue;
  238. }
  239. T& getFirst(const bool remove = false)
  240. {
  241. return _getFirstOrLast(true, remove);
  242. }
  243. T& getLast(const bool remove = false)
  244. {
  245. return _getFirstOrLast(false, remove);
  246. }
  247. void remove(Itenerator& it)
  248. {
  249. CARLA_SAFE_ASSERT_RETURN(it.fEntry != nullptr,);
  250. --fCount;
  251. list_del(it.fEntry);
  252. CARLA_SAFE_ASSERT_RETURN(it.fData != nullptr,);
  253. it.fData->~Data();
  254. _deallocate(it.fData);
  255. }
  256. bool removeOne(const T& value)
  257. {
  258. Data* data = nullptr;
  259. k_list_head* entry;
  260. k_list_head* entry2;
  261. list_for_each_safe(entry, entry2, &fQueue)
  262. {
  263. data = list_entry(entry, Data, siblings);
  264. CARLA_SAFE_ASSERT_CONTINUE(data != nullptr);
  265. if (data->value == value)
  266. {
  267. --fCount;
  268. list_del(entry);
  269. data->~Data();
  270. _deallocate(data);
  271. break;
  272. }
  273. }
  274. return (data != nullptr);
  275. }
  276. void removeAll(const T& value)
  277. {
  278. Data* data;
  279. k_list_head* entry;
  280. k_list_head* entry2;
  281. list_for_each_safe(entry, entry2, &fQueue)
  282. {
  283. data = list_entry(entry, Data, siblings);
  284. CARLA_SAFE_ASSERT_CONTINUE(data != nullptr);
  285. if (data->value == value)
  286. {
  287. --fCount;
  288. list_del(entry);
  289. data->~Data();
  290. _deallocate(data);
  291. }
  292. }
  293. }
  294. void spliceAppend(AbstractList& list, const bool init = true)
  295. {
  296. if (init)
  297. {
  298. list_splice_tail_init(&fQueue, &list.fQueue);
  299. list.fCount += fCount;
  300. fCount = 0;
  301. }
  302. else
  303. {
  304. list_splice_tail(&fQueue, &list.fQueue);
  305. list.fCount += fCount;
  306. }
  307. }
  308. void spliceInsert(AbstractList& list, const bool init = true)
  309. {
  310. if (init)
  311. {
  312. list_splice_init(&fQueue, &list.fQueue);
  313. list.fCount += fCount;
  314. fCount = 0;
  315. }
  316. else
  317. {
  318. list_splice(&fQueue, &list.fQueue);
  319. list.fCount += fCount;
  320. }
  321. }
  322. protected:
  323. const size_t fDataSize;
  324. size_t fCount;
  325. k_list_head fQueue;
  326. virtual Data* _allocate() = 0;
  327. virtual void _deallocate(Data*& dataPtr) = 0;
  328. private:
  329. T fRetValue;
  330. void _init() noexcept
  331. {
  332. fCount = 0;
  333. INIT_LIST_HEAD(&fQueue);
  334. }
  335. T& _getFirstOrLast(const bool first, const bool remove)
  336. {
  337. if (fCount == 0)
  338. return fRetValue;
  339. k_list_head* const entry = first ? fQueue.next : fQueue.prev;
  340. Data* data = list_entry(entry, Data, siblings);
  341. if (data != nullptr)
  342. fRetValue = data->value;
  343. if (remove)
  344. {
  345. --fCount;
  346. list_del(entry);
  347. if (data != nullptr)
  348. {
  349. data->~Data();
  350. _deallocate(data);
  351. }
  352. }
  353. return fRetValue;
  354. }
  355. LIST_DECLARATIONS(AbstractList)
  356. };
  357. // -----------------------------------------------------------------------
  358. // List
  359. template<typename T>
  360. class List : public AbstractList<T>
  361. {
  362. public:
  363. List()
  364. {
  365. }
  366. private:
  367. typename AbstractList<T>::Data* _allocate() override
  368. {
  369. return (typename AbstractList<T>::Data*)std::malloc(this->fDataSize);
  370. }
  371. void _deallocate(typename AbstractList<T>::Data*& dataPtr) override
  372. {
  373. CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr,);
  374. std::free(dataPtr);
  375. dataPtr = nullptr;
  376. }
  377. LIST_DECLARATIONS(List)
  378. };
  379. // -----------------------------------------------------------------------
  380. #endif // LIST_HPP_INCLUDED