|
- /*
- ==============================================================================
-
- This file is part of the Water library.
- Copyright (c) 2016 ROLI Ltd.
- Copyright (C) 2017-2018 Filipe Coelho <falktx@falktx.com>
-
- Permission is granted to use this software under the terms of the ISC license
- http://www.isc.org/downloads/software-support-policy/isc-license/
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
- TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
- OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
- USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- OF THIS SOFTWARE.
-
- ==============================================================================
- */
-
- #ifndef WATER_HEAPBLOCK_H_INCLUDED
- #define WATER_HEAPBLOCK_H_INCLUDED
-
- #include "Memory.h"
- #include "../maths/MathsFunctions.h"
-
- namespace water {
-
- //==============================================================================
- /**
- Very simple container class to hold a pointer to some data on the heap.
-
- When you need to allocate some heap storage for something, always try to use
- this class instead of allocating the memory directly using malloc/free.
-
- A HeapBlock<char> object can be treated in pretty much exactly the same way
- as an char*, but as long as you allocate it on the stack or as a class member,
- it's almost impossible for it to leak memory.
-
- It also makes your code much more concise and readable than doing the same thing
- using direct allocations,
-
- E.g. instead of this:
- @code
- int* temp = (int*) malloc (1024 * sizeof (int));
- memcpy (temp, xyz, 1024 * sizeof (int));
- free (temp);
- temp = (int*) calloc (2048 * sizeof (int));
- temp[0] = 1234;
- memcpy (foobar, temp, 2048 * sizeof (int));
- free (temp);
- @endcode
-
- ..you could just write this:
- @code
- HeapBlock<int> temp (1024);
- memcpy (temp, xyz, 1024 * sizeof (int));
- temp.calloc (2048);
- temp[0] = 1234;
- memcpy (foobar, temp, 2048 * sizeof (int));
- @endcode
-
- The class is extremely lightweight, containing only a pointer to the
- data, and exposes malloc/realloc/calloc/free methods that do the same jobs
- as their less object-oriented counterparts. Despite adding safety, you probably
- won't sacrifice any performance by using this in place of normal pointers.
-
- @see Array, OwnedArray, MemoryBlock
- */
- template <class ElementType>
- class HeapBlock
- {
- public:
- //==============================================================================
- /** Creates a HeapBlock which is initially just a null pointer.
-
- After creation, you can resize the array using the malloc(), calloc(),
- or realloc() methods.
- */
- HeapBlock() noexcept : data (nullptr)
- {
- }
-
- /** Destructor.
- This will free the data, if any has been allocated.
- */
- ~HeapBlock() noexcept
- {
- std::free (data);
- }
-
- #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS
- HeapBlock (HeapBlock&& other) noexcept
- : data (other.data)
- {
- other.data = nullptr;
- }
-
- HeapBlock& operator= (HeapBlock&& other) noexcept
- {
- std::swap (data, other.data);
- return *this;
- }
- #endif
-
- //==============================================================================
- /** Returns a raw pointer to the allocated data.
- This may be a null pointer if the data hasn't yet been allocated, or if it has been
- freed by calling the free() method.
- */
- inline operator ElementType*() const noexcept { return data; }
-
- /** Returns a raw pointer to the allocated data.
- This may be a null pointer if the data hasn't yet been allocated, or if it has been
- freed by calling the free() method.
- */
- inline ElementType* getData() const noexcept { return data; }
-
- /** Returns a void pointer to the allocated data.
- This may be a null pointer if the data hasn't yet been allocated, or if it has been
- freed by calling the free() method.
- */
- inline operator void*() const noexcept { return static_cast<void*> (data); }
-
- /** Returns a void pointer to the allocated data.
- This may be a null pointer if the data hasn't yet been allocated, or if it has been
- freed by calling the free() method.
- */
- inline operator const void*() const noexcept { return static_cast<const void*> (data); }
-
- /** Lets you use indirect calls to the first element in the array.
- Obviously this will cause problems if the array hasn't been initialised, because it'll
- be referencing a null pointer.
- */
- inline ElementType* operator->() const noexcept { return data; }
-
- /** Returns a reference to one of the data elements.
- Obviously there's no bounds-checking here, as this object is just a dumb pointer and
- has no idea of the size it currently has allocated.
- */
- template <typename IndexType>
- inline ElementType& operator[] (IndexType index) const noexcept { return data [index]; }
-
- /** Returns a pointer to a data element at an offset from the start of the array.
- This is the same as doing pointer arithmetic on the raw pointer itself.
- */
- template <typename IndexType>
- inline ElementType* operator+ (IndexType index) const noexcept { return data + index; }
-
- //==============================================================================
- /** Compares the pointer with another pointer.
- This can be handy for checking whether this is a null pointer.
- */
- inline bool operator== (const ElementType* const otherPointer) const noexcept { return otherPointer == data; }
-
- /** Compares the pointer with another pointer.
- This can be handy for checking whether this is a null pointer.
- */
- inline bool operator!= (const ElementType* const otherPointer) const noexcept { return otherPointer != data; }
-
- //==============================================================================
- /** Allocates a specified amount of memory.
-
- This uses the normal malloc to allocate an amount of memory for this object.
- Any previously allocated memory will be freed by this method.
-
- The number of bytes allocated will be (newNumElements * elementSize). Normally
- you wouldn't need to specify the second parameter, but it can be handy if you need
- to allocate a size in bytes rather than in terms of the number of elements.
-
- The data that is allocated will be freed when this object is deleted, or when you
- call free() or any of the allocation methods.
- */
- bool malloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType)) noexcept
- {
- std::free (data);
- data = static_cast<ElementType*> (std::malloc (newNumElements * elementSize));
-
- return data != nullptr;
- }
-
- /** Allocates a specified amount of memory and clears it.
- This does the same job as the malloc() method, but clears the memory that it allocates.
- */
- bool calloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType)) noexcept
- {
- std::free (data);
- data = static_cast<ElementType*> (std::calloc (newNumElements, elementSize));
-
- return data != nullptr;
- }
-
- /** Allocates a specified amount of memory and optionally clears it.
- This does the same job as either malloc() or calloc(), depending on the
- initialiseToZero parameter.
- */
- bool allocate (const size_t newNumElements, bool initialiseToZero) noexcept
- {
- std::free (data);
- data = static_cast<ElementType*> (initialiseToZero
- ? std::calloc (newNumElements, sizeof (ElementType))
- : std::malloc (newNumElements * sizeof (ElementType)));
-
- return data != nullptr;
- }
-
- /** Re-allocates a specified amount of memory.
-
- The semantics of this method are the same as malloc() and calloc(), but it
- uses realloc() to keep as much of the existing data as possible.
- */
- bool realloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType)) noexcept
- {
- data = static_cast<ElementType*> (data == nullptr ? std::malloc (newNumElements * elementSize)
- : std::realloc (data, newNumElements * elementSize));
- return data != nullptr;
- }
-
- /** Frees any currently-allocated data.
- This will free the data and reset this object to be a null pointer.
- */
- void free() noexcept
- {
- std::free (data);
- data = nullptr;
- }
-
- /** Swaps this object's data with the data of another HeapBlock.
- The two objects simply exchange their data pointers.
- */
- void swapWith (HeapBlock<ElementType>& other) noexcept
- {
- std::swap (data, other.data);
- }
-
- /** This fills the block with zeros, up to the number of elements specified.
- Since the block has no way of knowing its own size, you must make sure that the number of
- elements you specify doesn't exceed the allocated size.
- */
- void clear (size_t numElements) noexcept
- {
- zeromem (data, sizeof (ElementType) * numElements);
- }
-
- /** This typedef can be used to get the type of the heapblock's elements. */
- typedef ElementType Type;
-
- private:
- //==============================================================================
- ElementType* data;
- };
-
- }
-
- #endif // WATER_HEAPBLOCK_H_INCLUDED
|