fix macOS build (following Projucer changes made in Windows, which removed /Applications/JUCE/modules from its headers). move JUCE headers under source control, so that Windows and macOS can both build against same version of JUCE. remove AUv3 target (I think it's an iOS thing, so it will never work with this macOS fluidsynth dylib).

This commit is contained in:
Alex Birch
2018-06-17 13:34:53 +01:00
parent a2be47c887
commit dff4d13a1d
1563 changed files with 601601 additions and 3466 deletions

View File

@ -0,0 +1,146 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided 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.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
#ifndef DOXYGEN
namespace AtomicHelpers
{
template <typename T> struct DiffTypeHelper { using Type = T; };
template <typename T> struct DiffTypeHelper<T*> { using Type = std::ptrdiff_t; };
}
#endif
//==============================================================================
/**
A simple wrapper around std::atomic.
@tags{Core}
*/
template <typename Type>
struct Atomic final
{
typedef typename AtomicHelpers::DiffTypeHelper<Type>::Type DiffType;
/** Creates a new value, initialised to zero. */
Atomic() noexcept : value (0) {}
/** Creates a new value, with a given initial value. */
Atomic (Type initialValue) noexcept : value (initialValue) {}
/** Copies another value (atomically). */
Atomic (const Atomic& other) noexcept : value (other.get()) {}
/** Destructor. */
~Atomic() noexcept
{
#if __cpp_lib_atomic_is_always_lock_free
static_assert (std::atomic<Type>::is_always_lock_free,
"This class can only be used for lock-free types");
#endif
}
/** Atomically reads and returns the current value. */
Type get() const noexcept { return value.load(); }
/** Atomically sets the current value. */
void set (Type newValue) noexcept { value = newValue; }
/** Atomically sets the current value, returning the value that was replaced. */
Type exchange (Type newValue) noexcept { return value.exchange (newValue); }
/** Atomically compares this value with a target value, and if it is equal, sets
this to be equal to a new value.
This operation is the atomic equivalent of doing this:
@code
bool compareAndSetBool (Type newValue, Type valueToCompare)
{
if (get() == valueToCompare)
{
set (newValue);
return true;
}
return false;
}
@endcode
Internally, this method calls std::atomic::compare_exchange_strong with
memory_order_seq_cst (the strictest std::memory_order).
@returns true if the comparison was true and the value was replaced; false if
the comparison failed and the value was left unchanged.
@see compareAndSetValue
*/
bool compareAndSetBool (Type newValue, Type valueToCompare) noexcept
{
return value.compare_exchange_strong (valueToCompare, newValue);
}
/** Copies another value into this one (atomically). */
Atomic<Type>& operator= (const Atomic& other) noexcept
{
value = other.value.load();
return *this;
}
/** Copies another value into this one (atomically). */
Atomic<Type>& operator= (Type newValue) noexcept
{
value = newValue;
return *this;
}
/** Atomically adds a number to this value, returning the new value. */
Type operator+= (DiffType amountToAdd) noexcept { return value += amountToAdd; }
/** Atomically subtracts a number from this value, returning the new value. */
Type operator-= (DiffType amountToSubtract) noexcept { return value -= amountToSubtract; }
/** Atomically increments this value, returning the new value. */
Type operator++() noexcept { return ++value; }
/** Atomically decrements this value, returning the new value. */
Type operator--() noexcept { return --value; }
/** Implements a memory read/write barrier.
Internally this calls std::atomic_thread_fence with
memory_order_seq_cst (the strictest std::memory_order).
*/
void memoryBarrier() noexcept { atomic_thread_fence (std::memory_order_seq_cst); }
/** The std::atomic object that this class operates on. */
std::atomic<Type> value;
//==============================================================================
#ifndef DOXYGEN
/* This method has been deprecated as there is no equivalent method in
std::atomic. Use compareAndSetBool instead.
*/
JUCE_DEPRECATED (Type compareAndSetValue (Type, Type) noexcept);
#endif
};
} // namespace juce

View File

@ -0,0 +1,220 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided 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.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/** Contains static methods for converting the byte order between different
endiannesses.
@tags{Core}
*/
class JUCE_API ByteOrder
{
public:
//==============================================================================
/** Swaps the upper and lower bytes of a 16-bit integer. */
JUCE_CONSTEXPR static uint16 swap (uint16 value) noexcept;
/** Swaps the upper and lower bytes of a 16-bit integer. */
JUCE_CONSTEXPR static int16 swap (int16 value) noexcept;
/** Reverses the order of the 4 bytes in a 32-bit integer. */
static uint32 swap (uint32 value) noexcept;
/** Reverses the order of the 4 bytes in a 32-bit integer. */
static int32 swap (int32 value) noexcept;
/** Reverses the order of the 8 bytes in a 64-bit integer. */
static uint64 swap (uint64 value) noexcept;
/** Reverses the order of the 8 bytes in a 64-bit integer. */
static int64 swap (int64 value) noexcept;
/** Returns a garbled float which has the reverse byte-order of the original. */
static float swap (float value) noexcept;
/** Returns a garbled double which has the reverse byte-order of the original. */
static double swap (double value) noexcept;
//==============================================================================
/** Swaps the byte order of a signed or unsigned integer if the CPU is big-endian */
template <typename Type>
static Type swapIfBigEndian (Type value) noexcept
{
#if JUCE_LITTLE_ENDIAN
return value;
#else
return swap (value);
#endif
}
/** Swaps the byte order of a signed or unsigned integer if the CPU is little-endian */
template <typename Type>
static Type swapIfLittleEndian (Type value) noexcept
{
#if JUCE_LITTLE_ENDIAN
return swap (value);
#else
return value;
#endif
}
//==============================================================================
/** Turns 4 bytes into a little-endian integer. */
JUCE_CONSTEXPR static uint32 littleEndianInt (const void* bytes) noexcept;
/** Turns 8 bytes into a little-endian integer. */
JUCE_CONSTEXPR static uint64 littleEndianInt64 (const void* bytes) noexcept;
/** Turns 2 bytes into a little-endian integer. */
JUCE_CONSTEXPR static uint16 littleEndianShort (const void* bytes) noexcept;
/** Converts 3 little-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
JUCE_CONSTEXPR static int littleEndian24Bit (const void* bytes) noexcept;
/** Copies a 24-bit number to 3 little-endian bytes. */
static void littleEndian24BitToChars (int32 value, void* destBytes) noexcept;
//==============================================================================
/** Turns 4 bytes into a big-endian integer. */
JUCE_CONSTEXPR static uint32 bigEndianInt (const void* bytes) noexcept;
/** Turns 8 bytes into a big-endian integer. */
JUCE_CONSTEXPR static uint64 bigEndianInt64 (const void* bytes) noexcept;
/** Turns 2 bytes into a big-endian integer. */
JUCE_CONSTEXPR static uint16 bigEndianShort (const void* bytes) noexcept;
/** Converts 3 big-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
JUCE_CONSTEXPR static int bigEndian24Bit (const void* bytes) noexcept;
/** Copies a 24-bit number to 3 big-endian bytes. */
static void bigEndian24BitToChars (int32 value, void* destBytes) noexcept;
//==============================================================================
/** Constructs a 16-bit integer from its constituent bytes, in order of significance. */
JUCE_CONSTEXPR static uint16 makeInt (uint8 leastSig, uint8 mostSig) noexcept;
/** Constructs a 32-bit integer from its constituent bytes, in order of significance. */
JUCE_CONSTEXPR static uint32 makeInt (uint8 leastSig, uint8 byte1, uint8 byte2, uint8 mostSig) noexcept;
/** Constructs a 64-bit integer from its constituent bytes, in order of significance. */
JUCE_CONSTEXPR static uint64 makeInt (uint8 leastSig, uint8 byte1, uint8 byte2, uint8 byte3,
uint8 byte4, uint8 byte5, uint8 byte6, uint8 mostSig) noexcept;
//==============================================================================
/** Returns true if the current CPU is big-endian. */
JUCE_CONSTEXPR static bool isBigEndian() noexcept
{
#if JUCE_LITTLE_ENDIAN
return false;
#else
return true;
#endif
}
private:
ByteOrder() = delete;
};
//==============================================================================
JUCE_CONSTEXPR inline uint16 ByteOrder::swap (uint16 v) noexcept { return static_cast<uint16> ((v << 8) | (v >> 8)); }
JUCE_CONSTEXPR inline int16 ByteOrder::swap (int16 v) noexcept { return static_cast<int16> (swap (static_cast<uint16> (v))); }
inline int32 ByteOrder::swap (int32 v) noexcept { return static_cast<int32> (swap (static_cast<uint32> (v))); }
inline int64 ByteOrder::swap (int64 v) noexcept { return static_cast<int64> (swap (static_cast<uint64> (v))); }
inline float ByteOrder::swap (float v) noexcept { union { uint32 asUInt; float asFloat; } n; n.asFloat = v; n.asUInt = swap (n.asUInt); return n.asFloat; }
inline double ByteOrder::swap (double v) noexcept { union { uint64 asUInt; double asFloat; } n; n.asFloat = v; n.asUInt = swap (n.asUInt); return n.asFloat; }
#if JUCE_MSVC && ! defined (__INTEL_COMPILER)
#pragma intrinsic (_byteswap_ulong)
#endif
inline uint32 ByteOrder::swap (uint32 n) noexcept
{
#if JUCE_MAC || JUCE_IOS
return OSSwapInt32 (n);
#elif (JUCE_GCC || JUCE_CLANG) && JUCE_INTEL && ! JUCE_NO_INLINE_ASM
asm("bswap %%eax" : "=a"(n) : "a"(n));
return n;
#elif JUCE_MSVC
return _byteswap_ulong (n);
#elif JUCE_ANDROID
return bswap_32 (n);
#else
return (n << 24) | (n >> 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8);
#endif
}
inline uint64 ByteOrder::swap (uint64 value) noexcept
{
#if JUCE_MAC || JUCE_IOS
return OSSwapInt64 (value);
#elif JUCE_MSVC
return _byteswap_uint64 (value);
#else
return (((uint64) swap ((uint32) value)) << 32) | swap ((uint32) (value >> 32));
#endif
}
JUCE_CONSTEXPR inline uint16 ByteOrder::makeInt (uint8 b0, uint8 b1) noexcept
{
return static_cast<uint16> (static_cast<uint16> (b0) | (static_cast<uint16> (b1) << 8));
}
JUCE_CONSTEXPR inline uint32 ByteOrder::makeInt (uint8 b0, uint8 b1, uint8 b2, uint8 b3) noexcept
{
return static_cast<uint32> (b0) | (static_cast<uint32> (b1) << 8)
| (static_cast<uint32> (b2) << 16) | (static_cast<uint32> (b3) << 24);
}
JUCE_CONSTEXPR inline uint64 ByteOrder::makeInt (uint8 b0, uint8 b1, uint8 b2, uint8 b3, uint8 b4, uint8 b5, uint8 b6, uint8 b7) noexcept
{
return static_cast<uint64> (b0) | (static_cast<uint64> (b1) << 8) | (static_cast<uint64> (b2) << 16) | (static_cast<uint64> (b3) << 24)
| (static_cast<uint64> (b4) << 32) | (static_cast<uint64> (b5) << 40) | (static_cast<uint64> (b6) << 48) | (static_cast<uint64> (b7) << 56);
}
JUCE_CONSTEXPR inline uint16 ByteOrder::littleEndianShort (const void* bytes) noexcept { return makeInt (static_cast<const uint8*> (bytes)[0], static_cast<const uint8*> (bytes)[1]); }
JUCE_CONSTEXPR inline uint32 ByteOrder::littleEndianInt (const void* bytes) noexcept { return makeInt (static_cast<const uint8*> (bytes)[0], static_cast<const uint8*> (bytes)[1],
static_cast<const uint8*> (bytes)[2], static_cast<const uint8*> (bytes)[3]); }
JUCE_CONSTEXPR inline uint64 ByteOrder::littleEndianInt64 (const void* bytes) noexcept { return makeInt (static_cast<const uint8*> (bytes)[0], static_cast<const uint8*> (bytes)[1],
static_cast<const uint8*> (bytes)[2], static_cast<const uint8*> (bytes)[3],
static_cast<const uint8*> (bytes)[4], static_cast<const uint8*> (bytes)[5],
static_cast<const uint8*> (bytes)[6], static_cast<const uint8*> (bytes)[7]); }
JUCE_CONSTEXPR inline uint16 ByteOrder::bigEndianShort (const void* bytes) noexcept { return makeInt (static_cast<const uint8*> (bytes)[1], static_cast<const uint8*> (bytes)[0]); }
JUCE_CONSTEXPR inline uint32 ByteOrder::bigEndianInt (const void* bytes) noexcept { return makeInt (static_cast<const uint8*> (bytes)[3], static_cast<const uint8*> (bytes)[2],
static_cast<const uint8*> (bytes)[1], static_cast<const uint8*> (bytes)[0]); }
JUCE_CONSTEXPR inline uint64 ByteOrder::bigEndianInt64 (const void* bytes) noexcept { return makeInt (static_cast<const uint8*> (bytes)[7], static_cast<const uint8*> (bytes)[6],
static_cast<const uint8*> (bytes)[5], static_cast<const uint8*> (bytes)[4],
static_cast<const uint8*> (bytes)[3], static_cast<const uint8*> (bytes)[2],
static_cast<const uint8*> (bytes)[1], static_cast<const uint8*> (bytes)[0]); }
JUCE_CONSTEXPR inline int32 ByteOrder::littleEndian24Bit (const void* bytes) noexcept { return (int32) ((((uint32) static_cast<const int8*> (bytes)[2]) << 16) | (((uint32) static_cast<const uint8*> (bytes)[1]) << 8) | ((uint32) static_cast<const uint8*> (bytes)[0])); }
JUCE_CONSTEXPR inline int32 ByteOrder::bigEndian24Bit (const void* bytes) noexcept { return (int32) ((((uint32) static_cast<const int8*> (bytes)[0]) << 16) | (((uint32) static_cast<const uint8*> (bytes)[1]) << 8) | ((uint32) static_cast<const uint8*> (bytes)[2])); }
inline void ByteOrder::littleEndian24BitToChars (int32 value, void* destBytes) noexcept { static_cast<uint8*> (destBytes)[0] = (uint8) value; static_cast<uint8*> (destBytes)[1] = (uint8) (value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8) (value >> 16); }
inline void ByteOrder::bigEndian24BitToChars (int32 value, void* destBytes) noexcept { static_cast<uint8*> (destBytes)[0] = (uint8) (value >> 16); static_cast<uint8*> (destBytes)[1] = (uint8) (value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8) value; }
} // namespace juce

View File

@ -0,0 +1,58 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided 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.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
Used by container classes as an indirect way to delete an object of a
particular type.
The generic implementation of this class simply calls 'delete', but you can
create a specialised version of it for a particular class if you need to
delete that type of object in a more appropriate way.
@see ScopedPointer, OwnedArray
@tags{Core}
*/
template <typename ObjectType>
struct ContainerDeletePolicy
{
static void destroy (ObjectType* object)
{
// If the line below triggers a compiler error, it means that you are using
// an incomplete type for ObjectType (for example, a type that is declared
// but not defined). This is a problem because then the following delete is
// undefined behaviour. The purpose of the sizeof is to capture this situation.
// If this was caused by a ScopedPointer to a forward-declared type, move the
// implementation of all methods trying to use the ScopedPointer (e.g. the destructor
// of the class owning it) into cpp files where they can see to the definition
// of ObjectType. This should fix the error.
ignoreUnused (sizeof (ObjectType));
delete object;
}
};
} // namespace juce

View File

@ -0,0 +1,320 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided 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.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
#if ! (defined (DOXYGEN) || JUCE_EXCEPTIONS_DISABLED)
namespace HeapBlockHelper
{
template <bool shouldThrow>
struct ThrowOnFail { static void checkPointer (void*) {} };
template<>
struct ThrowOnFail<true> { static void checkPointer (void* data) { if (data == nullptr) throw std::bad_alloc(); } };
}
#endif
//==============================================================================
/**
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.
The throwOnFailure template parameter can be set to true if you'd like the class
to throw a std::bad_alloc exception when an allocation fails. If this is false,
then a failed allocation will just leave the heapblock with a null pointer (assuming
that the system's malloc() function doesn't throw).
@see Array, OwnedArray, MemoryBlock
@tags{Core}
*/
template <class ElementType, bool throwOnFailure = false>
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
{
}
/** Creates a HeapBlock containing a number of elements.
The contents of the block are undefined, as it will have been created by a
malloc call.
If you want an array of zero values, you can use the calloc() method or the
other constructor that takes an InitialisationState parameter.
*/
template <typename SizeType>
explicit HeapBlock (SizeType numElements)
: data (static_cast<ElementType*> (std::malloc (static_cast<size_t> (numElements) * sizeof (ElementType))))
{
throwOnAllocationFailure();
}
/** Creates a HeapBlock containing a number of elements.
The initialiseToZero parameter determines whether the new memory should be cleared,
or left uninitialised.
*/
template <typename SizeType>
HeapBlock (SizeType numElements, bool initialiseToZero)
: data (static_cast<ElementType*> (initialiseToZero
? std::calloc (static_cast<size_t> (numElements), sizeof (ElementType))
: std::malloc (static_cast<size_t> (numElements) * sizeof (ElementType))))
{
throwOnAllocationFailure();
}
/** Destructor.
This will free the data, if any has been allocated.
*/
~HeapBlock()
{
std::free (data);
}
/** Move constructor */
HeapBlock (HeapBlock&& other) noexcept
: data (other.data)
{
other.data = nullptr;
}
/** Move assignment operator */
HeapBlock& operator= (HeapBlock&& other) noexcept
{
std::swap (data, other.data);
return *this;
}
//==============================================================================
/** 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* get() 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>
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>
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* 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* 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.
*/
template <typename SizeType>
void malloc (SizeType newNumElements, size_t elementSize = sizeof (ElementType))
{
std::free (data);
data = static_cast<ElementType*> (std::malloc (static_cast<size_t> (newNumElements) * elementSize));
throwOnAllocationFailure();
}
/** 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.
*/
template <typename SizeType>
void calloc (SizeType newNumElements, const size_t elementSize = sizeof (ElementType))
{
std::free (data);
data = static_cast<ElementType*> (std::calloc (static_cast<size_t> (newNumElements), elementSize));
throwOnAllocationFailure();
}
/** 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.
*/
template <typename SizeType>
void allocate (SizeType newNumElements, bool initialiseToZero)
{
std::free (data);
data = static_cast<ElementType*> (initialiseToZero
? std::calloc (static_cast<size_t> (newNumElements), sizeof (ElementType))
: std::malloc (static_cast<size_t> (newNumElements) * sizeof (ElementType)));
throwOnAllocationFailure();
}
/** 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.
*/
template <typename SizeType>
void realloc (SizeType newNumElements, size_t elementSize = sizeof (ElementType))
{
data = static_cast<ElementType*> (data == nullptr ? std::malloc (static_cast<size_t> (newNumElements) * elementSize)
: std::realloc (data, static_cast<size_t> (newNumElements) * elementSize));
throwOnAllocationFailure();
}
/** 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.
*/
template <bool otherBlockThrows>
void swapWith (HeapBlock<ElementType, otherBlockThrows>& 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.
*/
template <typename SizeType>
void clear (SizeType numElements) noexcept
{
zeromem (data, sizeof (ElementType) * static_cast<size_t> (numElements));
}
/** This typedef can be used to get the type of the heapblock's elements. */
typedef ElementType Type;
private:
//==============================================================================
ElementType* data = nullptr;
void throwOnAllocationFailure() const
{
#if JUCE_EXCEPTIONS_DISABLED
jassert (data != nullptr); // without exceptions, you'll need to find a better way to handle this failure case.
#else
HeapBlockHelper::ThrowOnFail<throwOnFailure>::checkPointer (data);
#endif
}
#if ! (defined (JUCE_DLL) || defined (JUCE_DLL_BUILD))
JUCE_DECLARE_NON_COPYABLE (HeapBlock)
JUCE_PREVENT_HEAP_ALLOCATION // Creating a 'new HeapBlock' would be missing the point!
#endif
};
} // namespace juce

View File

@ -0,0 +1,140 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided 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.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
Embedding an instance of this class inside another class can be used as a low-overhead
way of detecting leaked instances.
This class keeps an internal static count of the number of instances that are
active, so that when the app is shutdown and the static destructors are called,
it can check whether there are any left-over instances that may have been leaked.
To use it, use the JUCE_LEAK_DETECTOR macro as a simple way to put one in your
class declaration. Have a look through the juce codebase for examples, it's used
in most of the classes.
@tags{Core}
*/
template <class OwnerClass>
class LeakedObjectDetector
{
public:
//==============================================================================
LeakedObjectDetector() noexcept { ++(getCounter().numObjects); }
LeakedObjectDetector (const LeakedObjectDetector&) noexcept { ++(getCounter().numObjects); }
~LeakedObjectDetector()
{
if (--(getCounter().numObjects) < 0)
{
DBG ("*** Dangling pointer deletion! Class: " << getLeakedObjectClassName());
/** If you hit this, then you've managed to delete more instances of this class than you've
created.. That indicates that you're deleting some dangling pointers.
Note that although this assertion will have been triggered during a destructor, it might
not be this particular deletion that's at fault - the incorrect one may have happened
at an earlier point in the program, and simply not been detected until now.
Most errors like this are caused by using old-fashioned, non-RAII techniques for
your object management. Tut, tut. Always, always use std::unique_ptrs, OwnedArrays,
ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
*/
jassertfalse;
}
}
private:
//==============================================================================
class LeakCounter
{
public:
LeakCounter() noexcept {}
~LeakCounter()
{
if (numObjects.value > 0)
{
DBG ("*** Leaked objects detected: " << numObjects.value << " instance(s) of class " << getLeakedObjectClassName());
/** If you hit this, then you've leaked one or more objects of the type specified by
the 'OwnerClass' template parameter - the name should have been printed by the line above.
If you're leaking, it's probably because you're using old-fashioned, non-RAII techniques for
your object management. Tut, tut. Always, always use std::unique_ptrs, OwnedArrays,
ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
*/
jassertfalse;
}
}
Atomic<int> numObjects;
};
static const char* getLeakedObjectClassName()
{
return OwnerClass::getLeakedObjectClassName();
}
static LeakCounter& getCounter() noexcept
{
static LeakCounter counter;
return counter;
}
};
//==============================================================================
#if DOXYGEN || ! defined (JUCE_LEAK_DETECTOR)
#if (DOXYGEN || JUCE_CHECK_MEMORY_LEAKS)
/** This macro lets you embed a leak-detecting object inside a class.
To use it, simply declare a JUCE_LEAK_DETECTOR(YourClassName) inside a private section
of the class declaration. E.g.
@code
class MyClass
{
public:
MyClass();
void blahBlah();
private:
JUCE_LEAK_DETECTOR (MyClass)
};
@endcode
@see JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR, LeakedObjectDetector
*/
#define JUCE_LEAK_DETECTOR(OwnerClass) \
friend class juce::LeakedObjectDetector<OwnerClass>; \
static const char* getLeakedObjectClassName() noexcept { return #OwnerClass; } \
juce::LeakedObjectDetector<OwnerClass> JUCE_JOIN_MACRO (leakDetector, __LINE__);
#else
#define JUCE_LEAK_DETECTOR(OwnerClass)
#endif
#endif
} // namespace juce

View File

@ -0,0 +1,146 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided 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.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/** Fills a block of memory with zeros. */
inline void zeromem (void* memory, size_t numBytes) noexcept { memset (memory, 0, numBytes); }
/** Overwrites a structure or object with zeros. */
template <typename Type>
inline void zerostruct (Type& structure) noexcept { memset (&structure, 0, sizeof (structure)); }
/** Delete an object pointer, and sets the pointer to null.
Remember that it's not good c++ practice to use delete directly - always try to use a std::unique_ptr
or other automatic lifetime-management system rather than resorting to deleting raw pointers!
*/
template <typename Type>
inline void deleteAndZero (Type& pointer) { delete pointer; pointer = nullptr; }
/** A handy function which adds a number of bytes to any type of pointer and returns the result.
This can be useful to avoid casting pointers to a char* and back when you want to move them by
a specific number of bytes,
*/
template <typename Type, typename IntegerType>
inline Type* addBytesToPointer (Type* basePointer, IntegerType bytes) noexcept { return (Type*) (((char*) basePointer) + bytes); }
/** A handy function to round up a pointer to the nearest multiple of a given number of bytes.
alignmentBytes must be a power of two. */
template <typename Type, typename IntegerType>
inline Type* snapPointerToAlignment (Type* basePointer, IntegerType alignmentBytes) noexcept
{
return (Type*) ((((size_t) basePointer) + (alignmentBytes - 1)) & ~(alignmentBytes - 1));
}
/** A handy function which returns the difference between any two pointers, in bytes.
The address of the second pointer is subtracted from the first, and the difference in bytes is returned.
*/
template <typename Type1, typename Type2>
inline int getAddressDifference (Type1* pointer1, Type2* pointer2) noexcept { return (int) (((const char*) pointer1) - (const char*) pointer2); }
/** If a pointer is non-null, this returns a new copy of the object that it points to, or safely returns
nullptr if the pointer is null.
*/
template <class Type>
inline Type* createCopyIfNotNull (const Type* objectToCopy) { return objectToCopy != nullptr ? new Type (*objectToCopy) : nullptr; }
//==============================================================================
/** A handy function to read un-aligned memory without a performance penalty or bus-error. */
template <typename Type>
inline Type readUnaligned (const void* srcPtr) noexcept
{
Type value;
memcpy (&value, srcPtr, sizeof (Type));
return value;
}
/** A handy function to write un-aligned memory without a performance penalty or bus-error. */
template <typename Type>
inline void writeUnaligned (void* dstPtr, Type value) noexcept
{
memcpy (dstPtr, &value, sizeof (Type));
}
//==============================================================================
#if JUCE_MAC || JUCE_IOS || DOXYGEN
/** A handy C++ wrapper that creates and deletes an NSAutoreleasePool object using RAII.
You should use the JUCE_AUTORELEASEPOOL macro to create a local auto-release pool on the stack.
@tags{Core}
*/
class JUCE_API ScopedAutoReleasePool
{
public:
ScopedAutoReleasePool();
~ScopedAutoReleasePool();
private:
void* pool;
JUCE_DECLARE_NON_COPYABLE (ScopedAutoReleasePool)
};
/** A macro that can be used to easily declare a local ScopedAutoReleasePool
object for RAII-based obj-C autoreleasing.
Because this may use the \@autoreleasepool syntax, you must follow the macro with
a set of braces to mark the scope of the pool.
*/
#if (JUCE_COMPILER_SUPPORTS_ARC && defined (__OBJC__)) || DOXYGEN
#define JUCE_AUTORELEASEPOOL @autoreleasepool
#else
#define JUCE_AUTORELEASEPOOL const juce::ScopedAutoReleasePool JUCE_JOIN_MACRO (autoReleasePool_, __LINE__);
#endif
#else
#define JUCE_AUTORELEASEPOOL
#endif
//==============================================================================
/* In a Windows DLL build, we'll expose some malloc/free functions that live inside the DLL, and use these for
allocating all the objects - that way all juce objects in the DLL and in the host will live in the same heap,
avoiding problems when an object is created in one module and passed across to another where it is deleted.
By piggy-backing on the JUCE_LEAK_DETECTOR macro, these allocators can be injected into most juce classes.
*/
#if JUCE_MSVC && (defined (JUCE_DLL) || defined (JUCE_DLL_BUILD)) && ! (JUCE_DISABLE_DLL_ALLOCATORS || DOXYGEN)
extern JUCE_API void* juceDLL_malloc (size_t);
extern JUCE_API void juceDLL_free (void*);
#define JUCE_LEAK_DETECTOR(OwnerClass) public:\
static void* operator new (size_t sz) { return juce::juceDLL_malloc (sz); } \
static void* operator new (size_t, void* p) { return p; } \
static void operator delete (void* p) { juce::juceDLL_free (p); } \
static void operator delete (void*, void*) {}
#endif
//==============================================================================
/** (Deprecated) This was a Windows-specific way of checking for object leaks - now please
use the JUCE_LEAK_DETECTOR instead.
*/
#ifndef juce_UseDebuggingNewOperator
#define juce_UseDebuggingNewOperator
#endif
} // namespace juce

View File

@ -0,0 +1,410 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided 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.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
MemoryBlock::MemoryBlock() noexcept {}
MemoryBlock::MemoryBlock (size_t initialSize, bool initialiseToZero)
{
if (initialSize > 0)
{
size = initialSize;
data.allocate (initialSize, initialiseToZero);
}
else
{
size = 0;
}
}
MemoryBlock::MemoryBlock (const MemoryBlock& other)
: size (other.size)
{
if (size > 0)
{
jassert (other.data != nullptr);
data.malloc (size);
memcpy (data, other.data, size);
}
}
MemoryBlock::MemoryBlock (const void* const dataToInitialiseFrom, const size_t sizeInBytes)
: size (sizeInBytes)
{
jassert (((ssize_t) sizeInBytes) >= 0);
if (size > 0)
{
jassert (dataToInitialiseFrom != nullptr); // non-zero size, but a zero pointer passed-in?
data.malloc (size);
if (dataToInitialiseFrom != nullptr)
memcpy (data, dataToInitialiseFrom, size);
}
}
MemoryBlock::~MemoryBlock() noexcept
{
}
MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other)
{
if (this != &other)
{
setSize (other.size, false);
memcpy (data, other.data, size);
}
return *this;
}
MemoryBlock::MemoryBlock (MemoryBlock&& other) noexcept
: data (static_cast<HeapBlockType&&> (other.data)),
size (other.size)
{
}
MemoryBlock& MemoryBlock::operator= (MemoryBlock&& other) noexcept
{
data = static_cast<HeapBlockType&&> (other.data);
size = other.size;
return *this;
}
//==============================================================================
bool MemoryBlock::operator== (const MemoryBlock& other) const noexcept
{
return matches (other.data, other.size);
}
bool MemoryBlock::operator!= (const MemoryBlock& other) const noexcept
{
return ! operator== (other);
}
bool MemoryBlock::matches (const void* dataToCompare, size_t dataSize) const noexcept
{
return size == dataSize
&& memcmp (data, dataToCompare, size) == 0;
}
//==============================================================================
// this will resize the block to this size
void MemoryBlock::setSize (const size_t newSize, const bool initialiseToZero)
{
if (size != newSize)
{
if (newSize <= 0)
{
reset();
}
else
{
if (data != nullptr)
{
data.realloc (newSize);
if (initialiseToZero && (newSize > size))
zeromem (data + size, newSize - size);
}
else
{
data.allocate (newSize, initialiseToZero);
}
size = newSize;
}
}
}
void MemoryBlock::reset()
{
data.free();
size = 0;
}
void MemoryBlock::ensureSize (size_t minimumSize, bool initialiseToZero)
{
if (size < minimumSize)
setSize (minimumSize, initialiseToZero);
}
void MemoryBlock::swapWith (MemoryBlock& other) noexcept
{
std::swap (size, other.size);
data.swapWith (other.data);
}
//==============================================================================
void MemoryBlock::fillWith (uint8 value) noexcept
{
memset (data, (int) value, size);
}
void MemoryBlock::append (const void* srcData, size_t numBytes)
{
if (numBytes > 0)
{
jassert (srcData != nullptr); // this must not be null!
auto oldSize = size;
setSize (size + numBytes);
memcpy (data + oldSize, srcData, numBytes);
}
}
void MemoryBlock::replaceWith (const void* srcData, size_t numBytes)
{
if (numBytes > 0)
{
jassert (srcData != nullptr); // this must not be null!
setSize (numBytes);
memcpy (data, srcData, numBytes);
}
}
void MemoryBlock::insert (const void* srcData, size_t numBytes, size_t insertPosition)
{
if (numBytes > 0)
{
jassert (srcData != nullptr); // this must not be null!
insertPosition = jmin (size, insertPosition);
auto trailingDataSize = size - insertPosition;
setSize (size + numBytes, false);
if (trailingDataSize > 0)
memmove (data + insertPosition + numBytes,
data + insertPosition,
trailingDataSize);
memcpy (data + insertPosition, srcData, numBytes);
}
}
void MemoryBlock::removeSection (size_t startByte, size_t numBytesToRemove)
{
if (startByte + numBytesToRemove >= size)
{
setSize (startByte);
}
else if (numBytesToRemove > 0)
{
memmove (data + startByte,
data + startByte + numBytesToRemove,
size - (startByte + numBytesToRemove));
setSize (size - numBytesToRemove);
}
}
void MemoryBlock::copyFrom (const void* const src, int offset, size_t num) noexcept
{
auto* d = static_cast<const char*> (src);
if (offset < 0)
{
d -= offset;
num += (size_t) -offset;
offset = 0;
}
if ((size_t) offset + num > size)
num = size - (size_t) offset;
if (num > 0)
memcpy (data + offset, d, num);
}
void MemoryBlock::copyTo (void* const dst, int offset, size_t num) const noexcept
{
auto* d = static_cast<char*> (dst);
if (offset < 0)
{
zeromem (d, (size_t) -offset);
d -= offset;
num -= (size_t) -offset;
offset = 0;
}
if ((size_t) offset + num > size)
{
auto newNum = (size_t) size - (size_t) offset;
zeromem (d + newNum, num - newNum);
num = newNum;
}
if (num > 0)
memcpy (d, data + offset, num);
}
String MemoryBlock::toString() const
{
return String::fromUTF8 (data, (int) size);
}
//==============================================================================
int MemoryBlock::getBitRange (size_t bitRangeStart, size_t numBits) const noexcept
{
int res = 0;
auto byte = bitRangeStart >> 3;
auto offsetInByte = bitRangeStart & 7;
size_t bitsSoFar = 0;
while (numBits > 0 && (size_t) byte < size)
{
auto bitsThisTime = jmin (numBits, 8 - offsetInByte);
const int mask = (0xff >> (8 - bitsThisTime)) << offsetInByte;
res |= (((data[byte] & mask) >> offsetInByte) << bitsSoFar);
bitsSoFar += bitsThisTime;
numBits -= bitsThisTime;
++byte;
offsetInByte = 0;
}
return res;
}
void MemoryBlock::setBitRange (const size_t bitRangeStart, size_t numBits, int bitsToSet) noexcept
{
auto byte = bitRangeStart >> 3;
auto offsetInByte = bitRangeStart & 7;
uint32 mask = ~((((uint32) 0xffffffff) << (32 - numBits)) >> (32 - numBits));
while (numBits > 0 && (size_t) byte < size)
{
auto bitsThisTime = jmin (numBits, 8 - offsetInByte);
const uint32 tempMask = (mask << offsetInByte) | ~((((uint32) 0xffffffff) >> offsetInByte) << offsetInByte);
const uint32 tempBits = (uint32) bitsToSet << offsetInByte;
data[byte] = (char) (((uint32) data[byte] & tempMask) | tempBits);
++byte;
numBits -= bitsThisTime;
bitsToSet >>= bitsThisTime;
mask >>= bitsThisTime;
offsetInByte = 0;
}
}
//==============================================================================
void MemoryBlock::loadFromHexString (StringRef hex)
{
ensureSize ((size_t) hex.length() >> 1);
char* dest = data;
auto t = hex.text;
for (;;)
{
int byte = 0;
for (int loop = 2; --loop >= 0;)
{
byte <<= 4;
for (;;)
{
auto c = t.getAndAdvance();
if (c >= '0' && c <= '9') { byte |= c - '0'; break; }
if (c >= 'a' && c <= 'z') { byte |= c - ('a' - 10); break; }
if (c >= 'A' && c <= 'Z') { byte |= c - ('A' - 10); break; }
if (c == 0)
{
setSize (static_cast<size_t> (dest - data));
return;
}
}
}
*dest++ = (char) byte;
}
}
//==============================================================================
static const char base64EncodingTable[] = ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+";
String MemoryBlock::toBase64Encoding() const
{
auto numChars = ((size << 3) + 5) / 6;
String destString ((unsigned int) size); // store the length, followed by a '.', and then the data.
auto initialLen = destString.length();
destString.preallocateBytes (sizeof (String::CharPointerType::CharType) * (size_t) initialLen + 2 + numChars);
auto d = destString.getCharPointer();
d += initialLen;
d.write ('.');
for (size_t i = 0; i < numChars; ++i)
d.write ((juce_wchar) (uint8) base64EncodingTable[getBitRange (i * 6, 6)]);
d.writeNull();
return destString;
}
static const char base64DecodingTable[] =
{
63, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 0, 0, 0, 0, 0, 0, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52
};
bool MemoryBlock::fromBase64Encoding (StringRef s)
{
auto dot = CharacterFunctions::find (s.text, (juce_wchar) '.');
if (dot.isEmpty())
return false;
auto numBytesNeeded = String (s.text, dot).getIntValue();
setSize ((size_t) numBytesNeeded, true);
auto srcChars = dot + 1;
int pos = 0;
for (;;)
{
auto c = (int) srcChars.getAndAdvance();
if (c == 0)
return true;
c -= 43;
if (isPositiveAndBelow (c, numElementsInArray (base64DecodingTable)))
{
setBitRange ((size_t) pos, 6, base64DecodingTable[c]);
pos += 6;
}
}
}
} // namespace juce

View File

@ -0,0 +1,262 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided 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.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A class to hold a resizable block of raw data.
@tags{Core}
*/
class JUCE_API MemoryBlock
{
public:
//==============================================================================
/** Create an uninitialised block with 0 size. */
MemoryBlock() noexcept;
/** Creates a memory block with a given initial size.
@param initialSize the size of block to create
@param initialiseToZero whether to clear the memory or just leave it uninitialised
*/
MemoryBlock (const size_t initialSize,
bool initialiseToZero = false);
/** Creates a copy of another memory block. */
MemoryBlock (const MemoryBlock&);
/** Creates a memory block using a copy of a block of data.
@param dataToInitialiseFrom some data to copy into this block
@param sizeInBytes how much space to use
*/
MemoryBlock (const void* dataToInitialiseFrom, size_t sizeInBytes);
/** Destructor. */
~MemoryBlock() noexcept;
/** Copies another memory block onto this one.
This block will be resized and copied to exactly match the other one.
*/
MemoryBlock& operator= (const MemoryBlock&);
/** Move constructor */
MemoryBlock (MemoryBlock&&) noexcept;
/** Move assignment operator */
MemoryBlock& operator= (MemoryBlock&&) noexcept;
//==============================================================================
/** Compares two memory blocks.
@returns true only if the two blocks are the same size and have identical contents.
*/
bool operator== (const MemoryBlock& other) const noexcept;
/** Compares two memory blocks.
@returns true if the two blocks are different sizes or have different contents.
*/
bool operator!= (const MemoryBlock& other) const noexcept;
/** Returns true if the data in this MemoryBlock matches the raw bytes passed-in. */
bool matches (const void* data, size_t dataSize) const noexcept;
//==============================================================================
/** Returns a void pointer to the data.
Note that the pointer returned will probably become invalid when the
block is resized.
*/
void* getData() const noexcept { return data; }
/** Returns a byte from the memory block.
This returns a reference, so you can also use it to set a byte.
*/
template <typename Type>
char& operator[] (const Type offset) const noexcept { return data [offset]; }
/** Returns an iterator for the data. */
char* begin() const noexcept { return data; }
/** Returns an end-iterator for the data. */
char* end() const noexcept { return begin() + getSize(); }
//==============================================================================
/** Returns the block's current allocated size, in bytes. */
size_t getSize() const noexcept { return size; }
/** Resizes the memory block.
Any data that is present in both the old and new sizes will be retained.
When enlarging the block, the new space that is allocated at the end can either be
cleared, or left uninitialised.
@param newSize the new desired size for the block
@param initialiseNewSpaceToZero if the block gets enlarged, this determines
whether to clear the new section or just leave it
uninitialised
@see ensureSize
*/
void setSize (const size_t newSize,
bool initialiseNewSpaceToZero = false);
/** Increases the block's size only if it's smaller than a given size.
@param minimumSize if the block is already bigger than this size, no action
will be taken; otherwise it will be increased to this size
@param initialiseNewSpaceToZero if the block gets enlarged, this determines
whether to clear the new section or just leave it
uninitialised
@see setSize
*/
void ensureSize (const size_t minimumSize,
bool initialiseNewSpaceToZero = false);
/** Frees all the blocks data, setting its size to 0. */
void reset();
//==============================================================================
/** Fills the entire memory block with a repeated byte value.
This is handy for clearing a block of memory to zero.
*/
void fillWith (uint8 valueToUse) noexcept;
/** Adds another block of data to the end of this one.
The data pointer must not be null. This block's size will be increased accordingly.
*/
void append (const void* data, size_t numBytes);
/** Resizes this block to the given size and fills its contents from the supplied buffer.
The data pointer must not be null.
*/
void replaceWith (const void* data, size_t numBytes);
/** Inserts some data into the block.
The dataToInsert pointer must not be null. This block's size will be increased accordingly.
If the insert position lies outside the valid range of the block, it will be clipped to
within the range before being used.
*/
void insert (const void* dataToInsert, size_t numBytesToInsert, size_t insertPosition);
/** Chops out a section of the block.
This will remove a section of the memory block and close the gap around it,
shifting any subsequent data downwards and reducing the size of the block.
If the range specified goes beyond the size of the block, it will be clipped.
*/
void removeSection (size_t startByte, size_t numBytesToRemove);
//==============================================================================
/** Copies data into this MemoryBlock from a memory address.
@param srcData the memory location of the data to copy into this block
@param destinationOffset the offset in this block at which the data being copied should begin
@param numBytes how much to copy in (if this goes beyond the size of the memory block,
it will be clipped so not to do anything nasty)
*/
void copyFrom (const void* srcData,
int destinationOffset,
size_t numBytes) noexcept;
/** Copies data from this MemoryBlock to a memory address.
@param destData the memory location to write to
@param sourceOffset the offset within this block from which the copied data will be read
@param numBytes how much to copy (if this extends beyond the limits of the memory block,
zeros will be used for that portion of the data)
*/
void copyTo (void* destData,
int sourceOffset,
size_t numBytes) const noexcept;
//==============================================================================
/** Exchanges the contents of this and another memory block.
No actual copying is required for this, so it's very fast.
*/
void swapWith (MemoryBlock& other) noexcept;
//==============================================================================
/** Attempts to parse the contents of the block as a zero-terminated UTF8 string. */
String toString() const;
//==============================================================================
/** Parses a string of hexadecimal numbers and writes this data into the memory block.
The block will be resized to the number of valid bytes read from the string.
Non-hex characters in the string will be ignored.
@see String::toHexString()
*/
void loadFromHexString (StringRef sourceHexString);
//==============================================================================
/** Sets a number of bits in the memory block, treating it as a long binary sequence. */
void setBitRange (size_t bitRangeStart,
size_t numBits,
int binaryNumberToApply) noexcept;
/** Reads a number of bits from the memory block, treating it as one long binary sequence */
int getBitRange (size_t bitRangeStart,
size_t numBitsToRead) const noexcept;
//==============================================================================
/** Returns a string of characters in a JUCE-specific text encoding that represents the
binary contents of this block.
This uses a JUCE-specific (i.e. not standard!) 64-bit encoding system to convert binary
data into a string of ASCII characters for purposes like storage in XML.
Note that this proprietary format is mainly kept here for backwards-compatibility, and
you may prefer to use the Base64::toBase64() method if you want to use the standard
base-64 encoding.
@see fromBase64Encoding, Base64::toBase64, Base64::convertToBase64
*/
String toBase64Encoding() const;
/** Takes a string created by MemoryBlock::toBase64Encoding() and extracts the original data.
The string passed in must have been created by to64BitEncoding(), and this
block will be resized to recreate the original data block.
Note that these methods use a JUCE-specific (i.e. not standard!) 64-bit encoding system.
You may prefer to use the Base64::convertFromBase64() method if you want to use the
standard base-64 encoding.
@see toBase64Encoding, Base64::convertFromBase64
*/
bool fromBase64Encoding (StringRef encodedString);
private:
//==============================================================================
typedef HeapBlock<char, true> HeapBlockType;
HeapBlockType data;
size_t size = 0;
JUCE_LEAK_DETECTOR (MemoryBlock)
};
} // namespace juce

View File

@ -0,0 +1,189 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided 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.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
Holds a pointer to an object which can optionally be deleted when this pointer
goes out of scope.
This acts in many ways like a ScopedPointer, but allows you to specify whether or
not the object is deleted.
@see ScopedPointer
@tags{Core}
*/
template <class ObjectType>
class OptionalScopedPointer
{
public:
//==============================================================================
/** Creates an empty OptionalScopedPointer. */
OptionalScopedPointer() : shouldDelete (false) {}
/** Creates an OptionalScopedPointer to point to a given object, and specifying whether
the OptionalScopedPointer will delete it.
If takeOwnership is true, then the OptionalScopedPointer will act like a ScopedPointer,
deleting the object when it is itself deleted. If this parameter is false, then the
OptionalScopedPointer just holds a normal pointer to the object, and won't delete it.
*/
OptionalScopedPointer (ObjectType* objectToHold, bool takeOwnership)
: object (objectToHold), shouldDelete (takeOwnership)
{
}
/** Takes ownership of the object that another OptionalScopedPointer holds.
Like a normal ScopedPointer, the objectToTransferFrom object will become null,
as ownership of the managed object is transferred to this object.
The flag to indicate whether or not to delete the managed object is also
copied from the source object.
*/
OptionalScopedPointer (OptionalScopedPointer& objectToTransferFrom)
: object (objectToTransferFrom.release()),
shouldDelete (objectToTransferFrom.shouldDelete)
{
}
/** Takes ownership of the object that another OptionalScopedPointer holds.
Like a normal ScopedPointer, the objectToTransferFrom object will become null,
as ownership of the managed object is transferred to this object.
The ownership flag that says whether or not to delete the managed object is also
copied from the source object.
*/
OptionalScopedPointer& operator= (OptionalScopedPointer& objectToTransferFrom)
{
if (object != objectToTransferFrom.object)
{
reset();
object.reset (objectToTransferFrom.object.release());
}
shouldDelete = objectToTransferFrom.shouldDelete;
return *this;
}
/** The destructor may or may not delete the object that is being held, depending on the
takeOwnership flag that was specified when the object was first passed into an
OptionalScopedPointer constructor.
*/
~OptionalScopedPointer()
{
reset();
}
//==============================================================================
/** Returns the object that this pointer is managing. */
inline operator ObjectType*() const noexcept { return object.get(); }
/** Returns the object that this pointer is managing. */
inline ObjectType* get() const noexcept { return object.get(); }
/** Returns the object that this pointer is managing. */
inline ObjectType& operator*() const noexcept { return *object; }
/** Lets you access methods and properties of the object that this pointer is holding. */
inline ObjectType* operator->() const noexcept { return object.get(); }
//==============================================================================
/** Removes the current object from this OptionalScopedPointer without deleting it.
This will return the current object, and set this OptionalScopedPointer to a null pointer.
*/
ObjectType* release() noexcept { return object.release(); }
/** Resets this pointer to null, possibly deleting the object that it holds, if it has
ownership of it.
*/
void reset()
{
if (! shouldDelete)
object.release();
}
/** Does the same thing as reset(). */
void clear() { reset(); }
/** Makes this OptionalScopedPointer point at a new object, specifying whether the
OptionalScopedPointer will take ownership of the object.
If takeOwnership is true, then the OptionalScopedPointer will act like a ScopedPointer,
deleting the object when it is itself deleted. If this parameter is false, then the
OptionalScopedPointer just holds a normal pointer to the object, and won't delete it.
*/
void set (ObjectType* newObject, bool takeOwnership)
{
if (object.get() != newObject)
{
reset();
object.reset (newObject);
}
shouldDelete = takeOwnership;
}
/** Makes this OptionalScopedPointer point at a new object, and take ownership of that object. */
void setOwned (ObjectType* newObject)
{
set (newObject, true);
}
/** Makes this OptionalScopedPointer point at a new object, but will not take ownership of that object. */
void setNonOwned (ObjectType* newObject)
{
set (newObject, false);
}
/** Returns true if the target object will be deleted when this pointer
object is deleted.
*/
bool willDeleteObject() const noexcept { return shouldDelete; }
//==============================================================================
/** Swaps this object with another OptionalScopedPointer.
The two objects simply exchange their states.
*/
void swapWith (OptionalScopedPointer<ObjectType>& other) noexcept
{
object.swapWith (other.object);
std::swap (shouldDelete, other.shouldDelete);
}
private:
//==============================================================================
ScopedPointer<ObjectType> object;
bool shouldDelete;
// This is here to avoid people accidentally taking a second owned copy of
// a scoped pointer, which is almost certainly not what you intended to do!
// If you hit a problem with this, you probably meant to say
// myPointer.setOwned (myScopedPointer.release())
void setOwned (const ScopedPointer<ObjectType>&) = delete;
};
} // namespace juce

View File

@ -0,0 +1,426 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided 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.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A base class which provides methods for reference-counting.
To add reference-counting to a class, derive it from this class, and
use the ReferenceCountedObjectPtr class to point to it.
e.g. @code
class MyClass : public ReferenceCountedObject
{
void foo();
// This is a neat way of declaring a typedef for a pointer class,
// rather than typing out the full templated name each time..
using Ptr = ReferenceCountedObjectPtr<MyClass>;
};
MyClass::Ptr p = new MyClass();
MyClass::Ptr p2 = p;
p = nullptr;
p2->foo();
@endcode
Once a new ReferenceCountedObject has been assigned to a pointer, be
careful not to delete the object manually.
This class uses an Atomic<int> value to hold the reference count, so that it
the pointers can be passed between threads safely. For a faster but non-thread-safe
version, use SingleThreadedReferenceCountedObject instead.
@see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject
@tags{Core}
*/
class JUCE_API ReferenceCountedObject
{
public:
//==============================================================================
/** Increments the object's reference count.
This is done automatically by the smart pointer, but is public just
in case it's needed for nefarious purposes.
*/
void incReferenceCount() noexcept
{
++refCount;
}
/** Decreases the object's reference count.
If the count gets to zero, the object will be deleted.
*/
void decReferenceCount() noexcept
{
jassert (getReferenceCount() > 0);
if (--refCount == 0)
delete this;
}
/** Decreases the object's reference count.
If the count gets to zero, the object will not be deleted, but this method
will return true, allowing the caller to take care of deletion.
*/
bool decReferenceCountWithoutDeleting() noexcept
{
jassert (getReferenceCount() > 0);
return --refCount == 0;
}
/** Returns the object's current reference count. */
int getReferenceCount() const noexcept { return refCount.get(); }
protected:
//==============================================================================
/** Creates the reference-counted object (with an initial ref count of zero). */
ReferenceCountedObject() {}
/** Copying from another object does not affect this one's reference-count. */
ReferenceCountedObject (const ReferenceCountedObject&) noexcept {}
/** Copying from another object does not affect this one's reference-count. */
ReferenceCountedObject (ReferenceCountedObject&&) noexcept {}
/** Copying from another object does not affect this one's reference-count. */
ReferenceCountedObject& operator= (const ReferenceCountedObject&) noexcept { return *this; }
/** Copying from another object does not affect this one's reference-count. */
ReferenceCountedObject& operator= (ReferenceCountedObject&&) noexcept { return *this; }
/** Destructor. */
virtual ~ReferenceCountedObject()
{
// it's dangerous to delete an object that's still referenced by something else!
jassert (getReferenceCount() == 0);
}
/** Resets the reference count to zero without deleting the object.
You should probably never need to use this!
*/
void resetReferenceCount() noexcept
{
refCount = 0;
}
private:
//==============================================================================
Atomic<int> refCount { 0 };
friend struct ContainerDeletePolicy<ReferenceCountedObject>;
};
//==============================================================================
/**
Adds reference-counting to an object.
This is effectively a version of the ReferenceCountedObject class, but which
uses a non-atomic counter, and so is not thread-safe (but which will be more
efficient).
For more details on how to use it, see the ReferenceCountedObject class notes.
@see ReferenceCountedObject, ReferenceCountedObjectPtr, ReferenceCountedArray
@tags{Core}
*/
class JUCE_API SingleThreadedReferenceCountedObject
{
public:
//==============================================================================
/** Increments the object's reference count.
This is done automatically by the smart pointer, but is public just
in case it's needed for nefarious purposes.
*/
void incReferenceCount() noexcept
{
++refCount;
}
/** Decreases the object's reference count.
If the count gets to zero, the object will be deleted.
*/
void decReferenceCount() noexcept
{
jassert (getReferenceCount() > 0);
if (--refCount == 0)
delete this;
}
/** Decreases the object's reference count.
If the count gets to zero, the object will not be deleted, but this method
will return true, allowing the caller to take care of deletion.
*/
bool decReferenceCountWithoutDeleting() noexcept
{
jassert (getReferenceCount() > 0);
return --refCount == 0;
}
/** Returns the object's current reference count. */
int getReferenceCount() const noexcept { return refCount; }
protected:
//==============================================================================
/** Creates the reference-counted object (with an initial ref count of zero). */
SingleThreadedReferenceCountedObject() {}
/** Copying from another object does not affect this one's reference-count. */
SingleThreadedReferenceCountedObject (const SingleThreadedReferenceCountedObject&) {}
/** Copying from another object does not affect this one's reference-count. */
SingleThreadedReferenceCountedObject (SingleThreadedReferenceCountedObject&&) {}
/** Copying from another object does not affect this one's reference-count. */
SingleThreadedReferenceCountedObject& operator= (const SingleThreadedReferenceCountedObject&) { return *this; }
/** Copying from another object does not affect this one's reference-count. */
SingleThreadedReferenceCountedObject& operator= (SingleThreadedReferenceCountedObject&&) { return *this; }
/** Destructor. */
virtual ~SingleThreadedReferenceCountedObject()
{
// it's dangerous to delete an object that's still referenced by something else!
jassert (getReferenceCount() == 0);
}
private:
//==============================================================================
int refCount = 0;
friend struct ContainerDeletePolicy<ReferenceCountedObject>;
};
//==============================================================================
/**
A smart-pointer class which points to a reference-counted object.
The template parameter specifies the class of the object you want to point to - the easiest
way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject
or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable
class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and
decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
should behave.
When using this class, you'll probably want to create a typedef to abbreviate the full
templated name - e.g.
@code
struct MyClass : public ReferenceCountedObject
{
using Ptr = ReferenceCountedObjectPtr<MyClass>;
...
}
@endcode
@see ReferenceCountedObject, ReferenceCountedObjectArray
@tags{Core}
*/
template <class ObjectType>
class ReferenceCountedObjectPtr
{
public:
/** The class being referenced by this pointer. */
using ReferencedType = ObjectType;
//==============================================================================
/** Creates a pointer to a null object. */
ReferenceCountedObjectPtr() noexcept {}
/** Creates a pointer to a null object. */
ReferenceCountedObjectPtr (decltype (nullptr)) noexcept {}
/** Creates a pointer to an object.
This will increment the object's reference-count.
*/
ReferenceCountedObjectPtr (ReferencedType* refCountedObject) noexcept
: referencedObject (refCountedObject)
{
incIfNotNull (refCountedObject);
}
/** Copies another pointer.
This will increment the object's reference-count.
*/
ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept
: referencedObject (other.referencedObject)
{
incIfNotNull (referencedObject);
}
/** Copies another pointer.
This will increment the object's reference-count (if it is non-null).
*/
template <typename Convertible>
ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr<Convertible>& other) noexcept
: referencedObject (other.get())
{
incIfNotNull (referencedObject);
}
/** Changes this pointer to point at a different object.
The reference count of the old object is decremented, and it might be
deleted if it hits zero. The new object's count is incremented.
*/
ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other)
{
return operator= (other.referencedObject);
}
/** Changes this pointer to point at a different object.
The reference count of the old object is decremented, and it might be
deleted if it hits zero. The new object's count is incremented.
*/
template <typename Convertible>
ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr<Convertible>& other)
{
return operator= (other.get());
}
/** Changes this pointer to point at a different object.
The reference count of the old object is decremented, and it might be
deleted if it hits zero. The new object's count is incremented.
*/
ReferenceCountedObjectPtr& operator= (ReferencedType* newObject)
{
if (referencedObject != newObject)
{
incIfNotNull (newObject);
auto* oldObject = referencedObject;
referencedObject = newObject;
decIfNotNull (oldObject);
}
return *this;
}
/** Takes-over the object from another pointer. */
ReferenceCountedObjectPtr (ReferenceCountedObjectPtr&& other) noexcept
: referencedObject (other.referencedObject)
{
other.referencedObject = nullptr;
}
/** Takes-over the object from another pointer. */
ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectPtr&& other)
{
std::swap (referencedObject, other.referencedObject);
return *this;
}
/** Destructor.
This will decrement the object's reference-count, which will cause the
object to be deleted when the ref-count hits zero.
*/
~ReferenceCountedObjectPtr()
{
decIfNotNull (referencedObject);
}
//==============================================================================
/** Returns the object that this pointer references.
The pointer returned may be null, of course.
*/
operator ReferencedType*() const noexcept { return referencedObject; }
/** Returns the object that this pointer references.
The pointer returned may be null, of course.
*/
ReferencedType* get() const noexcept { return referencedObject; }
/** Returns the object that this pointer references.
The pointer returned may be null, of course.
*/
ReferencedType* getObject() const noexcept { return referencedObject; }
// the -> operator is called on the referenced object
ReferencedType* operator->() const noexcept
{
jassert (referencedObject != nullptr); // null pointer method call!
return referencedObject;
}
private:
//==============================================================================
ReferencedType* referencedObject = nullptr;
static void incIfNotNull (ReferencedType* o) noexcept
{
if (o != nullptr)
o->incReferenceCount();
}
static void decIfNotNull (ReferencedType* o) noexcept
{
if (o != nullptr && o->decReferenceCountWithoutDeleting())
ContainerDeletePolicy<ReferencedType>::destroy (o);
}
};
//==============================================================================
/** Compares two ReferenceCountedObjectPtrs. */
template <typename ObjectType>
bool operator== (const ReferenceCountedObjectPtr<ObjectType>& object1, ObjectType* const object2) noexcept
{
return object1.get() == object2;
}
/** Compares two ReferenceCountedObjectPtrs. */
template <typename ObjectType>
bool operator== (const ReferenceCountedObjectPtr<ObjectType>& object1, const ReferenceCountedObjectPtr<ObjectType>& object2) noexcept
{
return object1.get() == object2.get();
}
/** Compares two ReferenceCountedObjectPtrs. */
template <typename ObjectType>
bool operator== (ObjectType* object1, const ReferenceCountedObjectPtr<ObjectType>& object2) noexcept
{
return object1 == object2.get();
}
/** Compares two ReferenceCountedObjectPtrs. */
template <typename ObjectType>
bool operator!= (const ReferenceCountedObjectPtr<ObjectType>& object1, const ObjectType* object2) noexcept
{
return object1.get() != object2;
}
/** Compares two ReferenceCountedObjectPtrs. */
template <typename ObjectType>
bool operator!= (const ReferenceCountedObjectPtr<ObjectType>& object1, const ReferenceCountedObjectPtr<ObjectType>& object2) noexcept
{
return object1.get() != object2.get();
}
/** Compares two ReferenceCountedObjectPtrs. */
template <typename ObjectType>
bool operator!= (ObjectType* object1, const ReferenceCountedObjectPtr<ObjectType>& object2) noexcept
{
return object1 != object2.get();
}
} // namespace juce

View File

@ -0,0 +1,287 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided 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.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
This class is deprecated. You should use std::unique_ptr instead.
A ScopedPointer holds a pointer that is automatically deleted when the ScopedPointer
goes out of scope.
Once a pointer has been passed to a ScopedPointer, it will make sure that the pointer
gets deleted when the ScopedPointer is deleted. Using the ScopedPointer on the stack or
as member variables is a good way to use RAII to avoid accidentally leaking dynamically
created objects.
A ScopedPointer can be used in pretty much the same way that you'd use a normal pointer
to an object. If you use the assignment operator to assign a different object to a
ScopedPointer, the old one will be automatically deleted.
Important note: The class is designed to hold a pointer to an object, NOT to an array!
It calls delete on its payload, not delete[], so do not give it an array to hold! For
that kind of purpose, you should be using HeapBlock or Array instead.
A const ScopedPointer is guaranteed not to lose ownership of its object or change the
object to which it points during its lifetime. This means that making a copy of a const
ScopedPointer is impossible, as that would involve the new copy taking ownership from the
old one.
If you need to get a pointer out of a ScopedPointer without it being deleted, you
can use the release() method.
@tags{Core}
*/
template <class ObjectType>
class ScopedPointer
{
public:
//==============================================================================
/** Creates a ScopedPointer containing a null pointer. */
inline ScopedPointer() noexcept {}
/** Creates a ScopedPointer containing a null pointer. */
inline ScopedPointer (decltype (nullptr)) noexcept {}
/** Creates a ScopedPointer that owns the specified object. */
inline ScopedPointer (ObjectType* objectToTakePossessionOf) noexcept
: object (objectToTakePossessionOf)
{
}
/** Creates a ScopedPointer that takes its pointer from another ScopedPointer.
Because a pointer can only belong to one ScopedPointer, this transfers
the pointer from the other object to this one, and the other object is reset to
be a null pointer.
*/
ScopedPointer (ScopedPointer& objectToTransferFrom) noexcept
: object (objectToTransferFrom.release())
{
}
/** Destructor.
If the ScopedPointer currently refers to an object, it'll be deleted.
*/
inline ~ScopedPointer() { reset(); }
/** Changes this ScopedPointer to point to a new object.
Because a pointer can only belong to one ScopedPointer, this transfers
the pointer from the other object to this one, and the other object is reset to
be a null pointer.
If this ScopedPointer already points to an object, that object
will first be deleted.
*/
ScopedPointer& operator= (ScopedPointer& objectToTransferFrom)
{
if (this != objectToTransferFrom.getAddress())
{
// Two ScopedPointers should never be able to refer to the same object - if
// this happens, you must have done something dodgy!
jassert (object == nullptr || object != objectToTransferFrom.object);
reset (objectToTransferFrom.release());
}
return *this;
}
/** Changes this ScopedPointer to point to a new object.
If this ScopedPointer already points to an object, that object will first be deleted.
The pointer that you pass in may be a nullptr.
*/
ScopedPointer& operator= (ObjectType* newObjectToTakePossessionOf)
{
reset (newObjectToTakePossessionOf);
return *this;
}
/** Take ownership of another ScopedPointer */
ScopedPointer (ScopedPointer&& other) noexcept : object (other.object)
{
other.object = nullptr;
}
/** Take ownership of another ScopedPointer */
ScopedPointer& operator= (ScopedPointer&& other) noexcept
{
reset (other.release());
return *this;
}
//==============================================================================
/** Returns the object that this ScopedPointer refers to. */
inline operator ObjectType*() const noexcept { return object; }
/** Returns the object that this ScopedPointer refers to. */
inline ObjectType* get() const noexcept { return object; }
/** Returns the object that this ScopedPointer refers to. */
inline ObjectType& operator*() const noexcept { return *object; }
/** Lets you access methods and properties of the object that this ScopedPointer refers to. */
inline ObjectType* operator->() const noexcept { return object; }
//==============================================================================
/** Clears this pointer, deleting the object it points to if there is one. */
void reset()
{
ContainerDeletePolicy<ObjectType>::destroy (object);
object = {};
}
/** Sets this pointer to a new object, deleting the old object that it was previously pointing to if there was one. */
void reset (ObjectType* newObject)
{
if (object != newObject)
{
auto* oldObject = object;
object = newObject;
ContainerDeletePolicy<ObjectType>::destroy (oldObject);
}
}
/** Sets this pointer to a new object, deleting the old object that it was previously pointing to if there was one. */
void reset (ScopedPointer& newObject)
{
reset (newObject.release());
}
/** Detaches and returns the current object from this ScopedPointer without deleting it.
This will return the current object, and set the ScopedPointer to a null pointer.
*/
ObjectType* release() noexcept { auto* o = object; object = {}; return o; }
//==============================================================================
/** Swaps this object with that of another ScopedPointer.
The two objects simply exchange their pointers.
*/
void swapWith (ScopedPointer<ObjectType>& other) noexcept
{
// Two ScopedPointers should never be able to refer to the same object - if
// this happens, you must have done something dodgy!
jassert (object != other.object || this == other.getAddress() || object == nullptr);
std::swap (object, other.object);
}
/** If the pointer is non-null, this will attempt to return a new copy of the object that is pointed to.
If the pointer is null, this will safely return a nullptr.
*/
inline ObjectType* createCopy() const { return createCopyIfNotNull (object); }
private:
//==============================================================================
ObjectType* object = nullptr;
const ScopedPointer* getAddress() const noexcept { return this; } // Used internally to avoid the & operator
#if ! JUCE_MSVC // (MSVC can't deal with multiple copy constructors)
ScopedPointer (const ScopedPointer&) = delete;
ScopedPointer& operator= (const ScopedPointer&) = delete;
#endif
};
//==============================================================================
/** Compares a ScopedPointer with another pointer. */
template <typename ObjectType1, typename ObjectType2>
bool operator== (ObjectType1* pointer1, const ScopedPointer<ObjectType2>& pointer2) noexcept
{
return pointer1 == pointer2.get();
}
/** Compares a ScopedPointer with another pointer. */
template <typename ObjectType1, typename ObjectType2>
bool operator!= (ObjectType1* pointer1, const ScopedPointer<ObjectType2>& pointer2) noexcept
{
return pointer1 != pointer2.get();
}
/** Compares a ScopedPointer with another pointer. */
template <typename ObjectType1, typename ObjectType2>
bool operator== (const ScopedPointer<ObjectType1>& pointer1, ObjectType2* pointer2) noexcept
{
return pointer1.get() == pointer2;
}
/** Compares a ScopedPointer with another pointer. */
template <typename ObjectType1, typename ObjectType2>
bool operator!= (const ScopedPointer<ObjectType1>& pointer1, ObjectType2* pointer2) noexcept
{
return pointer1.get() != pointer2;
}
/** Compares a ScopedPointer with another pointer. */
template <typename ObjectType1, typename ObjectType2>
bool operator== (const ScopedPointer<ObjectType1>& pointer1, const ScopedPointer<ObjectType2>& pointer2) noexcept
{
return pointer1.get() == pointer2.get();
}
/** Compares a ScopedPointer with another pointer. */
template <typename ObjectType1, typename ObjectType2>
bool operator!= (const ScopedPointer<ObjectType1>& pointer1, const ScopedPointer<ObjectType2>& pointer2) noexcept
{
return pointer1.get() != pointer2.get();
}
/** Compares a ScopedPointer with a nullptr. */
template <class ObjectType>
bool operator== (decltype (nullptr), const ScopedPointer<ObjectType>& pointer) noexcept
{
return pointer.get() == nullptr;
}
/** Compares a ScopedPointer with a nullptr. */
template <class ObjectType>
bool operator!= (decltype (nullptr), const ScopedPointer<ObjectType>& pointer) noexcept
{
return pointer.get() != nullptr;
}
/** Compares a ScopedPointer with a nullptr. */
template <class ObjectType>
bool operator== (const ScopedPointer<ObjectType>& pointer, decltype (nullptr)) noexcept
{
return pointer.get() == nullptr;
}
/** Compares a ScopedPointer with a nullptr. */
template <class ObjectType>
bool operator!= (const ScopedPointer<ObjectType>& pointer, decltype (nullptr)) noexcept
{
return pointer.get() != nullptr;
}
//==============================================================================
#ifndef DOXYGEN
// NB: This is just here to prevent any silly attempts to call deleteAndZero() on a ScopedPointer.
template <typename Type>
void deleteAndZero (ScopedPointer<Type>&) { static_assert (sizeof (Type) == 12345,
"Attempt to call deleteAndZero() on a ScopedPointer"); }
#endif
} // namespace juce

View File

@ -0,0 +1,164 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided 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.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A smart-pointer that automatically creates and manages the lifetime of a
shared static instance of a class.
The SharedObjectType template type indicates the class to use for the shared
object - the only requirements on this class are that it must have a public
default constructor and destructor.
The SharedResourcePointer offers a pattern that differs from using a singleton or
static instance of an object, because it uses reference-counting to make sure that
the underlying shared object is automatically created/destroyed according to the
number of SharedResourcePointer objects that exist. When the last one is deleted,
the underlying object is also immediately destroyed. This allows you to use scoping
to manage the lifetime of a shared resource.
Note: the construction/deletion of the shared object must not involve any
code that makes recursive calls to a SharedResourcePointer, or you'll cause
a deadlock.
Example:
@code
// An example of a class that contains the shared data you want to use.
struct MySharedData
{
// There's no need to ever create an instance of this class directly yourself,
// but it does need a public constructor that does the initialisation.
MySharedData()
{
sharedStuff = generateHeavyweightStuff();
}
Array<SomeKindOfData> sharedStuff;
};
struct DataUserClass
{
DataUserClass()
{
// Multiple instances of the DataUserClass will all have the same
// shared common instance of MySharedData referenced by their sharedData
// member variables.
useSharedStuff (sharedData->sharedStuff);
}
// By keeping this pointer as a member variable, the shared resource
// is guaranteed to be available for as long as the DataUserClass object.
SharedResourcePointer<MySharedData> sharedData;
};
@endcode
@tags{Core}
*/
template <typename SharedObjectType>
class SharedResourcePointer
{
public:
/** Creates an instance of the shared object.
If other SharedResourcePointer objects for this type already exist, then
this one will simply point to the same shared object that they are already
using. Otherwise, if this is the first SharedResourcePointer to be created,
then a shared object will be created automatically.
*/
SharedResourcePointer()
{
initialise();
}
SharedResourcePointer (const SharedResourcePointer&)
{
initialise();
}
/** Destructor.
If no other SharedResourcePointer objects exist, this will also delete
the shared object to which it refers.
*/
~SharedResourcePointer()
{
auto& holder = getSharedObjectHolder();
const SpinLock::ScopedLockType sl (holder.lock);
if (--(holder.refCount) == 0)
holder.sharedInstance = nullptr;
}
/** Returns the shared object. */
operator SharedObjectType*() const noexcept { return sharedObject; }
/** Returns the shared object. */
SharedObjectType& get() const noexcept { return *sharedObject; }
/** Returns the object that this pointer references.
The pointer returned may be a nullptr, of course.
*/
SharedObjectType& getObject() const noexcept { return *sharedObject; }
/** Returns the shared object. */
SharedObjectType* operator->() const noexcept { return sharedObject; }
/** Returns the number of SharedResourcePointers that are currently holding the shared object. */
int getReferenceCount() const noexcept { return getSharedObjectHolder().refCount; }
private:
struct SharedObjectHolder
{
SpinLock lock;
std::unique_ptr<SharedObjectType> sharedInstance;
int refCount;
};
static SharedObjectHolder& getSharedObjectHolder() noexcept
{
static void* holder [(sizeof (SharedObjectHolder) + sizeof(void*) - 1) / sizeof(void*)] = { 0 };
return *reinterpret_cast<SharedObjectHolder*> (holder);
}
SharedObjectType* sharedObject;
void initialise()
{
auto& holder = getSharedObjectHolder();
const SpinLock::ScopedLockType sl (holder.lock);
if (++(holder.refCount) == 1)
holder.sharedInstance.reset (new SharedObjectType());
sharedObject = holder.sharedInstance.get();
}
// There's no need to assign to a SharedResourcePointer because every
// instance of the class is exactly the same!
SharedResourcePointer& operator= (const SharedResourcePointer&) = delete;
JUCE_LEAK_DETECTOR (SharedResourcePointer)
};
} // namespace juce

View File

@ -0,0 +1,280 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided 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.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
Used by the JUCE_DECLARE_SINGLETON macros to manage a static pointer
to a singleton instance.
You generally won't use this directly, but see the macros JUCE_DECLARE_SINGLETON,
JUCE_DECLARE_SINGLETON_SINGLETHREADED, JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL,
and JUCE_IMPLEMENT_SINGLETON for how it is intended to be used.
@tags{Core}
*/
template <typename Type, typename MutexType, bool onlyCreateOncePerRun>
struct SingletonHolder : private MutexType // (inherited so we can use the empty-base-class optimisation)
{
SingletonHolder() noexcept {}
~SingletonHolder()
{
/* The static singleton holder is being deleted before the object that it holds
has been deleted. This could mean that you've forgotten to call clearSingletonInstance()
in the class's destructor, or have failed to delete it before your app shuts down.
If you're having trouble cleaning up your singletons, perhaps consider using the
SharedResourcePointer class instead.
*/
jassert (instance == nullptr);
}
/** Returns the current instance, or creates a new instance if there isn't one. */
Type* get()
{
if (instance == nullptr)
{
typename MutexType::ScopedLockType sl (*this);
if (instance == nullptr)
{
auto once = onlyCreateOncePerRun; // (local copy avoids VS compiler warning about this being constant)
if (once)
{
static bool createdOnceAlready = false;
if (createdOnceAlready)
{
// This means that the doNotRecreateAfterDeletion flag was set
// and you tried to create the singleton more than once.
jassertfalse;
return nullptr;
}
createdOnceAlready = true;
}
static bool alreadyInside = false;
if (alreadyInside)
{
// This means that your object's constructor has done something which has
// ended up causing a recursive loop of singleton creation..
jassertfalse;
}
else
{
alreadyInside = true;
getWithoutChecking();
alreadyInside = false;
}
}
}
return instance;
}
/** Returns the current instance, or creates a new instance if there isn't one, but doesn't do
any locking, or checking for recursion or error conditions.
*/
Type* getWithoutChecking()
{
if (instance == nullptr)
{
auto newObject = new Type(); // (create into a local so that instance is still null during construction)
instance = newObject;
}
return instance;
}
/** Deletes and resets the current instance, if there is one. */
void deleteInstance()
{
typename MutexType::ScopedLockType sl (*this);
auto old = instance;
instance = nullptr;
delete old;
}
/** Called by the class's destructor to clear the pointer if it is currently set to the given object. */
void clear (Type* expectedObject) noexcept
{
if (instance == expectedObject)
instance = nullptr;
}
Type* instance = nullptr;
};
//==============================================================================
/**
Macro to generate the appropriate methods and boilerplate for a singleton class.
To use this, add the line JUCE_DECLARE_SINGLETON(MyClass, doNotRecreateAfterDeletion)
to the class's definition.
Then put a macro JUCE_IMPLEMENT_SINGLETON(MyClass) along with the class's
implementation code.
It's also a very good idea to also add the call clearSingletonInstance() in your class's
destructor, in case it is deleted by other means than deleteInstance()
Clients can then call the static method MyClass::getInstance() to get a pointer
to the singleton, or MyClass::getInstanceWithoutCreating() which will return nullptr if
no instance currently exists.
e.g. @code
struct MySingleton
{
MySingleton() {}
~MySingleton()
{
// this ensures that no dangling pointers are left when the
// singleton is deleted.
clearSingletonInstance();
}
JUCE_DECLARE_SINGLETON (MySingleton, false)
};
// ..and this goes in a suitable .cpp file:
JUCE_IMPLEMENT_SINGLETON (MySingleton)
// example of usage:
auto* m = MySingleton::getInstance(); // creates the singleton if there isn't already one.
...
MySingleton::deleteInstance(); // safely deletes the singleton (if it's been created).
@endcode
If doNotRecreateAfterDeletion = true, it won't allow the object to be created more
than once during the process's lifetime - i.e. after you've created and deleted the
object, getInstance() will refuse to create another one. This can be useful to stop
objects being accidentally re-created during your app's shutdown code.
If you know that your object will only be created and deleted by a single thread, you
can use the slightly more efficient JUCE_DECLARE_SINGLETON_SINGLETHREADED macro instead
of this one.
@see JUCE_IMPLEMENT_SINGLETON, JUCE_DECLARE_SINGLETON_SINGLETHREADED
*/
#define JUCE_DECLARE_SINGLETON(Classname, doNotRecreateAfterDeletion) \
\
static juce::SingletonHolder<Classname, juce::CriticalSection, doNotRecreateAfterDeletion> singletonHolder; \
friend decltype (singletonHolder); \
\
static Classname* JUCE_CALLTYPE getInstance() { return singletonHolder.get(); } \
static Classname* JUCE_CALLTYPE getInstanceWithoutCreating() noexcept { return singletonHolder.instance; } \
static void JUCE_CALLTYPE deleteInstance() noexcept { singletonHolder.deleteInstance(); } \
void clearSingletonInstance() noexcept { singletonHolder.clear (this); }
//==============================================================================
/** This is a counterpart to the JUCE_DECLARE_SINGLETON macros.
After adding the JUCE_DECLARE_SINGLETON to the class definition, this macro has
to be used in the cpp file.
*/
#define JUCE_IMPLEMENT_SINGLETON(Classname) \
\
decltype (Classname::singletonHolder) Classname::singletonHolder;
//==============================================================================
/**
Macro to declare member variables and methods for a singleton class.
This is exactly the same as JUCE_DECLARE_SINGLETON, but doesn't use a critical
section to make access to it thread-safe. If you know that your object will
only ever be created or deleted by a single thread, then this is a
more efficient version to use.
If doNotRecreateAfterDeletion = true, it won't allow the object to be created more
than once during the process's lifetime - i.e. after you've created and deleted the
object, getInstance() will refuse to create another one. This can be useful to stop
objects being accidentally re-created during your app's shutdown code.
See the documentation for JUCE_DECLARE_SINGLETON for more information about
how to use it. Just like JUCE_DECLARE_SINGLETON you need to also have a
corresponding JUCE_IMPLEMENT_SINGLETON statement somewhere in your code.
@see JUCE_IMPLEMENT_SINGLETON, JUCE_DECLARE_SINGLETON, JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL
*/
#define JUCE_DECLARE_SINGLETON_SINGLETHREADED(Classname, doNotRecreateAfterDeletion) \
\
static juce::SingletonHolder<Classname, juce::DummyCriticalSection, doNotRecreateAfterDeletion> singletonHolder; \
friend decltype (singletonHolder); \
\
static Classname* JUCE_CALLTYPE getInstance() { return singletonHolder.get(); } \
static Classname* JUCE_CALLTYPE getInstanceWithoutCreating() noexcept { return singletonHolder.instance; } \
static void JUCE_CALLTYPE deleteInstance() noexcept { singletonHolder.deleteInstance(); } \
void clearSingletonInstance() noexcept { singletonHolder.clear (this); }
//==============================================================================
/**
Macro to declare member variables and methods for a singleton class.
This is like JUCE_DECLARE_SINGLETON_SINGLETHREADED, but doesn't do any checking
for recursion or repeated instantiation. It's intended for use as a lightweight
version of a singleton, where you're using it in very straightforward
circumstances and don't need the extra checking.
See the documentation for JUCE_DECLARE_SINGLETON for more information about
how to use it. Just like JUCE_DECLARE_SINGLETON you need to also have a
corresponding JUCE_IMPLEMENT_SINGLETON statement somewhere in your code.
@see JUCE_IMPLEMENT_SINGLETON, JUCE_DECLARE_SINGLETON
*/
#define JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL(Classname) \
\
static juce::SingletonHolder<Classname, juce::DummyCriticalSection, false> singletonHolder; \
friend decltype (singletonHolder); \
\
static Classname* JUCE_CALLTYPE getInstance() { return singletonHolder.getWithoutChecking(); } \
static Classname* JUCE_CALLTYPE getInstanceWithoutCreating() noexcept { return singletonHolder.instance; } \
static void JUCE_CALLTYPE deleteInstance() noexcept { singletonHolder.deleteInstance(); } \
void clearSingletonInstance() noexcept { singletonHolder.clear (this); }
//==============================================================================
#ifndef DOXYGEN
// These are ancient macros, and have now been updated with new names to match the JUCE style guide,
// so please update your code to use the newer versions!
#define juce_DeclareSingleton(Classname, doNotRecreate) JUCE_DECLARE_SINGLETON(Classname, doNotRecreate)
#define juce_DeclareSingleton_SingleThreaded(Classname, doNotRecreate) JUCE_DECLARE_SINGLETON_SINGLETHREADED(Classname, doNotRecreate)
#define juce_DeclareSingleton_SingleThreaded_Minimal(Classname) JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL(Classname)
#define juce_ImplementSingleton(Classname) JUCE_IMPLEMENT_SINGLETON(Classname)
#define juce_ImplementSingleton_SingleThreaded(Classname) JUCE_IMPLEMENT_SINGLETON(Classname)
#endif
} // namespace juce

View File

@ -0,0 +1,242 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided 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.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
This class acts as a pointer which will automatically become null if the object
to which it points is deleted.
To accomplish this, the source object needs to cooperate by performing a couple of simple tasks.
It must embed a WeakReference::Master object, which stores a shared pointer object, and must clear
this master pointer in its destructor.
E.g.
@code
class MyObject
{
public:
MyObject()
{
// If you're planning on using your WeakReferences in a multi-threaded situation, you may choose
// to create a WeakReference to the object here in the constructor, which will pre-initialise the
// embedded object, avoiding an (extremely unlikely) race condition that could occur if multiple
// threads overlap while creating the first WeakReference to it.
}
~MyObject()
{
// This will zero all the references - you need to call this in your destructor.
masterReference.clear();
}
private:
// You need to embed a variable of this type, with the name "masterReference" inside your object. If the
// variable is not public, you should make your class a friend of WeakReference<MyObject> so that the
// WeakReference class can access it.
WeakReference<MyObject>::Master masterReference;
friend class WeakReference<MyObject>;
};
OR: just use the handy JUCE_DECLARE_WEAK_REFERENCEABLE macro to do all this for you.
// Here's an example of using a pointer..
MyObject* n = new MyObject();
WeakReference<MyObject> myObjectRef = n;
MyObject* pointer1 = myObjectRef; // returns a valid pointer to 'n'
delete n;
MyObject* pointer2 = myObjectRef; // returns a null pointer
@endcode
@see WeakReference::Master
@tags{Core}
*/
template <class ObjectType, class ReferenceCountingType = ReferenceCountedObject>
class WeakReference
{
public:
/** Creates a null WeakReference. */
inline WeakReference() noexcept {}
/** Creates a WeakReference that points at the given object. */
WeakReference (ObjectType* object) : holder (getRef (object)) {}
/** Creates a copy of another WeakReference. */
WeakReference (const WeakReference& other) noexcept : holder (other.holder) {}
/** Move constructor */
WeakReference (WeakReference&& other) noexcept : holder (static_cast<SharedRef&&> (other.holder)) {}
/** Copies another pointer to this one. */
WeakReference& operator= (const WeakReference& other) { holder = other.holder; return *this; }
/** Copies another pointer to this one. */
WeakReference& operator= (ObjectType* newObject) { holder = getRef (newObject); return *this; }
/** Move assignment operator */
WeakReference& operator= (WeakReference&& other) noexcept { holder = static_cast<SharedRef&&> (other.holder); return *this; }
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
ObjectType* get() const noexcept { return holder != nullptr ? holder->get() : nullptr; }
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
operator ObjectType*() const noexcept { return get(); }
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
ObjectType* operator->() noexcept { return get(); }
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
const ObjectType* operator->() const noexcept { return get(); }
/** This returns true if this reference has been pointing at an object, but that object has
since been deleted.
If this reference was only ever pointing at a null pointer, this will return false. Using
operator=() to make this refer to a different object will reset this flag to match the status
of the reference from which you're copying.
*/
bool wasObjectDeleted() const noexcept { return holder != nullptr && holder->get() == nullptr; }
bool operator== (ObjectType* object) const noexcept { return get() == object; }
bool operator!= (ObjectType* object) const noexcept { return get() != object; }
//==============================================================================
/** This class is used internally by the WeakReference class - don't use it directly
in your code!
@see WeakReference
*/
class SharedPointer : public ReferenceCountingType
{
public:
explicit SharedPointer (ObjectType* obj) noexcept : owner (obj) {}
inline ObjectType* get() const noexcept { return owner; }
void clearPointer() noexcept { owner = nullptr; }
private:
ObjectType* owner;
JUCE_DECLARE_NON_COPYABLE (SharedPointer)
};
typedef ReferenceCountedObjectPtr<SharedPointer> SharedRef;
//==============================================================================
/**
This class is embedded inside an object to which you want to attach WeakReference pointers.
See the WeakReference class notes for an example of how to use this class.
@see WeakReference
*/
class Master
{
public:
Master() noexcept {}
~Master() noexcept
{
// You must remember to call clear() in your source object's destructor! See the notes
// for the WeakReference class for an example of how to do this.
jassert (sharedPointer == nullptr || sharedPointer->get() == nullptr);
}
/** The first call to this method will create an internal object that is shared by all weak
references to the object.
*/
SharedPointer* getSharedPointer (ObjectType* object)
{
if (sharedPointer == nullptr)
{
sharedPointer = new SharedPointer (object);
}
else
{
// You're trying to create a weak reference to an object that has already been deleted!!
jassert (sharedPointer->get() != nullptr);
}
return sharedPointer;
}
/** The object that owns this master pointer should call this before it gets destroyed,
to zero all the references to this object that may be out there. See the WeakReference
class notes for an example of how to do this.
*/
void clear() noexcept
{
if (sharedPointer != nullptr)
sharedPointer->clearPointer();
}
/** Returns the number of WeakReferences that are out there pointing to this object. */
int getNumActiveWeakReferences() const noexcept
{
return sharedPointer == nullptr ? 0 : (sharedPointer->getReferenceCount() - 1);
}
private:
SharedRef sharedPointer;
JUCE_DECLARE_NON_COPYABLE (Master)
};
private:
SharedRef holder;
static inline SharedPointer* getRef (ObjectType* o)
{
return (o != nullptr) ? o->masterReference.getSharedPointer (o) : nullptr;
}
};
//==============================================================================
/**
Macro to easily allow a class to be made weak-referenceable.
This can be inserted in a class definition to add the requisite weak-ref boilerplate to that class.
e.g.
@code
class MyObject
{
public:
MyObject();
~MyObject();
private:
JUCE_DECLARE_WEAK_REFERENCEABLE (MyObject)
};
@endcode
@see WeakReference, WeakReference::Master
*/
#define JUCE_DECLARE_WEAK_REFERENCEABLE(Class) \
struct WeakRefMaster : public WeakReference<Class>::Master { ~WeakRefMaster() { this->clear(); } }; \
WeakRefMaster masterReference; \
friend class WeakReference<Class>; \
} // namespace juce