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.

373 lines
12KB

  1. /*
  2. ==============================================================================
  3. This file is part of the Water library.
  4. Copyright (c) 2016 ROLI Ltd.
  5. Copyright (C) 2017 Filipe Coelho <falktx@falktx.com>
  6. Permission is granted to use this software under the terms of the ISC license
  7. http://www.isc.org/downloads/software-support-policy/isc-license/
  8. Permission to use, copy, modify, and/or distribute this software for any
  9. purpose with or without fee is hereby granted, provided that the above
  10. copyright notice and this permission notice appear in all copies.
  11. THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
  12. TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  13. FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
  14. OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  15. USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  16. TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  17. OF THIS SOFTWARE.
  18. ==============================================================================
  19. */
  20. #ifndef WATER_LINKEDLISTPOINTER_H_INCLUDED
  21. #define WATER_LINKEDLISTPOINTER_H_INCLUDED
  22. #include "../water.h"
  23. namespace water {
  24. //==============================================================================
  25. /**
  26. Helps to manipulate singly-linked lists of objects.
  27. For objects that are designed to contain a pointer to the subsequent item in the
  28. list, this class contains methods to deal with the list. To use it, the ObjectType
  29. class that it points to must contain a LinkedListPointer called nextListItem, e.g.
  30. @code
  31. struct MyObject
  32. {
  33. int x, y, z;
  34. // A linkable object must contain a member with this name and type, which must be
  35. // accessible by the LinkedListPointer class. (This doesn't mean it has to be public -
  36. // you could make your class a friend of a LinkedListPointer<MyObject> instead).
  37. LinkedListPointer<MyObject> nextListItem;
  38. };
  39. LinkedListPointer<MyObject> myList;
  40. myList.append (new MyObject());
  41. myList.append (new MyObject());
  42. int numItems = myList.size(); // returns 2
  43. MyObject* lastInList = myList.getLast();
  44. @endcode
  45. */
  46. template <class ObjectType>
  47. class LinkedListPointer
  48. {
  49. public:
  50. //==============================================================================
  51. /** Creates a null pointer to an empty list. */
  52. LinkedListPointer() noexcept
  53. : item (nullptr)
  54. {
  55. }
  56. /** Creates a pointer to a list whose head is the item provided. */
  57. explicit LinkedListPointer (ObjectType* const headItem) noexcept
  58. : item (headItem)
  59. {
  60. }
  61. /** Sets this pointer to point to a new list. */
  62. LinkedListPointer& operator= (ObjectType* const newItem) noexcept
  63. {
  64. item = newItem;
  65. return *this;
  66. }
  67. #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS
  68. LinkedListPointer (LinkedListPointer&& other) noexcept
  69. : item (other.item)
  70. {
  71. other.item = nullptr;
  72. }
  73. LinkedListPointer& operator= (LinkedListPointer&& other) noexcept
  74. {
  75. jassert (this != &other); // hopefully the compiler should make this situation impossible!
  76. item = other.item;
  77. other.item = nullptr;
  78. return *this;
  79. }
  80. #endif
  81. //==============================================================================
  82. /** Returns the item which this pointer points to. */
  83. inline operator ObjectType*() const noexcept
  84. {
  85. return item;
  86. }
  87. /** Returns the item which this pointer points to. */
  88. inline ObjectType* get() const noexcept
  89. {
  90. return item;
  91. }
  92. /** Returns the last item in the list which this pointer points to.
  93. This will iterate the list and return the last item found. Obviously the speed
  94. of this operation will be proportional to the size of the list. If the list is
  95. empty the return value will be this object.
  96. If you're planning on appending a number of items to your list, it's much more
  97. efficient to use the Appender class than to repeatedly call getLast() to find the end.
  98. */
  99. LinkedListPointer& getLast() noexcept
  100. {
  101. LinkedListPointer* l = this;
  102. while (l->item != nullptr)
  103. l = &(l->item->nextListItem);
  104. return *l;
  105. }
  106. /** Returns the number of items in the list.
  107. Obviously with a simple linked list, getting the size involves iterating the list, so
  108. this can be a lengthy operation - be careful when using this method in your code.
  109. */
  110. int size() const noexcept
  111. {
  112. int total = 0;
  113. for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
  114. ++total;
  115. return total;
  116. }
  117. /** Returns the item at a given index in the list.
  118. Since the only way to find an item is to iterate the list, this operation can obviously
  119. be slow, depending on its size, so you should be careful when using this in algorithms.
  120. */
  121. LinkedListPointer& operator[] (int index) noexcept
  122. {
  123. LinkedListPointer* l = this;
  124. while (--index >= 0 && l->item != nullptr)
  125. l = &(l->item->nextListItem);
  126. return *l;
  127. }
  128. /** Returns the item at a given index in the list.
  129. Since the only way to find an item is to iterate the list, this operation can obviously
  130. be slow, depending on its size, so you should be careful when using this in algorithms.
  131. */
  132. const LinkedListPointer& operator[] (int index) const noexcept
  133. {
  134. const LinkedListPointer* l = this;
  135. while (--index >= 0 && l->item != nullptr)
  136. l = &(l->item->nextListItem);
  137. return *l;
  138. }
  139. /** Returns true if the list contains the given item. */
  140. bool contains (const ObjectType* const itemToLookFor) const noexcept
  141. {
  142. for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
  143. if (itemToLookFor == i)
  144. return true;
  145. return false;
  146. }
  147. //==============================================================================
  148. /** Inserts an item into the list, placing it before the item that this pointer
  149. currently points to.
  150. */
  151. void insertNext (ObjectType* const newItem)
  152. {
  153. jassert (newItem != nullptr);
  154. jassert (newItem->nextListItem == nullptr);
  155. newItem->nextListItem = item;
  156. item = newItem;
  157. }
  158. /** Inserts an item at a numeric index in the list.
  159. Obviously this will involve iterating the list to find the item at the given index,
  160. so be careful about the impact this may have on execution time.
  161. */
  162. void insertAtIndex (int index, ObjectType* newItem)
  163. {
  164. jassert (newItem != nullptr);
  165. LinkedListPointer* l = this;
  166. while (index != 0 && l->item != nullptr)
  167. {
  168. l = &(l->item->nextListItem);
  169. --index;
  170. }
  171. l->insertNext (newItem);
  172. }
  173. /** Replaces the object that this pointer points to, appending the rest of the list to
  174. the new object, and returning the old one.
  175. */
  176. ObjectType* replaceNext (ObjectType* const newItem) noexcept
  177. {
  178. jassert (newItem != nullptr);
  179. jassert (newItem->nextListItem == nullptr);
  180. ObjectType* const oldItem = item;
  181. item = newItem;
  182. item->nextListItem = oldItem->nextListItem.item;
  183. oldItem->nextListItem.item = nullptr;
  184. return oldItem;
  185. }
  186. /** Adds an item to the end of the list.
  187. This operation involves iterating the whole list, so can be slow - if you need to
  188. append a number of items to your list, it's much more efficient to use the Appender
  189. class than to repeatedly call append().
  190. */
  191. void append (ObjectType* const newItem)
  192. {
  193. getLast().item = newItem;
  194. }
  195. /** Creates copies of all the items in another list and adds them to this one.
  196. This will use the ObjectType's copy constructor to try to create copies of each
  197. item in the other list, and appends them to this list.
  198. */
  199. void addCopyOfList (const LinkedListPointer& other)
  200. {
  201. LinkedListPointer* insertPoint = this;
  202. for (ObjectType* i = other.item; i != nullptr; i = i->nextListItem)
  203. {
  204. insertPoint->insertNext (new ObjectType (*i));
  205. insertPoint = &(insertPoint->item->nextListItem);
  206. }
  207. }
  208. /** Removes the head item from the list.
  209. This won't delete the object that is removed, but returns it, so the caller can
  210. delete it if necessary.
  211. */
  212. ObjectType* removeNext() noexcept
  213. {
  214. ObjectType* const oldItem = item;
  215. if (oldItem != nullptr)
  216. {
  217. item = oldItem->nextListItem;
  218. oldItem->nextListItem.item = nullptr;
  219. }
  220. return oldItem;
  221. }
  222. /** Removes a specific item from the list.
  223. Note that this will not delete the item, it simply unlinks it from the list.
  224. */
  225. void remove (ObjectType* const itemToRemove)
  226. {
  227. if (LinkedListPointer* const l = findPointerTo (itemToRemove))
  228. l->removeNext();
  229. }
  230. /** Iterates the list, calling the delete operator on all of its elements and
  231. leaving this pointer empty.
  232. */
  233. void deleteAll()
  234. {
  235. while (item != nullptr)
  236. {
  237. ObjectType* const oldItem = item;
  238. item = oldItem->nextListItem;
  239. delete oldItem;
  240. }
  241. }
  242. /** Finds a pointer to a given item.
  243. If the item is found in the list, this returns the pointer that points to it. If
  244. the item isn't found, this returns null.
  245. */
  246. LinkedListPointer* findPointerTo (ObjectType* const itemToLookFor) noexcept
  247. {
  248. LinkedListPointer* l = this;
  249. while (l->item != nullptr)
  250. {
  251. if (l->item == itemToLookFor)
  252. return l;
  253. l = &(l->item->nextListItem);
  254. }
  255. return nullptr;
  256. }
  257. /** Copies the items in the list to an array.
  258. The destArray must contain enough elements to hold the entire list - no checks are
  259. made for this!
  260. */
  261. void copyToArray (ObjectType** destArray) const noexcept
  262. {
  263. jassert (destArray != nullptr);
  264. for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
  265. *destArray++ = i;
  266. }
  267. /** Swaps this pointer with another one */
  268. void swapWith (LinkedListPointer& other) noexcept
  269. {
  270. std::swap (item, other.item);
  271. }
  272. //==============================================================================
  273. /**
  274. Allows efficient repeated insertions into a list.
  275. You can create an Appender object which points to the last element in your
  276. list, and then repeatedly call Appender::append() to add items to the end
  277. of the list in O(1) time.
  278. */
  279. class Appender
  280. {
  281. public:
  282. /** Creates an appender which will add items to the given list.
  283. */
  284. Appender (LinkedListPointer& endOfListPointer) noexcept
  285. : endOfList (&endOfListPointer)
  286. {
  287. // This can only be used to add to the end of a list.
  288. jassert (endOfListPointer.item == nullptr);
  289. }
  290. /** Appends an item to the list. */
  291. void append (ObjectType* const newItem) noexcept
  292. {
  293. *endOfList = newItem;
  294. endOfList = &(newItem->nextListItem);
  295. }
  296. private:
  297. LinkedListPointer* endOfList;
  298. CARLA_DECLARE_NON_COPY_CLASS (Appender)
  299. };
  300. private:
  301. //==============================================================================
  302. ObjectType* item;
  303. CARLA_DECLARE_NON_COPY_CLASS (LinkedListPointer)
  304. };
  305. }
  306. #endif // WATER_LINKEDLISTPOINTER_H_INCLUDED