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.

353 lines
7.2KB

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