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
27namespace juce
28{
29
30#if ! (defined (DOXYGEN) || JUCE_EXCEPTIONS_DISABLED)
31namespace 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*/
89template <class ElementType, bool throwOnFailure = false>
91{
92private:
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
97public:
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
332private:
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/** @}*/
Very simple container class to hold a pointer to some data on the heap.
~HeapBlock()
Destructor.
HeapBlock(HeapBlock< OtherElementType, otherThrowOnFailure > &&other) noexcept
Converting move constructor.
HeapBlock & operator=(HeapBlock &&other) noexcept
Move assignment operator.
ElementType Type
This typedef can be used to get the type of the heapblock's elements.
void clear(SizeType numElements) noexcept
This fills the block with zeros, up to the number of elements specified.
void swapWith(HeapBlock< ElementType, otherBlockThrows > &other) noexcept
Swaps this object's data with the data of another HeapBlock.
bool operator!=(const ElementType *otherPointer) const noexcept
Compares the pointer with another pointer.
HeapBlock(SizeType numElements, bool initialiseToZero)
Creates a HeapBlock containing a number of elements.
ElementType * operator+(IndexType index) const noexcept
Returns a pointer to a data element at an offset from the start of the array.
void malloc(SizeType newNumElements, size_t elementSize=sizeof(ElementType))
Allocates a specified amount of memory.
HeapBlock(HeapBlock &&other) noexcept
Move constructor.
ElementType * get() const noexcept
Returns a raw pointer to the allocated data.
ElementType * getData() const noexcept
Returns a raw pointer to the allocated data.
ElementType & operator[](IndexType index) const noexcept
Returns a reference to one of the data elements.
HeapBlock()=default
Creates a HeapBlock which is initially just a null pointer.
void allocate(SizeType newNumElements, bool initialiseToZero)
Allocates a specified amount of memory and optionally clears it.
HeapBlock(SizeType numElements)
Creates a HeapBlock containing a number of elements.
bool operator==(const ElementType *otherPointer) const noexcept
Compares the pointer with another pointer.
void realloc(SizeType newNumElements, size_t elementSize=sizeof(ElementType))
Re-allocates a specified amount of memory.
void free() noexcept
Frees any currently-allocated data.
ElementType * operator->() const noexcept
Lets you use indirect calls to the first element in the array.
void calloc(SizeType newNumElements, const size_t elementSize=sizeof(ElementType))
Allocates a specified amount of memory and clears it.