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.

315 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2016 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of the ISC license
  6. http://www.isc.org/downloads/software-support-policy/isc-license/
  7. Permission to use, copy, modify, and/or distribute this software for any
  8. purpose with or without fee is hereby granted, provided that the above
  9. copyright notice and this permission notice appear in all copies.
  10. THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
  11. TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  12. FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
  13. OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  14. USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  15. TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  16. OF THIS SOFTWARE.
  17. -----------------------------------------------------------------------------
  18. To release a closed-source product which uses other parts of JUCE not
  19. licensed under the ISC terms, commercial licenses are available: visit
  20. www.juce.com for more information.
  21. ==============================================================================
  22. */
  23. #ifndef JUCE_HEAPBLOCK_H_INCLUDED
  24. #define JUCE_HEAPBLOCK_H_INCLUDED
  25. #if ! (defined (DOXYGEN) || JUCE_EXCEPTIONS_DISABLED)
  26. namespace HeapBlockHelper
  27. {
  28. template <bool shouldThrow>
  29. struct ThrowOnFail { static void checkPointer (void*) {} };
  30. template<>
  31. struct ThrowOnFail<true> { static void checkPointer (void* data) { if (data == nullptr) throw std::bad_alloc(); } };
  32. }
  33. #endif
  34. //==============================================================================
  35. /**
  36. Very simple container class to hold a pointer to some data on the heap.
  37. When you need to allocate some heap storage for something, always try to use
  38. this class instead of allocating the memory directly using malloc/free.
  39. A HeapBlock<char> object can be treated in pretty much exactly the same way
  40. as an char*, but as long as you allocate it on the stack or as a class member,
  41. it's almost impossible for it to leak memory.
  42. It also makes your code much more concise and readable than doing the same thing
  43. using direct allocations,
  44. E.g. instead of this:
  45. @code
  46. int* temp = (int*) malloc (1024 * sizeof (int));
  47. memcpy (temp, xyz, 1024 * sizeof (int));
  48. free (temp);
  49. temp = (int*) calloc (2048 * sizeof (int));
  50. temp[0] = 1234;
  51. memcpy (foobar, temp, 2048 * sizeof (int));
  52. free (temp);
  53. @endcode
  54. ..you could just write this:
  55. @code
  56. HeapBlock<int> temp (1024);
  57. memcpy (temp, xyz, 1024 * sizeof (int));
  58. temp.calloc (2048);
  59. temp[0] = 1234;
  60. memcpy (foobar, temp, 2048 * sizeof (int));
  61. @endcode
  62. The class is extremely lightweight, containing only a pointer to the
  63. data, and exposes malloc/realloc/calloc/free methods that do the same jobs
  64. as their less object-oriented counterparts. Despite adding safety, you probably
  65. won't sacrifice any performance by using this in place of normal pointers.
  66. The throwOnFailure template parameter can be set to true if you'd like the class
  67. to throw a std::bad_alloc exception when an allocation fails. If this is false,
  68. then a failed allocation will just leave the heapblock with a null pointer (assuming
  69. that the system's malloc() function doesn't throw).
  70. @see Array, OwnedArray, MemoryBlock
  71. */
  72. template <class ElementType, bool throwOnFailure = false>
  73. class HeapBlock
  74. {
  75. public:
  76. //==============================================================================
  77. /** Creates a HeapBlock which is initially just a null pointer.
  78. After creation, you can resize the array using the malloc(), calloc(),
  79. or realloc() methods.
  80. */
  81. HeapBlock() noexcept : data (nullptr)
  82. {
  83. }
  84. /** Creates a HeapBlock containing a number of elements.
  85. The contents of the block are undefined, as it will have been created by a
  86. malloc call.
  87. If you want an array of zero values, you can use the calloc() method or the
  88. other constructor that takes an InitialisationState parameter.
  89. */
  90. explicit HeapBlock (const size_t numElements)
  91. : data (static_cast<ElementType*> (std::malloc (numElements * sizeof (ElementType))))
  92. {
  93. throwOnAllocationFailure();
  94. }
  95. /** Creates a HeapBlock containing a number of elements.
  96. The initialiseToZero parameter determines whether the new memory should be cleared,
  97. or left uninitialised.
  98. */
  99. HeapBlock (const size_t numElements, const bool initialiseToZero)
  100. : data (static_cast<ElementType*> (initialiseToZero
  101. ? std::calloc (numElements, sizeof (ElementType))
  102. : std::malloc (numElements * sizeof (ElementType))))
  103. {
  104. throwOnAllocationFailure();
  105. }
  106. /** Destructor.
  107. This will free the data, if any has been allocated.
  108. */
  109. ~HeapBlock()
  110. {
  111. std::free (data);
  112. }
  113. #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
  114. HeapBlock (HeapBlock&& other) noexcept
  115. : data (other.data)
  116. {
  117. other.data = nullptr;
  118. }
  119. HeapBlock& operator= (HeapBlock&& other) noexcept
  120. {
  121. std::swap (data, other.data);
  122. return *this;
  123. }
  124. #endif
  125. //==============================================================================
  126. /** Returns a raw pointer to the allocated data.
  127. This may be a null pointer if the data hasn't yet been allocated, or if it has been
  128. freed by calling the free() method.
  129. */
  130. inline operator ElementType*() const noexcept { return data; }
  131. /** Returns a raw pointer to the allocated data.
  132. This may be a null pointer if the data hasn't yet been allocated, or if it has been
  133. freed by calling the free() method.
  134. */
  135. inline ElementType* getData() const noexcept { return data; }
  136. /** Returns a void pointer to the allocated data.
  137. This may be a null pointer if the data hasn't yet been allocated, or if it has been
  138. freed by calling the free() method.
  139. */
  140. inline operator void*() const noexcept { return static_cast<void*> (data); }
  141. /** Returns a void pointer to the allocated data.
  142. This may be a null pointer if the data hasn't yet been allocated, or if it has been
  143. freed by calling the free() method.
  144. */
  145. inline operator const void*() const noexcept { return static_cast<const void*> (data); }
  146. /** Lets you use indirect calls to the first element in the array.
  147. Obviously this will cause problems if the array hasn't been initialised, because it'll
  148. be referencing a null pointer.
  149. */
  150. inline ElementType* operator->() const noexcept { return data; }
  151. /** Returns a reference to one of the data elements.
  152. Obviously there's no bounds-checking here, as this object is just a dumb pointer and
  153. has no idea of the size it currently has allocated.
  154. */
  155. template <typename IndexType>
  156. inline ElementType& operator[] (IndexType index) const noexcept { return data [index]; }
  157. /** Returns a pointer to a data element at an offset from the start of the array.
  158. This is the same as doing pointer arithmetic on the raw pointer itself.
  159. */
  160. template <typename IndexType>
  161. inline ElementType* operator+ (IndexType index) const noexcept { return data + index; }
  162. //==============================================================================
  163. /** Compares the pointer with another pointer.
  164. This can be handy for checking whether this is a null pointer.
  165. */
  166. inline bool operator== (const ElementType* const otherPointer) const noexcept { return otherPointer == data; }
  167. /** Compares the pointer with another pointer.
  168. This can be handy for checking whether this is a null pointer.
  169. */
  170. inline bool operator!= (const ElementType* const otherPointer) const noexcept { return otherPointer != data; }
  171. //==============================================================================
  172. /** Allocates a specified amount of memory.
  173. This uses the normal malloc to allocate an amount of memory for this object.
  174. Any previously allocated memory will be freed by this method.
  175. The number of bytes allocated will be (newNumElements * elementSize). Normally
  176. you wouldn't need to specify the second parameter, but it can be handy if you need
  177. to allocate a size in bytes rather than in terms of the number of elements.
  178. The data that is allocated will be freed when this object is deleted, or when you
  179. call free() or any of the allocation methods.
  180. */
  181. void malloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
  182. {
  183. std::free (data);
  184. data = static_cast<ElementType*> (std::malloc (newNumElements * elementSize));
  185. throwOnAllocationFailure();
  186. }
  187. /** Allocates a specified amount of memory and clears it.
  188. This does the same job as the malloc() method, but clears the memory that it allocates.
  189. */
  190. void calloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
  191. {
  192. std::free (data);
  193. data = static_cast<ElementType*> (std::calloc (newNumElements, elementSize));
  194. throwOnAllocationFailure();
  195. }
  196. /** Allocates a specified amount of memory and optionally clears it.
  197. This does the same job as either malloc() or calloc(), depending on the
  198. initialiseToZero parameter.
  199. */
  200. void allocate (const size_t newNumElements, bool initialiseToZero)
  201. {
  202. std::free (data);
  203. data = static_cast<ElementType*> (initialiseToZero
  204. ? std::calloc (newNumElements, sizeof (ElementType))
  205. : std::malloc (newNumElements * sizeof (ElementType)));
  206. throwOnAllocationFailure();
  207. }
  208. /** Re-allocates a specified amount of memory.
  209. The semantics of this method are the same as malloc() and calloc(), but it
  210. uses realloc() to keep as much of the existing data as possible.
  211. */
  212. void realloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
  213. {
  214. data = static_cast<ElementType*> (data == nullptr ? std::malloc (newNumElements * elementSize)
  215. : std::realloc (data, newNumElements * elementSize));
  216. throwOnAllocationFailure();
  217. }
  218. /** Frees any currently-allocated data.
  219. This will free the data and reset this object to be a null pointer.
  220. */
  221. void free() noexcept
  222. {
  223. std::free (data);
  224. data = nullptr;
  225. }
  226. /** Swaps this object's data with the data of another HeapBlock.
  227. The two objects simply exchange their data pointers.
  228. */
  229. template <bool otherBlockThrows>
  230. void swapWith (HeapBlock<ElementType, otherBlockThrows>& other) noexcept
  231. {
  232. std::swap (data, other.data);
  233. }
  234. /** This fills the block with zeros, up to the number of elements specified.
  235. Since the block has no way of knowing its own size, you must make sure that the number of
  236. elements you specify doesn't exceed the allocated size.
  237. */
  238. void clear (size_t numElements) noexcept
  239. {
  240. zeromem (data, sizeof (ElementType) * numElements);
  241. }
  242. /** This typedef can be used to get the type of the heapblock's elements. */
  243. typedef ElementType Type;
  244. private:
  245. //==============================================================================
  246. ElementType* data;
  247. void throwOnAllocationFailure() const
  248. {
  249. #if JUCE_EXCEPTIONS_DISABLED
  250. jassert (data != nullptr); // without exceptions, you'll need to find a better way to handle this failure case.
  251. #else
  252. HeapBlockHelper::ThrowOnFail<throwOnFailure>::checkPointer (data);
  253. #endif
  254. }
  255. #if ! (defined (JUCE_DLL) || defined (JUCE_DLL_BUILD))
  256. JUCE_DECLARE_NON_COPYABLE (HeapBlock)
  257. JUCE_PREVENT_HEAP_ALLOCATION // Creating a 'new HeapBlock' would be missing the point!
  258. #endif
  259. };
  260. #endif // JUCE_HEAPBLOCK_H_INCLUDED