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.

369 lines
7.7KB

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