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.

398 lines
8.4KB

  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 GPL.txt file
  16. */
  17. #ifndef __RT_LIST_HPP__
  18. #define __RT_LIST_HPP__
  19. extern "C" {
  20. #include "rtmempool/list.h"
  21. #include "rtmempool/rtmempool.h"
  22. }
  23. #include "carla_utils.hpp"
  24. // list_entry C++11 version (using nullptr instead of 0)
  25. #undef list_entry
  26. #define list_entry(ptr, type, member) \
  27. ((type *)((char *)(ptr)-(unsigned long)(&((type *)nullptr)->member)))
  28. // Declare non copyable and prevent heap allocation
  29. #define LIST_DECLARATIONS(className) \
  30. className(const className&); \
  31. className& operator= (const className&); \
  32. static void* operator new (size_t) { return nullptr; } \
  33. static void operator delete (void*) {}
  34. typedef struct list_head k_list_head;
  35. // -----------------------------------------------------------------------
  36. template<typename T>
  37. class List
  38. {
  39. protected:
  40. List()
  41. : kDataSize(sizeof(Data)),
  42. fCount(0)
  43. {
  44. _init();
  45. }
  46. public:
  47. virtual ~List()
  48. {
  49. CARLA_ASSERT(fCount == 0);
  50. }
  51. void clear()
  52. {
  53. if (fCount != 0)
  54. {
  55. k_list_head* entry;
  56. list_for_each(entry, &fQueue)
  57. {
  58. if (Data* data = list_entry(entry, Data, siblings))
  59. _deallocate(data);
  60. }
  61. }
  62. _init();
  63. }
  64. size_t count() const
  65. {
  66. return fCount;
  67. }
  68. bool isEmpty() const
  69. {
  70. return (fCount == 0);
  71. }
  72. bool append(const T& value)
  73. {
  74. if (Data* const data = _allocate())
  75. {
  76. std::memcpy(&data->value, &value, sizeof(T));
  77. list_add_tail(&data->siblings, &fQueue);
  78. fCount++;
  79. return true;
  80. }
  81. return false;
  82. }
  83. bool insert(const T& value)
  84. {
  85. if (Data* const data = _allocate())
  86. {
  87. std::memcpy(&data->value, &value, sizeof(T));
  88. list_add(&data->siblings, &fQueue);
  89. fCount++;
  90. return true;
  91. }
  92. return false;
  93. }
  94. T& getAt(const size_t index, const bool remove = false)
  95. {
  96. if (fCount == 0 || index >= fCount)
  97. return _retEmpty();
  98. size_t i = 0;
  99. Data* data = nullptr;
  100. k_list_head* entry;
  101. list_for_each(entry, &fQueue)
  102. {
  103. if (index != i++)
  104. continue;
  105. data = list_entry(entry, Data, siblings);
  106. if (remove)
  107. {
  108. fCount--;
  109. list_del(entry);
  110. if (data != nullptr)
  111. _deallocate(data);
  112. }
  113. break;
  114. }
  115. CARLA_ASSERT(data != nullptr);
  116. return (data != nullptr) ? data->value : _retEmpty();
  117. }
  118. T& getFirst(const bool remove = false)
  119. {
  120. return _getFirstOrLast(true, remove);
  121. }
  122. T& getLast(const bool remove = false)
  123. {
  124. return _getFirstOrLast(false, remove);
  125. }
  126. bool removeOne(const T& value)
  127. {
  128. Data* data = nullptr;
  129. k_list_head* entry;
  130. list_for_each(entry, &fQueue)
  131. {
  132. data = list_entry(entry, Data, siblings);
  133. CARLA_ASSERT(data != nullptr);
  134. if (data != nullptr && data->value == value)
  135. {
  136. fCount--;
  137. list_del(entry);
  138. _deallocate(data);
  139. break;
  140. }
  141. }
  142. return (data != nullptr);
  143. }
  144. void removeAll(const T& value)
  145. {
  146. Data* data;
  147. k_list_head* entry;
  148. k_list_head* tmp;
  149. list_for_each_safe(entry, tmp, &fQueue)
  150. {
  151. data = list_entry(entry, Data, siblings);
  152. CARLA_ASSERT(data != nullptr);
  153. if (data != nullptr && data->value == value)
  154. {
  155. fCount--;
  156. list_del(entry);
  157. _deallocate(data);
  158. }
  159. }
  160. }
  161. void splice(List& list, const bool init = false)
  162. {
  163. if (init)
  164. {
  165. list_splice_init(&fQueue, &list.fQueue);
  166. list.fCount += fCount;
  167. fCount = 0;
  168. }
  169. else
  170. {
  171. list_splice(&fQueue, &list.fQueue);
  172. list.fCount += fCount;
  173. }
  174. }
  175. protected:
  176. const size_t kDataSize;
  177. size_t fCount;
  178. k_list_head fQueue;
  179. struct Data {
  180. T value;
  181. k_list_head siblings;
  182. };
  183. virtual Data* _allocate() = 0;
  184. virtual void _deallocate(Data* const dataPtr) = 0;
  185. private:
  186. void _init()
  187. {
  188. fCount = 0;
  189. INIT_LIST_HEAD(&fQueue);
  190. }
  191. T& _getFirstOrLast(const bool first, const bool remove)
  192. {
  193. if (fCount == 0)
  194. return _retEmpty();
  195. k_list_head* const entry = first ? fQueue.prev : fQueue.next;
  196. Data* const data = list_entry(entry, Data, siblings);
  197. CARLA_ASSERT(data != nullptr);
  198. if (data == nullptr)
  199. return _retEmpty();
  200. T& ret = data->value;
  201. if (data != nullptr && remove)
  202. {
  203. fCount--;
  204. list_del(entry);
  205. _deallocate(data);
  206. }
  207. return ret;
  208. }
  209. T& _retEmpty()
  210. {
  211. // FIXME ?
  212. static T value;
  213. static bool reset = true;
  214. if (reset)
  215. {
  216. reset = false;
  217. std::memset(&value, 0, sizeof(T));
  218. }
  219. return value;
  220. }
  221. LIST_DECLARATIONS(List)
  222. };
  223. template<typename T>
  224. class RtList : public List<T>
  225. {
  226. public:
  227. RtList(const size_t minPreallocated, const size_t maxPreallocated)
  228. : fMemPool(nullptr)
  229. {
  230. rtsafe_memory_pool_create(&fMemPool, nullptr, this->kDataSize, minPreallocated, maxPreallocated);
  231. CARLA_ASSERT(fMemPool != nullptr);
  232. }
  233. ~RtList()
  234. {
  235. if (fMemPool != nullptr)
  236. rtsafe_memory_pool_destroy(fMemPool);
  237. }
  238. void append_sleepy(const T& value)
  239. {
  240. if (typename List<T>::Data* const data = _allocate_sleepy())
  241. {
  242. std::memcpy(&data->value, &value, sizeof(T));
  243. list_add_tail(&data->siblings, &this->fQueue);
  244. this->fCount++;
  245. }
  246. }
  247. void resize(const size_t minPreallocated, const size_t maxPreallocated)
  248. {
  249. this->clear();
  250. if (fMemPool != nullptr)
  251. rtsafe_memory_pool_destroy(fMemPool);
  252. fMemPool = nullptr;
  253. rtsafe_memory_pool_create(&fMemPool, nullptr, this->fDataSize, minPreallocated, maxPreallocated);
  254. CARLA_ASSERT(fMemPool != nullptr);
  255. }
  256. private:
  257. RtMemPool_Handle fMemPool;
  258. typename List<T>::Data* _allocate()
  259. {
  260. return _allocate_atomic();
  261. }
  262. typename List<T>::Data* _allocate_atomic()
  263. {
  264. return (typename List<T>::Data*)rtsafe_memory_pool_allocate_atomic(fMemPool);
  265. }
  266. typename List<T>::Data* _allocate_sleepy()
  267. {
  268. return (typename List<T>::Data*)rtsafe_memory_pool_allocate_sleepy(fMemPool);
  269. }
  270. void _deallocate(typename List<T>::Data* const dataPtr)
  271. {
  272. rtsafe_memory_pool_deallocate(fMemPool, dataPtr);
  273. }
  274. LIST_DECLARATIONS(RtList)
  275. };
  276. template<typename T>
  277. class NonRtList : public List<T>
  278. {
  279. public:
  280. NonRtList()
  281. {
  282. }
  283. ~NonRtList()
  284. {
  285. }
  286. private:
  287. typename List<T>::Data* _allocate()
  288. {
  289. return (typename List<T>::Data*)malloc(this->fDataSize);
  290. }
  291. void _deallocate(typename List<T>::Data* const dataPtr)
  292. {
  293. free(dataPtr);
  294. }
  295. LIST_DECLARATIONS(NonRtList)
  296. };
  297. template<typename T>
  298. class NonRtListNew : public List<T>
  299. {
  300. public:
  301. NonRtListNew()
  302. {
  303. }
  304. ~NonRtListNew()
  305. {
  306. }
  307. private:
  308. typename List<T>::Data* _allocate()
  309. {
  310. return new typename List<T>::Data;
  311. }
  312. void _deallocate(typename List<T>::Data* const dataPtr)
  313. {
  314. delete dataPtr;
  315. }
  316. LIST_DECLARATIONS(NonRtListNew)
  317. };
  318. // -----------------------------------------------------------------------
  319. #endif // __RT_LIST_HPP__