OpenShot Library | OpenShotAudio  0.2.2
juce_HeapBlock.h
1 
2 /** @weakgroup juce_core-memory
3  * @{
4  */
5 /*
6  ==============================================================================
7 
8  This file is part of the JUCE library.
9  Copyright (c) 2017 - ROLI Ltd.
10 
11  JUCE is an open source library subject to commercial or open-source
12  licensing.
13 
14  The code included in this file is provided under the terms of the ISC license
15  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
16  To use, copy, modify, and/or distribute this software for any purpose with or
17  without fee is hereby granted provided that the above copyright notice and
18  this permission notice appear in all copies.
19 
20  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22  DISCLAIMED.
23 
24  ==============================================================================
25 */
26 
27 namespace juce
28 {
29 
30 #if ! (defined (DOXYGEN) || JUCE_EXCEPTIONS_DISABLED)
31 namespace HeapBlockHelper
32 {
33  template <bool shouldThrow>
34  struct ThrowOnFail { static void checkPointer (void*) {} };
35 
36  template<>
37  struct ThrowOnFail<true> { static void checkPointer (void* data) { if (data == nullptr) throw std::bad_alloc(); } };
38 }
39 #endif
40 
41 //==============================================================================
42 /**
43  Very simple container class to hold a pointer to some data on the heap.
44 
45  When you need to allocate some heap storage for something, always try to use
46  this class instead of allocating the memory directly using malloc/free.
47 
48  A HeapBlock<char> object can be treated in pretty much exactly the same way
49  as an char*, but as long as you allocate it on the stack or as a class member,
50  it's almost impossible for it to leak memory.
51 
52  It also makes your code much more concise and readable than doing the same thing
53  using direct allocations,
54 
55  E.g. instead of this:
56  @code
57  int* temp = (int*) malloc (1024 * sizeof (int));
58  memcpy (temp, xyz, 1024 * sizeof (int));
59  free (temp);
60  temp = (int*) calloc (2048 * sizeof (int));
61  temp[0] = 1234;
62  memcpy (foobar, temp, 2048 * sizeof (int));
63  free (temp);
64  @endcode
65 
66  ..you could just write this:
67  @code
68  HeapBlock<int> temp (1024);
69  memcpy (temp, xyz, 1024 * sizeof (int));
70  temp.calloc (2048);
71  temp[0] = 1234;
72  memcpy (foobar, temp, 2048 * sizeof (int));
73  @endcode
74 
75  The class is extremely lightweight, containing only a pointer to the
76  data, and exposes malloc/realloc/calloc/free methods that do the same jobs
77  as their less object-oriented counterparts. Despite adding safety, you probably
78  won't sacrifice any performance by using this in place of normal pointers.
79 
80  The throwOnFailure template parameter can be set to true if you'd like the class
81  to throw a std::bad_alloc exception when an allocation fails. If this is false,
82  then a failed allocation will just leave the heapblock with a null pointer (assuming
83  that the system's malloc() function doesn't throw).
84 
85  @see Array, OwnedArray, MemoryBlock
86 
87  @tags{Core}
88 */
89 template <class ElementType, bool throwOnFailure = false>
90 class HeapBlock
91 {
92 private:
93  template <class OtherElementType>
94  using AllowConversion = typename std::enable_if<std::is_base_of<typename std::remove_pointer<ElementType>::type,
95  typename std::remove_pointer<OtherElementType>::type>::value>::type;
96 
97 public:
98  //==============================================================================
99  /** Creates a HeapBlock which is initially just a null pointer.
100 
101  After creation, you can resize the array using the malloc(), calloc(),
102  or realloc() methods.
103  */
104  HeapBlock() = default;
105 
106  /** Creates a HeapBlock containing a number of elements.
107 
108  The contents of the block are undefined, as it will have been created by a
109  malloc call.
110 
111  If you want an array of zero values, you can use the calloc() method or the
112  other constructor that takes an InitialisationState parameter.
113  */
114  template <typename SizeType>
115  explicit HeapBlock (SizeType numElements)
116  : data (static_cast<ElementType*> (std::malloc (static_cast<size_t> (numElements) * sizeof (ElementType))))
117  {
118  throwOnAllocationFailure();
119  }
120 
121  /** Creates a HeapBlock containing a number of elements.
122 
123  The initialiseToZero parameter determines whether the new memory should be cleared,
124  or left uninitialised.
125  */
126  template <typename SizeType>
127  HeapBlock (SizeType numElements, bool initialiseToZero)
128  : data (static_cast<ElementType*> (initialiseToZero
129  ? std::calloc (static_cast<size_t> (numElements), sizeof (ElementType))
130  : std::malloc (static_cast<size_t> (numElements) * sizeof (ElementType))))
131  {
132  throwOnAllocationFailure();
133  }
134 
135  /** Destructor.
136  This will free the data, if any has been allocated.
137  */
139  {
140  std::free (data);
141  }
142 
143  /** Move constructor */
144  HeapBlock (HeapBlock&& other) noexcept
145  : data (other.data)
146  {
147  other.data = nullptr;
148  }
149 
150  /** Move assignment operator */
151  HeapBlock& operator= (HeapBlock&& other) noexcept
152  {
153  std::swap (data, other.data);
154  return *this;
155  }
156 
157  /** Converting move constructor.
158  Only enabled if this is a HeapBlock<Base*> and the other object is a HeapBlock<Derived*>,
159  where std::is_base_of<Base, Derived>::value == true.
160  */
161  template <class OtherElementType, bool otherThrowOnFailure, typename = AllowConversion<OtherElementType>>
163  : data (reinterpret_cast<ElementType*> (other.data))
164  {
165  other.data = nullptr;
166  }
167 
168  /** Converting move assignment operator.
169  Only enabled if this is a HeapBlock<Base*> and the other object is a HeapBlock<Derived*>,
170  where std::is_base_of<Base, Derived>::value == true.
171  */
172  template <class OtherElementType, bool otherThrowOnFailure, typename = AllowConversion<OtherElementType>>
174  {
175  free();
176  data = reinterpret_cast<ElementType*> (other.data);
177  other.data = nullptr;
178  return *this;
179  }
180 
181  //==============================================================================
182  /** Returns a raw pointer to the allocated data.
183  This may be a null pointer if the data hasn't yet been allocated, or if it has been
184  freed by calling the free() method.
185  */
186  inline operator ElementType*() const noexcept { return data; }
187 
188  /** Returns a raw pointer to the allocated data.
189  This may be a null pointer if the data hasn't yet been allocated, or if it has been
190  freed by calling the free() method.
191  */
192  inline ElementType* get() const noexcept { return data; }
193 
194  /** Returns a raw pointer to the allocated data.
195  This may be a null pointer if the data hasn't yet been allocated, or if it has been
196  freed by calling the free() method.
197  */
198  inline ElementType* getData() const noexcept { return data; }
199 
200  /** Returns a void pointer to the allocated data.
201  This may be a null pointer if the data hasn't yet been allocated, or if it has been
202  freed by calling the free() method.
203  */
204  inline operator void*() const noexcept { return static_cast<void*> (data); }
205 
206  /** Returns a void pointer to the allocated data.
207  This may be a null pointer if the data hasn't yet been allocated, or if it has been
208  freed by calling the free() method.
209  */
210  inline operator const void*() const noexcept { return static_cast<const void*> (data); }
211 
212  /** Lets you use indirect calls to the first element in the array.
213  Obviously this will cause problems if the array hasn't been initialised, because it'll
214  be referencing a null pointer.
215  */
216  inline ElementType* operator->() const noexcept { return data; }
217 
218  /** Returns a reference to one of the data elements.
219  Obviously there's no bounds-checking here, as this object is just a dumb pointer and
220  has no idea of the size it currently has allocated.
221  */
222  template <typename IndexType>
223  ElementType& operator[] (IndexType index) const noexcept { return data [index]; }
224 
225  /** Returns a pointer to a data element at an offset from the start of the array.
226  This is the same as doing pointer arithmetic on the raw pointer itself.
227  */
228  template <typename IndexType>
229  ElementType* operator+ (IndexType index) const noexcept { return data + index; }
230 
231  //==============================================================================
232  /** Compares the pointer with another pointer.
233  This can be handy for checking whether this is a null pointer.
234  */
235  inline bool operator== (const ElementType* otherPointer) const noexcept { return otherPointer == data; }
236 
237  /** Compares the pointer with another pointer.
238  This can be handy for checking whether this is a null pointer.
239  */
240  inline bool operator!= (const ElementType* otherPointer) const noexcept { return otherPointer != data; }
241 
242  //==============================================================================
243  /** Allocates a specified amount of memory.
244 
245  This uses the normal malloc to allocate an amount of memory for this object.
246  Any previously allocated memory will be freed by this method.
247 
248  The number of bytes allocated will be (newNumElements * elementSize). Normally
249  you wouldn't need to specify the second parameter, but it can be handy if you need
250  to allocate a size in bytes rather than in terms of the number of elements.
251 
252  The data that is allocated will be freed when this object is deleted, or when you
253  call free() or any of the allocation methods.
254  */
255  template <typename SizeType>
256  void malloc (SizeType newNumElements, size_t elementSize = sizeof (ElementType))
257  {
258  std::free (data);
259  data = static_cast<ElementType*> (std::malloc (static_cast<size_t> (newNumElements) * elementSize));
260  throwOnAllocationFailure();
261  }
262 
263  /** Allocates a specified amount of memory and clears it.
264  This does the same job as the malloc() method, but clears the memory that it allocates.
265  */
266  template <typename SizeType>
267  void calloc (SizeType newNumElements, const size_t elementSize = sizeof (ElementType))
268  {
269  std::free (data);
270  data = static_cast<ElementType*> (std::calloc (static_cast<size_t> (newNumElements), elementSize));
271  throwOnAllocationFailure();
272  }
273 
274  /** Allocates a specified amount of memory and optionally clears it.
275  This does the same job as either malloc() or calloc(), depending on the
276  initialiseToZero parameter.
277  */
278  template <typename SizeType>
279  void allocate (SizeType newNumElements, bool initialiseToZero)
280  {
281  std::free (data);
282  data = static_cast<ElementType*> (initialiseToZero
283  ? std::calloc (static_cast<size_t> (newNumElements), sizeof (ElementType))
284  : std::malloc (static_cast<size_t> (newNumElements) * sizeof (ElementType)));
285  throwOnAllocationFailure();
286  }
287 
288  /** Re-allocates a specified amount of memory.
289 
290  The semantics of this method are the same as malloc() and calloc(), but it
291  uses realloc() to keep as much of the existing data as possible.
292  */
293  template <typename SizeType>
294  void realloc (SizeType newNumElements, size_t elementSize = sizeof (ElementType))
295  {
296  data = static_cast<ElementType*> (data == nullptr ? std::malloc (static_cast<size_t> (newNumElements) * elementSize)
297  : std::realloc (data, static_cast<size_t> (newNumElements) * elementSize));
298  throwOnAllocationFailure();
299  }
300 
301  /** Frees any currently-allocated data.
302  This will free the data and reset this object to be a null pointer.
303  */
304  void free() noexcept
305  {
306  std::free (data);
307  data = nullptr;
308  }
309 
310  /** Swaps this object's data with the data of another HeapBlock.
311  The two objects simply exchange their data pointers.
312  */
313  template <bool otherBlockThrows>
315  {
316  std::swap (data, other.data);
317  }
318 
319  /** This fills the block with zeros, up to the number of elements specified.
320  Since the block has no way of knowing its own size, you must make sure that the number of
321  elements you specify doesn't exceed the allocated size.
322  */
323  template <typename SizeType>
324  void clear (SizeType numElements) noexcept
325  {
326  zeromem (data, sizeof (ElementType) * static_cast<size_t> (numElements));
327  }
328 
329  /** This typedef can be used to get the type of the heapblock's elements. */
330  using Type = ElementType;
331 
332 private:
333  //==============================================================================
334  ElementType* data = nullptr;
335 
336  void throwOnAllocationFailure() const
337  {
338  #if JUCE_EXCEPTIONS_DISABLED
339  jassert (data != nullptr); // without exceptions, you'll need to find a better way to handle this failure case.
340  #else
341  HeapBlockHelper::ThrowOnFail<throwOnFailure>::checkPointer (data);
342  #endif
343  }
344 
345  template <class OtherElementType, bool otherThrowOnFailure>
346  friend class HeapBlock;
347 
348  #if ! (defined (JUCE_DLL) || defined (JUCE_DLL_BUILD))
349  JUCE_DECLARE_NON_COPYABLE (HeapBlock)
350  JUCE_PREVENT_HEAP_ALLOCATION // Creating a 'new HeapBlock' would be missing the point!
351  #endif
352 };
353 
354 } // namespace juce
355 
356 /** @}*/
void allocate(SizeType newNumElements, bool initialiseToZero)
Allocates a specified amount of memory and optionally clears it.
~HeapBlock()
Destructor.
void malloc(SizeType newNumElements, size_t elementSize=sizeof(ElementType))
Allocates a specified amount of memory.
ElementType * getData() const noexcept
Returns a raw pointer to the allocated data.
void realloc(SizeType newNumElements, size_t elementSize=sizeof(ElementType))
Re-allocates a specified amount of memory.
Very simple container class to hold a pointer to some data on the heap.
STL namespace.
void calloc(SizeType newNumElements, const size_t elementSize=sizeof(ElementType))
Allocates a specified amount of memory and clears it.
HeapBlock(HeapBlock &&other) noexcept
Move constructor.
HeapBlock(HeapBlock< OtherElementType, otherThrowOnFailure > &&other) noexcept
Converting move constructor.
ElementType * operator->() const noexcept
Lets you use indirect calls to the first element in the array.
void clear(SizeType numElements) noexcept
This fills the block with zeros, up to the number of elements specified.
void free() noexcept
Frees any currently-allocated data.
void swapWith(HeapBlock< ElementType, otherBlockThrows > &other) noexcept
Swaps this object&#39;s data with the data of another HeapBlock.
This structure holds a set of properties describing the current audio setup.
HeapBlock(SizeType numElements)
Creates a HeapBlock containing a number of elements.
HeapBlock(SizeType numElements, bool initialiseToZero)
Creates a HeapBlock containing a number of elements.