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.

573 lines
13KB

  1. /*
  2. * High-level, real-time safe, 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 RT_LIST_HPP_INCLUDED
  18. #define RT_LIST_HPP_INCLUDED
  19. #include "CarlaUtils.hpp"
  20. #include <new>
  21. extern "C" {
  22. #include "rtmempool/list.h"
  23. #include "rtmempool/rtmempool.h"
  24. }
  25. // Declare non copyable and prevent heap allocation
  26. #define LIST_DECLARATIONS(ClassName) \
  27. ClassName(ClassName&); \
  28. ClassName(const ClassName&); \
  29. ClassName& operator=(const ClassName&); \
  30. static void* operator new (size_t) { return nullptr; } \
  31. static void operator delete (void*) {}
  32. typedef struct list_head k_list_head;
  33. // -----------------------------------------------------------------------
  34. // Abstract List class
  35. // _allocate() and _deallocate are virtual calls provided by subclasses
  36. template<typename T>
  37. class List
  38. {
  39. protected:
  40. struct Data {
  41. T value;
  42. k_list_head siblings;
  43. };
  44. List()
  45. : fDataSize(sizeof(Data)),
  46. fCount(0)
  47. {
  48. _init();
  49. }
  50. virtual ~List()
  51. {
  52. CARLA_ASSERT(fCount == 0);
  53. }
  54. public:
  55. class Itenerator {
  56. public:
  57. Itenerator(const k_list_head* queue)
  58. : fData(nullptr),
  59. fEntry(queue->next),
  60. fEntry2(fEntry->next),
  61. fQueue(queue)
  62. {
  63. CARLA_ASSERT(fEntry != nullptr);
  64. CARLA_ASSERT(fEntry2 != nullptr);
  65. CARLA_ASSERT(fQueue != nullptr);
  66. }
  67. bool valid() const noexcept
  68. {
  69. return (fEntry != fQueue);
  70. }
  71. void next() noexcept
  72. {
  73. fEntry = fEntry2;
  74. fEntry2 = fEntry->next;
  75. }
  76. T& operator*()
  77. {
  78. fData = list_entry(fEntry, Data, siblings);
  79. CARLA_ASSERT(fData != nullptr);
  80. return fData->value;
  81. }
  82. private:
  83. Data* fData;
  84. k_list_head* fEntry;
  85. k_list_head* fEntry2;
  86. const k_list_head* const fQueue;
  87. friend class List;
  88. };
  89. Itenerator begin() const
  90. {
  91. return Itenerator(&fQueue);
  92. }
  93. void clear()
  94. {
  95. if (fCount != 0)
  96. {
  97. k_list_head* entry;
  98. k_list_head* entry2;
  99. list_for_each_safe(entry, entry2, &fQueue)
  100. {
  101. if (Data* data = list_entry(entry, Data, siblings))
  102. {
  103. data->~Data();
  104. _deallocate(data);
  105. }
  106. }
  107. }
  108. _init();
  109. }
  110. size_t count() const noexcept
  111. {
  112. return fCount;
  113. }
  114. bool isEmpty() const noexcept
  115. {
  116. return (fCount == 0);
  117. }
  118. bool append(const T& value)
  119. {
  120. if (Data* const data = _allocate())
  121. {
  122. new(data)Data();
  123. data->value = value;
  124. list_add_tail(&data->siblings, &fQueue);
  125. ++fCount;
  126. return true;
  127. }
  128. return false;
  129. }
  130. bool appendAt(const T& value, const Itenerator& it)
  131. {
  132. if (Data* const data = _allocate())
  133. {
  134. new(data)Data();
  135. data->value = value;
  136. list_add_tail(&data->siblings, it.fEntry->next);
  137. ++fCount;
  138. return true;
  139. }
  140. return false;
  141. }
  142. bool insert(const T& value)
  143. {
  144. if (Data* const data = _allocate())
  145. {
  146. new(data)Data();
  147. data->value = value;
  148. list_add(&data->siblings, &fQueue);
  149. ++fCount;
  150. return true;
  151. }
  152. return false;
  153. }
  154. bool insertAt(const T& value, const Itenerator& it)
  155. {
  156. if (Data* const data = _allocate())
  157. {
  158. new(data)Data();
  159. data->value = value;
  160. list_add(&data->siblings, it.fEntry->prev);
  161. ++fCount;
  162. return true;
  163. }
  164. return false;
  165. }
  166. T& getAt(const size_t index, const bool remove = false)
  167. {
  168. if (fCount == 0 || index >= fCount)
  169. return fRetValue;
  170. size_t i = 0;
  171. Data* data = nullptr;
  172. k_list_head* entry;
  173. k_list_head* entry2;
  174. list_for_each_safe(entry, entry2, &fQueue)
  175. {
  176. if (index != i++)
  177. continue;
  178. data = list_entry(entry, Data, siblings);
  179. if (data != nullptr)
  180. fRetValue = data->value;
  181. if (remove)
  182. {
  183. --fCount;
  184. list_del(entry);
  185. if (data != nullptr)
  186. {
  187. data->~Data();
  188. _deallocate(data);
  189. }
  190. }
  191. break;
  192. }
  193. return fRetValue;
  194. }
  195. T& getFirst(const bool remove = false)
  196. {
  197. return _getFirstOrLast(true, remove);
  198. }
  199. T& getLast(const bool remove = false)
  200. {
  201. return _getFirstOrLast(false, remove);
  202. }
  203. void remove(Itenerator& it)
  204. {
  205. CARLA_ASSERT(it.fEntry != nullptr);
  206. CARLA_ASSERT(it.fData != nullptr);
  207. if (it.fEntry != nullptr && it.fData != nullptr)
  208. {
  209. --fCount;
  210. list_del(it.fEntry);
  211. it.fData->~Data();
  212. _deallocate(it.fData);
  213. }
  214. }
  215. bool removeOne(const T& value)
  216. {
  217. Data* data = nullptr;
  218. k_list_head* entry;
  219. k_list_head* entry2;
  220. list_for_each_safe(entry, entry2, &fQueue)
  221. {
  222. data = list_entry(entry, Data, siblings);
  223. CARLA_SAFE_ASSERT_CONTINUE(data != nullptr);
  224. if (data->value == value)
  225. {
  226. --fCount;
  227. list_del(entry);
  228. data->~Data();
  229. _deallocate(data);
  230. break;
  231. }
  232. }
  233. return (data != nullptr);
  234. }
  235. void removeAll(const T& value)
  236. {
  237. Data* data;
  238. k_list_head* entry;
  239. k_list_head* entry2;
  240. list_for_each_safe(entry, entry2, &fQueue)
  241. {
  242. data = list_entry(entry, Data, siblings);
  243. CARLA_SAFE_ASSERT_CONTINUE(data != nullptr);
  244. if (data->value == value)
  245. {
  246. --fCount;
  247. list_del(entry);
  248. data->~Data();
  249. _deallocate(data);
  250. }
  251. }
  252. }
  253. void spliceAppend(List& list, const bool init = true)
  254. {
  255. if (init)
  256. {
  257. list_splice_tail_init(&fQueue, &list.fQueue);
  258. list.fCount += fCount;
  259. fCount = 0;
  260. }
  261. else
  262. {
  263. list_splice_tail(&fQueue, &list.fQueue);
  264. list.fCount += fCount;
  265. }
  266. }
  267. void spliceInsert(List& list, const bool init = true)
  268. {
  269. if (init)
  270. {
  271. list_splice_init(&fQueue, &list.fQueue);
  272. list.fCount += fCount;
  273. fCount = 0;
  274. }
  275. else
  276. {
  277. list_splice(&fQueue, &list.fQueue);
  278. list.fCount += fCount;
  279. }
  280. }
  281. protected:
  282. const size_t fDataSize;
  283. size_t fCount;
  284. k_list_head fQueue;
  285. virtual Data* _allocate() = 0;
  286. virtual void _deallocate(Data*& dataPtr) = 0;
  287. private:
  288. T fRetValue;
  289. void _init() noexcept
  290. {
  291. fCount = 0;
  292. INIT_LIST_HEAD(&fQueue);
  293. }
  294. T& _getFirstOrLast(const bool first, const bool remove)
  295. {
  296. if (fCount == 0)
  297. return fRetValue;
  298. k_list_head* const entry = first ? fQueue.next : fQueue.prev;
  299. Data* data = list_entry(entry, Data, siblings);
  300. if (data != nullptr)
  301. fRetValue = data->value;
  302. if (remove)
  303. {
  304. --fCount;
  305. list_del(entry);
  306. if (data != nullptr)
  307. {
  308. data->~Data();
  309. _deallocate(data);
  310. }
  311. }
  312. return fRetValue;
  313. }
  314. LIST_DECLARATIONS(List)
  315. };
  316. // -----------------------------------------------------------------------
  317. // Realtime safe list
  318. template<typename T>
  319. class RtList : public List<T>
  320. {
  321. public:
  322. // -------------------------------------------------------------------
  323. // RtMemPool C++ class
  324. class Pool
  325. {
  326. public:
  327. Pool(const size_t minPreallocated, const size_t maxPreallocated)
  328. : fHandle(nullptr),
  329. fDataSize(sizeof(typename List<T>::Data))
  330. {
  331. resize(minPreallocated, maxPreallocated);
  332. }
  333. ~Pool()
  334. {
  335. if (fHandle != nullptr)
  336. {
  337. rtsafe_memory_pool_destroy(fHandle);
  338. fHandle = nullptr;
  339. }
  340. }
  341. void* allocate_atomic()
  342. {
  343. return rtsafe_memory_pool_allocate_atomic(fHandle);
  344. }
  345. void* allocate_sleepy()
  346. {
  347. return rtsafe_memory_pool_allocate_sleepy(fHandle);
  348. }
  349. void deallocate(void* const dataPtr)
  350. {
  351. rtsafe_memory_pool_deallocate(fHandle, dataPtr);
  352. }
  353. void resize(const size_t minPreallocated, const size_t maxPreallocated)
  354. {
  355. if (fHandle != nullptr)
  356. {
  357. rtsafe_memory_pool_destroy(fHandle);
  358. fHandle = nullptr;
  359. }
  360. rtsafe_memory_pool_create(&fHandle, nullptr, fDataSize, minPreallocated, maxPreallocated);
  361. CARLA_ASSERT(fHandle != nullptr);
  362. }
  363. bool operator==(const Pool& pool) const noexcept
  364. {
  365. return (fHandle == pool.fHandle && fDataSize == pool.fDataSize);
  366. }
  367. bool operator!=(const Pool& pool) const noexcept
  368. {
  369. return (fHandle != pool.fHandle || fDataSize != pool.fDataSize);
  370. }
  371. private:
  372. RtMemPool_Handle fHandle;
  373. const size_t fDataSize;
  374. };
  375. // -------------------------------------------------------------------
  376. // Now the actual list code
  377. RtList(Pool& memPool)
  378. : fMemPool(memPool)
  379. {
  380. }
  381. ~RtList() override
  382. {
  383. }
  384. void append_sleepy(const T& value)
  385. {
  386. if (typename List<T>::Data* const data = _allocate_sleepy())
  387. {
  388. new(data)typename List<T>::Data();
  389. data->value = value;
  390. list_add_tail(&data->siblings, &this->fQueue);
  391. ++this->fCount;
  392. }
  393. }
  394. void insert_sleepy(const T& value)
  395. {
  396. if (typename List<T>::Data* const data = _allocate_sleepy())
  397. {
  398. new(data)typename List<T>::Data();
  399. data->value = value;
  400. list_add(&data->siblings, &this->fQueue);
  401. ++this->fCount;
  402. }
  403. }
  404. void resize(const size_t minPreallocated, const size_t maxPreallocated)
  405. {
  406. this->clear();
  407. fMemPool.resize(minPreallocated, maxPreallocated);
  408. }
  409. void spliceAppend(RtList& list, const bool init = true)
  410. {
  411. CARLA_ASSERT(fMemPool == list.fMemPool);
  412. List<T>::spliceAppend(list, init);
  413. }
  414. void spliceInsert(RtList& list, const bool init = true)
  415. {
  416. CARLA_ASSERT(fMemPool == list.fMemPool);
  417. List<T>::spliceInsert(list, init);
  418. }
  419. private:
  420. Pool& fMemPool;
  421. typename List<T>::Data* _allocate() override
  422. {
  423. return _allocate_atomic();
  424. }
  425. typename List<T>::Data* _allocate_atomic()
  426. {
  427. return (typename List<T>::Data*)fMemPool.allocate_atomic();
  428. }
  429. typename List<T>::Data* _allocate_sleepy()
  430. {
  431. return (typename List<T>::Data*)fMemPool.allocate_sleepy();
  432. }
  433. void _deallocate(typename List<T>::Data*& dataPtr) override
  434. {
  435. CARLA_ASSERT(dataPtr != nullptr);
  436. fMemPool.deallocate(dataPtr);
  437. dataPtr = nullptr;
  438. }
  439. LIST_DECLARATIONS(RtList)
  440. };
  441. // -----------------------------------------------------------------------
  442. // Non-Realtime list
  443. template<typename T>
  444. class NonRtList : public List<T>
  445. {
  446. public:
  447. NonRtList()
  448. {
  449. }
  450. ~NonRtList() override
  451. {
  452. }
  453. private:
  454. typename List<T>::Data* _allocate() override
  455. {
  456. return (typename List<T>::Data*)std::malloc(this->fDataSize);
  457. }
  458. void _deallocate(typename List<T>::Data*& dataPtr) override
  459. {
  460. CARLA_ASSERT(dataPtr != nullptr);
  461. std::free(dataPtr);
  462. dataPtr = nullptr;
  463. }
  464. LIST_DECLARATIONS(NonRtList)
  465. };
  466. // -----------------------------------------------------------------------
  467. #endif // RT_LIST_HPP_INCLUDED