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.

366 lines
7.5KB

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