git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
271
deps/juce/modules/juce_core/containers/juce_AbstractFifo.cpp
vendored
Normal file
271
deps/juce/modules/juce_core/containers/juce_AbstractFifo.cpp
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
AbstractFifo::AbstractFifo (int capacity) noexcept : bufferSize (capacity)
|
||||
{
|
||||
jassert (bufferSize > 0);
|
||||
}
|
||||
|
||||
AbstractFifo::~AbstractFifo() {}
|
||||
|
||||
int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
|
||||
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady() - 1; }
|
||||
|
||||
int AbstractFifo::getNumReady() const noexcept
|
||||
{
|
||||
auto vs = validStart.get();
|
||||
auto ve = validEnd.get();
|
||||
return ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
|
||||
}
|
||||
|
||||
void AbstractFifo::reset() noexcept
|
||||
{
|
||||
validEnd = 0;
|
||||
validStart = 0;
|
||||
}
|
||||
|
||||
void AbstractFifo::setTotalSize (int newSize) noexcept
|
||||
{
|
||||
jassert (newSize > 0);
|
||||
reset();
|
||||
bufferSize = newSize;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1,
|
||||
int& startIndex2, int& blockSize2) const noexcept
|
||||
{
|
||||
auto vs = validStart.get();
|
||||
auto ve = validEnd.get();
|
||||
|
||||
auto freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve);
|
||||
numToWrite = jmin (numToWrite, freeSpace - 1);
|
||||
|
||||
if (numToWrite <= 0)
|
||||
{
|
||||
startIndex1 = 0;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = 0;
|
||||
blockSize2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
startIndex1 = ve;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = jmin (bufferSize - ve, numToWrite);
|
||||
numToWrite -= blockSize1;
|
||||
blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, vs);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractFifo::finishedWrite (int numWritten) noexcept
|
||||
{
|
||||
jassert (numWritten >= 0 && numWritten < bufferSize);
|
||||
|
||||
auto newEnd = validEnd.get() + numWritten;
|
||||
|
||||
if (newEnd >= bufferSize)
|
||||
newEnd -= bufferSize;
|
||||
|
||||
validEnd = newEnd;
|
||||
}
|
||||
|
||||
void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1,
|
||||
int& startIndex2, int& blockSize2) const noexcept
|
||||
{
|
||||
auto vs = validStart.get();
|
||||
auto ve = validEnd.get();
|
||||
|
||||
auto numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
|
||||
numWanted = jmin (numWanted, numReady);
|
||||
|
||||
if (numWanted <= 0)
|
||||
{
|
||||
startIndex1 = 0;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = 0;
|
||||
blockSize2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
startIndex1 = vs;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = jmin (bufferSize - vs, numWanted);
|
||||
numWanted -= blockSize1;
|
||||
blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, ve);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractFifo::finishedRead (int numRead) noexcept
|
||||
{
|
||||
jassert (numRead >= 0 && numRead <= bufferSize);
|
||||
|
||||
auto newStart = validStart.get() + numRead;
|
||||
|
||||
if (newStart >= bufferSize)
|
||||
newStart -= bufferSize;
|
||||
|
||||
validStart = newStart;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
template <AbstractFifo::ReadOrWrite mode>
|
||||
AbstractFifo::ScopedReadWrite<mode>::ScopedReadWrite (ScopedReadWrite&& other) noexcept
|
||||
: startIndex1 (other.startIndex1),
|
||||
blockSize1 (other.blockSize1),
|
||||
startIndex2 (other.startIndex2),
|
||||
blockSize2 (other.blockSize2)
|
||||
{
|
||||
swap (other);
|
||||
}
|
||||
|
||||
template <AbstractFifo::ReadOrWrite mode>
|
||||
AbstractFifo::ScopedReadWrite<mode>&
|
||||
AbstractFifo::ScopedReadWrite<mode>::operator= (ScopedReadWrite&& other) noexcept
|
||||
{
|
||||
swap (other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <AbstractFifo::ReadOrWrite mode>
|
||||
void AbstractFifo::ScopedReadWrite<mode>::swap (ScopedReadWrite& other) noexcept
|
||||
{
|
||||
std::swap (other.fifo, fifo);
|
||||
std::swap (other.startIndex1, startIndex1);
|
||||
std::swap (other.blockSize1, blockSize1);
|
||||
std::swap (other.startIndex2, startIndex2);
|
||||
std::swap (other.blockSize2, blockSize2);
|
||||
}
|
||||
|
||||
template class AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>;
|
||||
template class AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>;
|
||||
|
||||
AbstractFifo::ScopedRead AbstractFifo::read (int numToRead) noexcept { return { *this, numToRead }; }
|
||||
AbstractFifo::ScopedWrite AbstractFifo::write (int numToWrite) noexcept { return { *this, numToWrite }; }
|
||||
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
class AbstractFifoTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
AbstractFifoTests()
|
||||
: UnitTest ("Abstract Fifo", UnitTestCategories::containers)
|
||||
{}
|
||||
|
||||
struct WriteThread : public Thread
|
||||
{
|
||||
WriteThread (AbstractFifo& f, int* b, Random rng)
|
||||
: Thread ("fifo writer"), fifo (f), buffer (b), random (rng)
|
||||
{
|
||||
startThread();
|
||||
}
|
||||
|
||||
~WriteThread()
|
||||
{
|
||||
stopThread (5000);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
int num = random.nextInt (2000) + 1;
|
||||
|
||||
auto writer = fifo.write (num);
|
||||
|
||||
jassert (writer.blockSize1 >= 0 && writer.blockSize2 >= 0);
|
||||
jassert (writer.blockSize1 == 0
|
||||
|| (writer.startIndex1 >= 0 && writer.startIndex1 < fifo.getTotalSize()));
|
||||
jassert (writer.blockSize2 == 0
|
||||
|| (writer.startIndex2 >= 0 && writer.startIndex2 < fifo.getTotalSize()));
|
||||
|
||||
writer.forEach ([this, &n] (int index) { this->buffer[index] = n++; });
|
||||
}
|
||||
}
|
||||
|
||||
AbstractFifo& fifo;
|
||||
int* buffer;
|
||||
Random random;
|
||||
};
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6262)
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("AbstractFifo");
|
||||
|
||||
int buffer[5000];
|
||||
AbstractFifo fifo (numElementsInArray (buffer));
|
||||
|
||||
WriteThread writer (fifo, buffer, getRandom());
|
||||
|
||||
int n = 0;
|
||||
Random r = getRandom();
|
||||
r.combineSeed (12345);
|
||||
|
||||
for (int count = 100000; --count >= 0;)
|
||||
{
|
||||
int num = r.nextInt (6000) + 1;
|
||||
|
||||
auto reader = fifo.read (num);
|
||||
|
||||
if (! (reader.blockSize1 >= 0 && reader.blockSize2 >= 0)
|
||||
&& (reader.blockSize1 == 0
|
||||
|| (reader.startIndex1 >= 0 && reader.startIndex1 < fifo.getTotalSize()))
|
||||
&& (reader.blockSize2 == 0
|
||||
|| (reader.startIndex2 >= 0 && reader.startIndex2 < fifo.getTotalSize())))
|
||||
{
|
||||
expect (false, "prepareToRead returned -ve values");
|
||||
break;
|
||||
}
|
||||
|
||||
bool failed = false;
|
||||
|
||||
reader.forEach ([&failed, &buffer, &n] (int index)
|
||||
{
|
||||
failed = (buffer[index] != n++) || failed;
|
||||
});
|
||||
|
||||
if (failed)
|
||||
{
|
||||
expect (false, "read values were incorrect");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
};
|
||||
|
||||
static AbstractFifoTests fifoUnitTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
336
deps/juce/modules/juce_core/containers/juce_AbstractFifo.h
vendored
Normal file
336
deps/juce/modules/juce_core/containers/juce_AbstractFifo.h
vendored
Normal file
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Encapsulates the logic required to implement a lock-free FIFO.
|
||||
|
||||
This class handles the logic needed when building a single-reader, single-writer FIFO.
|
||||
|
||||
It doesn't actually hold any data itself, but your FIFO class can use one of these to manage
|
||||
its position and status when reading or writing to it.
|
||||
|
||||
To use it, you can call prepareToWrite() to determine the position within your own buffer that
|
||||
an incoming block of data should be stored, and prepareToRead() to find out when the next
|
||||
outgoing block should be read from.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
struct MyFifo
|
||||
{
|
||||
void addToFifo (const int* someData, int numItems)
|
||||
{
|
||||
const auto scope = abstractFifo.write (numItems);
|
||||
|
||||
if (scope.blockSize1 > 0)
|
||||
copySomeData (myBuffer + scope.startIndex1, someData, scope.blockSize1);
|
||||
|
||||
if (scope.blockSize2 > 0)
|
||||
copySomeData (myBuffer + scope.startIndex2, someData, scope.blockSize2);
|
||||
}
|
||||
|
||||
void readFromFifo (int* someData, int numItems)
|
||||
{
|
||||
const auto scope = abstractFifo.read (numItems);
|
||||
|
||||
if (scope.blockSize1 > 0)
|
||||
copySomeData (someData, myBuffer + scope.startIndex1, scope.blockSize1);
|
||||
|
||||
if (scope.blockSize2 > 0)
|
||||
copySomeData (someData + scope.blockSize1, myBuffer + scope.startIndex2, scope.blockSize2);
|
||||
}
|
||||
|
||||
AbstractFifo abstractFifo { 1024 };
|
||||
int myBuffer[1024];
|
||||
};
|
||||
@endcode
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API AbstractFifo
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a FIFO to manage a buffer with the specified capacity. */
|
||||
AbstractFifo (int capacity) noexcept;
|
||||
|
||||
/** Destructor */
|
||||
~AbstractFifo();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the total size of the buffer being managed. */
|
||||
int getTotalSize() const noexcept;
|
||||
|
||||
/** Returns the number of items that can currently be added to the buffer without it overflowing. */
|
||||
int getFreeSpace() const noexcept;
|
||||
|
||||
/** Returns the number of items that can currently be read from the buffer. */
|
||||
int getNumReady() const noexcept;
|
||||
|
||||
/** Clears the buffer positions, so that it appears empty. */
|
||||
void reset() noexcept;
|
||||
|
||||
/** Changes the buffer's total size.
|
||||
Note that this isn't thread-safe, so don't call it if there's any danger that it
|
||||
might overlap with a call to any other method in this class!
|
||||
*/
|
||||
void setTotalSize (int newSize) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the location within the buffer at which an incoming block of data should be written.
|
||||
|
||||
Because the section of data that you want to add to the buffer may overlap the end
|
||||
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||
should copy your data into the first one, with any remaining data spilling over into
|
||||
the second.
|
||||
|
||||
If the number of items you ask for is too large to fit within the buffer's free space, then
|
||||
blockSize1 + blockSize2 may add up to a lower value than numToWrite. If this happens, you
|
||||
may decide to keep waiting and re-trying the method until there's enough space available.
|
||||
|
||||
After calling this method, if you choose to write your data into the blocks returned, you
|
||||
must call finishedWrite() to tell the FIFO how much data you actually added.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
void addToFifo (const int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToWrite (numItems, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (myBuffer + start1, someData, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||
|
||||
finishedWrite (size1 + size2);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param numToWrite indicates how many items you'd like to add to the buffer
|
||||
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||
the first block should be written
|
||||
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||
@see finishedWrite
|
||||
*/
|
||||
void prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
|
||||
|
||||
/** Called after writing from the FIFO, to indicate that this many items have been added.
|
||||
@see prepareToWrite
|
||||
*/
|
||||
void finishedWrite (int numWritten) noexcept;
|
||||
|
||||
/** Returns the location within the buffer from which the next block of data should be read.
|
||||
|
||||
Because the section of data that you want to read from the buffer may overlap the end
|
||||
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||
should read from both of them.
|
||||
|
||||
If the number of items you ask for is greater than the amount of data available, then
|
||||
blockSize1 + blockSize2 may add up to a lower value than numWanted. If this happens, you
|
||||
may decide to keep waiting and re-trying the method until there's enough data available.
|
||||
|
||||
After calling this method, if you choose to read the data, you must call finishedRead() to
|
||||
tell the FIFO how much data you have consumed.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
void readFromFifo (int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToRead (numSamples, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (someData, myBuffer + start1, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||
|
||||
finishedRead (size1 + size2);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param numWanted indicates how many items you'd like to add to the buffer
|
||||
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||
the first block should be written
|
||||
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||
@see finishedRead
|
||||
*/
|
||||
void prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
|
||||
|
||||
/** Called after reading from the FIFO, to indicate that this many items have now been consumed.
|
||||
@see prepareToRead
|
||||
*/
|
||||
void finishedRead (int numRead) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
|
||||
private:
|
||||
enum class ReadOrWrite
|
||||
{
|
||||
read,
|
||||
write
|
||||
};
|
||||
|
||||
public:
|
||||
/** Class for a scoped reader/writer */
|
||||
template <ReadOrWrite mode>
|
||||
class ScopedReadWrite final
|
||||
{
|
||||
public:
|
||||
/** Construct an unassigned reader/writer. Doesn't do anything upon destruction. */
|
||||
ScopedReadWrite() = default;
|
||||
|
||||
/** Construct a reader/writer and immediately call prepareRead/prepareWrite
|
||||
on the abstractFifo which was passed in.
|
||||
This object will hold a pointer back to the fifo, so make sure that
|
||||
the fifo outlives this object.
|
||||
*/
|
||||
ScopedReadWrite (AbstractFifo& f, int num) noexcept : fifo (&f)
|
||||
{
|
||||
prepare (*fifo, num);
|
||||
}
|
||||
|
||||
ScopedReadWrite (const ScopedReadWrite&) = delete;
|
||||
ScopedReadWrite (ScopedReadWrite&&) noexcept;
|
||||
|
||||
ScopedReadWrite& operator= (const ScopedReadWrite&) = delete;
|
||||
ScopedReadWrite& operator= (ScopedReadWrite&&) noexcept;
|
||||
|
||||
/** Calls finishedRead or finishedWrite if this is a non-null scoped
|
||||
reader/writer.
|
||||
*/
|
||||
~ScopedReadWrite() noexcept
|
||||
{
|
||||
if (fifo != nullptr)
|
||||
finish (*fifo, blockSize1 + blockSize2);
|
||||
}
|
||||
|
||||
/** Calls the passed function with each index that was deemed valid
|
||||
for the current read/write operation.
|
||||
*/
|
||||
template <typename FunctionToApply>
|
||||
void forEach (FunctionToApply&& func) const
|
||||
{
|
||||
for (auto i = startIndex1, e = startIndex1 + blockSize1; i != e; ++i) func (i);
|
||||
for (auto i = startIndex2, e = startIndex2 + blockSize2; i != e; ++i) func (i);
|
||||
}
|
||||
|
||||
int startIndex1, blockSize1, startIndex2, blockSize2;
|
||||
|
||||
private:
|
||||
void prepare (AbstractFifo&, int) noexcept;
|
||||
static void finish (AbstractFifo&, int) noexcept;
|
||||
void swap (ScopedReadWrite&) noexcept;
|
||||
|
||||
AbstractFifo* fifo = nullptr;
|
||||
};
|
||||
|
||||
using ScopedRead = ScopedReadWrite<ReadOrWrite::read>;
|
||||
using ScopedWrite = ScopedReadWrite<ReadOrWrite::write>;
|
||||
|
||||
/** Replaces prepareToRead/finishedRead with a single function.
|
||||
This function returns an object which contains the start indices and
|
||||
block sizes, and also automatically finishes the read operation when
|
||||
it goes out of scope.
|
||||
@code
|
||||
{
|
||||
auto readHandle = fifo.read (4);
|
||||
|
||||
for (auto i = 0; i != readHandle.blockSize1; ++i)
|
||||
{
|
||||
// read the item at index readHandle.startIndex1 + i
|
||||
}
|
||||
|
||||
for (auto i = 0; i != readHandle.blockSize2; ++i)
|
||||
{
|
||||
// read the item at index readHandle.startIndex2 + i
|
||||
}
|
||||
} // readHandle goes out of scope here, finishing the read operation
|
||||
@endcode
|
||||
*/
|
||||
ScopedRead read (int numToRead) noexcept;
|
||||
|
||||
/** Replaces prepareToWrite/finishedWrite with a single function.
|
||||
This function returns an object which contains the start indices and
|
||||
block sizes, and also automatically finishes the write operation when
|
||||
it goes out of scope.
|
||||
@code
|
||||
{
|
||||
auto writeHandle = fifo.write (5);
|
||||
|
||||
for (auto i = 0; i != writeHandle.blockSize1; ++i)
|
||||
{
|
||||
// write the item at index writeHandle.startIndex1 + i
|
||||
}
|
||||
|
||||
for (auto i = 0; i != writeHandle.blockSize2; ++i)
|
||||
{
|
||||
// write the item at index writeHandle.startIndex2 + i
|
||||
}
|
||||
} // writeHandle goes out of scope here, finishing the write operation
|
||||
@endcode
|
||||
*/
|
||||
ScopedWrite write (int numToWrite) noexcept;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
int bufferSize;
|
||||
Atomic<int> validStart, validEnd;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AbstractFifo)
|
||||
};
|
||||
|
||||
template <>
|
||||
inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>::finish (AbstractFifo& f, int num) noexcept
|
||||
{
|
||||
f.finishedRead (num);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>::finish (AbstractFifo& f, int num) noexcept
|
||||
{
|
||||
f.finishedWrite (num);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>::prepare (AbstractFifo& f, int num) noexcept
|
||||
{
|
||||
f.prepareToRead (num, startIndex1, blockSize1, startIndex2, blockSize2);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>::prepare (AbstractFifo& f, int num) noexcept
|
||||
{
|
||||
f.prepareToWrite (num, startIndex1, blockSize1, startIndex2, blockSize2);
|
||||
}
|
||||
|
||||
|
||||
} // namespace juce
|
||||
1150
deps/juce/modules/juce_core/containers/juce_Array.h
vendored
Normal file
1150
deps/juce/modules/juce_core/containers/juce_Array.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
121
deps/juce/modules/juce_core/containers/juce_ArrayAllocationBase.h
vendored
Normal file
121
deps/juce/modules/juce_core/containers/juce_ArrayAllocationBase.h
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Implements some basic array storage allocation functions.
|
||||
|
||||
This class isn't really for public use - it used to be part of the
|
||||
container classes but has since been superseded by ArrayBase. Eventually
|
||||
it will be removed from the API.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class ElementType, class TypeOfCriticalSectionToUse>
|
||||
class ArrayAllocationBase : public TypeOfCriticalSectionToUse
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty array. */
|
||||
ArrayAllocationBase() = default;
|
||||
|
||||
/** Destructor. */
|
||||
~ArrayAllocationBase() = default;
|
||||
|
||||
ArrayAllocationBase (ArrayAllocationBase&& other) noexcept
|
||||
: elements (std::move (other.elements)),
|
||||
numAllocated (other.numAllocated)
|
||||
{
|
||||
}
|
||||
|
||||
ArrayAllocationBase& operator= (ArrayAllocationBase&& other) noexcept
|
||||
{
|
||||
elements = std::move (other.elements);
|
||||
numAllocated = other.numAllocated;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Changes the amount of storage allocated.
|
||||
|
||||
This will retain any data currently held in the array, and either add or
|
||||
remove extra space at the end.
|
||||
|
||||
@param numElements the number of elements that are needed
|
||||
*/
|
||||
void setAllocatedSize (int numElements)
|
||||
{
|
||||
if (numAllocated != numElements)
|
||||
{
|
||||
if (numElements > 0)
|
||||
elements.realloc ((size_t) numElements);
|
||||
else
|
||||
elements.free();
|
||||
|
||||
numAllocated = numElements;
|
||||
}
|
||||
}
|
||||
|
||||
/** Increases the amount of storage allocated if it is less than a given amount.
|
||||
|
||||
This will retain any data currently held in the array, but will add
|
||||
extra space at the end to make sure there it's at least as big as the size
|
||||
passed in. If it's already bigger, no action is taken.
|
||||
|
||||
@param minNumElements the minimum number of elements that are needed
|
||||
*/
|
||||
void ensureAllocatedSize (int minNumElements)
|
||||
{
|
||||
if (minNumElements > numAllocated)
|
||||
setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
|
||||
|
||||
jassert (numAllocated <= 0 || elements != nullptr);
|
||||
}
|
||||
|
||||
/** Minimises the amount of storage allocated so that it's no more than
|
||||
the given number of elements.
|
||||
*/
|
||||
void shrinkToNoMoreThan (int maxNumElements)
|
||||
{
|
||||
if (maxNumElements < numAllocated)
|
||||
setAllocatedSize (maxNumElements);
|
||||
}
|
||||
|
||||
/** Swap the contents of two objects. */
|
||||
void swapWith (ArrayAllocationBase& other) noexcept
|
||||
{
|
||||
elements.swapWith (other.elements);
|
||||
std::swap (numAllocated, other.numAllocated);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
HeapBlock<ElementType> elements;
|
||||
int numAllocated = 0;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE (ArrayAllocationBase)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
600
deps/juce/modules/juce_core/containers/juce_ArrayBase.cpp
vendored
Normal file
600
deps/juce/modules/juce_core/containers/juce_ArrayBase.cpp
vendored
Normal file
@@ -0,0 +1,600 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 JUCE_UNIT_TESTS
|
||||
|
||||
namespace ArrayBaseTestsHelpers
|
||||
{
|
||||
class TriviallyCopyableType
|
||||
{
|
||||
public:
|
||||
TriviallyCopyableType() = default;
|
||||
|
||||
TriviallyCopyableType (int v)
|
||||
: value (v)
|
||||
{}
|
||||
|
||||
TriviallyCopyableType (float v)
|
||||
: value ((int) v)
|
||||
{}
|
||||
|
||||
bool operator== (const TriviallyCopyableType& other) const
|
||||
{
|
||||
return getValue() == other.getValue();
|
||||
}
|
||||
|
||||
int getValue() const { return value; }
|
||||
|
||||
private:
|
||||
int value { -1111 };
|
||||
};
|
||||
|
||||
class NonTriviallyCopyableType
|
||||
{
|
||||
public:
|
||||
NonTriviallyCopyableType() = default;
|
||||
|
||||
NonTriviallyCopyableType (int v)
|
||||
: value (v)
|
||||
{}
|
||||
|
||||
NonTriviallyCopyableType (float v)
|
||||
: value ((int) v)
|
||||
{}
|
||||
|
||||
NonTriviallyCopyableType (const NonTriviallyCopyableType& other)
|
||||
: value (other.value)
|
||||
{}
|
||||
|
||||
NonTriviallyCopyableType& operator= (const NonTriviallyCopyableType& other)
|
||||
{
|
||||
value = other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator== (const NonTriviallyCopyableType& other) const
|
||||
{
|
||||
return getValue() == other.getValue();
|
||||
}
|
||||
|
||||
int getValue() const { return *ptr; }
|
||||
|
||||
private:
|
||||
int value { -1111 };
|
||||
int* ptr = &value;
|
||||
};
|
||||
}
|
||||
|
||||
static bool operator== (const ArrayBaseTestsHelpers::TriviallyCopyableType& tct,
|
||||
const ArrayBaseTestsHelpers::NonTriviallyCopyableType& ntct)
|
||||
{
|
||||
return tct.getValue() == ntct.getValue();
|
||||
}
|
||||
|
||||
static bool operator== (const ArrayBaseTestsHelpers::NonTriviallyCopyableType& ntct,
|
||||
const ArrayBaseTestsHelpers::TriviallyCopyableType& tct)
|
||||
{
|
||||
return tct == ntct;
|
||||
}
|
||||
|
||||
class ArrayBaseTests : public UnitTest
|
||||
{
|
||||
using CopyableType = ArrayBaseTestsHelpers::TriviallyCopyableType;
|
||||
using NoncopyableType = ArrayBaseTestsHelpers::NonTriviallyCopyableType;
|
||||
|
||||
#if ! (defined(__GNUC__) && __GNUC__ < 5 && ! defined(__clang__))
|
||||
static_assert (std::is_trivially_copyable<CopyableType>::value,
|
||||
"Test TriviallyCopyableType is not trivially copyable");
|
||||
static_assert (! std::is_trivially_copyable<NoncopyableType>::value,
|
||||
"Test NonTriviallyCopyableType is trivially copyable");
|
||||
#endif
|
||||
|
||||
public:
|
||||
ArrayBaseTests()
|
||||
: UnitTest ("ArrayBase", UnitTestCategories::containers)
|
||||
{}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("grow capacity");
|
||||
{
|
||||
std::vector<CopyableType> referenceContainer;
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
|
||||
int originalCapacity = 4;
|
||||
referenceContainer.reserve ((size_t) originalCapacity);
|
||||
expectEquals ((int) referenceContainer.capacity(), originalCapacity);
|
||||
copyableContainer.setAllocatedSize (originalCapacity);
|
||||
expectEquals (copyableContainer.capacity(), originalCapacity);
|
||||
noncopyableContainer.setAllocatedSize (originalCapacity);
|
||||
expectEquals (noncopyableContainer.capacity(), originalCapacity);
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
|
||||
addData (referenceContainer, copyableContainer, noncopyableContainer, 33);
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
|
||||
expect ((int) referenceContainer.capacity() != originalCapacity);
|
||||
expect (copyableContainer.capacity() != originalCapacity);
|
||||
expect (noncopyableContainer.capacity() != originalCapacity);
|
||||
}
|
||||
|
||||
beginTest ("shrink capacity");
|
||||
{
|
||||
std::vector<CopyableType> referenceContainer;
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
|
||||
|
||||
int numElements = 45;
|
||||
addData (referenceContainer, copyableContainer, noncopyableContainer, numElements);
|
||||
|
||||
copyableContainer.shrinkToNoMoreThan (numElements);
|
||||
noncopyableContainer.setAllocatedSize (numElements + 1);
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
|
||||
referenceContainer.clear();
|
||||
copyableContainer.removeElements (0, numElements);
|
||||
noncopyableContainer.removeElements (0, numElements);
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
|
||||
copyableContainer.setAllocatedSize (0);
|
||||
noncopyableContainer.setAllocatedSize (0);
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
|
||||
addData (referenceContainer, copyableContainer, noncopyableContainer, numElements);
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
}
|
||||
|
||||
beginTest ("equality");
|
||||
{
|
||||
std::vector<int> referenceContainer = { 1, 2, 3 };
|
||||
ArrayBase<int, DummyCriticalSection> testContainer1, testContainer2;
|
||||
|
||||
for (auto i : referenceContainer)
|
||||
{
|
||||
testContainer1.add (i);
|
||||
testContainer2.add (i);
|
||||
}
|
||||
|
||||
expect (testContainer1 == referenceContainer);
|
||||
expect (testContainer2 == testContainer1);
|
||||
|
||||
testContainer1.ensureAllocatedSize (257);
|
||||
referenceContainer.shrink_to_fit();
|
||||
|
||||
expect (testContainer1 == referenceContainer);
|
||||
expect (testContainer2 == testContainer1);
|
||||
|
||||
testContainer1.removeElements (0, 1);
|
||||
|
||||
expect (testContainer1 != referenceContainer);
|
||||
expect (testContainer2 != testContainer1);
|
||||
}
|
||||
|
||||
beginTest ("accessors");
|
||||
{
|
||||
std::vector<CopyableType> referenceContainer;
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
|
||||
|
||||
addData (referenceContainer, copyableContainer, noncopyableContainer, 3);
|
||||
|
||||
int testValue = -123;
|
||||
referenceContainer[0] = testValue;
|
||||
copyableContainer[0] = testValue;
|
||||
noncopyableContainer[0] = testValue;
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
|
||||
expect (copyableContainer .getFirst().getValue() == testValue);
|
||||
expect (noncopyableContainer.getFirst().getValue() == testValue);
|
||||
|
||||
auto last = referenceContainer.back().getValue();
|
||||
|
||||
expectEquals (copyableContainer .getLast().getValue(), last);
|
||||
expectEquals (noncopyableContainer.getLast().getValue(), last);
|
||||
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableEmpty;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableEmpty;
|
||||
|
||||
auto defualtValue = CopyableType().getValue();
|
||||
expectEquals (defualtValue, NoncopyableType().getValue());
|
||||
|
||||
expectEquals (copyableEmpty .getFirst().getValue(), defualtValue);
|
||||
expectEquals (noncopyableEmpty.getFirst().getValue(), defualtValue);
|
||||
expectEquals (copyableEmpty .getLast() .getValue(), defualtValue);
|
||||
expectEquals (noncopyableEmpty.getLast() .getValue(), defualtValue);
|
||||
|
||||
ArrayBase<float*, DummyCriticalSection> floatPointers;
|
||||
expect (floatPointers.getValueWithDefault (-3) == nullptr);
|
||||
}
|
||||
|
||||
beginTest ("add moved");
|
||||
{
|
||||
std::vector<CopyableType> referenceContainer;
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
CopyableType ref (-i);
|
||||
CopyableType ct (-i);
|
||||
NoncopyableType nct (-i);
|
||||
referenceContainer.push_back (std::move (ref));
|
||||
copyableContainer.add (std::move (ct));
|
||||
noncopyableContainer.add (std::move (nct));
|
||||
}
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
}
|
||||
|
||||
beginTest ("add multiple");
|
||||
{
|
||||
std::vector<CopyableType> referenceContainer;
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
|
||||
|
||||
for (int i = 4; i < 7; ++i)
|
||||
referenceContainer.push_back ({ -i });
|
||||
|
||||
copyableContainer.add (CopyableType (-4), CopyableType (-5), CopyableType (-6));
|
||||
noncopyableContainer.add (NoncopyableType (-4), NoncopyableType (-5), NoncopyableType (-6));
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
}
|
||||
|
||||
beginTest ("add array from a pointer");
|
||||
{
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
|
||||
|
||||
std::vector<CopyableType> copyableData = { 3, 4, 5 };
|
||||
std::vector<NoncopyableType> noncopyableData = { 3, 4, 5 };
|
||||
|
||||
copyableContainer.addArray (copyableData.data(), (int) copyableData.size());
|
||||
noncopyableContainer.addArray (noncopyableData.data(), (int) noncopyableData.size());
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, copyableData);
|
||||
}
|
||||
|
||||
beginTest ("add array from a pointer of a different type");
|
||||
{
|
||||
std::vector<CopyableType> referenceContainer;
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
|
||||
|
||||
std::vector<float> floatData = { 1.4f, 2.5f, 3.6f };
|
||||
|
||||
for (auto f : floatData)
|
||||
referenceContainer.push_back ({ f });
|
||||
|
||||
copyableContainer.addArray (floatData.data(), (int) floatData.size());
|
||||
noncopyableContainer.addArray (floatData.data(), (int) floatData.size());
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
}
|
||||
|
||||
beginTest ("add array from initializer_list");
|
||||
{
|
||||
std::vector<CopyableType> referenceContainer;
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
|
||||
|
||||
std::initializer_list<CopyableType> ilct { { 3 }, { 4 }, { 5 } };
|
||||
std::initializer_list<NoncopyableType> ilnct { { 3 }, { 4 }, { 5 } };
|
||||
|
||||
for (auto v : ilct)
|
||||
referenceContainer.push_back ({ v });
|
||||
|
||||
copyableContainer.addArray (ilct);
|
||||
noncopyableContainer.addArray (ilnct);
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
}
|
||||
|
||||
beginTest ("add array from containers");
|
||||
{
|
||||
std::vector<CopyableType> referenceContainer;
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
|
||||
|
||||
addData (referenceContainer, copyableContainer, noncopyableContainer, 5);
|
||||
|
||||
std::vector<CopyableType> referenceContainerCopy (referenceContainer);
|
||||
std::vector<NoncopyableType> noncopyableReferenceContainerCopy;
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableContainerCopy;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainerCopy;
|
||||
|
||||
for (auto& v : referenceContainerCopy)
|
||||
noncopyableReferenceContainerCopy.push_back ({ v.getValue() });
|
||||
|
||||
for (size_t i = 0; i < referenceContainerCopy.size(); ++i)
|
||||
{
|
||||
auto value = referenceContainerCopy[i].getValue();
|
||||
copyableContainerCopy.add ({ value });
|
||||
noncopyableContainerCopy.add ({ value });
|
||||
}
|
||||
|
||||
// From self-types
|
||||
copyableContainer.addArray (copyableContainerCopy);
|
||||
noncopyableContainer.addArray (noncopyableContainerCopy);
|
||||
|
||||
for (auto v : referenceContainerCopy)
|
||||
referenceContainer.push_back (v);
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
|
||||
// From std containers
|
||||
copyableContainer.addArray (referenceContainerCopy);
|
||||
noncopyableContainer.addArray (noncopyableReferenceContainerCopy);
|
||||
|
||||
for (auto v : referenceContainerCopy)
|
||||
referenceContainer.push_back (v);
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
|
||||
// From std containers with offset
|
||||
int offset = 5;
|
||||
copyableContainer.addArray (referenceContainerCopy, offset);
|
||||
noncopyableContainer.addArray (noncopyableReferenceContainerCopy, offset);
|
||||
|
||||
for (size_t i = 5; i < referenceContainerCopy.size(); ++i)
|
||||
referenceContainer.push_back (referenceContainerCopy[i]);
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
}
|
||||
|
||||
beginTest ("insert");
|
||||
{
|
||||
std::vector<CopyableType> referenceContainer;
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
|
||||
|
||||
addData (referenceContainer, copyableContainer, noncopyableContainer, 8);
|
||||
|
||||
referenceContainer.insert (referenceContainer.begin(), -4);
|
||||
copyableContainer.insert (0, -4, 1);
|
||||
noncopyableContainer.insert (0, -4, 1);
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
referenceContainer.insert (referenceContainer.begin() + 1, -3);
|
||||
|
||||
copyableContainer.insert (1, -3, 3);
|
||||
noncopyableContainer.insert (1, -3, 3);
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
|
||||
for (int i = 0; i < 50; ++i)
|
||||
referenceContainer.insert (referenceContainer.end() - 1, -9);
|
||||
|
||||
copyableContainer.insert (copyableContainer.size() - 2, -9, 50);
|
||||
noncopyableContainer.insert (noncopyableContainer.size() - 2, -9, 50);
|
||||
}
|
||||
|
||||
beginTest ("insert array");
|
||||
{
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
|
||||
|
||||
std::vector<CopyableType> copyableData = { 3, 4, 5, 6, 7, 8 };
|
||||
std::vector<NoncopyableType> noncopyableData = { 3, 4, 5, 6, 7, 8 };
|
||||
|
||||
std::vector<CopyableType> referenceContainer { copyableData };
|
||||
|
||||
copyableContainer.insertArray (0, copyableData.data(), (int) copyableData.size());
|
||||
noncopyableContainer.insertArray (0, noncopyableData.data(), (int) noncopyableData.size());
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
|
||||
int insertPos = copyableContainer.size() - 1;
|
||||
|
||||
for (auto it = copyableData.end(); it != copyableData.begin(); --it)
|
||||
referenceContainer.insert (referenceContainer.begin() + insertPos, CopyableType (*(it - 1)));
|
||||
|
||||
copyableContainer.insertArray (insertPos, copyableData.data(), (int) copyableData.size());
|
||||
noncopyableContainer.insertArray (insertPos, noncopyableData.data(), (int) noncopyableData.size());
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
}
|
||||
|
||||
beginTest ("remove");
|
||||
{
|
||||
std::vector<CopyableType> referenceContainer;
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
|
||||
|
||||
addData (referenceContainer, copyableContainer, noncopyableContainer, 17);
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
referenceContainer.erase (referenceContainer.begin() + i);
|
||||
copyableContainer.removeElements (i, 1);
|
||||
noncopyableContainer.removeElements (i, 1);
|
||||
}
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
|
||||
addData (referenceContainer, copyableContainer, noncopyableContainer, 17);
|
||||
int blockSize = 3;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
for (int j = 0; j < blockSize; ++j)
|
||||
referenceContainer.erase (referenceContainer.begin() + i);
|
||||
|
||||
copyableContainer.removeElements (i, blockSize);
|
||||
noncopyableContainer.removeElements (i, blockSize);
|
||||
}
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
|
||||
auto numToRemove = copyableContainer.size() - 2;
|
||||
|
||||
for (int i = 0; i < numToRemove; ++i)
|
||||
referenceContainer.erase (referenceContainer.begin() + 1);
|
||||
|
||||
copyableContainer.removeElements (1, numToRemove);
|
||||
noncopyableContainer.removeElements (1, numToRemove);
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
}
|
||||
|
||||
beginTest ("move");
|
||||
{
|
||||
std::vector<CopyableType> referenceContainer;
|
||||
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
|
||||
|
||||
addData (referenceContainer, copyableContainer, noncopyableContainer, 6);
|
||||
|
||||
std::vector<std::pair<int, int>> testValues;
|
||||
testValues.emplace_back (2, 4);
|
||||
testValues.emplace_back (0, 5);
|
||||
testValues.emplace_back (4, 1);
|
||||
testValues.emplace_back (5, 0);
|
||||
|
||||
for (auto p : testValues)
|
||||
{
|
||||
if (p.second > p.first)
|
||||
std::rotate (referenceContainer.begin() + p.first,
|
||||
referenceContainer.begin() + p.first + 1,
|
||||
referenceContainer.begin() + p.second + 1);
|
||||
else
|
||||
std::rotate (referenceContainer.begin() + p.second,
|
||||
referenceContainer.begin() + p.first,
|
||||
referenceContainer.begin() + p.first + 1);
|
||||
|
||||
copyableContainer.move (p.first, p.second);
|
||||
noncopyableContainer.move (p.first, p.second);
|
||||
|
||||
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
|
||||
}
|
||||
}
|
||||
|
||||
beginTest ("After converting move construction, ownership is transferred");
|
||||
{
|
||||
Derived obj;
|
||||
ArrayBase<Derived*, DummyCriticalSection> derived;
|
||||
derived.setAllocatedSize (5);
|
||||
derived.add (&obj);
|
||||
|
||||
ArrayBase<Base*, DummyCriticalSection> base { std::move (derived) };
|
||||
|
||||
expectEquals (base.capacity(), 5);
|
||||
expectEquals (base.size(), 1);
|
||||
expect (base.getFirst() == &obj);
|
||||
expectEquals (derived.capacity(), 0);
|
||||
expectEquals (derived.size(), 0);
|
||||
expect (derived.data() == nullptr);
|
||||
}
|
||||
|
||||
beginTest ("After converting move assignment, ownership is transferred");
|
||||
{
|
||||
Derived obj;
|
||||
ArrayBase<Derived*, DummyCriticalSection> derived;
|
||||
derived.setAllocatedSize (5);
|
||||
derived.add (&obj);
|
||||
ArrayBase<Base*, DummyCriticalSection> base;
|
||||
|
||||
base = std::move (derived);
|
||||
|
||||
expectEquals (base.capacity(), 5);
|
||||
expectEquals (base.size(), 1);
|
||||
expect (base.getFirst() == &obj);
|
||||
expectEquals (derived.capacity(), 0);
|
||||
expectEquals (derived.size(), 0);
|
||||
expect (derived.data() == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct Base
|
||||
{
|
||||
virtual ~Base() = default;
|
||||
};
|
||||
|
||||
struct Derived : Base
|
||||
{
|
||||
};
|
||||
|
||||
static void addData (std::vector<CopyableType>& referenceContainer,
|
||||
ArrayBase<CopyableType, DummyCriticalSection>& copyableContainer,
|
||||
ArrayBase<NoncopyableType, DummyCriticalSection>& NoncopyableContainer,
|
||||
int numValues)
|
||||
{
|
||||
for (int i = 0; i < numValues; ++i)
|
||||
{
|
||||
referenceContainer.push_back ({ i });
|
||||
copyableContainer.add ({ i });
|
||||
NoncopyableContainer.add ({ i });
|
||||
}
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
void checkEqual (const ArrayBase<A, DummyCriticalSection>& a,
|
||||
const ArrayBase<B, DummyCriticalSection>& b)
|
||||
{
|
||||
expectEquals ((int) a.size(), (int) b.size());
|
||||
|
||||
for (int i = 0; i < (int) a.size(); ++i)
|
||||
expect (a[i] == b[i]);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
void checkEqual (ArrayBase<A, DummyCriticalSection>& a,
|
||||
std::vector<B>& b)
|
||||
{
|
||||
expectEquals ((int) a.size(), (int) b.size());
|
||||
|
||||
for (int i = 0; i < (int) a.size(); ++i)
|
||||
expect (a[i] == b[(size_t) i]);
|
||||
}
|
||||
|
||||
template <typename A, typename B, typename C>
|
||||
void checkEqual (ArrayBase<A, DummyCriticalSection>& a,
|
||||
ArrayBase<B, DummyCriticalSection>& b,
|
||||
std::vector<C>& c)
|
||||
{
|
||||
checkEqual (a, b);
|
||||
checkEqual (a, c);
|
||||
checkEqual (b, c);
|
||||
}
|
||||
};
|
||||
|
||||
static ArrayBaseTests arrayBaseTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
607
deps/juce/modules/juce_core/containers/juce_ArrayBase.h
vendored
Normal file
607
deps/juce/modules/juce_core/containers/juce_ArrayBase.h
vendored
Normal file
@@ -0,0 +1,607 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 basic object container.
|
||||
|
||||
This class isn't really for public use - it's used by the other
|
||||
array classes, but might come in handy for some purposes.
|
||||
|
||||
It inherits from a critical section class to allow the arrays to use
|
||||
the "empty base class optimisation" pattern to reduce their footprint.
|
||||
|
||||
@see Array, OwnedArray, ReferenceCountedArray
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class ElementType, class TypeOfCriticalSectionToUse>
|
||||
class ArrayBase : public TypeOfCriticalSectionToUse
|
||||
{
|
||||
private:
|
||||
using ParameterType = typename TypeHelpers::ParameterType<ElementType>::type;
|
||||
|
||||
template <class OtherElementType, class OtherCriticalSection>
|
||||
using AllowConversion = typename std::enable_if<! std::is_same<std::tuple<ElementType, TypeOfCriticalSectionToUse>,
|
||||
std::tuple<OtherElementType, OtherCriticalSection>>::value>::type;
|
||||
|
||||
public:
|
||||
//==============================================================================
|
||||
ArrayBase() = default;
|
||||
|
||||
~ArrayBase()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
ArrayBase (ArrayBase&& other) noexcept
|
||||
: elements (std::move (other.elements)),
|
||||
numAllocated (other.numAllocated),
|
||||
numUsed (other.numUsed)
|
||||
{
|
||||
other.numAllocated = 0;
|
||||
other.numUsed = 0;
|
||||
}
|
||||
|
||||
ArrayBase& operator= (ArrayBase&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
auto tmp (std::move (other));
|
||||
swapWith (tmp);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Converting move constructor.
|
||||
Only enabled when the other array has a different type to this one.
|
||||
If you see a compile error here, it's probably because you're attempting a conversion that
|
||||
HeapBlock won't allow.
|
||||
*/
|
||||
template <class OtherElementType,
|
||||
class OtherCriticalSection,
|
||||
typename = AllowConversion<OtherElementType, OtherCriticalSection>>
|
||||
ArrayBase (ArrayBase<OtherElementType, OtherCriticalSection>&& other) noexcept
|
||||
: elements (std::move (other.elements)),
|
||||
numAllocated (other.numAllocated),
|
||||
numUsed (other.numUsed)
|
||||
{
|
||||
other.numAllocated = 0;
|
||||
other.numUsed = 0;
|
||||
}
|
||||
|
||||
/** Converting move assignment operator.
|
||||
Only enabled when the other array has a different type to this one.
|
||||
If you see a compile error here, it's probably because you're attempting a conversion that
|
||||
HeapBlock won't allow.
|
||||
*/
|
||||
template <class OtherElementType,
|
||||
class OtherCriticalSection,
|
||||
typename = AllowConversion<OtherElementType, OtherCriticalSection>>
|
||||
ArrayBase& operator= (ArrayBase<OtherElementType, OtherCriticalSection>&& other) noexcept
|
||||
{
|
||||
// No need to worry about assignment to *this, because 'other' must be of a different type.
|
||||
elements = std::move (other.elements);
|
||||
numAllocated = other.numAllocated;
|
||||
numUsed = other.numUsed;
|
||||
|
||||
other.numAllocated = 0;
|
||||
other.numUsed = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
template <class OtherArrayType>
|
||||
bool operator== (const OtherArrayType& other) const noexcept
|
||||
{
|
||||
if (size() != (int) other.size())
|
||||
return false;
|
||||
|
||||
auto* e = begin();
|
||||
|
||||
for (auto& o : other)
|
||||
if (! (*e++ == o))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class OtherArrayType>
|
||||
bool operator!= (const OtherArrayType& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
inline ElementType& operator[] (const int index) noexcept
|
||||
{
|
||||
jassert (elements != nullptr);
|
||||
jassert (isPositiveAndBelow (index, numUsed));
|
||||
return elements[index];
|
||||
}
|
||||
|
||||
inline const ElementType& operator[] (const int index) const noexcept
|
||||
{
|
||||
jassert (elements != nullptr);
|
||||
jassert (isPositiveAndBelow (index, numUsed));
|
||||
return elements[index];
|
||||
}
|
||||
|
||||
inline ElementType getValueWithDefault (const int index) const noexcept
|
||||
{
|
||||
return isPositiveAndBelow (index, numUsed) ? elements[index] : ElementType();
|
||||
}
|
||||
|
||||
inline ElementType getFirst() const noexcept
|
||||
{
|
||||
return numUsed > 0 ? elements[0] : ElementType();
|
||||
}
|
||||
|
||||
inline ElementType getLast() const noexcept
|
||||
{
|
||||
return numUsed > 0 ? elements[numUsed - 1] : ElementType();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
inline ElementType* begin() noexcept
|
||||
{
|
||||
return elements;
|
||||
}
|
||||
|
||||
inline const ElementType* begin() const noexcept
|
||||
{
|
||||
return elements;
|
||||
}
|
||||
|
||||
inline ElementType* end() noexcept
|
||||
{
|
||||
return elements + numUsed;
|
||||
}
|
||||
|
||||
inline const ElementType* end() const noexcept
|
||||
{
|
||||
return elements + numUsed;
|
||||
}
|
||||
|
||||
inline ElementType* data() noexcept
|
||||
{
|
||||
return elements;
|
||||
}
|
||||
|
||||
inline const ElementType* data() const noexcept
|
||||
{
|
||||
return elements;
|
||||
}
|
||||
|
||||
inline int size() const noexcept
|
||||
{
|
||||
return numUsed;
|
||||
}
|
||||
|
||||
inline int capacity() const noexcept
|
||||
{
|
||||
return numAllocated;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void setAllocatedSize (int numElements)
|
||||
{
|
||||
jassert (numElements >= numUsed);
|
||||
|
||||
if (numAllocated != numElements)
|
||||
{
|
||||
if (numElements > 0)
|
||||
setAllocatedSizeInternal (numElements);
|
||||
else
|
||||
elements.free();
|
||||
}
|
||||
|
||||
numAllocated = numElements;
|
||||
}
|
||||
|
||||
void ensureAllocatedSize (int minNumElements)
|
||||
{
|
||||
if (minNumElements > numAllocated)
|
||||
setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
|
||||
|
||||
jassert (numAllocated <= 0 || elements != nullptr);
|
||||
}
|
||||
|
||||
void shrinkToNoMoreThan (int maxNumElements)
|
||||
{
|
||||
if (maxNumElements < numAllocated)
|
||||
setAllocatedSize (maxNumElements);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (int i = 0; i < numUsed; ++i)
|
||||
elements[i].~ElementType();
|
||||
|
||||
numUsed = 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void swapWith (ArrayBase& other) noexcept
|
||||
{
|
||||
elements.swapWith (other.elements);
|
||||
std::swap (numAllocated, other.numAllocated);
|
||||
std::swap (numUsed, other.numUsed);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void add (const ElementType& newElement)
|
||||
{
|
||||
addImpl (newElement);
|
||||
}
|
||||
|
||||
void add (ElementType&& newElement)
|
||||
{
|
||||
addImpl (std::move (newElement));
|
||||
}
|
||||
|
||||
template <typename... OtherElements>
|
||||
void add (const ElementType& firstNewElement, OtherElements&&... otherElements)
|
||||
{
|
||||
addImpl (firstNewElement, std::forward<OtherElements> (otherElements)...);
|
||||
}
|
||||
|
||||
template <typename... OtherElements>
|
||||
void add (ElementType&& firstNewElement, OtherElements&&... otherElements)
|
||||
{
|
||||
addImpl (std::move (firstNewElement), std::forward<OtherElements> (otherElements)...);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
template <typename Type>
|
||||
void addArray (const Type* elementsToAdd, int numElementsToAdd)
|
||||
{
|
||||
ensureAllocatedSize (numUsed + numElementsToAdd);
|
||||
addArrayInternal (elementsToAdd, numElementsToAdd);
|
||||
numUsed += numElementsToAdd;
|
||||
}
|
||||
|
||||
template <typename TypeToCreateFrom>
|
||||
void addArray (const std::initializer_list<TypeToCreateFrom>& items)
|
||||
{
|
||||
ensureAllocatedSize (numUsed + (int) items.size());
|
||||
|
||||
for (auto& item : items)
|
||||
new (elements + numUsed++) ElementType (item);
|
||||
}
|
||||
|
||||
template <class OtherArrayType>
|
||||
void addArray (const OtherArrayType& arrayToAddFrom)
|
||||
{
|
||||
jassert ((const void*) this != (const void*) &arrayToAddFrom); // can't add from our own elements!
|
||||
ensureAllocatedSize (numUsed + (int) arrayToAddFrom.size());
|
||||
|
||||
for (auto& e : arrayToAddFrom)
|
||||
addAssumingCapacityIsReady (e);
|
||||
}
|
||||
|
||||
template <class OtherArrayType>
|
||||
typename std::enable_if<! std::is_pointer<OtherArrayType>::value, int>::type
|
||||
addArray (const OtherArrayType& arrayToAddFrom,
|
||||
int startIndex, int numElementsToAdd = -1)
|
||||
{
|
||||
jassert ((const void*) this != (const void*) &arrayToAddFrom); // can't add from our own elements!
|
||||
|
||||
if (startIndex < 0)
|
||||
{
|
||||
jassertfalse;
|
||||
startIndex = 0;
|
||||
}
|
||||
|
||||
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > (int) arrayToAddFrom.size())
|
||||
numElementsToAdd = (int) arrayToAddFrom.size() - startIndex;
|
||||
|
||||
addArray (arrayToAddFrom.data() + startIndex, numElementsToAdd);
|
||||
|
||||
return numElementsToAdd;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void insert (int indexToInsertAt, ParameterType newElement, int numberOfTimesToInsertIt)
|
||||
{
|
||||
checkSourceIsNotAMember (newElement);
|
||||
auto* space = createInsertSpace (indexToInsertAt, numberOfTimesToInsertIt);
|
||||
|
||||
for (int i = 0; i < numberOfTimesToInsertIt; ++i)
|
||||
new (space++) ElementType (newElement);
|
||||
|
||||
numUsed += numberOfTimesToInsertIt;
|
||||
}
|
||||
|
||||
void insertArray (int indexToInsertAt, const ElementType* newElements, int numberOfElements)
|
||||
{
|
||||
auto* space = createInsertSpace (indexToInsertAt, numberOfElements);
|
||||
|
||||
for (int i = 0; i < numberOfElements; ++i)
|
||||
new (space++) ElementType (*(newElements++));
|
||||
|
||||
numUsed += numberOfElements;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void removeElements (int indexToRemoveAt, int numElementsToRemove)
|
||||
{
|
||||
jassert (indexToRemoveAt >= 0);
|
||||
jassert (numElementsToRemove >= 0);
|
||||
jassert (indexToRemoveAt + numElementsToRemove <= numUsed);
|
||||
|
||||
if (numElementsToRemove > 0)
|
||||
{
|
||||
removeElementsInternal (indexToRemoveAt, numElementsToRemove);
|
||||
numUsed -= numElementsToRemove;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void swap (int index1, int index2)
|
||||
{
|
||||
if (isPositiveAndBelow (index1, numUsed)
|
||||
&& isPositiveAndBelow (index2, numUsed))
|
||||
{
|
||||
std::swap (elements[index1],
|
||||
elements[index2]);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void move (int currentIndex, int newIndex) noexcept
|
||||
{
|
||||
if (isPositiveAndBelow (currentIndex, numUsed))
|
||||
{
|
||||
if (! isPositiveAndBelow (newIndex, numUsed))
|
||||
newIndex = numUsed - 1;
|
||||
|
||||
moveInternal (currentIndex, newIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
template <typename T>
|
||||
#if defined(__GNUC__) && __GNUC__ < 5 && ! defined(__clang__)
|
||||
using IsTriviallyCopyable = std::is_scalar<T>;
|
||||
#else
|
||||
using IsTriviallyCopyable = std::is_trivially_copyable<T>;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
using TriviallyCopyableVoid = typename std::enable_if<IsTriviallyCopyable<T>::value, void>::type;
|
||||
|
||||
template <typename T>
|
||||
using NonTriviallyCopyableVoid = typename std::enable_if<! IsTriviallyCopyable<T>::value, void>::type;
|
||||
|
||||
//==============================================================================
|
||||
template <typename T = ElementType>
|
||||
TriviallyCopyableVoid<T> addArrayInternal (const ElementType* otherElements, int numElements)
|
||||
{
|
||||
if (numElements > 0)
|
||||
memcpy (elements + numUsed, otherElements, (size_t) numElements * sizeof (ElementType));
|
||||
}
|
||||
|
||||
template <typename Type, typename T = ElementType>
|
||||
TriviallyCopyableVoid<T> addArrayInternal (const Type* otherElements, int numElements)
|
||||
{
|
||||
auto* start = elements + numUsed;
|
||||
|
||||
while (--numElements >= 0)
|
||||
new (start++) ElementType (*(otherElements++));
|
||||
}
|
||||
|
||||
template <typename Type, typename T = ElementType>
|
||||
NonTriviallyCopyableVoid<T> addArrayInternal (const Type* otherElements, int numElements)
|
||||
{
|
||||
auto* start = elements + numUsed;
|
||||
|
||||
while (--numElements >= 0)
|
||||
new (start++) ElementType (*(otherElements++));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
template <typename T = ElementType>
|
||||
TriviallyCopyableVoid<T> setAllocatedSizeInternal (int numElements)
|
||||
{
|
||||
elements.realloc ((size_t) numElements);
|
||||
}
|
||||
|
||||
template <typename T = ElementType>
|
||||
NonTriviallyCopyableVoid<T> setAllocatedSizeInternal (int numElements)
|
||||
{
|
||||
HeapBlock<ElementType> newElements (numElements);
|
||||
|
||||
for (int i = 0; i < numUsed; ++i)
|
||||
{
|
||||
new (newElements + i) ElementType (std::move (elements[i]));
|
||||
elements[i].~ElementType();
|
||||
}
|
||||
|
||||
elements = std::move (newElements);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ElementType* createInsertSpace (int indexToInsertAt, int numElements)
|
||||
{
|
||||
ensureAllocatedSize (numUsed + numElements);
|
||||
|
||||
if (! isPositiveAndBelow (indexToInsertAt, numUsed))
|
||||
return elements + numUsed;
|
||||
|
||||
createInsertSpaceInternal (indexToInsertAt, numElements);
|
||||
|
||||
return elements + indexToInsertAt;
|
||||
}
|
||||
|
||||
template <typename T = ElementType>
|
||||
TriviallyCopyableVoid<T> createInsertSpaceInternal (int indexToInsertAt, int numElements)
|
||||
{
|
||||
auto* start = elements + indexToInsertAt;
|
||||
auto numElementsToShift = numUsed - indexToInsertAt;
|
||||
memmove (start + numElements, start, (size_t) numElementsToShift * sizeof (ElementType));
|
||||
}
|
||||
|
||||
template <typename T = ElementType>
|
||||
NonTriviallyCopyableVoid<T> createInsertSpaceInternal (int indexToInsertAt, int numElements)
|
||||
{
|
||||
auto* end = elements + numUsed;
|
||||
auto* newEnd = end + numElements;
|
||||
auto numElementsToShift = numUsed - indexToInsertAt;
|
||||
|
||||
for (int i = 0; i < numElementsToShift; ++i)
|
||||
{
|
||||
new (--newEnd) ElementType (std::move (*(--end)));
|
||||
end->~ElementType();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
template <typename T = ElementType>
|
||||
TriviallyCopyableVoid<T> removeElementsInternal (int indexToRemoveAt, int numElementsToRemove)
|
||||
{
|
||||
auto* start = elements + indexToRemoveAt;
|
||||
auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
|
||||
memmove (start, start + numElementsToRemove, (size_t) numElementsToShift * sizeof (ElementType));
|
||||
}
|
||||
|
||||
template <typename T = ElementType>
|
||||
NonTriviallyCopyableVoid<T> removeElementsInternal (int indexToRemoveAt, int numElementsToRemove)
|
||||
{
|
||||
auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
|
||||
auto* destination = elements + indexToRemoveAt;
|
||||
auto* source = destination + numElementsToRemove;
|
||||
|
||||
for (int i = 0; i < numElementsToShift; ++i)
|
||||
moveAssignElement (destination++, std::move (*(source++)));
|
||||
|
||||
for (int i = 0; i < numElementsToRemove; ++i)
|
||||
(destination++)->~ElementType();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
template <typename T = ElementType>
|
||||
TriviallyCopyableVoid<T> moveInternal (int currentIndex, int newIndex) noexcept
|
||||
{
|
||||
char tempCopy[sizeof (ElementType)];
|
||||
memcpy (tempCopy, elements + currentIndex, sizeof (ElementType));
|
||||
|
||||
if (newIndex > currentIndex)
|
||||
{
|
||||
memmove (elements + currentIndex,
|
||||
elements + currentIndex + 1,
|
||||
(size_t) (newIndex - currentIndex) * sizeof (ElementType));
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove (elements + newIndex + 1,
|
||||
elements + newIndex,
|
||||
(size_t) (currentIndex - newIndex) * sizeof (ElementType));
|
||||
}
|
||||
|
||||
memcpy (elements + newIndex, tempCopy, sizeof (ElementType));
|
||||
}
|
||||
|
||||
template <typename T = ElementType>
|
||||
NonTriviallyCopyableVoid<T> moveInternal (int currentIndex, int newIndex) noexcept
|
||||
{
|
||||
auto* e = elements + currentIndex;
|
||||
ElementType tempCopy (std::move (*e));
|
||||
auto delta = newIndex - currentIndex;
|
||||
|
||||
if (delta > 0)
|
||||
{
|
||||
for (int i = 0; i < delta; ++i)
|
||||
{
|
||||
moveAssignElement (e, std::move (*(e + 1)));
|
||||
++e;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < -delta; ++i)
|
||||
{
|
||||
moveAssignElement (e, std::move (*(e - 1)));
|
||||
--e;
|
||||
}
|
||||
}
|
||||
|
||||
moveAssignElement (e, std::move (tempCopy));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
template <typename... Elements>
|
||||
void addImpl (Elements&&... toAdd)
|
||||
{
|
||||
ignoreUnused (std::initializer_list<int> { (((void) checkSourceIsNotAMember (toAdd)), 0)... });
|
||||
ensureAllocatedSize (numUsed + (int) sizeof... (toAdd));
|
||||
addAssumingCapacityIsReady (std::forward<Elements> (toAdd)...);
|
||||
}
|
||||
|
||||
template <typename... Elements>
|
||||
void addAssumingCapacityIsReady (Elements&&... toAdd)
|
||||
{
|
||||
ignoreUnused (std::initializer_list<int> { ((void) (new (elements + numUsed++) ElementType (std::forward<Elements> (toAdd))), 0)... });
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
template <typename T = ElementType>
|
||||
typename std::enable_if<std::is_move_assignable<T>::value, void>::type
|
||||
moveAssignElement (ElementType* destination, ElementType&& source)
|
||||
{
|
||||
*destination = std::move (source);
|
||||
}
|
||||
|
||||
template <typename T = ElementType>
|
||||
typename std::enable_if<! std::is_move_assignable<T>::value, void>::type
|
||||
moveAssignElement (ElementType* destination, ElementType&& source)
|
||||
{
|
||||
destination->~ElementType();
|
||||
new (destination) ElementType (std::move (source));
|
||||
}
|
||||
|
||||
void checkSourceIsNotAMember (const ElementType& element)
|
||||
{
|
||||
// when you pass a reference to an existing element into a method like add() which
|
||||
// may need to reallocate the array to make more space, the incoming reference may
|
||||
// be deleted indirectly during the reallocation operation! To work around this,
|
||||
// make a local copy of the item you're trying to add (and maybe use std::move to
|
||||
// move it into the add() method to avoid any extra overhead)
|
||||
jassertquiet (std::addressof (element) < begin() || end() <= std::addressof (element));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
HeapBlock<ElementType> elements;
|
||||
int numAllocated = 0, numUsed = 0;
|
||||
|
||||
template <class OtherElementType, class OtherCriticalSection>
|
||||
friend class ArrayBase;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (ArrayBase)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
132
deps/juce/modules/juce_core/containers/juce_DynamicObject.cpp
vendored
Normal file
132
deps/juce/modules/juce_core/containers/juce_DynamicObject.cpp
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
DynamicObject::DynamicObject()
|
||||
{
|
||||
}
|
||||
|
||||
DynamicObject::DynamicObject (const DynamicObject& other)
|
||||
: ReferenceCountedObject(), properties (other.properties)
|
||||
{
|
||||
}
|
||||
|
||||
DynamicObject::~DynamicObject()
|
||||
{
|
||||
}
|
||||
|
||||
bool DynamicObject::hasProperty (const Identifier& propertyName) const
|
||||
{
|
||||
const var* const v = properties.getVarPointer (propertyName);
|
||||
return v != nullptr && ! v->isMethod();
|
||||
}
|
||||
|
||||
const var& DynamicObject::getProperty (const Identifier& propertyName) const
|
||||
{
|
||||
return properties [propertyName];
|
||||
}
|
||||
|
||||
void DynamicObject::setProperty (const Identifier& propertyName, const var& newValue)
|
||||
{
|
||||
properties.set (propertyName, newValue);
|
||||
}
|
||||
|
||||
void DynamicObject::removeProperty (const Identifier& propertyName)
|
||||
{
|
||||
properties.remove (propertyName);
|
||||
}
|
||||
|
||||
bool DynamicObject::hasMethod (const Identifier& methodName) const
|
||||
{
|
||||
return getProperty (methodName).isMethod();
|
||||
}
|
||||
|
||||
var DynamicObject::invokeMethod (Identifier method, const var::NativeFunctionArgs& args)
|
||||
{
|
||||
if (auto function = properties [method].getNativeFunction())
|
||||
return function (args);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void DynamicObject::setMethod (Identifier name, var::NativeFunction function)
|
||||
{
|
||||
properties.set (name, var (function));
|
||||
}
|
||||
|
||||
void DynamicObject::clear()
|
||||
{
|
||||
properties.clear();
|
||||
}
|
||||
|
||||
void DynamicObject::cloneAllProperties()
|
||||
{
|
||||
for (int i = properties.size(); --i >= 0;)
|
||||
if (auto* v = properties.getVarPointerAt (i))
|
||||
*v = v->clone();
|
||||
}
|
||||
|
||||
DynamicObject::Ptr DynamicObject::clone()
|
||||
{
|
||||
Ptr d (new DynamicObject (*this));
|
||||
d->cloneAllProperties();
|
||||
return d;
|
||||
}
|
||||
|
||||
void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const bool allOnOneLine, int maximumDecimalPlaces)
|
||||
{
|
||||
out << '{';
|
||||
if (! allOnOneLine)
|
||||
out << newLine;
|
||||
|
||||
const int numValues = properties.size();
|
||||
|
||||
for (int i = 0; i < numValues; ++i)
|
||||
{
|
||||
if (! allOnOneLine)
|
||||
JSONFormatter::writeSpaces (out, indentLevel + JSONFormatter::indentSize);
|
||||
|
||||
out << '"';
|
||||
JSONFormatter::writeString (out, properties.getName (i));
|
||||
out << "\": ";
|
||||
JSONFormatter::write (out, properties.getValueAt (i), indentLevel + JSONFormatter::indentSize, allOnOneLine, maximumDecimalPlaces);
|
||||
|
||||
if (i < numValues - 1)
|
||||
{
|
||||
if (allOnOneLine)
|
||||
out << ", ";
|
||||
else
|
||||
out << ',' << newLine;
|
||||
}
|
||||
else if (! allOnOneLine)
|
||||
out << newLine;
|
||||
}
|
||||
|
||||
if (! allOnOneLine)
|
||||
JSONFormatter::writeSpaces (out, indentLevel);
|
||||
|
||||
out << '}';
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
127
deps/juce/modules/juce_core/containers/juce_DynamicObject.h
vendored
Normal file
127
deps/juce/modules/juce_core/containers/juce_DynamicObject.h
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents a dynamically implemented object.
|
||||
|
||||
This class is primarily intended for wrapping scripting language objects,
|
||||
but could be used for other purposes.
|
||||
|
||||
An instance of a DynamicObject can be used to store named properties, and
|
||||
by subclassing hasMethod() and invokeMethod(), you can give your object
|
||||
methods.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API DynamicObject : public ReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
DynamicObject();
|
||||
DynamicObject (const DynamicObject&);
|
||||
~DynamicObject() override;
|
||||
|
||||
using Ptr = ReferenceCountedObjectPtr<DynamicObject>;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the object has a property with this name.
|
||||
Note that if the property is actually a method, this will return false.
|
||||
*/
|
||||
virtual bool hasProperty (const Identifier& propertyName) const;
|
||||
|
||||
/** Returns a named property.
|
||||
This returns var() if no such property exists.
|
||||
*/
|
||||
virtual const var& getProperty (const Identifier& propertyName) const;
|
||||
|
||||
/** Sets a named property. */
|
||||
virtual void setProperty (const Identifier& propertyName, const var& newValue);
|
||||
|
||||
/** Removes a named property. */
|
||||
virtual void removeProperty (const Identifier& propertyName);
|
||||
|
||||
//==============================================================================
|
||||
/** Checks whether this object has the specified method.
|
||||
|
||||
The default implementation of this just checks whether there's a property
|
||||
with this name that's actually a method, but this can be overridden for
|
||||
building objects with dynamic invocation.
|
||||
*/
|
||||
virtual bool hasMethod (const Identifier& methodName) const;
|
||||
|
||||
/** Invokes a named method on this object.
|
||||
|
||||
The default implementation looks up the named property, and if it's a method
|
||||
call, then it invokes it.
|
||||
|
||||
This method is virtual to allow more dynamic invocation to used for objects
|
||||
where the methods may not already be set as properties.
|
||||
*/
|
||||
virtual var invokeMethod (Identifier methodName,
|
||||
const var::NativeFunctionArgs& args);
|
||||
|
||||
/** Adds a method to the class.
|
||||
|
||||
This is basically the same as calling setProperty (methodName, (var::NativeFunction) myFunction), but
|
||||
helps to avoid accidentally invoking the wrong type of var constructor. It also makes
|
||||
the code easier to read.
|
||||
*/
|
||||
void setMethod (Identifier methodName, var::NativeFunction function);
|
||||
|
||||
//==============================================================================
|
||||
/** Removes all properties and methods from the object. */
|
||||
void clear();
|
||||
|
||||
/** Returns the NamedValueSet that holds the object's properties. */
|
||||
NamedValueSet& getProperties() noexcept { return properties; }
|
||||
|
||||
/** Calls var::clone() on all the properties that this object contains. */
|
||||
void cloneAllProperties();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a clone of this object.
|
||||
The default implementation of this method just returns a new DynamicObject
|
||||
with a (deep) copy of all of its properties. Subclasses can override this to
|
||||
implement their own custom copy routines.
|
||||
*/
|
||||
virtual Ptr clone();
|
||||
|
||||
//==============================================================================
|
||||
/** Writes this object to a text stream in JSON format.
|
||||
This method is used by JSON::toString and JSON::writeToStream, and you should
|
||||
never need to call it directly, but it's virtual so that custom object types
|
||||
can stringify themselves appropriately.
|
||||
*/
|
||||
virtual void writeAsJSON (OutputStream&, int indentLevel, bool allOnOneLine, int maximumDecimalPlaces);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
NamedValueSet properties;
|
||||
|
||||
JUCE_LEAK_DETECTOR (DynamicObject)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
197
deps/juce/modules/juce_core/containers/juce_ElementComparator.h
vendored
Normal file
197
deps/juce/modules/juce_core/containers/juce_ElementComparator.h
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
|
||||
/** This is an internal helper class which converts a juce ElementComparator style
|
||||
class (using a "compareElements" method) into a class that's compatible with
|
||||
std::sort (i.e. using an operator() to compare the elements)
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <typename ElementComparator>
|
||||
struct SortFunctionConverter
|
||||
{
|
||||
SortFunctionConverter (ElementComparator& e) : comparator (e) {}
|
||||
|
||||
template <typename Type>
|
||||
bool operator() (Type a, Type b) { return comparator.compareElements (a, b) < 0; }
|
||||
|
||||
private:
|
||||
ElementComparator& comparator;
|
||||
SortFunctionConverter& operator= (const SortFunctionConverter&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Sorts a range of elements in an array.
|
||||
|
||||
The comparator object that is passed-in must define a public method with the following
|
||||
signature:
|
||||
@code
|
||||
int compareElements (ElementType first, ElementType second);
|
||||
@endcode
|
||||
|
||||
..and this method must return:
|
||||
- a value of < 0 if the first comes before the second
|
||||
- a value of 0 if the two objects are equivalent
|
||||
- a value of > 0 if the second comes before the first
|
||||
|
||||
To improve performance, the compareElements() method can be declared as static or const.
|
||||
|
||||
@param comparator an object which defines a compareElements() method
|
||||
@param array the array to sort
|
||||
@param firstElement the index of the first element of the range to be sorted
|
||||
@param lastElement the index of the last element in the range that needs
|
||||
sorting (this is inclusive)
|
||||
@param retainOrderOfEquivalentItems if true, the order of items that the
|
||||
comparator deems the same will be maintained - this will be
|
||||
a slower algorithm than if they are allowed to be moved around.
|
||||
|
||||
@see sortArrayRetainingOrder
|
||||
*/
|
||||
template <class ElementType, class ElementComparator>
|
||||
static void sortArray (ElementComparator& comparator,
|
||||
ElementType* const array,
|
||||
int firstElement,
|
||||
int lastElement,
|
||||
const bool retainOrderOfEquivalentItems)
|
||||
{
|
||||
jassert (firstElement >= 0);
|
||||
|
||||
if (lastElement > firstElement)
|
||||
{
|
||||
SortFunctionConverter<ElementComparator> converter (comparator);
|
||||
|
||||
if (retainOrderOfEquivalentItems)
|
||||
std::stable_sort (array + firstElement, array + lastElement + 1, converter);
|
||||
else
|
||||
std::sort (array + firstElement, array + lastElement + 1, converter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Searches a sorted array of elements, looking for the index at which a specified value
|
||||
should be inserted for it to be in the correct order.
|
||||
|
||||
The comparator object that is passed-in must define a public method with the following
|
||||
signature:
|
||||
@code
|
||||
int compareElements (ElementType first, ElementType second);
|
||||
@endcode
|
||||
|
||||
..and this method must return:
|
||||
- a value of < 0 if the first comes before the second
|
||||
- a value of 0 if the two objects are equivalent
|
||||
- a value of > 0 if the second comes before the first
|
||||
|
||||
To improve performance, the compareElements() method can be declared as static or const.
|
||||
|
||||
@param comparator an object which defines a compareElements() method
|
||||
@param array the array to search
|
||||
@param newElement the value that is going to be inserted
|
||||
@param firstElement the index of the first element to search
|
||||
@param lastElement the index of the last element in the range (this is non-inclusive)
|
||||
*/
|
||||
template <class ElementType, class ElementComparator>
|
||||
static int findInsertIndexInSortedArray (ElementComparator& comparator,
|
||||
ElementType* const array,
|
||||
const ElementType newElement,
|
||||
int firstElement,
|
||||
int lastElement)
|
||||
{
|
||||
jassert (firstElement <= lastElement);
|
||||
|
||||
ignoreUnused (comparator); // if you pass in an object with a static compareElements() method, this
|
||||
// avoids getting warning messages about the parameter being unused
|
||||
|
||||
while (firstElement < lastElement)
|
||||
{
|
||||
if (comparator.compareElements (newElement, array [firstElement]) == 0)
|
||||
{
|
||||
++firstElement;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int halfway = (firstElement + lastElement) >> 1;
|
||||
|
||||
if (halfway == firstElement)
|
||||
{
|
||||
if (comparator.compareElements (newElement, array [halfway]) >= 0)
|
||||
++firstElement;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (comparator.compareElements (newElement, array [halfway]) >= 0)
|
||||
{
|
||||
firstElement = halfway;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastElement = halfway;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return firstElement;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A simple ElementComparator class that can be used to sort an array of
|
||||
objects that support the '<' operator.
|
||||
|
||||
This will work for primitive types and objects that implement operator<().
|
||||
|
||||
Example: @code
|
||||
Array<int> myArray;
|
||||
DefaultElementComparator<int> sorter;
|
||||
myArray.sort (sorter);
|
||||
@endcode
|
||||
|
||||
@see ElementComparator
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class ElementType>
|
||||
class DefaultElementComparator
|
||||
{
|
||||
private:
|
||||
using ParameterType = typename TypeHelpers::ParameterType<ElementType>::type;
|
||||
|
||||
public:
|
||||
static int compareElements (ParameterType first, ParameterType second)
|
||||
{
|
||||
return (first < second) ? -1 : ((second < first) ? 1 : 0);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
506
deps/juce/modules/juce_core/containers/juce_HashMap.h
vendored
Normal file
506
deps/juce/modules/juce_core/containers/juce_HashMap.h
vendored
Normal file
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 simple class to generate hash functions for some primitive types, intended for
|
||||
use with the HashMap class.
|
||||
@see HashMap
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
struct DefaultHashFunctions
|
||||
{
|
||||
/** Generates a simple hash from an unsigned int. */
|
||||
static int generateHash (uint32 key, int upperLimit) noexcept { return (int) (key % (uint32) upperLimit); }
|
||||
/** Generates a simple hash from an integer. */
|
||||
static int generateHash (int32 key, int upperLimit) noexcept { return generateHash ((uint32) key, upperLimit); }
|
||||
/** Generates a simple hash from a uint64. */
|
||||
static int generateHash (uint64 key, int upperLimit) noexcept { return (int) (key % (uint64) upperLimit); }
|
||||
/** Generates a simple hash from an int64. */
|
||||
static int generateHash (int64 key, int upperLimit) noexcept { return generateHash ((uint64) key, upperLimit); }
|
||||
/** Generates a simple hash from a string. */
|
||||
static int generateHash (const String& key, int upperLimit) noexcept { return generateHash ((uint32) key.hashCode(), upperLimit); }
|
||||
/** Generates a simple hash from a variant. */
|
||||
static int generateHash (const var& key, int upperLimit) noexcept { return generateHash (key.toString(), upperLimit); }
|
||||
/** Generates a simple hash from a void ptr. */
|
||||
static int generateHash (const void* key, int upperLimit) noexcept { return generateHash ((uint64) (pointer_sized_uint) key, upperLimit); }
|
||||
/** Generates a simple hash from a UUID. */
|
||||
static int generateHash (const Uuid& key, int upperLimit) noexcept { return generateHash (key.hash(), upperLimit); }
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Holds a set of mappings between some key/value pairs.
|
||||
|
||||
The types of the key and value objects are set as template parameters.
|
||||
You can also specify a class to supply a hash function that converts a key value
|
||||
into an hashed integer. This class must have the form:
|
||||
|
||||
@code
|
||||
struct MyHashGenerator
|
||||
{
|
||||
int generateHash (MyKeyType key, int upperLimit) const
|
||||
{
|
||||
// The function must return a value 0 <= x < upperLimit
|
||||
return someFunctionOfMyKeyType (key) % upperLimit;
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
Like the Array class, the key and value types are expected to be copy-by-value
|
||||
types, so if you define them to be pointer types, this class won't delete the
|
||||
objects that they point to.
|
||||
|
||||
If you don't supply a class for the HashFunctionType template parameter, the
|
||||
default one provides some simple mappings for strings and ints.
|
||||
|
||||
@code
|
||||
HashMap<int, String> hash;
|
||||
hash.set (1, "item1");
|
||||
hash.set (2, "item2");
|
||||
|
||||
DBG (hash [1]); // prints "item1"
|
||||
DBG (hash [2]); // prints "item2"
|
||||
|
||||
// This iterates the map, printing all of its key -> value pairs..
|
||||
for (HashMap<int, String>::Iterator i (hash); i.next();)
|
||||
DBG (i.getKey() << " -> " << i.getValue());
|
||||
@endcode
|
||||
|
||||
@tparam HashFunctionType The class of hash function, which must be copy-constructible.
|
||||
@see CriticalSection, DefaultHashFunctions, NamedValueSet, SortedSet
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <typename KeyType,
|
||||
typename ValueType,
|
||||
class HashFunctionType = DefaultHashFunctions,
|
||||
class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||
class HashMap
|
||||
{
|
||||
private:
|
||||
using KeyTypeParameter = typename TypeHelpers::ParameterType<KeyType>::type;
|
||||
using ValueTypeParameter = typename TypeHelpers::ParameterType<ValueType>::type;
|
||||
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty hash-map.
|
||||
|
||||
@param numberOfSlots Specifies the number of hash entries the map will use. This will be
|
||||
the "upperLimit" parameter that is passed to your generateHash()
|
||||
function. The number of hash slots will grow automatically if necessary,
|
||||
or it can be remapped manually using remapTable().
|
||||
@param hashFunction An instance of HashFunctionType, which will be copied and
|
||||
stored to use with the HashMap. This parameter can be omitted
|
||||
if HashFunctionType has a default constructor.
|
||||
*/
|
||||
explicit HashMap (int numberOfSlots = defaultHashTableSize,
|
||||
HashFunctionType hashFunction = HashFunctionType())
|
||||
: hashFunctionToUse (hashFunction)
|
||||
{
|
||||
hashSlots.insertMultiple (0, nullptr, numberOfSlots);
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
~HashMap()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Removes all values from the map.
|
||||
Note that this will clear the content, but won't affect the number of slots (see
|
||||
remapTable and getNumSlots).
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
|
||||
for (auto i = hashSlots.size(); --i >= 0;)
|
||||
{
|
||||
auto* h = hashSlots.getUnchecked(i);
|
||||
|
||||
while (h != nullptr)
|
||||
{
|
||||
const std::unique_ptr<HashEntry> deleter (h);
|
||||
h = h->nextEntry;
|
||||
}
|
||||
|
||||
hashSlots.set (i, nullptr);
|
||||
}
|
||||
|
||||
totalNumItems = 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the current number of items in the map. */
|
||||
inline int size() const noexcept
|
||||
{
|
||||
return totalNumItems;
|
||||
}
|
||||
|
||||
/** Returns the value corresponding to a given key.
|
||||
If the map doesn't contain the key, a default instance of the value type is returned.
|
||||
@param keyToLookFor the key of the item being requested
|
||||
*/
|
||||
inline ValueType operator[] (KeyTypeParameter keyToLookFor) const
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
|
||||
if (auto* entry = getEntry (getSlot (keyToLookFor), keyToLookFor))
|
||||
return entry->value;
|
||||
|
||||
return ValueType();
|
||||
}
|
||||
|
||||
/** Returns a reference to the value corresponding to a given key.
|
||||
If the map doesn't contain the key, a default instance of the value type is
|
||||
added to the map and a reference to this is returned.
|
||||
@param keyToLookFor the key of the item being requested
|
||||
*/
|
||||
inline ValueType& getReference (KeyTypeParameter keyToLookFor)
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
auto hashIndex = generateHashFor (keyToLookFor, getNumSlots());
|
||||
|
||||
auto* firstEntry = hashSlots.getUnchecked (hashIndex);
|
||||
|
||||
if (auto* entry = getEntry (firstEntry, keyToLookFor))
|
||||
return entry->value;
|
||||
|
||||
auto* entry = new HashEntry (keyToLookFor, ValueType(), firstEntry);
|
||||
hashSlots.set (hashIndex, entry);
|
||||
++totalNumItems;
|
||||
|
||||
if (totalNumItems > (getNumSlots() * 3) / 2)
|
||||
remapTable (getNumSlots() * 2);
|
||||
|
||||
return entry->value;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the map contains an item with the specified key. */
|
||||
bool contains (KeyTypeParameter keyToLookFor) const
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
|
||||
return (getEntry (getSlot (keyToLookFor), keyToLookFor) != nullptr);
|
||||
}
|
||||
|
||||
/** Returns true if the hash contains at least one occurrence of a given value. */
|
||||
bool containsValue (ValueTypeParameter valueToLookFor) const
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
|
||||
for (auto i = getNumSlots(); --i >= 0;)
|
||||
for (auto* entry = hashSlots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry)
|
||||
if (entry->value == valueToLookFor)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Adds or replaces an element in the hash-map.
|
||||
If there's already an item with the given key, this will replace its value. Otherwise, a new item
|
||||
will be added to the map.
|
||||
*/
|
||||
void set (KeyTypeParameter newKey, ValueTypeParameter newValue) { getReference (newKey) = newValue; }
|
||||
|
||||
/** Removes an item with the given key. */
|
||||
void remove (KeyTypeParameter keyToRemove)
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
auto hashIndex = generateHashFor (keyToRemove, getNumSlots());
|
||||
auto* entry = hashSlots.getUnchecked (hashIndex);
|
||||
HashEntry* previous = nullptr;
|
||||
|
||||
while (entry != nullptr)
|
||||
{
|
||||
if (entry->key == keyToRemove)
|
||||
{
|
||||
const std::unique_ptr<HashEntry> deleter (entry);
|
||||
|
||||
entry = entry->nextEntry;
|
||||
|
||||
if (previous != nullptr)
|
||||
previous->nextEntry = entry;
|
||||
else
|
||||
hashSlots.set (hashIndex, entry);
|
||||
|
||||
--totalNumItems;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous = entry;
|
||||
entry = entry->nextEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes all items with the given value. */
|
||||
void removeValue (ValueTypeParameter valueToRemove)
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
|
||||
for (auto i = getNumSlots(); --i >= 0;)
|
||||
{
|
||||
auto* entry = hashSlots.getUnchecked(i);
|
||||
HashEntry* previous = nullptr;
|
||||
|
||||
while (entry != nullptr)
|
||||
{
|
||||
if (entry->value == valueToRemove)
|
||||
{
|
||||
const std::unique_ptr<HashEntry> deleter (entry);
|
||||
|
||||
entry = entry->nextEntry;
|
||||
|
||||
if (previous != nullptr)
|
||||
previous->nextEntry = entry;
|
||||
else
|
||||
hashSlots.set (i, entry);
|
||||
|
||||
--totalNumItems;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous = entry;
|
||||
entry = entry->nextEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Remaps the hash-map to use a different number of slots for its hash function.
|
||||
Each slot corresponds to a single hash-code, and each one can contain multiple items.
|
||||
@see getNumSlots()
|
||||
*/
|
||||
void remapTable (int newNumberOfSlots)
|
||||
{
|
||||
const ScopedLockType sl (getLock());
|
||||
|
||||
Array<HashEntry*> newSlots;
|
||||
newSlots.insertMultiple (0, nullptr, newNumberOfSlots);
|
||||
|
||||
for (auto i = getNumSlots(); --i >= 0;)
|
||||
{
|
||||
HashEntry* nextEntry = nullptr;
|
||||
|
||||
for (auto* entry = hashSlots.getUnchecked(i); entry != nullptr; entry = nextEntry)
|
||||
{
|
||||
auto hashIndex = generateHashFor (entry->key, newNumberOfSlots);
|
||||
|
||||
nextEntry = entry->nextEntry;
|
||||
entry->nextEntry = newSlots.getUnchecked (hashIndex);
|
||||
|
||||
newSlots.set (hashIndex, entry);
|
||||
}
|
||||
}
|
||||
|
||||
hashSlots.swapWith (newSlots);
|
||||
}
|
||||
|
||||
/** Returns the number of slots which are available for hashing.
|
||||
Each slot corresponds to a single hash-code, and each one can contain multiple items.
|
||||
@see getNumSlots()
|
||||
*/
|
||||
inline int getNumSlots() const noexcept
|
||||
{
|
||||
return hashSlots.size();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Efficiently swaps the contents of two hash-maps. */
|
||||
template <class OtherHashMapType>
|
||||
void swapWith (OtherHashMapType& otherHashMap) noexcept
|
||||
{
|
||||
const ScopedLockType lock1 (getLock());
|
||||
const typename OtherHashMapType::ScopedLockType lock2 (otherHashMap.getLock());
|
||||
|
||||
hashSlots.swapWith (otherHashMap.hashSlots);
|
||||
std::swap (totalNumItems, otherHashMap.totalNumItems);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the CriticalSection that locks this structure.
|
||||
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||
an object of ScopedLockType as an RAII lock for it.
|
||||
*/
|
||||
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return lock; }
|
||||
|
||||
/** Returns the type of scoped lock to use for locking this array */
|
||||
using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class HashEntry
|
||||
{
|
||||
public:
|
||||
HashEntry (KeyTypeParameter k, ValueTypeParameter val, HashEntry* const next)
|
||||
: key (k), value (val), nextEntry (next)
|
||||
{}
|
||||
|
||||
const KeyType key;
|
||||
ValueType value;
|
||||
HashEntry* nextEntry;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (HashEntry)
|
||||
};
|
||||
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Iterates over the items in a HashMap.
|
||||
|
||||
To use it, repeatedly call next() until it returns false, e.g.
|
||||
@code
|
||||
HashMap <String, String> myMap;
|
||||
|
||||
HashMap<String, String>::Iterator i (myMap);
|
||||
|
||||
while (i.next())
|
||||
{
|
||||
DBG (i.getKey() << " -> " << i.getValue());
|
||||
}
|
||||
@endcode
|
||||
|
||||
The order in which items are iterated bears no resemblance to the order in which
|
||||
they were originally added!
|
||||
|
||||
Obviously as soon as you call any non-const methods on the original hash-map, any
|
||||
iterators that were created beforehand will cease to be valid, and should not be used.
|
||||
|
||||
@see HashMap
|
||||
*/
|
||||
struct Iterator
|
||||
{
|
||||
Iterator (const HashMap& hashMapToIterate) noexcept
|
||||
: hashMap (hashMapToIterate), entry (nullptr), index (0)
|
||||
{}
|
||||
|
||||
Iterator (const Iterator& other) noexcept
|
||||
: hashMap (other.hashMap), entry (other.entry), index (other.index)
|
||||
{}
|
||||
|
||||
/** Moves to the next item, if one is available.
|
||||
When this returns true, you can get the item's key and value using getKey() and
|
||||
getValue(). If it returns false, the iteration has finished and you should stop.
|
||||
*/
|
||||
bool next() noexcept
|
||||
{
|
||||
if (entry != nullptr)
|
||||
entry = entry->nextEntry;
|
||||
|
||||
while (entry == nullptr)
|
||||
{
|
||||
if (index >= hashMap.getNumSlots())
|
||||
return false;
|
||||
|
||||
entry = hashMap.hashSlots.getUnchecked (index++);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Returns the current item's key.
|
||||
This should only be called when a call to next() has just returned true.
|
||||
*/
|
||||
KeyType getKey() const
|
||||
{
|
||||
return entry != nullptr ? entry->key : KeyType();
|
||||
}
|
||||
|
||||
/** Returns the current item's value.
|
||||
This should only be called when a call to next() has just returned true.
|
||||
*/
|
||||
ValueType getValue() const
|
||||
{
|
||||
return entry != nullptr ? entry->value : ValueType();
|
||||
}
|
||||
|
||||
/** Resets the iterator to its starting position. */
|
||||
void reset() noexcept
|
||||
{
|
||||
entry = nullptr;
|
||||
index = 0;
|
||||
}
|
||||
|
||||
Iterator& operator++() noexcept { next(); return *this; }
|
||||
ValueType operator*() const { return getValue(); }
|
||||
bool operator!= (const Iterator& other) const noexcept { return entry != other.entry || index != other.index; }
|
||||
void resetToEnd() noexcept { index = hashMap.getNumSlots(); }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
const HashMap& hashMap;
|
||||
HashEntry* entry;
|
||||
int index;
|
||||
|
||||
// using the copy constructor is ok, but you cannot assign iterators
|
||||
Iterator& operator= (const Iterator&) = delete;
|
||||
|
||||
JUCE_LEAK_DETECTOR (Iterator)
|
||||
};
|
||||
|
||||
/** Returns a start iterator for the values in this tree. */
|
||||
Iterator begin() const noexcept { Iterator i (*this); i.next(); return i; }
|
||||
|
||||
/** Returns an end iterator for the values in this tree. */
|
||||
Iterator end() const noexcept { Iterator i (*this); i.resetToEnd(); return i; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
enum { defaultHashTableSize = 101 };
|
||||
friend struct Iterator;
|
||||
|
||||
HashFunctionType hashFunctionToUse;
|
||||
Array<HashEntry*> hashSlots;
|
||||
int totalNumItems = 0;
|
||||
TypeOfCriticalSectionToUse lock;
|
||||
|
||||
int generateHashFor (KeyTypeParameter key, int numSlots) const
|
||||
{
|
||||
const int hash = hashFunctionToUse.generateHash (key, numSlots);
|
||||
jassert (isPositiveAndBelow (hash, numSlots)); // your hash function is generating out-of-range numbers!
|
||||
return hash;
|
||||
}
|
||||
|
||||
static HashEntry* getEntry (HashEntry* firstEntry, KeyType keyToLookFor) noexcept
|
||||
{
|
||||
for (auto* entry = firstEntry; entry != nullptr; entry = entry->nextEntry)
|
||||
if (entry->key == keyToLookFor)
|
||||
return entry;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline HashEntry* getSlot (KeyType key) const noexcept { return hashSlots.getUnchecked (generateHashFor (key, getNumSlots())); }
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HashMap)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
278
deps/juce/modules/juce_core/containers/juce_HashMap_test.cpp
vendored
Normal file
278
deps/juce/modules/juce_core/containers/juce_HashMap_test.cpp
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
struct HashMapTest : public UnitTest
|
||||
{
|
||||
HashMapTest()
|
||||
: UnitTest ("HashMap", UnitTestCategories::containers)
|
||||
{}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
doTest<AddElementsTest> ("AddElementsTest");
|
||||
doTest<AccessTest> ("AccessTest");
|
||||
doTest<RemoveTest> ("RemoveTest");
|
||||
doTest<PersistantMemoryLocationOfValues> ("PersistantMemoryLocationOfValues");
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct AddElementsTest
|
||||
{
|
||||
template <typename KeyType>
|
||||
static void run (UnitTest& u)
|
||||
{
|
||||
AssociativeMap<KeyType, int> groundTruth;
|
||||
HashMap<KeyType, int> hashMap;
|
||||
|
||||
RandomKeys<KeyType> keyOracle (300, 3827829);
|
||||
Random valueOracle (48735);
|
||||
|
||||
int totalValues = 0;
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
{
|
||||
auto key = keyOracle.next();
|
||||
auto value = valueOracle.nextInt();
|
||||
|
||||
bool contains = (groundTruth.find (key) != nullptr);
|
||||
u.expectEquals ((int) contains, (int) hashMap.contains (key));
|
||||
|
||||
groundTruth.add (key, value);
|
||||
hashMap.set (key, value);
|
||||
|
||||
if (! contains) totalValues++;
|
||||
|
||||
u.expectEquals (hashMap.size(), totalValues);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct AccessTest
|
||||
{
|
||||
template <typename KeyType>
|
||||
static void run (UnitTest& u)
|
||||
{
|
||||
AssociativeMap<KeyType, int> groundTruth;
|
||||
HashMap<KeyType, int> hashMap;
|
||||
|
||||
fillWithRandomValues (hashMap, groundTruth);
|
||||
|
||||
for (auto pair : groundTruth.pairs)
|
||||
u.expectEquals (hashMap[pair.key], pair.value);
|
||||
}
|
||||
};
|
||||
|
||||
struct RemoveTest
|
||||
{
|
||||
template <typename KeyType>
|
||||
static void run (UnitTest& u)
|
||||
{
|
||||
AssociativeMap<KeyType, int> groundTruth;
|
||||
HashMap<KeyType, int> hashMap;
|
||||
|
||||
fillWithRandomValues (hashMap, groundTruth);
|
||||
auto n = groundTruth.size();
|
||||
|
||||
Random r (3827387);
|
||||
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
auto idx = r.nextInt (n-- - 1);
|
||||
auto key = groundTruth.pairs.getReference (idx).key;
|
||||
|
||||
groundTruth.pairs.remove (idx);
|
||||
hashMap.remove (key);
|
||||
|
||||
u.expect (! hashMap.contains (key));
|
||||
|
||||
for (auto pair : groundTruth.pairs)
|
||||
u.expectEquals (hashMap[pair.key], pair.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ensure that the addresses of object references don't change
|
||||
struct PersistantMemoryLocationOfValues
|
||||
{
|
||||
struct AddressAndValue { int value; const int* valueAddress; };
|
||||
|
||||
template <typename KeyType>
|
||||
static void run (UnitTest& u)
|
||||
{
|
||||
AssociativeMap<KeyType, AddressAndValue> groundTruth;
|
||||
HashMap<KeyType, int> hashMap;
|
||||
|
||||
RandomKeys<KeyType> keyOracle (300, 3827829);
|
||||
Random valueOracle (48735);
|
||||
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
auto key = keyOracle.next();
|
||||
auto value = valueOracle.nextInt();
|
||||
|
||||
hashMap.set (key, value);
|
||||
|
||||
if (auto* existing = groundTruth.find (key))
|
||||
{
|
||||
// don't change the address: only the value
|
||||
existing->value = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
groundTruth.add (key, { value, &hashMap.getReference (key) });
|
||||
}
|
||||
|
||||
for (auto pair : groundTruth.pairs)
|
||||
{
|
||||
const auto& hashMapValue = hashMap.getReference (pair.key);
|
||||
|
||||
u.expectEquals (hashMapValue, pair.value.value);
|
||||
u.expect (&hashMapValue == pair.value.valueAddress);
|
||||
}
|
||||
}
|
||||
|
||||
auto n = groundTruth.size();
|
||||
Random r (3827387);
|
||||
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
auto idx = r.nextInt (n-- - 1);
|
||||
auto key = groundTruth.pairs.getReference (idx).key;
|
||||
|
||||
groundTruth.pairs.remove (idx);
|
||||
hashMap.remove (key);
|
||||
|
||||
for (auto pair : groundTruth.pairs)
|
||||
{
|
||||
const auto& hashMapValue = hashMap.getReference (pair.key);
|
||||
|
||||
u.expectEquals (hashMapValue, pair.value.value);
|
||||
u.expect (&hashMapValue == pair.value.valueAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
template <class Test>
|
||||
void doTest (const String& testName)
|
||||
{
|
||||
beginTest (testName);
|
||||
|
||||
Test::template run<int> (*this);
|
||||
Test::template run<void*> (*this);
|
||||
Test::template run<String> (*this);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
template <typename KeyType, typename ValueType>
|
||||
struct AssociativeMap
|
||||
{
|
||||
struct KeyValuePair { KeyType key; ValueType value; };
|
||||
|
||||
ValueType* find (KeyType key)
|
||||
{
|
||||
auto n = pairs.size();
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
auto& pair = pairs.getReference (i);
|
||||
|
||||
if (pair.key == key)
|
||||
return &pair.value;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void add (KeyType key, ValueType value)
|
||||
{
|
||||
if (ValueType* v = find (key))
|
||||
*v = value;
|
||||
else
|
||||
pairs.add ({key, value});
|
||||
}
|
||||
|
||||
int size() const { return pairs.size(); }
|
||||
|
||||
Array<KeyValuePair> pairs;
|
||||
};
|
||||
|
||||
template <typename KeyType, typename ValueType>
|
||||
static void fillWithRandomValues (HashMap<KeyType, int>& hashMap, AssociativeMap<KeyType, ValueType>& groundTruth)
|
||||
{
|
||||
RandomKeys<KeyType> keyOracle (300, 3827829);
|
||||
Random valueOracle (48735);
|
||||
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
{
|
||||
auto key = keyOracle.next();
|
||||
auto value = valueOracle.nextInt();
|
||||
|
||||
groundTruth.add (key, value);
|
||||
hashMap.set (key, value);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
template <typename KeyType>
|
||||
class RandomKeys
|
||||
{
|
||||
public:
|
||||
RandomKeys (int maxUniqueKeys, int seed) : r (seed)
|
||||
{
|
||||
for (int i = 0; i < maxUniqueKeys; ++i)
|
||||
keys.add (generateRandomKey (r));
|
||||
}
|
||||
|
||||
const KeyType& next()
|
||||
{
|
||||
int i = r.nextInt (keys.size() - 1);
|
||||
return keys.getReference (i);
|
||||
}
|
||||
private:
|
||||
static KeyType generateRandomKey (Random&);
|
||||
|
||||
Random r;
|
||||
Array<KeyType> keys;
|
||||
};
|
||||
};
|
||||
|
||||
template <> int HashMapTest::RandomKeys<int> ::generateRandomKey (Random& rnd) { return rnd.nextInt(); }
|
||||
template <> void* HashMapTest::RandomKeys<void*>::generateRandomKey (Random& rnd) { return reinterpret_cast<void*> (rnd.nextInt64()); }
|
||||
|
||||
template <> String HashMapTest::RandomKeys<String>::generateRandomKey (Random& rnd)
|
||||
{
|
||||
String str;
|
||||
|
||||
int len = rnd.nextInt (8)+1;
|
||||
for (int i = 0; i < len; ++i)
|
||||
str += static_cast<char> (rnd.nextInt (95) + 32);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static HashMapTest hashMapTest;
|
||||
|
||||
} // namespace juce
|
||||
370
deps/juce/modules/juce_core/containers/juce_LinkedListPointer.h
vendored
Normal file
370
deps/juce/modules/juce_core/containers/juce_LinkedListPointer.h
vendored
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Helps to manipulate singly-linked lists of objects.
|
||||
|
||||
For objects that are designed to contain a pointer to the subsequent item in the
|
||||
list, this class contains methods to deal with the list. To use it, the ObjectType
|
||||
class that it points to must contain a LinkedListPointer called nextListItem, e.g.
|
||||
|
||||
@code
|
||||
struct MyObject
|
||||
{
|
||||
int x, y, z;
|
||||
|
||||
// A linkable object must contain a member with this name and type, which must be
|
||||
// accessible by the LinkedListPointer class. (This doesn't mean it has to be public -
|
||||
// you could make your class a friend of a LinkedListPointer<MyObject> instead).
|
||||
LinkedListPointer<MyObject> nextListItem;
|
||||
};
|
||||
|
||||
LinkedListPointer<MyObject> myList;
|
||||
myList.append (new MyObject());
|
||||
myList.append (new MyObject());
|
||||
|
||||
int numItems = myList.size(); // returns 2
|
||||
MyObject* lastInList = myList.getLast();
|
||||
@endcode
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class ObjectType>
|
||||
class LinkedListPointer
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a null pointer to an empty list. */
|
||||
LinkedListPointer() noexcept
|
||||
: item (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a pointer to a list whose head is the item provided. */
|
||||
explicit LinkedListPointer (ObjectType* const headItem) noexcept
|
||||
: item (headItem)
|
||||
{
|
||||
}
|
||||
|
||||
/** Sets this pointer to point to a new list. */
|
||||
LinkedListPointer& operator= (ObjectType* const newItem) noexcept
|
||||
{
|
||||
item = newItem;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LinkedListPointer (LinkedListPointer&& other) noexcept
|
||||
: item (other.item)
|
||||
{
|
||||
other.item = nullptr;
|
||||
}
|
||||
|
||||
LinkedListPointer& operator= (LinkedListPointer&& other) noexcept
|
||||
{
|
||||
jassert (this != &other); // hopefully the compiler should make this situation impossible!
|
||||
|
||||
item = other.item;
|
||||
other.item = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the item which this pointer points to. */
|
||||
inline operator ObjectType*() const noexcept
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
/** Returns the item which this pointer points to. */
|
||||
inline ObjectType* get() const noexcept
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
/** Returns the last item in the list which this pointer points to.
|
||||
This will iterate the list and return the last item found. Obviously the speed
|
||||
of this operation will be proportional to the size of the list. If the list is
|
||||
empty the return value will be this object.
|
||||
If you're planning on appending a number of items to your list, it's much more
|
||||
efficient to use the Appender class than to repeatedly call getLast() to find the end.
|
||||
*/
|
||||
LinkedListPointer& getLast() noexcept
|
||||
{
|
||||
auto* l = this;
|
||||
|
||||
while (l->item != nullptr)
|
||||
l = &(l->item->nextListItem);
|
||||
|
||||
return *l;
|
||||
}
|
||||
|
||||
/** Returns the number of items in the list.
|
||||
Obviously with a simple linked list, getting the size involves iterating the list, so
|
||||
this can be a lengthy operation - be careful when using this method in your code.
|
||||
*/
|
||||
int size() const noexcept
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
for (auto* i = item; i != nullptr; i = i->nextListItem)
|
||||
++total;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/** Returns the item at a given index in the list.
|
||||
Since the only way to find an item is to iterate the list, this operation can obviously
|
||||
be slow, depending on its size, so you should be careful when using this in algorithms.
|
||||
*/
|
||||
LinkedListPointer& operator[] (int index) noexcept
|
||||
{
|
||||
auto* l = this;
|
||||
|
||||
while (--index >= 0 && l->item != nullptr)
|
||||
l = &(l->item->nextListItem);
|
||||
|
||||
return *l;
|
||||
}
|
||||
|
||||
/** Returns the item at a given index in the list.
|
||||
Since the only way to find an item is to iterate the list, this operation can obviously
|
||||
be slow, depending on its size, so you should be careful when using this in algorithms.
|
||||
*/
|
||||
const LinkedListPointer& operator[] (int index) const noexcept
|
||||
{
|
||||
auto* l = this;
|
||||
|
||||
while (--index >= 0 && l->item != nullptr)
|
||||
l = &(l->item->nextListItem);
|
||||
|
||||
return *l;
|
||||
}
|
||||
|
||||
/** Returns true if the list contains the given item. */
|
||||
bool contains (const ObjectType* const itemToLookFor) const noexcept
|
||||
{
|
||||
for (auto* i = item; i != nullptr; i = i->nextListItem)
|
||||
if (itemToLookFor == i)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Inserts an item into the list, placing it before the item that this pointer
|
||||
currently points to.
|
||||
*/
|
||||
void insertNext (ObjectType* const newItem)
|
||||
{
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011)
|
||||
jassert (newItem != nullptr);
|
||||
jassert (newItem->nextListItem == nullptr);
|
||||
newItem->nextListItem = item;
|
||||
item = newItem;
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
}
|
||||
|
||||
/** Inserts an item at a numeric index in the list.
|
||||
Obviously this will involve iterating the list to find the item at the given index,
|
||||
so be careful about the impact this may have on execution time.
|
||||
*/
|
||||
void insertAtIndex (int index, ObjectType* newItem)
|
||||
{
|
||||
jassert (newItem != nullptr);
|
||||
auto* l = this;
|
||||
|
||||
while (index != 0 && l->item != nullptr)
|
||||
{
|
||||
l = &(l->item->nextListItem);
|
||||
--index;
|
||||
}
|
||||
|
||||
l->insertNext (newItem);
|
||||
}
|
||||
|
||||
/** Replaces the object that this pointer points to, appending the rest of the list to
|
||||
the new object, and returning the old one.
|
||||
*/
|
||||
ObjectType* replaceNext (ObjectType* const newItem) noexcept
|
||||
{
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011 28182)
|
||||
jassert (newItem != nullptr);
|
||||
jassert (newItem->nextListItem == nullptr);
|
||||
|
||||
auto oldItem = item;
|
||||
item = newItem;
|
||||
item->nextListItem = oldItem->nextListItem.item;
|
||||
oldItem->nextListItem.item = nullptr;
|
||||
return oldItem;
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
}
|
||||
|
||||
/** Adds an item to the end of the list.
|
||||
|
||||
This operation involves iterating the whole list, so can be slow - if you need to
|
||||
append a number of items to your list, it's much more efficient to use the Appender
|
||||
class than to repeatedly call append().
|
||||
*/
|
||||
void append (ObjectType* const newItem)
|
||||
{
|
||||
getLast().item = newItem;
|
||||
}
|
||||
|
||||
/** Creates copies of all the items in another list and adds them to this one.
|
||||
This will use the ObjectType's copy constructor to try to create copies of each
|
||||
item in the other list, and appends them to this list.
|
||||
*/
|
||||
void addCopyOfList (const LinkedListPointer& other)
|
||||
{
|
||||
auto* insertPoint = this;
|
||||
|
||||
for (auto* i = other.item; i != nullptr; i = i->nextListItem)
|
||||
{
|
||||
insertPoint->insertNext (new ObjectType (*i));
|
||||
insertPoint = &(insertPoint->item->nextListItem);
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes the head item from the list.
|
||||
This won't delete the object that is removed, but returns it, so the caller can
|
||||
delete it if necessary.
|
||||
*/
|
||||
ObjectType* removeNext() noexcept
|
||||
{
|
||||
auto oldItem = item;
|
||||
|
||||
if (oldItem != nullptr)
|
||||
{
|
||||
item = oldItem->nextListItem;
|
||||
oldItem->nextListItem.item = nullptr;
|
||||
}
|
||||
|
||||
return oldItem;
|
||||
}
|
||||
|
||||
/** Removes a specific item from the list.
|
||||
Note that this will not delete the item, it simply unlinks it from the list.
|
||||
*/
|
||||
void remove (ObjectType* const itemToRemove)
|
||||
{
|
||||
if (auto* l = findPointerTo (itemToRemove))
|
||||
l->removeNext();
|
||||
}
|
||||
|
||||
/** Iterates the list, calling the delete operator on all of its elements and
|
||||
leaving this pointer empty.
|
||||
*/
|
||||
void deleteAll()
|
||||
{
|
||||
while (item != nullptr)
|
||||
{
|
||||
auto oldItem = item;
|
||||
item = oldItem->nextListItem;
|
||||
delete oldItem;
|
||||
}
|
||||
}
|
||||
|
||||
/** Finds a pointer to a given item.
|
||||
If the item is found in the list, this returns the pointer that points to it. If
|
||||
the item isn't found, this returns null.
|
||||
*/
|
||||
LinkedListPointer* findPointerTo (ObjectType* const itemToLookFor) noexcept
|
||||
{
|
||||
auto* l = this;
|
||||
|
||||
while (l->item != nullptr)
|
||||
{
|
||||
if (l->item == itemToLookFor)
|
||||
return l;
|
||||
|
||||
l = &(l->item->nextListItem);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** Copies the items in the list to an array.
|
||||
The destArray must contain enough elements to hold the entire list - no checks are
|
||||
made for this!
|
||||
*/
|
||||
void copyToArray (ObjectType** destArray) const noexcept
|
||||
{
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011)
|
||||
jassert (destArray != nullptr);
|
||||
|
||||
for (auto* i = item; i != nullptr; i = i->nextListItem)
|
||||
*destArray++ = i;
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
}
|
||||
|
||||
/** Swaps this pointer with another one */
|
||||
void swapWith (LinkedListPointer& other) noexcept
|
||||
{
|
||||
std::swap (item, other.item);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Allows efficient repeated insertions into a list.
|
||||
|
||||
You can create an Appender object which points to the last element in your
|
||||
list, and then repeatedly call Appender::append() to add items to the end
|
||||
of the list in O(1) time.
|
||||
*/
|
||||
class Appender
|
||||
{
|
||||
public:
|
||||
/** Creates an appender which will add items to the given list.
|
||||
*/
|
||||
Appender (LinkedListPointer& endOfListPointer) noexcept
|
||||
: endOfList (&endOfListPointer)
|
||||
{
|
||||
// This can only be used to add to the end of a list.
|
||||
jassert (endOfListPointer.item == nullptr);
|
||||
}
|
||||
|
||||
/** Appends an item to the list. */
|
||||
void append (ObjectType* const newItem) noexcept
|
||||
{
|
||||
*endOfList = newItem;
|
||||
endOfList = &(newItem->nextListItem);
|
||||
}
|
||||
|
||||
private:
|
||||
LinkedListPointer* endOfList;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (Appender)
|
||||
};
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ObjectType* item;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (LinkedListPointer)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
313
deps/juce/modules/juce_core/containers/juce_ListenerList.h
vendored
Normal file
313
deps/juce/modules/juce_core/containers/juce_ListenerList.h
vendored
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 set of objects and can invoke a member function callback on each object
|
||||
in the set with a single call.
|
||||
|
||||
Use a ListenerList to manage a set of objects which need a callback, and you
|
||||
can invoke a member function by simply calling call() or callChecked().
|
||||
|
||||
E.g.
|
||||
@code
|
||||
class MyListenerType
|
||||
{
|
||||
public:
|
||||
void myCallbackMethod (int foo, bool bar);
|
||||
};
|
||||
|
||||
ListenerList<MyListenerType> listeners;
|
||||
listeners.add (someCallbackObjects...);
|
||||
|
||||
// This will invoke myCallbackMethod (1234, true) on each of the objects
|
||||
// in the list...
|
||||
listeners.call ([] (MyListenerType& l) { l.myCallbackMethod (1234, true); });
|
||||
@endcode
|
||||
|
||||
If you add or remove listeners from the list during one of the callbacks - i.e. while
|
||||
it's in the middle of iterating the listeners, then it's guaranteed that no listeners
|
||||
will be mistakenly called after they've been removed, but it may mean that some of the
|
||||
listeners could be called more than once, or not at all, depending on the list's order.
|
||||
|
||||
Sometimes, there's a chance that invoking one of the callbacks might result in the
|
||||
list itself being deleted while it's still iterating - to survive this situation, you can
|
||||
use callChecked() instead of call(), passing it a local object to act as a "BailOutChecker".
|
||||
The BailOutChecker must implement a method of the form "bool shouldBailOut()", and
|
||||
the list will check this after each callback to determine whether it should abort the
|
||||
operation. For an example of a bail-out checker, see the Component::BailOutChecker class,
|
||||
which can be used to check when a Component has been deleted. See also
|
||||
ListenerList::DummyBailOutChecker, which is a dummy checker that always returns false.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class ListenerClass,
|
||||
class ArrayType = Array<ListenerClass*>>
|
||||
class ListenerList
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty list. */
|
||||
ListenerList() = default;
|
||||
|
||||
/** Destructor. */
|
||||
~ListenerList() = default;
|
||||
|
||||
//==============================================================================
|
||||
/** Adds a listener to the list.
|
||||
A listener can only be added once, so if the listener is already in the list,
|
||||
this method has no effect.
|
||||
@see remove
|
||||
*/
|
||||
void add (ListenerClass* listenerToAdd)
|
||||
{
|
||||
if (listenerToAdd != nullptr)
|
||||
listeners.addIfNotAlreadyThere (listenerToAdd);
|
||||
else
|
||||
jassertfalse; // Listeners can't be null pointers!
|
||||
}
|
||||
|
||||
/** Removes a listener from the list.
|
||||
If the listener wasn't in the list, this has no effect.
|
||||
*/
|
||||
void remove (ListenerClass* listenerToRemove)
|
||||
{
|
||||
jassert (listenerToRemove != nullptr); // Listeners can't be null pointers!
|
||||
listeners.removeFirstMatchingValue (listenerToRemove);
|
||||
}
|
||||
|
||||
/** Returns the number of registered listeners. */
|
||||
int size() const noexcept { return listeners.size(); }
|
||||
|
||||
/** Returns true if no listeners are registered, false otherwise. */
|
||||
bool isEmpty() const noexcept { return listeners.isEmpty(); }
|
||||
|
||||
/** Clears the list. */
|
||||
void clear() { listeners.clear(); }
|
||||
|
||||
/** Returns true if the specified listener has been added to the list. */
|
||||
bool contains (ListenerClass* listener) const noexcept { return listeners.contains (listener); }
|
||||
|
||||
/** Returns the raw array of listeners. */
|
||||
const ArrayType& getListeners() const noexcept { return listeners; }
|
||||
|
||||
//==============================================================================
|
||||
/** Calls a member function on each listener in the list, with multiple parameters. */
|
||||
template <typename Callback>
|
||||
void call (Callback&& callback)
|
||||
{
|
||||
typename ArrayType::ScopedLockType lock (listeners.getLock());
|
||||
|
||||
for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
|
||||
callback (*iter.getListener());
|
||||
}
|
||||
|
||||
/** Calls a member function with 1 parameter, on all but the specified listener in the list.
|
||||
This can be useful if the caller is also a listener and needs to exclude itself.
|
||||
*/
|
||||
template <typename Callback>
|
||||
void callExcluding (ListenerClass* listenerToExclude, Callback&& callback)
|
||||
{
|
||||
typename ArrayType::ScopedLockType lock (listeners.getLock());
|
||||
|
||||
for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
|
||||
{
|
||||
auto* l = iter.getListener();
|
||||
|
||||
if (l != listenerToExclude)
|
||||
callback (*l);
|
||||
}
|
||||
}
|
||||
|
||||
/** Calls a member function on each listener in the list, with 1 parameter and a bail-out-checker.
|
||||
See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <typename Callback, typename BailOutCheckerType>
|
||||
void callChecked (const BailOutCheckerType& bailOutChecker, Callback&& callback)
|
||||
{
|
||||
typename ArrayType::ScopedLockType lock (listeners.getLock());
|
||||
|
||||
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
|
||||
callback (*iter.getListener());
|
||||
}
|
||||
|
||||
/** Calls a member function, with 1 parameter, on all but the specified listener in the list
|
||||
with a bail-out-checker. This can be useful if the caller is also a listener and needs to
|
||||
exclude itself. See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <typename Callback, typename BailOutCheckerType>
|
||||
void callCheckedExcluding (ListenerClass* listenerToExclude,
|
||||
const BailOutCheckerType& bailOutChecker,
|
||||
Callback&& callback)
|
||||
{
|
||||
typename ArrayType::ScopedLockType lock (listeners.getLock());
|
||||
|
||||
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
|
||||
{
|
||||
auto* l = iter.getListener();
|
||||
|
||||
if (l != listenerToExclude)
|
||||
callback (*l);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** A dummy bail-out checker that always returns false.
|
||||
See the ListenerList notes for more info about bail-out checkers.
|
||||
*/
|
||||
struct DummyBailOutChecker
|
||||
{
|
||||
bool shouldBailOut() const noexcept { return false; }
|
||||
};
|
||||
|
||||
using ThisType = ListenerList<ListenerClass, ArrayType>;
|
||||
using ListenerType = ListenerClass;
|
||||
|
||||
//==============================================================================
|
||||
/** Iterates the listeners in a ListenerList. */
|
||||
template <class BailOutCheckerType, class ListType>
|
||||
struct Iterator
|
||||
{
|
||||
Iterator (const ListType& listToIterate) noexcept
|
||||
: list (listToIterate), index (listToIterate.size())
|
||||
{}
|
||||
|
||||
~Iterator() = default;
|
||||
|
||||
//==============================================================================
|
||||
bool next() noexcept
|
||||
{
|
||||
if (index <= 0)
|
||||
return false;
|
||||
|
||||
auto listSize = list.size();
|
||||
|
||||
if (--index < listSize)
|
||||
return true;
|
||||
|
||||
index = listSize - 1;
|
||||
return index >= 0;
|
||||
}
|
||||
|
||||
bool next (const BailOutCheckerType& bailOutChecker) noexcept
|
||||
{
|
||||
return (! bailOutChecker.shouldBailOut()) && next();
|
||||
}
|
||||
|
||||
typename ListType::ListenerType* getListener() const noexcept
|
||||
{
|
||||
return list.getListeners().getUnchecked (index);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private:
|
||||
const ListType& list;
|
||||
int index;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (Iterator)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
// There are now lambda-based call functions that can be used to replace these old method-based versions.
|
||||
// We'll eventually deprecate these old ones, so please begin moving your code to use lambdas!
|
||||
void call (void (ListenerClass::*callbackFunction) ())
|
||||
{
|
||||
call ([=] (ListenerClass& l) { (l.*callbackFunction)(); });
|
||||
}
|
||||
|
||||
void callExcluding (ListenerClass* listenerToExclude, void (ListenerClass::*callbackFunction) ())
|
||||
{
|
||||
callExcluding (listenerToExclude, [=] (ListenerClass& l) { (l.*callbackFunction)(); });
|
||||
}
|
||||
|
||||
template <class BailOutCheckerType>
|
||||
void callChecked (const BailOutCheckerType& bailOutChecker, void (ListenerClass::*callbackFunction) ())
|
||||
{
|
||||
callChecked (bailOutChecker, [=] (ListenerClass& l) { (l.*callbackFunction)(); });
|
||||
}
|
||||
|
||||
template <class BailOutCheckerType>
|
||||
void callCheckedExcluding (ListenerClass* listenerToExclude,
|
||||
const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) ())
|
||||
{
|
||||
callCheckedExcluding (listenerToExclude, bailOutChecker, [=] (ListenerClass& l) { (l.*callbackFunction)(); });
|
||||
}
|
||||
|
||||
template <typename... MethodArgs, typename... Args>
|
||||
void call (void (ListenerClass::*callbackFunction) (MethodArgs...), Args&&... args)
|
||||
{
|
||||
typename ArrayType::ScopedLockType lock (listeners.getLock());
|
||||
|
||||
for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
|
||||
(iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
|
||||
}
|
||||
|
||||
template <typename... MethodArgs, typename... Args>
|
||||
void callExcluding (ListenerClass* listenerToExclude,
|
||||
void (ListenerClass::*callbackFunction) (MethodArgs...),
|
||||
Args&&... args)
|
||||
{
|
||||
typename ArrayType::ScopedLockType lock (listeners.getLock());
|
||||
|
||||
for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
|
||||
if (iter.getListener() != listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
|
||||
}
|
||||
|
||||
template <typename BailOutCheckerType, typename... MethodArgs, typename... Args>
|
||||
void callChecked (const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) (MethodArgs...),
|
||||
Args&&... args)
|
||||
{
|
||||
typename ArrayType::ScopedLockType lock (listeners.getLock());
|
||||
|
||||
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
|
||||
(iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
|
||||
}
|
||||
|
||||
template <typename BailOutCheckerType, typename... MethodArgs, typename... Args>
|
||||
void callCheckedExcluding (ListenerClass* listenerToExclude,
|
||||
const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) (MethodArgs...),
|
||||
Args&&... args)
|
||||
{
|
||||
typename ArrayType::ScopedLockType lock (listeners.getLock());
|
||||
|
||||
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
|
||||
if (iter.getListener() != listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ArrayType listeners;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (ListenerList)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
306
deps/juce/modules/juce_core/containers/juce_NamedValueSet.cpp
vendored
Normal file
306
deps/juce/modules/juce_core/containers/juce_NamedValueSet.cpp
vendored
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
NamedValueSet::NamedValue::NamedValue() noexcept {}
|
||||
NamedValueSet::NamedValue::~NamedValue() noexcept {}
|
||||
|
||||
NamedValueSet::NamedValue::NamedValue (const Identifier& n, const var& v) : name (n), value (v) {}
|
||||
NamedValueSet::NamedValue::NamedValue (const NamedValue& other) : NamedValue (other.name, other.value) {}
|
||||
|
||||
NamedValueSet::NamedValue::NamedValue (NamedValue&& other) noexcept
|
||||
: NamedValue (std::move (other.name),
|
||||
std::move (other.value))
|
||||
{}
|
||||
|
||||
NamedValueSet::NamedValue::NamedValue (const Identifier& n, var&& v) noexcept
|
||||
: name (n), value (std::move (v))
|
||||
{
|
||||
}
|
||||
|
||||
NamedValueSet::NamedValue::NamedValue (Identifier&& n, var&& v) noexcept
|
||||
: name (std::move (n)),
|
||||
value (std::move (v))
|
||||
{}
|
||||
|
||||
NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (NamedValue&& other) noexcept
|
||||
{
|
||||
name = std::move (other.name);
|
||||
value = std::move (other.value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool NamedValueSet::NamedValue::operator== (const NamedValue& other) const noexcept { return name == other.name && value == other.value; }
|
||||
bool NamedValueSet::NamedValue::operator!= (const NamedValue& other) const noexcept { return ! operator== (other); }
|
||||
|
||||
//==============================================================================
|
||||
NamedValueSet::NamedValueSet() noexcept {}
|
||||
NamedValueSet::~NamedValueSet() noexcept {}
|
||||
|
||||
NamedValueSet::NamedValueSet (const NamedValueSet& other) : values (other.values) {}
|
||||
|
||||
NamedValueSet::NamedValueSet (NamedValueSet&& other) noexcept
|
||||
: values (std::move (other.values)) {}
|
||||
|
||||
NamedValueSet::NamedValueSet (std::initializer_list<NamedValue> list)
|
||||
: values (std::move (list))
|
||||
{
|
||||
}
|
||||
|
||||
NamedValueSet& NamedValueSet::operator= (const NamedValueSet& other)
|
||||
{
|
||||
clear();
|
||||
values = other.values;
|
||||
return *this;
|
||||
}
|
||||
|
||||
NamedValueSet& NamedValueSet::operator= (NamedValueSet&& other) noexcept
|
||||
{
|
||||
other.values.swapWith (values);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void NamedValueSet::clear()
|
||||
{
|
||||
values.clear();
|
||||
}
|
||||
|
||||
bool NamedValueSet::operator== (const NamedValueSet& other) const noexcept
|
||||
{
|
||||
auto num = values.size();
|
||||
|
||||
if (num != other.values.size())
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
// optimise for the case where the keys are in the same order
|
||||
if (values.getReference(i).name == other.values.getReference(i).name)
|
||||
{
|
||||
if (values.getReference(i).value != other.values.getReference(i).value)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we encounter keys that are in a different order, search remaining items by brute force..
|
||||
for (int j = i; j < num; ++j)
|
||||
{
|
||||
if (auto* otherVal = other.getVarPointer (values.getReference(j).name))
|
||||
if (values.getReference(j).value == *otherVal)
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NamedValueSet::operator!= (const NamedValueSet& other) const noexcept { return ! operator== (other); }
|
||||
|
||||
int NamedValueSet::size() const noexcept { return values.size(); }
|
||||
bool NamedValueSet::isEmpty() const noexcept { return values.isEmpty(); }
|
||||
|
||||
static const var& getNullVarRef() noexcept
|
||||
{
|
||||
static var nullVar;
|
||||
return nullVar;
|
||||
}
|
||||
|
||||
const var& NamedValueSet::operator[] (const Identifier& name) const noexcept
|
||||
{
|
||||
if (auto* v = getVarPointer (name))
|
||||
return *v;
|
||||
|
||||
return getNullVarRef();
|
||||
}
|
||||
|
||||
var NamedValueSet::getWithDefault (const Identifier& name, const var& defaultReturnValue) const
|
||||
{
|
||||
if (auto* v = getVarPointer (name))
|
||||
return *v;
|
||||
|
||||
return defaultReturnValue;
|
||||
}
|
||||
|
||||
var* NamedValueSet::getVarPointer (const Identifier& name) noexcept
|
||||
{
|
||||
for (auto& i : values)
|
||||
if (i.name == name)
|
||||
return &(i.value);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const var* NamedValueSet::getVarPointer (const Identifier& name) const noexcept
|
||||
{
|
||||
for (auto& i : values)
|
||||
if (i.name == name)
|
||||
return &(i.value);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool NamedValueSet::set (const Identifier& name, var&& newValue)
|
||||
{
|
||||
if (auto* v = getVarPointer (name))
|
||||
{
|
||||
if (v->equalsWithSameType (newValue))
|
||||
return false;
|
||||
|
||||
*v = std::move (newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
values.add ({ name, std::move (newValue) });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NamedValueSet::set (const Identifier& name, const var& newValue)
|
||||
{
|
||||
if (auto* v = getVarPointer (name))
|
||||
{
|
||||
if (v->equalsWithSameType (newValue))
|
||||
return false;
|
||||
|
||||
*v = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
values.add ({ name, newValue });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NamedValueSet::contains (const Identifier& name) const noexcept
|
||||
{
|
||||
return getVarPointer (name) != nullptr;
|
||||
}
|
||||
|
||||
int NamedValueSet::indexOf (const Identifier& name) const noexcept
|
||||
{
|
||||
auto numValues = values.size();
|
||||
|
||||
for (int i = 0; i < numValues; ++i)
|
||||
if (values.getReference(i).name == name)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool NamedValueSet::remove (const Identifier& name)
|
||||
{
|
||||
auto numValues = values.size();
|
||||
|
||||
for (int i = 0; i < numValues; ++i)
|
||||
{
|
||||
if (values.getReference(i).name == name)
|
||||
{
|
||||
values.remove (i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Identifier NamedValueSet::getName (const int index) const noexcept
|
||||
{
|
||||
if (isPositiveAndBelow (index, values.size()))
|
||||
return values.getReference (index).name;
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
const var& NamedValueSet::getValueAt (const int index) const noexcept
|
||||
{
|
||||
if (isPositiveAndBelow (index, values.size()))
|
||||
return values.getReference (index).value;
|
||||
|
||||
jassertfalse;
|
||||
return getNullVarRef();
|
||||
}
|
||||
|
||||
var* NamedValueSet::getVarPointerAt (int index) noexcept
|
||||
{
|
||||
if (isPositiveAndBelow (index, values.size()))
|
||||
return &(values.getReference (index).value);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const var* NamedValueSet::getVarPointerAt (int index) const noexcept
|
||||
{
|
||||
if (isPositiveAndBelow (index, values.size()))
|
||||
return &(values.getReference (index).value);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void NamedValueSet::setFromXmlAttributes (const XmlElement& xml)
|
||||
{
|
||||
values.clearQuick();
|
||||
|
||||
for (auto* att = xml.attributes.get(); att != nullptr; att = att->nextListItem)
|
||||
{
|
||||
if (att->name.toString().startsWith ("base64:"))
|
||||
{
|
||||
MemoryBlock mb;
|
||||
|
||||
if (mb.fromBase64Encoding (att->value))
|
||||
{
|
||||
values.add ({ att->name.toString().substring (7), var (mb) });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
values.add ({ att->name, var (att->value) });
|
||||
}
|
||||
}
|
||||
|
||||
void NamedValueSet::copyToXmlAttributes (XmlElement& xml) const
|
||||
{
|
||||
for (auto& i : values)
|
||||
{
|
||||
if (auto* mb = i.value.getBinaryData())
|
||||
{
|
||||
xml.setAttribute ("base64:" + i.name.toString(), mb->toBase64Encoding());
|
||||
}
|
||||
else
|
||||
{
|
||||
// These types can't be stored as XML!
|
||||
jassert (! i.value.isObject());
|
||||
jassert (! i.value.isMethod());
|
||||
jassert (! i.value.isArray());
|
||||
|
||||
xml.setAttribute (i.name.toString(),
|
||||
i.value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
185
deps/juce/modules/juce_core/containers/juce_NamedValueSet.h
vendored
Normal file
185
deps/juce/modules/juce_core/containers/juce_NamedValueSet.h
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 set of named var objects.
|
||||
|
||||
This can be used as a basic structure to hold a set of var object, which can
|
||||
be retrieved by using their identifier.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API NamedValueSet
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Structure for a named var object */
|
||||
struct JUCE_API NamedValue
|
||||
{
|
||||
NamedValue() noexcept;
|
||||
~NamedValue() noexcept;
|
||||
|
||||
NamedValue (const Identifier& name, const var& value);
|
||||
NamedValue (const Identifier& name, var&& value) noexcept;
|
||||
NamedValue (Identifier&& name, var&& value) noexcept;
|
||||
|
||||
NamedValue (const NamedValue&);
|
||||
NamedValue (NamedValue&&) noexcept;
|
||||
NamedValue& operator= (NamedValue&&) noexcept;
|
||||
|
||||
bool operator== (const NamedValue&) const noexcept;
|
||||
bool operator!= (const NamedValue&) const noexcept;
|
||||
|
||||
Identifier name;
|
||||
var value;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Creates an empty set. */
|
||||
NamedValueSet() noexcept;
|
||||
|
||||
NamedValueSet (const NamedValueSet&);
|
||||
NamedValueSet (NamedValueSet&&) noexcept;
|
||||
NamedValueSet& operator= (const NamedValueSet&);
|
||||
NamedValueSet& operator= (NamedValueSet&&) noexcept;
|
||||
|
||||
/** Creates a NamedValueSet from a list of names and properties. */
|
||||
NamedValueSet (std::initializer_list<NamedValue>);
|
||||
|
||||
/** Destructor. */
|
||||
~NamedValueSet() noexcept;
|
||||
|
||||
/** Two NamedValueSets are considered equal if they contain all the same key/value
|
||||
pairs, regardless of the order.
|
||||
*/
|
||||
bool operator== (const NamedValueSet&) const noexcept;
|
||||
bool operator!= (const NamedValueSet&) const noexcept;
|
||||
|
||||
const NamedValueSet::NamedValue* begin() const noexcept { return values.begin(); }
|
||||
const NamedValueSet::NamedValue* end() const noexcept { return values.end(); }
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the total number of values that the set contains. */
|
||||
int size() const noexcept;
|
||||
|
||||
/** Returns true if the set is empty. */
|
||||
bool isEmpty() const noexcept;
|
||||
|
||||
/** Returns the value of a named item.
|
||||
If the name isn't found, this will return a void variant.
|
||||
*/
|
||||
const var& operator[] (const Identifier& name) const noexcept;
|
||||
|
||||
/** Tries to return the named value, but if no such value is found, this will
|
||||
instead return the supplied default value.
|
||||
*/
|
||||
var getWithDefault (const Identifier& name, const var& defaultReturnValue) const;
|
||||
|
||||
/** Changes or adds a named value.
|
||||
@returns true if a value was changed or added; false if the
|
||||
value was already set the value passed-in.
|
||||
*/
|
||||
bool set (const Identifier& name, const var& newValue);
|
||||
|
||||
/** Changes or adds a named value.
|
||||
@returns true if a value was changed or added; false if the
|
||||
value was already set the value passed-in.
|
||||
*/
|
||||
bool set (const Identifier& name, var&& newValue);
|
||||
|
||||
/** Returns true if the set contains an item with the specified name. */
|
||||
bool contains (const Identifier& name) const noexcept;
|
||||
|
||||
/** Removes a value from the set.
|
||||
@returns true if a value was removed; false if there was no value
|
||||
with the name that was given.
|
||||
*/
|
||||
bool remove (const Identifier& name);
|
||||
|
||||
/** Returns the name of the value at a given index.
|
||||
The index must be between 0 and size() - 1.
|
||||
*/
|
||||
Identifier getName (int index) const noexcept;
|
||||
|
||||
/** Returns a pointer to the var that holds a named value, or null if there is
|
||||
no value with this name.
|
||||
|
||||
Do not use this method unless you really need access to the internal var object
|
||||
for some reason - for normal reading and writing always prefer operator[]() and set().
|
||||
Also note that the pointer returned may become invalid as soon as any subsequent
|
||||
methods are called on the NamedValueSet.
|
||||
*/
|
||||
var* getVarPointer (const Identifier& name) noexcept;
|
||||
|
||||
/** Returns a pointer to the var that holds a named value, or null if there is
|
||||
no value with this name.
|
||||
|
||||
Do not use this method unless you really need access to the internal var object
|
||||
for some reason - for normal reading and writing always prefer operator[]() and set().
|
||||
Also note that the pointer returned may become invalid as soon as any subsequent
|
||||
methods are called on the NamedValueSet.
|
||||
*/
|
||||
const var* getVarPointer (const Identifier& name) const noexcept;
|
||||
|
||||
/** Returns the value of the item at a given index.
|
||||
The index must be between 0 and size() - 1.
|
||||
*/
|
||||
const var& getValueAt (int index) const noexcept;
|
||||
|
||||
/** Returns the value of the item at a given index.
|
||||
The index must be between 0 and size() - 1, or this will return a nullptr
|
||||
Also note that the pointer returned may become invalid as soon as any subsequent
|
||||
methods are called on the NamedValueSet.
|
||||
*/
|
||||
var* getVarPointerAt (int index) noexcept;
|
||||
|
||||
/** Returns the value of the item at a given index.
|
||||
The index must be between 0 and size() - 1, or this will return a nullptr
|
||||
Also note that the pointer returned may become invalid as soon as any subsequent
|
||||
methods are called on the NamedValueSet.
|
||||
*/
|
||||
const var* getVarPointerAt (int index) const noexcept;
|
||||
|
||||
/** Returns the index of the given name, or -1 if it's not found. */
|
||||
int indexOf (const Identifier& name) const noexcept;
|
||||
|
||||
/** Removes all values. */
|
||||
void clear();
|
||||
|
||||
//==============================================================================
|
||||
/** Sets properties to the values of all of an XML element's attributes. */
|
||||
void setFromXmlAttributes (const XmlElement& xml);
|
||||
|
||||
/** Sets attributes in an XML element corresponding to each of this object's
|
||||
properties.
|
||||
*/
|
||||
void copyToXmlAttributes (XmlElement& xml) const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Array<NamedValue> values;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
130
deps/juce/modules/juce_core/containers/juce_OwnedArray.cpp
vendored
Normal file
130
deps/juce/modules/juce_core/containers/juce_OwnedArray.cpp
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 JUCE_UNIT_TESTS
|
||||
|
||||
static struct OwnedArrayTest : public UnitTest
|
||||
{
|
||||
struct Base
|
||||
{
|
||||
Base() = default;
|
||||
virtual ~Base() = default;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Base)
|
||||
};
|
||||
|
||||
struct Derived : Base
|
||||
{
|
||||
Derived() = default;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Derived)
|
||||
};
|
||||
|
||||
struct DestructorObj
|
||||
{
|
||||
DestructorObj (OwnedArrayTest& p,
|
||||
OwnedArray<DestructorObj>& arr)
|
||||
: parent (p), objectArray (arr)
|
||||
{}
|
||||
|
||||
~DestructorObj()
|
||||
{
|
||||
data = 0;
|
||||
|
||||
for (auto* o : objectArray)
|
||||
{
|
||||
parent.expect (o != nullptr);
|
||||
parent.expect (o != this);
|
||||
|
||||
if (o != nullptr)
|
||||
parent.expectEquals (o->data, 956);
|
||||
}
|
||||
}
|
||||
|
||||
OwnedArrayTest& parent;
|
||||
OwnedArray<DestructorObj>& objectArray;
|
||||
int data = 956;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DestructorObj)
|
||||
};
|
||||
|
||||
OwnedArrayTest()
|
||||
: UnitTest ("OwnedArray", UnitTestCategories::containers)
|
||||
{}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("After converting move construction, ownership is transferred");
|
||||
{
|
||||
OwnedArray<Derived> derived { new Derived{}, new Derived{}, new Derived{} };
|
||||
|
||||
OwnedArray<Base> base { std::move (derived) };
|
||||
|
||||
expectEquals (base.size(), 3);
|
||||
expectEquals (derived.size(), 0);
|
||||
}
|
||||
|
||||
beginTest ("After converting move assignment, ownership is transferred");
|
||||
{
|
||||
OwnedArray<Base> base;
|
||||
|
||||
base = OwnedArray<Derived> { new Derived{}, new Derived{}, new Derived{} };
|
||||
|
||||
expectEquals (base.size(), 3);
|
||||
}
|
||||
|
||||
beginTest ("Iterate in destructor");
|
||||
{
|
||||
{
|
||||
OwnedArray<DestructorObj> arr;
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
arr.add (new DestructorObj (*this, arr));
|
||||
}
|
||||
|
||||
OwnedArray<DestructorObj> arr;
|
||||
|
||||
for (int i = 0; i < 1025; ++i)
|
||||
arr.add (new DestructorObj (*this, arr));
|
||||
|
||||
while (! arr.isEmpty())
|
||||
arr.remove (0);
|
||||
|
||||
for (int i = 0; i < 1025; ++i)
|
||||
arr.add (new DestructorObj (*this, arr));
|
||||
|
||||
arr.removeRange (1, arr.size() - 3);
|
||||
|
||||
for (int i = 0; i < 1025; ++i)
|
||||
arr.add (new DestructorObj (*this, arr));
|
||||
|
||||
arr.set (500, new DestructorObj (*this, arr));
|
||||
}
|
||||
}
|
||||
} ownedArrayTest;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
873
deps/juce/modules/juce_core/containers/juce_OwnedArray.h
vendored
Normal file
873
deps/juce/modules/juce_core/containers/juce_OwnedArray.h
vendored
Normal file
@@ -0,0 +1,873 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/** An array designed for holding objects.
|
||||
|
||||
This holds a list of pointers to objects, and will automatically
|
||||
delete the objects when they are removed from the array, or when the
|
||||
array is itself deleted.
|
||||
|
||||
Declare it in the form: OwnedArray<MyObjectClass>
|
||||
|
||||
..and then add new objects, e.g. myOwnedArray.add (new MyObjectClass());
|
||||
|
||||
After adding objects, they are 'owned' by the array and will be deleted when
|
||||
removed or replaced.
|
||||
|
||||
To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
|
||||
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
|
||||
|
||||
@see Array, ReferenceCountedArray, StringArray, CriticalSection
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class ObjectClass,
|
||||
class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||
|
||||
class OwnedArray
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty array. */
|
||||
OwnedArray() = default;
|
||||
|
||||
/** Deletes the array and also deletes any objects inside it.
|
||||
|
||||
To get rid of the array without deleting its objects, use its
|
||||
clear (false) method before deleting it.
|
||||
*/
|
||||
~OwnedArray()
|
||||
{
|
||||
deleteAllObjects();
|
||||
}
|
||||
|
||||
/** Move constructor. */
|
||||
OwnedArray (OwnedArray&& other) noexcept
|
||||
: values (std::move (other.values))
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates an array from a list of objects. */
|
||||
OwnedArray (const std::initializer_list<ObjectClass*>& items)
|
||||
{
|
||||
addArray (items);
|
||||
}
|
||||
|
||||
/** Move assignment operator. */
|
||||
OwnedArray& operator= (OwnedArray&& other) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
deleteAllObjects();
|
||||
values = std::move (other.values);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Converting move constructor. */
|
||||
template <class OtherObjectClass, class OtherCriticalSection>
|
||||
OwnedArray (OwnedArray<OtherObjectClass, OtherCriticalSection>&& other) noexcept
|
||||
: values (std::move (other.values))
|
||||
{
|
||||
}
|
||||
|
||||
/** Converting move assignment operator. */
|
||||
template <class OtherObjectClass, class OtherCriticalSection>
|
||||
OwnedArray& operator= (OwnedArray<OtherObjectClass, OtherCriticalSection>&& other) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
deleteAllObjects();
|
||||
values = std::move (other.values);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Clears the array, optionally deleting the objects inside it first. */
|
||||
void clear (bool deleteObjects = true)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
clearQuick (deleteObjects);
|
||||
values.setAllocatedSize (0);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Clears the array, optionally deleting the objects inside it first. */
|
||||
void clearQuick (bool deleteObjects)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (deleteObjects)
|
||||
deleteAllObjects();
|
||||
else
|
||||
values.clear();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of items currently in the array.
|
||||
@see operator[]
|
||||
*/
|
||||
inline int size() const noexcept
|
||||
{
|
||||
return values.size();
|
||||
}
|
||||
|
||||
/** Returns true if the array is empty, false otherwise. */
|
||||
inline bool isEmpty() const noexcept
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
/** Returns a pointer to the object at this index in the array.
|
||||
|
||||
If the index is out-of-range, this will return a null pointer, (and
|
||||
it could be null anyway, because it's ok for the array to hold null
|
||||
pointers as well as objects).
|
||||
|
||||
@see getUnchecked
|
||||
*/
|
||||
inline ObjectClass* operator[] (int index) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return values.getValueWithDefault (index);
|
||||
}
|
||||
|
||||
/** Returns a pointer to the object at this index in the array, without checking whether the index is in-range.
|
||||
|
||||
This is a faster and less safe version of operator[] which doesn't check the index passed in, so
|
||||
it can be used when you're sure the index is always going to be legal.
|
||||
*/
|
||||
inline ObjectClass* getUnchecked (int index) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return values[index];
|
||||
}
|
||||
|
||||
/** Returns a pointer to the first object in the array.
|
||||
|
||||
This will return a null pointer if the array's empty.
|
||||
@see getLast
|
||||
*/
|
||||
inline ObjectClass* getFirst() const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return values.getFirst();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the last object in the array.
|
||||
|
||||
This will return a null pointer if the array's empty.
|
||||
@see getFirst
|
||||
*/
|
||||
inline ObjectClass* getLast() const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return values.getLast();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the actual array data.
|
||||
This pointer will only be valid until the next time a non-const method
|
||||
is called on the array.
|
||||
*/
|
||||
inline ObjectClass** getRawDataPointer() noexcept
|
||||
{
|
||||
return values.begin();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a pointer to the first element in the array.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline ObjectClass** begin() noexcept
|
||||
{
|
||||
return values.begin();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the first element in the array.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline ObjectClass* const* begin() const noexcept
|
||||
{
|
||||
return values.begin();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the element which follows the last element in the array.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline ObjectClass** end() noexcept
|
||||
{
|
||||
return values.end();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the element which follows the last element in the array.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline ObjectClass* const* end() const noexcept
|
||||
{
|
||||
return values.end();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the first element in the array.
|
||||
This method is provided for compatibility with the standard C++ containers.
|
||||
*/
|
||||
inline ObjectClass** data() noexcept
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the first element in the array.
|
||||
This method is provided for compatibility with the standard C++ containers.
|
||||
*/
|
||||
inline ObjectClass* const* data() const noexcept
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Finds the index of an object which might be in the array.
|
||||
|
||||
@param objectToLookFor the object to look for
|
||||
@returns the index at which the object was found, or -1 if it's not found
|
||||
*/
|
||||
int indexOf (const ObjectClass* objectToLookFor) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
auto* e = values.begin();
|
||||
|
||||
for (; e != values.end(); ++e)
|
||||
if (objectToLookFor == *e)
|
||||
return static_cast<int> (e - values.begin());
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Returns true if the array contains a specified object.
|
||||
|
||||
@param objectToLookFor the object to look for
|
||||
@returns true if the object is in the array
|
||||
*/
|
||||
bool contains (const ObjectClass* objectToLookFor) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
auto* e = values.begin();
|
||||
|
||||
for (; e != values.end(); ++e)
|
||||
if (objectToLookFor == *e)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Appends a new object to the end of the array.
|
||||
|
||||
Note that this object will be deleted by the OwnedArray when it is removed,
|
||||
so be careful not to delete it somewhere else.
|
||||
|
||||
Also be careful not to add the same object to the array more than once,
|
||||
as this will obviously cause deletion of dangling pointers.
|
||||
|
||||
@param newObject the new object to add to the array
|
||||
@returns the new object that was added
|
||||
@see set, insert, addSorted
|
||||
*/
|
||||
ObjectClass* add (ObjectClass* newObject)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
values.add (newObject);
|
||||
return newObject;
|
||||
}
|
||||
|
||||
/** Appends a new object to the end of the array.
|
||||
|
||||
Note that this object will be deleted by the OwnedArray when it is removed,
|
||||
so be careful not to delete it somewhere else.
|
||||
|
||||
Also be careful not to add the same object to the array more than once,
|
||||
as this will obviously cause deletion of dangling pointers.
|
||||
|
||||
@param newObject the new object to add to the array
|
||||
@returns the new object that was added
|
||||
@see set, insert, addSorted
|
||||
*/
|
||||
ObjectClass* add (std::unique_ptr<ObjectClass> newObject)
|
||||
{
|
||||
return add (newObject.release());
|
||||
}
|
||||
|
||||
/** Inserts a new object into the array at the given index.
|
||||
|
||||
Note that this object will be deleted by the OwnedArray when it is removed,
|
||||
so be careful not to delete it somewhere else.
|
||||
|
||||
If the index is less than 0 or greater than the size of the array, the
|
||||
element will be added to the end of the array.
|
||||
Otherwise, it will be inserted into the array, moving all the later elements
|
||||
along to make room.
|
||||
|
||||
Be careful not to add the same object to the array more than once,
|
||||
as this will obviously cause deletion of dangling pointers.
|
||||
|
||||
@param indexToInsertAt the index at which the new element should be inserted
|
||||
@param newObject the new object to add to the array
|
||||
@returns the new object that was added
|
||||
@see add, addSorted, set
|
||||
*/
|
||||
ObjectClass* insert (int indexToInsertAt, ObjectClass* newObject)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
values.insert (indexToInsertAt, newObject, 1);
|
||||
return newObject;
|
||||
}
|
||||
|
||||
/** Inserts a new object into the array at the given index.
|
||||
|
||||
Note that this object will be deleted by the OwnedArray when it is removed,
|
||||
so be careful not to delete it somewhere else.
|
||||
|
||||
If the index is less than 0 or greater than the size of the array, the
|
||||
element will be added to the end of the array.
|
||||
Otherwise, it will be inserted into the array, moving all the later elements
|
||||
along to make room.
|
||||
|
||||
Be careful not to add the same object to the array more than once,
|
||||
as this will obviously cause deletion of dangling pointers.
|
||||
|
||||
@param indexToInsertAt the index at which the new element should be inserted
|
||||
@param newObject the new object to add to the array
|
||||
@returns the new object that was added
|
||||
@see add, addSorted, set
|
||||
*/
|
||||
ObjectClass* insert (int indexToInsertAt, std::unique_ptr<ObjectClass> newObject)
|
||||
{
|
||||
return insert (indexToInsertAt, newObject.release());
|
||||
}
|
||||
|
||||
/** Inserts an array of values into this array at a given position.
|
||||
|
||||
If the index is less than 0 or greater than the size of the array, the
|
||||
new elements will be added to the end of the array.
|
||||
Otherwise, they will be inserted into the array, moving all the later elements
|
||||
along to make room.
|
||||
|
||||
@param indexToInsertAt the index at which the first new element should be inserted
|
||||
@param newObjects the new values to add to the array
|
||||
@param numberOfElements how many items are in the array
|
||||
@see insert, add, addSorted, set
|
||||
*/
|
||||
void insertArray (int indexToInsertAt,
|
||||
ObjectClass* const* newObjects,
|
||||
int numberOfElements)
|
||||
{
|
||||
if (numberOfElements > 0)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
values.insertArray (indexToInsertAt, newObjects, numberOfElements);
|
||||
}
|
||||
}
|
||||
|
||||
/** Replaces an object in the array with a different one.
|
||||
|
||||
If the index is less than zero, this method does nothing.
|
||||
If the index is beyond the end of the array, the new object is added to the end of the array.
|
||||
|
||||
Be careful not to add the same object to the array more than once,
|
||||
as this will obviously cause deletion of dangling pointers.
|
||||
|
||||
@param indexToChange the index whose value you want to change
|
||||
@param newObject the new value to set for this index.
|
||||
@param deleteOldElement whether to delete the object that's being replaced with the new one
|
||||
@see add, insert, remove
|
||||
*/
|
||||
ObjectClass* set (int indexToChange, ObjectClass* newObject, bool deleteOldElement = true)
|
||||
{
|
||||
if (indexToChange >= 0)
|
||||
{
|
||||
std::unique_ptr<ObjectClass> toDelete;
|
||||
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (indexToChange < values.size())
|
||||
{
|
||||
if (deleteOldElement)
|
||||
{
|
||||
toDelete.reset (values[indexToChange]);
|
||||
|
||||
if (toDelete.get() == newObject)
|
||||
toDelete.release();
|
||||
}
|
||||
|
||||
values[indexToChange] = newObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
values.add (newObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
jassertfalse; // you're trying to set an object at a negative index, which doesn't have
|
||||
// any effect - but since the object is not being added, it may be leaking..
|
||||
}
|
||||
|
||||
return newObject;
|
||||
}
|
||||
|
||||
/** Replaces an object in the array with a different one.
|
||||
|
||||
If the index is less than zero, this method does nothing.
|
||||
If the index is beyond the end of the array, the new object is added to the end of the array.
|
||||
|
||||
Be careful not to add the same object to the array more than once,
|
||||
as this will obviously cause deletion of dangling pointers.
|
||||
|
||||
@param indexToChange the index whose value you want to change
|
||||
@param newObject the new value to set for this index.
|
||||
@param deleteOldElement whether to delete the object that's being replaced with the new one
|
||||
@see add, insert, remove
|
||||
*/
|
||||
ObjectClass* set (int indexToChange, std::unique_ptr<ObjectClass> newObject, bool deleteOldElement = true)
|
||||
{
|
||||
return set (indexToChange, newObject.release(), deleteOldElement);
|
||||
}
|
||||
|
||||
/** Adds elements from another array to the end of this array.
|
||||
|
||||
@param arrayToAddFrom the array from which to copy the elements
|
||||
@param startIndex the first element of the other array to start copying from
|
||||
@param numElementsToAdd how many elements to add from the other array. If this
|
||||
value is negative or greater than the number of available elements,
|
||||
all available elements will be copied.
|
||||
@see add
|
||||
*/
|
||||
template <class OtherArrayType>
|
||||
void addArray (const OtherArrayType& arrayToAddFrom,
|
||||
int startIndex = 0,
|
||||
int numElementsToAdd = -1)
|
||||
{
|
||||
const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
|
||||
const ScopedLockType lock2 (getLock());
|
||||
values.addArray (arrayToAddFrom, startIndex, numElementsToAdd);
|
||||
}
|
||||
|
||||
/** Adds elements from another array to the end of this array. */
|
||||
template <typename OtherArrayType>
|
||||
void addArray (const std::initializer_list<OtherArrayType>& items)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
values.addArray (items);
|
||||
}
|
||||
|
||||
/** Adds copies of the elements in another array to the end of this array.
|
||||
|
||||
The other array must be either an OwnedArray of a compatible type of object, or an Array
|
||||
containing pointers to the same kind of object. The objects involved must provide
|
||||
a copy constructor, and this will be used to create new copies of each element, and
|
||||
add them to this array.
|
||||
|
||||
@param arrayToAddFrom the array from which to copy the elements
|
||||
@param startIndex the first element of the other array to start copying from
|
||||
@param numElementsToAdd how many elements to add from the other array. If this
|
||||
value is negative or greater than the number of available elements,
|
||||
all available elements will be copied.
|
||||
@see add
|
||||
*/
|
||||
template <class OtherArrayType>
|
||||
void addCopiesOf (const OtherArrayType& arrayToAddFrom,
|
||||
int startIndex = 0,
|
||||
int numElementsToAdd = -1)
|
||||
{
|
||||
const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
|
||||
const ScopedLockType lock2 (getLock());
|
||||
|
||||
if (startIndex < 0)
|
||||
{
|
||||
jassertfalse;
|
||||
startIndex = 0;
|
||||
}
|
||||
|
||||
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
|
||||
numElementsToAdd = arrayToAddFrom.size() - startIndex;
|
||||
|
||||
jassert (numElementsToAdd >= 0);
|
||||
values.ensureAllocatedSize (values.size() + numElementsToAdd);
|
||||
|
||||
while (--numElementsToAdd >= 0)
|
||||
values.add (createCopyIfNotNull (arrayToAddFrom.getUnchecked (startIndex++)));
|
||||
}
|
||||
|
||||
/** Inserts a new object into the array assuming that the array is sorted.
|
||||
|
||||
This will use a comparator to find the position at which the new object
|
||||
should go. If the array isn't sorted, the behaviour of this
|
||||
method will be unpredictable.
|
||||
|
||||
@param comparator the comparator to use to compare the elements - see the sort method
|
||||
for details about this object's structure
|
||||
@param newObject the new object to insert to the array
|
||||
@returns the index at which the new object was added
|
||||
@see add, sort, indexOfSorted
|
||||
*/
|
||||
template <class ElementComparator>
|
||||
int addSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept
|
||||
{
|
||||
// If you pass in an object with a static compareElements() method, this
|
||||
// avoids getting warning messages about the parameter being unused
|
||||
ignoreUnused (comparator);
|
||||
|
||||
const ScopedLockType lock (getLock());
|
||||
auto index = findInsertIndexInSortedArray (comparator, values.begin(), newObject, 0, values.size());
|
||||
insert (index, newObject);
|
||||
return index;
|
||||
}
|
||||
|
||||
/** Finds the index of an object in the array, assuming that the array is sorted.
|
||||
|
||||
This will use a comparator to do a binary-chop to find the index of the given
|
||||
element, if it exists. If the array isn't sorted, the behaviour of this
|
||||
method will be unpredictable.
|
||||
|
||||
@param comparator the comparator to use to compare the elements - see the sort()
|
||||
method for details about the form this object should take
|
||||
@param objectToLookFor the object to search for
|
||||
@returns the index of the element, or -1 if it's not found
|
||||
@see addSorted, sort
|
||||
*/
|
||||
template <typename ElementComparator>
|
||||
int indexOfSorted (ElementComparator& comparator, const ObjectClass* objectToLookFor) const noexcept
|
||||
{
|
||||
// If you pass in an object with a static compareElements() method, this
|
||||
// avoids getting warning messages about the parameter being unused
|
||||
ignoreUnused (comparator);
|
||||
|
||||
const ScopedLockType lock (getLock());
|
||||
int s = 0, e = values.size();
|
||||
|
||||
while (s < e)
|
||||
{
|
||||
if (comparator.compareElements (objectToLookFor, values[s]) == 0)
|
||||
return s;
|
||||
|
||||
auto halfway = (s + e) / 2;
|
||||
|
||||
if (halfway == s)
|
||||
break;
|
||||
|
||||
if (comparator.compareElements (objectToLookFor, values[halfway]) >= 0)
|
||||
s = halfway;
|
||||
else
|
||||
e = halfway;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Removes an object from the array.
|
||||
|
||||
This will remove the object at a given index (optionally also
|
||||
deleting it) and move back all the subsequent objects to close the gap.
|
||||
If the index passed in is out-of-range, nothing will happen.
|
||||
|
||||
@param indexToRemove the index of the element to remove
|
||||
@param deleteObject whether to delete the object that is removed
|
||||
@see removeObject, removeRange
|
||||
*/
|
||||
void remove (int indexToRemove, bool deleteObject = true)
|
||||
{
|
||||
std::unique_ptr<ObjectClass> toDelete;
|
||||
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (indexToRemove, values.size()))
|
||||
{
|
||||
auto** e = values.begin() + indexToRemove;
|
||||
|
||||
if (deleteObject)
|
||||
toDelete.reset (*e);
|
||||
|
||||
values.removeElements (indexToRemove, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if ((values.size() << 1) < values.capacity())
|
||||
minimiseStorageOverheads();
|
||||
}
|
||||
|
||||
/** Removes and returns an object from the array without deleting it.
|
||||
|
||||
This will remove the object at a given index and return it, moving back all
|
||||
the subsequent objects to close the gap. If the index passed in is out-of-range,
|
||||
nothing will happen.
|
||||
|
||||
@param indexToRemove the index of the element to remove
|
||||
@see remove, removeObject, removeRange
|
||||
*/
|
||||
ObjectClass* removeAndReturn (int indexToRemove)
|
||||
{
|
||||
ObjectClass* removedItem = nullptr;
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (indexToRemove, values.size()))
|
||||
{
|
||||
removedItem = values[indexToRemove];
|
||||
|
||||
values.removeElements (indexToRemove, 1);
|
||||
|
||||
if ((values.size() << 1) < values.capacity())
|
||||
minimiseStorageOverheads();
|
||||
}
|
||||
|
||||
return removedItem;
|
||||
}
|
||||
|
||||
/** Removes a specified object from the array.
|
||||
|
||||
If the item isn't found, no action is taken.
|
||||
|
||||
@param objectToRemove the object to try to remove
|
||||
@param deleteObject whether to delete the object (if it's found)
|
||||
@see remove, removeRange
|
||||
*/
|
||||
void removeObject (const ObjectClass* objectToRemove, bool deleteObject = true)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
for (int i = 0; i < values.size(); ++i)
|
||||
{
|
||||
if (objectToRemove == values[i])
|
||||
{
|
||||
remove (i, deleteObject);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes a range of objects from the array.
|
||||
|
||||
This will remove a set of objects, starting from the given index,
|
||||
and move any subsequent elements down to close the gap.
|
||||
|
||||
If the range extends beyond the bounds of the array, it will
|
||||
be safely clipped to the size of the array.
|
||||
|
||||
@param startIndex the index of the first object to remove
|
||||
@param numberToRemove how many objects should be removed
|
||||
@param deleteObjects whether to delete the objects that get removed
|
||||
@see remove, removeObject
|
||||
*/
|
||||
void removeRange (int startIndex, int numberToRemove, bool deleteObjects = true)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
auto endIndex = jlimit (0, values.size(), startIndex + numberToRemove);
|
||||
startIndex = jlimit (0, values.size(), startIndex);
|
||||
numberToRemove = endIndex - startIndex;
|
||||
|
||||
if (numberToRemove > 0)
|
||||
{
|
||||
Array<ObjectClass*> objectsToDelete;
|
||||
|
||||
if (deleteObjects)
|
||||
objectsToDelete.addArray (values.begin() + startIndex, numberToRemove);
|
||||
|
||||
values.removeElements (startIndex, numberToRemove);
|
||||
|
||||
for (auto& o : objectsToDelete)
|
||||
ContainerDeletePolicy<ObjectClass>::destroy (o);
|
||||
|
||||
if ((values.size() << 1) < values.capacity())
|
||||
minimiseStorageOverheads();
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes the last n objects from the array.
|
||||
|
||||
@param howManyToRemove how many objects to remove from the end of the array
|
||||
@param deleteObjects whether to also delete the objects that are removed
|
||||
@see remove, removeObject, removeRange
|
||||
*/
|
||||
void removeLast (int howManyToRemove = 1,
|
||||
bool deleteObjects = true)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (howManyToRemove >= values.size())
|
||||
clear (deleteObjects);
|
||||
else
|
||||
removeRange (values.size() - howManyToRemove, howManyToRemove, deleteObjects);
|
||||
}
|
||||
|
||||
/** Swaps a pair of objects in the array.
|
||||
|
||||
If either of the indexes passed in is out-of-range, nothing will happen,
|
||||
otherwise the two objects at these positions will be exchanged.
|
||||
*/
|
||||
void swap (int index1, int index2) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
values.swap (index1, index2);
|
||||
}
|
||||
|
||||
/** Moves one of the objects to a different position.
|
||||
|
||||
This will move the object to a specified index, shuffling along
|
||||
any intervening elements as required.
|
||||
|
||||
So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
|
||||
move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
|
||||
|
||||
@param currentIndex the index of the object to be moved. If this isn't a
|
||||
valid index, then nothing will be done
|
||||
@param newIndex the index at which you'd like this object to end up. If this
|
||||
is less than zero, it will be moved to the end of the array
|
||||
*/
|
||||
void move (int currentIndex, int newIndex) noexcept
|
||||
{
|
||||
if (currentIndex != newIndex)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
values.move (currentIndex, newIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/** This swaps the contents of this array with those of another array.
|
||||
|
||||
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
|
||||
because it just swaps their internal pointers.
|
||||
*/
|
||||
template <class OtherArrayType>
|
||||
void swapWith (OtherArrayType& otherArray) noexcept
|
||||
{
|
||||
const ScopedLockType lock1 (getLock());
|
||||
const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
|
||||
values.swapWith (otherArray.values);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Reduces the amount of storage being used by the array.
|
||||
|
||||
Arrays typically allocate slightly more storage than they need, and after
|
||||
removing elements, they may have quite a lot of unused space allocated.
|
||||
This method will reduce the amount of allocated storage to a minimum.
|
||||
*/
|
||||
void minimiseStorageOverheads() noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
values.shrinkToNoMoreThan (values.size());
|
||||
}
|
||||
|
||||
/** Increases the array's internal storage to hold a minimum number of elements.
|
||||
|
||||
Calling this before adding a large known number of elements means that
|
||||
the array won't have to keep dynamically resizing itself as the elements
|
||||
are added, and it'll therefore be more efficient.
|
||||
*/
|
||||
void ensureStorageAllocated (int minNumElements) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
values.ensureAllocatedSize (minNumElements);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Sorts the elements in the array.
|
||||
|
||||
This will use a comparator object to sort the elements into order. The object
|
||||
passed must have a method of the form:
|
||||
@code
|
||||
int compareElements (ElementType* first, ElementType* second);
|
||||
@endcode
|
||||
|
||||
..and this method must return:
|
||||
- a value of < 0 if the first comes before the second
|
||||
- a value of 0 if the two objects are equivalent
|
||||
- a value of > 0 if the second comes before the first
|
||||
|
||||
To improve performance, the compareElements() method can be declared as static or const.
|
||||
|
||||
@param comparator the comparator to use for comparing elements.
|
||||
@param retainOrderOfEquivalentItems if this is true, then items
|
||||
which the comparator says are equivalent will be
|
||||
kept in the order in which they currently appear
|
||||
in the array. This is slower to perform, but may
|
||||
be important in some cases. If it's false, a faster
|
||||
algorithm is used, but equivalent elements may be
|
||||
rearranged.
|
||||
@see sortArray, indexOfSorted
|
||||
*/
|
||||
template <class ElementComparator>
|
||||
void sort (ElementComparator& comparator,
|
||||
bool retainOrderOfEquivalentItems = false) noexcept
|
||||
{
|
||||
// If you pass in an object with a static compareElements() method, this
|
||||
// avoids getting warning messages about the parameter being unused
|
||||
ignoreUnused (comparator);
|
||||
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (size() > 1)
|
||||
sortArray (comparator, values.begin(), 0, size() - 1, retainOrderOfEquivalentItems);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the CriticalSection that locks this array.
|
||||
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||
an object of ScopedLockType as an RAII lock for it.
|
||||
*/
|
||||
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return values; }
|
||||
|
||||
/** Returns the type of scoped lock to use for locking this array */
|
||||
using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
[[deprecated ("This method has been replaced by a more flexible templated version and renamed "
|
||||
"to swapWith to be more consistent with the names used in other classes.")]]
|
||||
void swapWithArray (OwnedArray& other) noexcept { swapWith (other); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ArrayBase <ObjectClass*, TypeOfCriticalSectionToUse> values;
|
||||
|
||||
void deleteAllObjects()
|
||||
{
|
||||
auto i = values.size();
|
||||
|
||||
while (--i >= 0)
|
||||
{
|
||||
auto* e = values[i];
|
||||
values.removeElements (i, 1);
|
||||
ContainerDeletePolicy<ObjectClass>::destroy (e);
|
||||
}
|
||||
}
|
||||
|
||||
template <class OtherObjectClass, class OtherCriticalSection>
|
||||
friend class OwnedArray;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OwnedArray)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
217
deps/juce/modules/juce_core/containers/juce_PropertySet.cpp
vendored
Normal file
217
deps/juce/modules/juce_core/containers/juce_PropertySet.cpp
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
PropertySet::PropertySet (bool ignoreCaseOfKeyNames)
|
||||
: properties (ignoreCaseOfKeyNames),
|
||||
fallbackProperties (nullptr),
|
||||
ignoreCaseOfKeys (ignoreCaseOfKeyNames)
|
||||
{
|
||||
}
|
||||
|
||||
PropertySet::PropertySet (const PropertySet& other)
|
||||
: properties (other.properties),
|
||||
fallbackProperties (other.fallbackProperties),
|
||||
ignoreCaseOfKeys (other.ignoreCaseOfKeys)
|
||||
{
|
||||
}
|
||||
|
||||
PropertySet& PropertySet::operator= (const PropertySet& other)
|
||||
{
|
||||
properties = other.properties;
|
||||
fallbackProperties = other.fallbackProperties;
|
||||
ignoreCaseOfKeys = other.ignoreCaseOfKeys;
|
||||
|
||||
propertyChanged();
|
||||
return *this;
|
||||
}
|
||||
|
||||
PropertySet::~PropertySet()
|
||||
{
|
||||
}
|
||||
|
||||
void PropertySet::clear()
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
if (properties.size() > 0)
|
||||
{
|
||||
properties.clear();
|
||||
propertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
String PropertySet::getValue (StringRef keyName, const String& defaultValue) const noexcept
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
auto index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||
|
||||
if (index >= 0)
|
||||
return properties.getAllValues() [index];
|
||||
|
||||
return fallbackProperties != nullptr ? fallbackProperties->getValue (keyName, defaultValue)
|
||||
: defaultValue;
|
||||
}
|
||||
|
||||
int PropertySet::getIntValue (StringRef keyName, int defaultValue) const noexcept
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
auto index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||
|
||||
if (index >= 0)
|
||||
return properties.getAllValues() [index].getIntValue();
|
||||
|
||||
return fallbackProperties != nullptr ? fallbackProperties->getIntValue (keyName, defaultValue)
|
||||
: defaultValue;
|
||||
}
|
||||
|
||||
double PropertySet::getDoubleValue (StringRef keyName, double defaultValue) const noexcept
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
auto index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||
|
||||
if (index >= 0)
|
||||
return properties.getAllValues()[index].getDoubleValue();
|
||||
|
||||
return fallbackProperties != nullptr ? fallbackProperties->getDoubleValue (keyName, defaultValue)
|
||||
: defaultValue;
|
||||
}
|
||||
|
||||
bool PropertySet::getBoolValue (StringRef keyName, bool defaultValue) const noexcept
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
auto index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||
|
||||
if (index >= 0)
|
||||
return properties.getAllValues() [index].getIntValue() != 0;
|
||||
|
||||
return fallbackProperties != nullptr ? fallbackProperties->getBoolValue (keyName, defaultValue)
|
||||
: defaultValue;
|
||||
}
|
||||
|
||||
std::unique_ptr<XmlElement> PropertySet::getXmlValue (StringRef keyName) const
|
||||
{
|
||||
return parseXML (getValue (keyName));
|
||||
}
|
||||
|
||||
void PropertySet::setValue (StringRef keyName, const var& v)
|
||||
{
|
||||
jassert (keyName.isNotEmpty()); // shouldn't use an empty key name!
|
||||
|
||||
if (keyName.isNotEmpty())
|
||||
{
|
||||
auto value = v.toString();
|
||||
const ScopedLock sl (lock);
|
||||
auto index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||
|
||||
if (index < 0 || properties.getAllValues() [index] != value)
|
||||
{
|
||||
properties.set (keyName, value);
|
||||
propertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertySet::removeValue (StringRef keyName)
|
||||
{
|
||||
if (keyName.isNotEmpty())
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
auto index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
properties.remove (keyName);
|
||||
propertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertySet::setValue (StringRef keyName, const XmlElement* xml)
|
||||
{
|
||||
setValue (keyName, xml == nullptr ? var()
|
||||
: var (xml->toString (XmlElement::TextFormat().singleLine().withoutHeader())));
|
||||
}
|
||||
|
||||
bool PropertySet::containsKey (StringRef keyName) const noexcept
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
return properties.getAllKeys().contains (keyName, ignoreCaseOfKeys);
|
||||
}
|
||||
|
||||
void PropertySet::addAllPropertiesFrom (const PropertySet& source)
|
||||
{
|
||||
const ScopedLock sl (source.getLock());
|
||||
|
||||
for (int i = 0; i < source.properties.size(); ++i)
|
||||
setValue (source.properties.getAllKeys() [i],
|
||||
source.properties.getAllValues() [i]);
|
||||
}
|
||||
|
||||
void PropertySet::setFallbackPropertySet (PropertySet* fallbackProperties_) noexcept
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
fallbackProperties = fallbackProperties_;
|
||||
}
|
||||
|
||||
std::unique_ptr<XmlElement> PropertySet::createXml (const String& nodeName) const
|
||||
{
|
||||
auto xml = std::make_unique<XmlElement> (nodeName);
|
||||
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
for (int i = 0; i < properties.getAllKeys().size(); ++i)
|
||||
{
|
||||
auto e = xml->createNewChildElement ("VALUE");
|
||||
e->setAttribute ("name", properties.getAllKeys()[i]);
|
||||
e->setAttribute ("val", properties.getAllValues()[i]);
|
||||
}
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
void PropertySet::restoreFromXml (const XmlElement& xml)
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
clear();
|
||||
|
||||
for (auto* e : xml.getChildWithTagNameIterator ("VALUE"))
|
||||
{
|
||||
if (e->hasAttribute ("name")
|
||||
&& e->hasAttribute ("val"))
|
||||
{
|
||||
properties.set (e->getStringAttribute ("name"),
|
||||
e->getStringAttribute ("val"));
|
||||
}
|
||||
}
|
||||
|
||||
if (properties.size() > 0)
|
||||
propertyChanged();
|
||||
}
|
||||
|
||||
void PropertySet::propertyChanged()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
205
deps/juce/modules/juce_core/containers/juce_PropertySet.h
vendored
Normal file
205
deps/juce/modules/juce_core/containers/juce_PropertySet.h
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 set of named property values, which can be strings, integers, floating point, etc.
|
||||
|
||||
Effectively, this just wraps a StringPairArray in an interface that makes it easier
|
||||
to load and save types other than strings.
|
||||
|
||||
See the PropertiesFile class for a subclass of this, which automatically broadcasts change
|
||||
messages and saves/loads the list from a file.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API PropertySet
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty PropertySet.
|
||||
@param ignoreCaseOfKeyNames if true, the names of properties are compared in a
|
||||
case-insensitive way
|
||||
*/
|
||||
PropertySet (bool ignoreCaseOfKeyNames = false);
|
||||
|
||||
/** Creates a copy of another PropertySet. */
|
||||
PropertySet (const PropertySet& other);
|
||||
|
||||
/** Copies another PropertySet over this one. */
|
||||
PropertySet& operator= (const PropertySet& other);
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~PropertySet();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns one of the properties as a string.
|
||||
|
||||
If the value isn't found in this set, then this will look for it in a fallback
|
||||
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||
and if it can't find one there, it'll return the default value passed-in.
|
||||
|
||||
@param keyName the name of the property to retrieve
|
||||
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||
*/
|
||||
String getValue (StringRef keyName, const String& defaultReturnValue = String()) const noexcept;
|
||||
|
||||
/** Returns one of the properties as an integer.
|
||||
|
||||
If the value isn't found in this set, then this will look for it in a fallback
|
||||
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||
and if it can't find one there, it'll return the default value passed-in.
|
||||
|
||||
@param keyName the name of the property to retrieve
|
||||
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||
*/
|
||||
int getIntValue (StringRef keyName, int defaultReturnValue = 0) const noexcept;
|
||||
|
||||
/** Returns one of the properties as an double.
|
||||
|
||||
If the value isn't found in this set, then this will look for it in a fallback
|
||||
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||
and if it can't find one there, it'll return the default value passed-in.
|
||||
|
||||
@param keyName the name of the property to retrieve
|
||||
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||
*/
|
||||
double getDoubleValue (StringRef keyName, double defaultReturnValue = 0.0) const noexcept;
|
||||
|
||||
/** Returns one of the properties as an boolean.
|
||||
|
||||
The result will be true if the string found for this key name can be parsed as a non-zero
|
||||
integer.
|
||||
|
||||
If the value isn't found in this set, then this will look for it in a fallback
|
||||
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||
and if it can't find one there, it'll return the default value passed-in.
|
||||
|
||||
@param keyName the name of the property to retrieve
|
||||
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||
*/
|
||||
bool getBoolValue (StringRef keyName, bool defaultReturnValue = false) const noexcept;
|
||||
|
||||
/** Returns one of the properties as an XML element.
|
||||
|
||||
The result will a new XMLElement object. It may return nullptr if the key isn't found,
|
||||
or if the entry contains an string that isn't valid XML.
|
||||
|
||||
If the value isn't found in this set, then this will look for it in a fallback
|
||||
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||
and if it can't find one there, it'll return the default value passed-in.
|
||||
|
||||
@param keyName the name of the property to retrieve
|
||||
*/
|
||||
std::unique_ptr<XmlElement> getXmlValue (StringRef keyName) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Sets a named property.
|
||||
|
||||
@param keyName the name of the property to set. (This mustn't be an empty string)
|
||||
@param value the new value to set it to
|
||||
*/
|
||||
void setValue (StringRef keyName, const var& value);
|
||||
|
||||
/** Sets a named property to an XML element.
|
||||
|
||||
@param keyName the name of the property to set. (This mustn't be an empty string)
|
||||
@param xml the new element to set it to. If this is a nullptr, the value will
|
||||
be set to an empty string
|
||||
@see getXmlValue
|
||||
*/
|
||||
void setValue (StringRef keyName, const XmlElement* xml);
|
||||
|
||||
/** This copies all the values from a source PropertySet to this one.
|
||||
This won't remove any existing settings, it just adds any that it finds in the source set.
|
||||
*/
|
||||
void addAllPropertiesFrom (const PropertySet& source);
|
||||
|
||||
//==============================================================================
|
||||
/** Deletes a property.
|
||||
@param keyName the name of the property to delete. (This mustn't be an empty string)
|
||||
*/
|
||||
void removeValue (StringRef keyName);
|
||||
|
||||
/** Returns true if the properties include the given key. */
|
||||
bool containsKey (StringRef keyName) const noexcept;
|
||||
|
||||
/** Removes all values. */
|
||||
void clear();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the keys/value pair array containing all the properties. */
|
||||
StringPairArray& getAllProperties() noexcept { return properties; }
|
||||
|
||||
/** Returns the lock used when reading or writing to this set */
|
||||
const CriticalSection& getLock() const noexcept { return lock; }
|
||||
|
||||
//==============================================================================
|
||||
/** Returns an XML element which encapsulates all the items in this property set.
|
||||
The string parameter is the tag name that should be used for the node.
|
||||
@see restoreFromXml
|
||||
*/
|
||||
std::unique_ptr<XmlElement> createXml (const String& nodeName) const;
|
||||
|
||||
/** Reloads a set of properties that were previously stored as XML.
|
||||
The node passed in must have been created by the createXml() method.
|
||||
@see createXml
|
||||
*/
|
||||
void restoreFromXml (const XmlElement& xml);
|
||||
|
||||
//==============================================================================
|
||||
/** Sets up a second PopertySet that will be used to look up any values that aren't
|
||||
set in this one.
|
||||
|
||||
If you set this up to be a pointer to a second property set, then whenever one
|
||||
of the getValue() methods fails to find an entry in this set, it will look up that
|
||||
value in the fallback set, and if it finds it, it will return that.
|
||||
|
||||
Make sure that you don't delete the fallback set while it's still being used by
|
||||
another set! To remove the fallback set, just call this method with a null pointer.
|
||||
|
||||
@see getFallbackPropertySet
|
||||
*/
|
||||
void setFallbackPropertySet (PropertySet* fallbackProperties) noexcept;
|
||||
|
||||
/** Returns the fallback property set.
|
||||
@see setFallbackPropertySet
|
||||
*/
|
||||
PropertySet* getFallbackPropertySet() const noexcept { return fallbackProperties; }
|
||||
|
||||
protected:
|
||||
/** Subclasses can override this to be told when one of the properties has been changed. */
|
||||
virtual void propertyChanged();
|
||||
|
||||
private:
|
||||
StringPairArray properties;
|
||||
PropertySet* fallbackProperties;
|
||||
CriticalSection lock;
|
||||
bool ignoreCaseOfKeys;
|
||||
|
||||
JUCE_LEAK_DETECTOR (PropertySet)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
179
deps/juce/modules/juce_core/containers/juce_ReferenceCountedArray.cpp
vendored
Normal file
179
deps/juce/modules/juce_core/containers/juce_ReferenceCountedArray.cpp
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 JUCE_UNIT_TESTS
|
||||
|
||||
class ReferenceCountedArrayTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
ReferenceCountedArrayTests()
|
||||
: UnitTest ("ReferenceCountedArray", UnitTestCategories::containers)
|
||||
{}
|
||||
|
||||
//==============================================================================
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("Add derived objects");
|
||||
{
|
||||
ReferenceCountedArray<TestDerivedObj> derivedArray;
|
||||
derivedArray.add (static_cast<TestDerivedObj*> (new TestBaseObj()));
|
||||
expectEquals (derivedArray.size(), 1);
|
||||
expectEquals (derivedArray.getObjectPointer (0)->getReferenceCount(), 1);
|
||||
expectEquals (derivedArray[0]->getReferenceCount(), 2);
|
||||
|
||||
for (auto o : derivedArray)
|
||||
expectEquals (o->getReferenceCount(), 1);
|
||||
|
||||
ReferenceCountedArray<TestBaseObj> baseArray;
|
||||
baseArray.addArray (derivedArray);
|
||||
|
||||
for (auto o : baseArray)
|
||||
expectEquals (o->getReferenceCount(), 2);
|
||||
|
||||
derivedArray.clearQuick();
|
||||
baseArray.clearQuick();
|
||||
|
||||
auto* baseObject = new TestBaseObj();
|
||||
TestBaseObj::Ptr baseObjectPtr = baseObject;
|
||||
expectEquals (baseObject->getReferenceCount(), 1);
|
||||
|
||||
auto* derivedObject = new TestDerivedObj();
|
||||
TestDerivedObj::Ptr derivedObjectPtr = derivedObject;
|
||||
expectEquals (derivedObject->getReferenceCount(), 1);
|
||||
|
||||
baseArray.add (baseObject);
|
||||
baseArray.add (derivedObject);
|
||||
|
||||
for (auto o : baseArray)
|
||||
expectEquals (o->getReferenceCount(), 2);
|
||||
|
||||
expectEquals (baseObject->getReferenceCount(), 2);
|
||||
expectEquals (derivedObject->getReferenceCount(), 2);
|
||||
|
||||
derivedArray.add (derivedObject);
|
||||
|
||||
for (auto o : derivedArray)
|
||||
expectEquals (o->getReferenceCount(), 3);
|
||||
|
||||
derivedArray.clearQuick();
|
||||
baseArray.clearQuick();
|
||||
|
||||
expectEquals (baseObject->getReferenceCount(), 1);
|
||||
expectEquals (derivedObject->getReferenceCount(), 1);
|
||||
|
||||
baseArray.add (baseObjectPtr);
|
||||
baseArray.add (derivedObjectPtr.get());
|
||||
|
||||
for (auto o : baseArray)
|
||||
expectEquals (o->getReferenceCount(), 2);
|
||||
|
||||
derivedArray.add (derivedObjectPtr);
|
||||
|
||||
for (auto o : derivedArray)
|
||||
expectEquals (o->getReferenceCount(), 3);
|
||||
}
|
||||
|
||||
beginTest ("Iterate in destructor");
|
||||
{
|
||||
{
|
||||
ReferenceCountedArray<DestructorObj> arr;
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
arr.add (new DestructorObj (*this, arr));
|
||||
}
|
||||
|
||||
ReferenceCountedArray<DestructorObj> arr;
|
||||
|
||||
for (int i = 0; i < 1025; ++i)
|
||||
arr.add (new DestructorObj (*this, arr));
|
||||
|
||||
while (! arr.isEmpty())
|
||||
arr.remove (0);
|
||||
|
||||
for (int i = 0; i < 1025; ++i)
|
||||
arr.add (new DestructorObj (*this, arr));
|
||||
|
||||
arr.removeRange (1, arr.size() - 3);
|
||||
|
||||
for (int i = 0; i < 1025; ++i)
|
||||
arr.add (new DestructorObj (*this, arr));
|
||||
|
||||
arr.set (500, new DestructorObj (*this, arr));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct TestBaseObj : public ReferenceCountedObject
|
||||
{
|
||||
using Ptr = ReferenceCountedObjectPtr<TestBaseObj>;
|
||||
|
||||
TestBaseObj() = default;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TestBaseObj)
|
||||
};
|
||||
|
||||
struct TestDerivedObj : public TestBaseObj
|
||||
{
|
||||
using Ptr = ReferenceCountedObjectPtr<TestDerivedObj>;
|
||||
|
||||
TestDerivedObj() = default;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TestDerivedObj)
|
||||
};
|
||||
|
||||
struct DestructorObj : public ReferenceCountedObject
|
||||
{
|
||||
DestructorObj (ReferenceCountedArrayTests& p,
|
||||
ReferenceCountedArray<DestructorObj>& arr)
|
||||
: parent (p), objectArray (arr)
|
||||
{}
|
||||
|
||||
~DestructorObj()
|
||||
{
|
||||
data = 0;
|
||||
|
||||
for (auto* o : objectArray)
|
||||
{
|
||||
parent.expect (o != nullptr);
|
||||
parent.expect (o != this);
|
||||
|
||||
if (o != nullptr)
|
||||
parent.expectEquals (o->data, 374);
|
||||
}
|
||||
}
|
||||
|
||||
ReferenceCountedArrayTests& parent;
|
||||
ReferenceCountedArray<DestructorObj>& objectArray;
|
||||
int data = 374;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DestructorObj)
|
||||
};
|
||||
};
|
||||
|
||||
static ReferenceCountedArrayTests referenceCountedArrayTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
907
deps/juce/modules/juce_core/containers/juce_ReferenceCountedArray.h
vendored
Normal file
907
deps/juce/modules/juce_core/containers/juce_ReferenceCountedArray.h
vendored
Normal file
@@ -0,0 +1,907 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 list of objects derived from ReferenceCountedObject, or which implement basic
|
||||
reference-count handling methods.
|
||||
|
||||
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.
|
||||
|
||||
A ReferenceCountedArray holds objects derived from ReferenceCountedObject,
|
||||
and takes care of incrementing and decrementing their ref counts when they
|
||||
are added and removed from the array.
|
||||
|
||||
To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
|
||||
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
|
||||
|
||||
@see Array, OwnedArray, StringArray
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||
class ReferenceCountedArray
|
||||
{
|
||||
public:
|
||||
using ObjectClassPtr = ReferenceCountedObjectPtr<ObjectClass>;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates an empty array.
|
||||
@see ReferenceCountedObject, Array, OwnedArray
|
||||
*/
|
||||
ReferenceCountedArray() = default;
|
||||
|
||||
/** Creates a copy of another array */
|
||||
ReferenceCountedArray (const ReferenceCountedArray& other) noexcept
|
||||
{
|
||||
const ScopedLockType lock (other.getLock());
|
||||
values.addArray (other.begin(), other.size());
|
||||
|
||||
for (auto* o : *this)
|
||||
if (o != nullptr)
|
||||
o->incReferenceCount();
|
||||
}
|
||||
|
||||
/** Moves from another array */
|
||||
ReferenceCountedArray (ReferenceCountedArray&& other) noexcept
|
||||
: values (std::move (other.values))
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a copy of another array */
|
||||
template <class OtherObjectClass, class OtherCriticalSection>
|
||||
ReferenceCountedArray (const ReferenceCountedArray<OtherObjectClass, OtherCriticalSection>& other) noexcept
|
||||
{
|
||||
const typename ReferenceCountedArray<OtherObjectClass, OtherCriticalSection>::ScopedLockType lock (other.getLock());
|
||||
values.addArray (other.begin(), other.size());
|
||||
|
||||
for (auto* o : *this)
|
||||
if (o != nullptr)
|
||||
o->incReferenceCount();
|
||||
}
|
||||
|
||||
/** Copies another array into this one.
|
||||
Any existing objects in this array will first be released.
|
||||
*/
|
||||
ReferenceCountedArray& operator= (const ReferenceCountedArray& other) noexcept
|
||||
{
|
||||
releaseAllObjects();
|
||||
auto otherCopy = other;
|
||||
swapWith (otherCopy);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Copies another array into this one.
|
||||
Any existing objects in this array will first be released.
|
||||
*/
|
||||
template <class OtherObjectClass>
|
||||
ReferenceCountedArray& operator= (const ReferenceCountedArray<OtherObjectClass, TypeOfCriticalSectionToUse>& other) noexcept
|
||||
{
|
||||
auto otherCopy = other;
|
||||
swapWith (otherCopy);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Moves from another array */
|
||||
ReferenceCountedArray& operator= (ReferenceCountedArray&& other) noexcept
|
||||
{
|
||||
releaseAllObjects();
|
||||
values = std::move (other.values);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Destructor.
|
||||
Any objects in the array will be released, and may be deleted if not referenced from elsewhere.
|
||||
*/
|
||||
~ReferenceCountedArray()
|
||||
{
|
||||
releaseAllObjects();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Removes all objects from the array.
|
||||
Any objects in the array whose reference counts drop to zero will be deleted.
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
clearQuick();
|
||||
values.setAllocatedSize (0);
|
||||
}
|
||||
|
||||
/** Removes all objects from the array without freeing the array's allocated storage.
|
||||
Any objects in the array that whose reference counts drop to zero will be deleted.
|
||||
@see clear
|
||||
*/
|
||||
void clearQuick()
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
releaseAllObjects();
|
||||
}
|
||||
|
||||
/** Returns the current number of objects in the array. */
|
||||
inline int size() const noexcept
|
||||
{
|
||||
return values.size();
|
||||
}
|
||||
|
||||
/** Returns true if the array is empty, false otherwise. */
|
||||
inline bool isEmpty() const noexcept
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
/** Returns a pointer to the object at this index in the array.
|
||||
|
||||
If the index is out-of-range, this will return a null pointer, (and
|
||||
it could be null anyway, because it's ok for the array to hold null
|
||||
pointers as well as objects).
|
||||
|
||||
@see getUnchecked
|
||||
*/
|
||||
inline ObjectClassPtr operator[] (int index) const noexcept
|
||||
{
|
||||
return ObjectClassPtr (getObjectPointer (index));
|
||||
}
|
||||
|
||||
/** Returns a pointer to the object at this index in the array, without checking
|
||||
whether the index is in-range.
|
||||
|
||||
This is a faster and less safe version of operator[] which doesn't check the index passed in, so
|
||||
it can be used when you're sure the index is always going to be legal.
|
||||
*/
|
||||
inline ObjectClassPtr getUnchecked (int index) const noexcept
|
||||
{
|
||||
return ObjectClassPtr (getObjectPointerUnchecked (index));
|
||||
}
|
||||
|
||||
/** Returns a raw pointer to the object at this index in the array.
|
||||
|
||||
If the index is out-of-range, this will return a null pointer, (and
|
||||
it could be null anyway, because it's ok for the array to hold null
|
||||
pointers as well as objects).
|
||||
|
||||
@see getUnchecked
|
||||
*/
|
||||
inline ObjectClass* getObjectPointer (int index) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return values.getValueWithDefault (index);
|
||||
}
|
||||
|
||||
/** Returns a raw pointer to the object at this index in the array, without checking
|
||||
whether the index is in-range.
|
||||
*/
|
||||
inline ObjectClass* getObjectPointerUnchecked (int index) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return values[index];
|
||||
}
|
||||
|
||||
/** Returns a pointer to the first object in the array.
|
||||
|
||||
This will return a null pointer if the array's empty.
|
||||
@see getLast
|
||||
*/
|
||||
inline ObjectClassPtr getFirst() const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return values.getFirst();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the last object in the array.
|
||||
|
||||
This will return a null pointer if the array's empty.
|
||||
@see getFirst
|
||||
*/
|
||||
inline ObjectClassPtr getLast() const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return values.getLast();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the actual array data.
|
||||
This pointer will only be valid until the next time a non-const method
|
||||
is called on the array.
|
||||
*/
|
||||
inline ObjectClass** getRawDataPointer() const noexcept
|
||||
{
|
||||
return values.begin();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a pointer to the first element in the array.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline ObjectClass** begin() noexcept
|
||||
{
|
||||
return values.begin();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the first element in the array.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline ObjectClass* const* begin() const noexcept
|
||||
{
|
||||
return values.begin();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the element which follows the last element in the array.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline ObjectClass** end() noexcept
|
||||
{
|
||||
return values.end();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the element which follows the last element in the array.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline ObjectClass* const* end() const noexcept
|
||||
{
|
||||
return values.end();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the first element in the array.
|
||||
This method is provided for compatibility with the standard C++ containers.
|
||||
*/
|
||||
inline ObjectClass** data() noexcept
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the first element in the array.
|
||||
This method is provided for compatibility with the standard C++ containers.
|
||||
*/
|
||||
inline ObjectClass* const* data() const noexcept
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Finds the index of the first occurrence of an object in the array.
|
||||
|
||||
@param objectToLookFor the object to look for
|
||||
@returns the index at which the object was found, or -1 if it's not found
|
||||
*/
|
||||
int indexOf (const ObjectClass* objectToLookFor) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
auto* e = values.begin();
|
||||
auto* endPointer = values.end();
|
||||
|
||||
while (e != endPointer)
|
||||
{
|
||||
if (objectToLookFor == *e)
|
||||
return static_cast<int> (e - values.begin());
|
||||
|
||||
++e;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Finds the index of the first occurrence of an object in the array.
|
||||
|
||||
@param objectToLookFor the object to look for
|
||||
@returns the index at which the object was found, or -1 if it's not found
|
||||
*/
|
||||
int indexOf (const ObjectClassPtr& objectToLookFor) const noexcept { return indexOf (objectToLookFor.get()); }
|
||||
|
||||
/** Returns true if the array contains a specified object.
|
||||
|
||||
@param objectToLookFor the object to look for
|
||||
@returns true if the object is in the array
|
||||
*/
|
||||
bool contains (const ObjectClass* objectToLookFor) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
auto* e = values.begin();
|
||||
auto* endPointer = values.end();
|
||||
|
||||
while (e != endPointer)
|
||||
{
|
||||
if (objectToLookFor == *e)
|
||||
return true;
|
||||
|
||||
++e;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns true if the array contains a specified object.
|
||||
|
||||
@param objectToLookFor the object to look for
|
||||
@returns true if the object is in the array
|
||||
*/
|
||||
bool contains (const ObjectClassPtr& objectToLookFor) const noexcept { return contains (objectToLookFor.get()); }
|
||||
|
||||
/** Appends a new object to the end of the array.
|
||||
|
||||
This will increase the new object's reference count.
|
||||
|
||||
@param newObject the new object to add to the array
|
||||
@see set, insert, addIfNotAlreadyThere, addSorted, addArray
|
||||
*/
|
||||
ObjectClass* add (ObjectClass* newObject)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
values.add (newObject);
|
||||
|
||||
if (newObject != nullptr)
|
||||
newObject->incReferenceCount();
|
||||
|
||||
return newObject;
|
||||
}
|
||||
|
||||
/** Appends a new object to the end of the array.
|
||||
|
||||
This will increase the new object's reference count.
|
||||
|
||||
@param newObject the new object to add to the array
|
||||
@see set, insert, addIfNotAlreadyThere, addSorted, addArray
|
||||
*/
|
||||
ObjectClass* add (const ObjectClassPtr& newObject) { return add (newObject.get()); }
|
||||
|
||||
/** Inserts a new object into the array at the given index.
|
||||
|
||||
If the index is less than 0 or greater than the size of the array, the
|
||||
element will be added to the end of the array.
|
||||
Otherwise, it will be inserted into the array, moving all the later elements
|
||||
along to make room.
|
||||
|
||||
This will increase the new object's reference count.
|
||||
|
||||
@param indexToInsertAt the index at which the new element should be inserted
|
||||
@param newObject the new object to add to the array
|
||||
@see add, addSorted, addIfNotAlreadyThere, set
|
||||
*/
|
||||
ObjectClass* insert (int indexToInsertAt, ObjectClass* newObject)
|
||||
{
|
||||
values.insert (indexToInsertAt, newObject, 1);
|
||||
|
||||
if (newObject != nullptr)
|
||||
newObject->incReferenceCount();
|
||||
|
||||
return newObject;
|
||||
}
|
||||
|
||||
/** Inserts a new object into the array at the given index.
|
||||
|
||||
If the index is less than 0 or greater than the size of the array, the
|
||||
element will be added to the end of the array.
|
||||
Otherwise, it will be inserted into the array, moving all the later elements
|
||||
along to make room.
|
||||
|
||||
This will increase the new object's reference count.
|
||||
|
||||
@param indexToInsertAt the index at which the new element should be inserted
|
||||
@param newObject the new object to add to the array
|
||||
@see add, addSorted, addIfNotAlreadyThere, set
|
||||
*/
|
||||
ObjectClass* insert (int indexToInsertAt, const ObjectClassPtr& newObject) { return insert (indexToInsertAt, newObject.get()); }
|
||||
|
||||
/** Appends a new object at the end of the array as long as the array doesn't
|
||||
already contain it.
|
||||
|
||||
If the array already contains a matching object, nothing will be done.
|
||||
|
||||
@param newObject the new object to add to the array
|
||||
@returns true if the object has been added, false otherwise
|
||||
*/
|
||||
bool addIfNotAlreadyThere (ObjectClass* newObject)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (contains (newObject))
|
||||
return false;
|
||||
|
||||
add (newObject);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Appends a new object at the end of the array as long as the array doesn't
|
||||
already contain it.
|
||||
|
||||
If the array already contains a matching object, nothing will be done.
|
||||
|
||||
@param newObject the new object to add to the array
|
||||
@returns true if the object has been added, false otherwise
|
||||
*/
|
||||
bool addIfNotAlreadyThere (const ObjectClassPtr& newObject) { return addIfNotAlreadyThere (newObject.get()); }
|
||||
|
||||
/** Replaces an object in the array with a different one.
|
||||
|
||||
If the index is less than zero, this method does nothing.
|
||||
If the index is beyond the end of the array, the new object is added to the end of the array.
|
||||
|
||||
The object being added has its reference count increased, and if it's replacing
|
||||
another object, then that one has its reference count decreased, and may be deleted.
|
||||
|
||||
@param indexToChange the index whose value you want to change
|
||||
@param newObject the new value to set for this index.
|
||||
@see add, insert, remove
|
||||
*/
|
||||
void set (int indexToChange, ObjectClass* newObject)
|
||||
{
|
||||
if (indexToChange >= 0)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (newObject != nullptr)
|
||||
newObject->incReferenceCount();
|
||||
|
||||
if (indexToChange < values.size())
|
||||
{
|
||||
auto* e = values[indexToChange];
|
||||
values[indexToChange] = newObject;
|
||||
releaseObject (e);
|
||||
}
|
||||
else
|
||||
{
|
||||
values.add (newObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Replaces an object in the array with a different one.
|
||||
|
||||
If the index is less than zero, this method does nothing.
|
||||
If the index is beyond the end of the array, the new object is added to the end of the array.
|
||||
|
||||
The object being added has its reference count increased, and if it's replacing
|
||||
another object, then that one has its reference count decreased, and may be deleted.
|
||||
|
||||
@param indexToChange the index whose value you want to change
|
||||
@param newObject the new value to set for this index.
|
||||
@see add, insert, remove
|
||||
*/
|
||||
void set (int indexToChange, const ObjectClassPtr& newObject) { set (indexToChange, newObject.get()); }
|
||||
|
||||
/** Adds elements from another array to the end of this array.
|
||||
|
||||
@param arrayToAddFrom the array from which to copy the elements
|
||||
@param startIndex the first element of the other array to start copying from
|
||||
@param numElementsToAdd how many elements to add from the other array. If this
|
||||
value is negative or greater than the number of available elements,
|
||||
all available elements will be copied.
|
||||
@see add
|
||||
*/
|
||||
void addArray (const ReferenceCountedArray& arrayToAddFrom,
|
||||
int startIndex = 0,
|
||||
int numElementsToAdd = -1) noexcept
|
||||
{
|
||||
const ScopedLockType lock1 (arrayToAddFrom.getLock());
|
||||
|
||||
{
|
||||
const ScopedLockType lock2 (getLock());
|
||||
|
||||
auto numElementsAdded = values.addArray (arrayToAddFrom.values, startIndex, numElementsToAdd);
|
||||
auto** e = values.end();
|
||||
|
||||
for (int i = 0; i < numElementsAdded; ++i)
|
||||
(*(--e))->incReferenceCount();
|
||||
}
|
||||
}
|
||||
|
||||
/** Inserts a new object into the array assuming that the array is sorted.
|
||||
|
||||
This will use a comparator to find the position at which the new object
|
||||
should go. If the array isn't sorted, the behaviour of this
|
||||
method will be unpredictable.
|
||||
|
||||
@param comparator the comparator object to use to compare the elements - see the
|
||||
sort() method for details about this object's form
|
||||
@param newObject the new object to insert to the array
|
||||
@returns the index at which the new object was added
|
||||
@see add, sort
|
||||
*/
|
||||
template <class ElementComparator>
|
||||
int addSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
auto index = findInsertIndexInSortedArray (comparator, values.begin(), newObject, 0, values.size());
|
||||
insert (index, newObject);
|
||||
return index;
|
||||
}
|
||||
|
||||
/** Inserts or replaces an object in the array, assuming it is sorted.
|
||||
|
||||
This is similar to addSorted, but if a matching element already exists, then it will be
|
||||
replaced by the new one, rather than the new one being added as well.
|
||||
*/
|
||||
template <class ElementComparator>
|
||||
void addOrReplaceSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
auto index = findInsertIndexInSortedArray (comparator, values.begin(), newObject, 0, values.size());
|
||||
|
||||
if (index > 0 && comparator.compareElements (newObject, values[index - 1]) == 0)
|
||||
set (index - 1, newObject); // replace an existing object that matches
|
||||
else
|
||||
insert (index, newObject); // no match, so insert the new one
|
||||
}
|
||||
|
||||
/** Finds the index of an object in the array, assuming that the array is sorted.
|
||||
|
||||
This will use a comparator to do a binary-chop to find the index of the given
|
||||
element, if it exists. If the array isn't sorted, the behaviour of this
|
||||
method will be unpredictable.
|
||||
|
||||
@param comparator the comparator to use to compare the elements - see the sort()
|
||||
method for details about the form this object should take
|
||||
@param objectToLookFor the object to search for
|
||||
@returns the index of the element, or -1 if it's not found
|
||||
@see addSorted, sort
|
||||
*/
|
||||
template <class ElementComparator>
|
||||
int indexOfSorted (ElementComparator& comparator,
|
||||
const ObjectClass* objectToLookFor) const noexcept
|
||||
{
|
||||
ignoreUnused (comparator);
|
||||
const ScopedLockType lock (getLock());
|
||||
int s = 0, e = values.size();
|
||||
|
||||
while (s < e)
|
||||
{
|
||||
if (comparator.compareElements (objectToLookFor, values[s]) == 0)
|
||||
return s;
|
||||
|
||||
auto halfway = (s + e) / 2;
|
||||
|
||||
if (halfway == s)
|
||||
break;
|
||||
|
||||
if (comparator.compareElements (objectToLookFor, values[halfway]) >= 0)
|
||||
s = halfway;
|
||||
else
|
||||
e = halfway;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Removes an object from the array.
|
||||
|
||||
This will remove the object at a given index and move back all the
|
||||
subsequent objects to close the gap.
|
||||
|
||||
If the index passed in is out-of-range, nothing will happen.
|
||||
|
||||
The object that is removed will have its reference count decreased,
|
||||
and may be deleted if not referenced from elsewhere.
|
||||
|
||||
@param indexToRemove the index of the element to remove
|
||||
@see removeObject, removeRange
|
||||
*/
|
||||
void remove (int indexToRemove)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (indexToRemove, values.size()))
|
||||
{
|
||||
auto* e = *(values.begin() + indexToRemove);
|
||||
values.removeElements (indexToRemove, 1);
|
||||
releaseObject (e);
|
||||
|
||||
if ((values.size() << 1) < values.capacity())
|
||||
minimiseStorageOverheads();
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes and returns an object from the array.
|
||||
|
||||
This will remove the object at a given index and return it, moving back all
|
||||
the subsequent objects to close the gap. If the index passed in is out-of-range,
|
||||
nothing will happen and a null pointer will be returned.
|
||||
|
||||
@param indexToRemove the index of the element to remove
|
||||
@see remove, removeObject, removeRange
|
||||
*/
|
||||
ObjectClassPtr removeAndReturn (int indexToRemove)
|
||||
{
|
||||
ObjectClassPtr removedItem;
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (indexToRemove, values.size()))
|
||||
{
|
||||
auto* e = *(values.begin() + indexToRemove);
|
||||
removedItem = e;
|
||||
values.removeElements (indexToRemove, 1);
|
||||
releaseObject (e);
|
||||
|
||||
if ((values.size() << 1) < values.capacity())
|
||||
minimiseStorageOverheads();
|
||||
}
|
||||
|
||||
return removedItem;
|
||||
}
|
||||
|
||||
/** Removes the first occurrence of a specified object from the array.
|
||||
|
||||
If the item isn't found, no action is taken. If it is found, it is
|
||||
removed and has its reference count decreased.
|
||||
|
||||
@param objectToRemove the object to try to remove
|
||||
@see remove, removeRange
|
||||
*/
|
||||
void removeObject (ObjectClass* objectToRemove)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
remove (indexOf (objectToRemove));
|
||||
}
|
||||
|
||||
/** Removes the first occurrence of a specified object from the array.
|
||||
|
||||
If the item isn't found, no action is taken. If it is found, it is
|
||||
removed and has its reference count decreased.
|
||||
|
||||
@param objectToRemove the object to try to remove
|
||||
@see remove, removeRange
|
||||
*/
|
||||
void removeObject (const ObjectClassPtr& objectToRemove) { removeObject (objectToRemove.get()); }
|
||||
|
||||
/** Removes a range of objects from the array.
|
||||
|
||||
This will remove a set of objects, starting from the given index,
|
||||
and move any subsequent elements down to close the gap.
|
||||
|
||||
If the range extends beyond the bounds of the array, it will
|
||||
be safely clipped to the size of the array.
|
||||
|
||||
The objects that are removed will have their reference counts decreased,
|
||||
and may be deleted if not referenced from elsewhere.
|
||||
|
||||
@param startIndex the index of the first object to remove
|
||||
@param numberToRemove how many objects should be removed
|
||||
@see remove, removeObject
|
||||
*/
|
||||
void removeRange (int startIndex,
|
||||
int numberToRemove)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
startIndex = jlimit (0, values.size(), startIndex);
|
||||
auto endIndex = jlimit (0, values.size(), startIndex + numberToRemove);
|
||||
numberToRemove = endIndex - startIndex;
|
||||
|
||||
if (numberToRemove > 0)
|
||||
{
|
||||
Array<ObjectClass*> objectsToRemove;
|
||||
objectsToRemove.addArray (values.begin() + startIndex, numberToRemove);
|
||||
|
||||
values.removeElements (startIndex, numberToRemove);
|
||||
|
||||
for (auto& o : objectsToRemove)
|
||||
releaseObject (o);
|
||||
|
||||
if ((values.size() << 1) < values.capacity())
|
||||
minimiseStorageOverheads();
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes the last n objects from the array.
|
||||
|
||||
The objects that are removed will have their reference counts decreased,
|
||||
and may be deleted if not referenced from elsewhere.
|
||||
|
||||
@param howManyToRemove how many objects to remove from the end of the array
|
||||
@see remove, removeObject, removeRange
|
||||
*/
|
||||
void removeLast (int howManyToRemove = 1)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (howManyToRemove > values.size())
|
||||
howManyToRemove = values.size();
|
||||
|
||||
while (--howManyToRemove >= 0)
|
||||
remove (values.size() - 1);
|
||||
}
|
||||
|
||||
/** Swaps a pair of objects in the array.
|
||||
|
||||
If either of the indexes passed in is out-of-range, nothing will happen,
|
||||
otherwise the two objects at these positions will be exchanged.
|
||||
*/
|
||||
void swap (int index1, int index2) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (index1, values.size())
|
||||
&& isPositiveAndBelow (index2, values.size()))
|
||||
{
|
||||
std::swap (values[index1], values[index2]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Moves one of the objects to a different position.
|
||||
|
||||
This will move the object to a specified index, shuffling along
|
||||
any intervening elements as required.
|
||||
|
||||
So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
|
||||
move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
|
||||
|
||||
@param currentIndex the index of the object to be moved. If this isn't a
|
||||
valid index, then nothing will be done
|
||||
@param newIndex the index at which you'd like this object to end up. If this
|
||||
is less than zero, it will be moved to the end of the array
|
||||
*/
|
||||
void move (int currentIndex, int newIndex) noexcept
|
||||
{
|
||||
if (currentIndex != newIndex)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
values.move (currentIndex, newIndex);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** This swaps the contents of this array with those of another array.
|
||||
|
||||
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
|
||||
because it just swaps their internal pointers.
|
||||
*/
|
||||
template <class OtherArrayType>
|
||||
void swapWith (OtherArrayType& otherArray) noexcept
|
||||
{
|
||||
const ScopedLockType lock1 (getLock());
|
||||
const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
|
||||
values.swapWith (otherArray.values);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Compares this array to another one.
|
||||
|
||||
@returns true only if the other array contains the same objects in the same order
|
||||
*/
|
||||
bool operator== (const ReferenceCountedArray& other) const noexcept
|
||||
{
|
||||
const ScopedLockType lock2 (other.getLock());
|
||||
const ScopedLockType lock1 (getLock());
|
||||
return values == other.values;
|
||||
}
|
||||
|
||||
/** Compares this array to another one.
|
||||
|
||||
@see operator==
|
||||
*/
|
||||
bool operator!= (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Sorts the elements in the array.
|
||||
|
||||
This will use a comparator object to sort the elements into order. The object
|
||||
passed must have a method of the form:
|
||||
@code
|
||||
int compareElements (ElementType first, ElementType second);
|
||||
@endcode
|
||||
|
||||
..and this method must return:
|
||||
- a value of < 0 if the first comes before the second
|
||||
- a value of 0 if the two objects are equivalent
|
||||
- a value of > 0 if the second comes before the first
|
||||
|
||||
To improve performance, the compareElements() method can be declared as static or const.
|
||||
|
||||
@param comparator the comparator to use for comparing elements.
|
||||
@param retainOrderOfEquivalentItems if this is true, then items
|
||||
which the comparator says are equivalent will be
|
||||
kept in the order in which they currently appear
|
||||
in the array. This is slower to perform, but may
|
||||
be important in some cases. If it's false, a faster
|
||||
algorithm is used, but equivalent elements may be
|
||||
rearranged.
|
||||
|
||||
@see sortArray
|
||||
*/
|
||||
template <class ElementComparator>
|
||||
void sort (ElementComparator& comparator,
|
||||
bool retainOrderOfEquivalentItems = false) noexcept
|
||||
{
|
||||
// If you pass in an object with a static compareElements() method, this
|
||||
// avoids getting warning messages about the parameter being unused
|
||||
ignoreUnused (comparator);
|
||||
|
||||
const ScopedLockType lock (getLock());
|
||||
sortArray (comparator, values.begin(), 0, values.size() - 1, retainOrderOfEquivalentItems);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Reduces the amount of storage being used by the array.
|
||||
|
||||
Arrays typically allocate slightly more storage than they need, and after
|
||||
removing elements, they may have quite a lot of unused space allocated.
|
||||
This method will reduce the amount of allocated storage to a minimum.
|
||||
*/
|
||||
void minimiseStorageOverheads() noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
values.shrinkToNoMoreThan (values.size());
|
||||
}
|
||||
|
||||
/** Increases the array's internal storage to hold a minimum number of elements.
|
||||
|
||||
Calling this before adding a large known number of elements means that
|
||||
the array won't have to keep dynamically resizing itself as the elements
|
||||
are added, and it'll therefore be more efficient.
|
||||
*/
|
||||
void ensureStorageAllocated (const int minNumElements)
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
values.ensureAllocatedSize (minNumElements);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the CriticalSection that locks this array.
|
||||
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||
an object of ScopedLockType as an RAII lock for it.
|
||||
*/
|
||||
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return values; }
|
||||
|
||||
/** Returns the type of scoped lock to use for locking this array */
|
||||
using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
[[deprecated ("This method has been replaced by a more flexible templated version and renamed "
|
||||
"to swapWith to be more consistent with the names used in other classes.")]]
|
||||
void swapWithArray (ReferenceCountedArray& other) noexcept { swapWith (other); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ArrayBase<ObjectClass*, TypeOfCriticalSectionToUse> values;
|
||||
|
||||
void releaseAllObjects()
|
||||
{
|
||||
auto i = values.size();
|
||||
|
||||
while (--i >= 0)
|
||||
{
|
||||
auto* e = values[i];
|
||||
values.removeElements (i, 1);
|
||||
releaseObject (e);
|
||||
}
|
||||
}
|
||||
|
||||
static void releaseObject (ObjectClass* o)
|
||||
{
|
||||
if (o != nullptr && o->decReferenceCountWithoutDeleting())
|
||||
ContainerDeletePolicy<ObjectClass>::destroy (o);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
93
deps/juce/modules/juce_core/containers/juce_ScopedValueSetter.h
vendored
Normal file
93
deps/juce/modules/juce_core/containers/juce_ScopedValueSetter.h
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Helper class providing an RAII-based mechanism for temporarily setting and
|
||||
then re-setting a value.
|
||||
|
||||
E.g. @code
|
||||
int x = 1;
|
||||
|
||||
{
|
||||
ScopedValueSetter setter (x, 2);
|
||||
|
||||
// x is now 2
|
||||
}
|
||||
|
||||
// x is now 1 again
|
||||
|
||||
{
|
||||
ScopedValueSetter setter (x, 3, 4);
|
||||
|
||||
// x is now 3
|
||||
}
|
||||
|
||||
// x is now 4
|
||||
@endcode
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <typename ValueType>
|
||||
class ScopedValueSetter
|
||||
{
|
||||
public:
|
||||
/** Creates a ScopedValueSetter that will immediately change the specified value to the
|
||||
given new value, and will then reset it to its original value when this object is deleted.
|
||||
*/
|
||||
ScopedValueSetter (ValueType& valueToSet,
|
||||
ValueType newValue)
|
||||
: value (valueToSet),
|
||||
originalValue (valueToSet)
|
||||
{
|
||||
valueToSet = newValue;
|
||||
}
|
||||
|
||||
/** Creates a ScopedValueSetter that will immediately change the specified value to the
|
||||
given new value, and will then reset it to be valueWhenDeleted when this object is deleted.
|
||||
*/
|
||||
ScopedValueSetter (ValueType& valueToSet,
|
||||
ValueType newValue,
|
||||
ValueType valueWhenDeleted)
|
||||
: value (valueToSet),
|
||||
originalValue (valueWhenDeleted)
|
||||
{
|
||||
valueToSet = newValue;
|
||||
}
|
||||
|
||||
~ScopedValueSetter()
|
||||
{
|
||||
value = originalValue;
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ValueType& value;
|
||||
const ValueType originalValue;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (ScopedValueSetter)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
126
deps/juce/modules/juce_core/containers/juce_SingleThreadedAbstractFifo.h
vendored
Normal file
126
deps/juce/modules/juce_core/containers/juce_SingleThreadedAbstractFifo.h
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Encapsulates the logic for a single-threaded FIFO.
|
||||
|
||||
This might be useful for building buffers which can be written and read in
|
||||
blocks of different sizes. For example, in an audio effect we might wish to
|
||||
run some processing on fixed-size blocks of audio input, but the host may
|
||||
provide input blocks of varying sizes. In this situation, we might want to
|
||||
store the previous input in a buffer, and extract a fixed-size block
|
||||
whenever there are enough samples available. The SingleThreadedAbstractFifo
|
||||
implements logic suitable for this use-case.
|
||||
|
||||
This class is quite similar to AbstractFifo, in that it only keeps track of
|
||||
the current read/write locations. The user is responsible for providing the
|
||||
actual buffer that will be read/written.
|
||||
|
||||
The intended usage of this class is as follows:
|
||||
- Create some backing storage in a vector, AudioBuffer etc.
|
||||
- Construct a SingleThreadedAbstractFifo to manage the buffer, passing the
|
||||
number of items in the buffer.
|
||||
- Each time new input is ready, call write(), passing the number of items
|
||||
you wish to write into the buffer. This function returns a pair of ranges
|
||||
describing which indices in the backing storage should be written.
|
||||
- Call getNumReadable() to find out how many items are ready to read from
|
||||
the buffer.
|
||||
- If there are enough items ready to read, call read(), passing the number
|
||||
of items you require. This function returns a pair of ranges describing
|
||||
which indices in the backing storage may be read.
|
||||
|
||||
Unlike AbstractFifo, the SingleThreadedAbstractFifo is intended for use
|
||||
from a single thread. It is not safe to call any non-const member function
|
||||
of SingleThreadedAbstractFifo concurrently with any other member function.
|
||||
|
||||
@see AbstractFifo
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class SingleThreadedAbstractFifo
|
||||
{
|
||||
public:
|
||||
/** Creates a SingleThreadedAbstractFifo with no size. */
|
||||
SingleThreadedAbstractFifo() = default;
|
||||
|
||||
/** Creates a SingleThreadedAbstractFifo that can manage a buffer of the specified size. */
|
||||
explicit SingleThreadedAbstractFifo (int sizeIn)
|
||||
: size (sizeIn)
|
||||
{
|
||||
// This class only works properly when the size is a power of two.
|
||||
// Use nextPowerOfTwo() to find a good size, and ensure that your
|
||||
// backing storage is the same size.
|
||||
jassert (isPowerOfTwo (sizeIn));
|
||||
}
|
||||
|
||||
/** Returns the number of unused elements present in the buffer. */
|
||||
int getRemainingSpace() const { return size - numReadable; }
|
||||
|
||||
/** Returns the number of pending elements present in the buffer. */
|
||||
int getNumReadable() const { return numReadable; }
|
||||
|
||||
/** Returns the size of the managed buffer. */
|
||||
int getSize() const { return size; }
|
||||
|
||||
/** Returns two blocks in the buffer where new items may be written.
|
||||
|
||||
Note that if the buffer is running low on free space, the sum of the lengths of
|
||||
the returned ranges may be less than num!
|
||||
*/
|
||||
std::array<Range<int>, 2> write (int num)
|
||||
{
|
||||
const auto startPos = (readPos + numReadable) & (size - 1);
|
||||
const auto maxToWrite = jmin (getRemainingSpace(), num);
|
||||
const auto firstBlockSize = jmin (maxToWrite, size - startPos);
|
||||
|
||||
numReadable += maxToWrite;
|
||||
|
||||
return { { { startPos, startPos + firstBlockSize }, { 0, maxToWrite - firstBlockSize } } };
|
||||
}
|
||||
|
||||
/** Returns two blocks in the buffer from which new items may be read.
|
||||
|
||||
Note that if the buffer doesn't have the requested number of items available,
|
||||
the sum of the lengths of the returned ranges may be less than num!
|
||||
*/
|
||||
std::array<Range<int>, 2> read (int num)
|
||||
{
|
||||
const auto startPos = readPos;
|
||||
const auto maxToRead = jmin (numReadable, num);
|
||||
const auto firstBlockSize = jmin (maxToRead, size - startPos);
|
||||
|
||||
readPos = (startPos + maxToRead) & (size - 1);
|
||||
numReadable -= maxToRead;
|
||||
|
||||
return { { { startPos, startPos + firstBlockSize }, { 0, maxToRead - firstBlockSize } } };
|
||||
}
|
||||
|
||||
private:
|
||||
int size = 0, readPos = 0, numReadable = 0;
|
||||
};
|
||||
|
||||
|
||||
} // namespace juce
|
||||
489
deps/juce/modules/juce_core/containers/juce_SortedSet.h
vendored
Normal file
489
deps/juce/modules/juce_core/containers/juce_SortedSet.h
vendored
Normal file
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4512)
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Holds a set of unique primitive objects, such as ints or doubles.
|
||||
|
||||
A set can only hold one item with a given value, so if for example it's a
|
||||
set of integers, attempting to add the same integer twice will do nothing
|
||||
the second time.
|
||||
|
||||
Internally, the list of items is kept sorted (which means that whatever
|
||||
kind of primitive type is used must support the ==, <, >, <= and >= operators
|
||||
to determine the order), and searching the set for known values is very fast
|
||||
because it uses a binary-chop method.
|
||||
|
||||
Note that if you're using a class or struct as the element type, it must be
|
||||
capable of being copied or moved with a straightforward memcpy, rather than
|
||||
needing construction and destruction code.
|
||||
|
||||
To make all the set's methods thread-safe, pass in "CriticalSection" as the templated
|
||||
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
|
||||
|
||||
@see Array, OwnedArray, ReferenceCountedArray, StringArray, CriticalSection
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class ElementType, class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||
class SortedSet
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty set. */
|
||||
SortedSet() = default;
|
||||
|
||||
/** Creates a copy of another set. */
|
||||
SortedSet (const SortedSet&) = default;
|
||||
|
||||
/** Creates a copy of another set. */
|
||||
SortedSet (SortedSet&&) noexcept = default;
|
||||
|
||||
/** Makes a copy of another set. */
|
||||
SortedSet& operator= (const SortedSet&) = default;
|
||||
|
||||
/** Makes a copy of another set. */
|
||||
SortedSet& operator= (SortedSet&&) noexcept = default;
|
||||
|
||||
/** Destructor. */
|
||||
~SortedSet() = default;
|
||||
|
||||
//==============================================================================
|
||||
/** Compares this set to another one.
|
||||
Two sets are considered equal if they both contain the same set of elements.
|
||||
@param other the other set to compare with
|
||||
*/
|
||||
bool operator== (const SortedSet<ElementType>& other) const noexcept
|
||||
{
|
||||
return data == other.data;
|
||||
}
|
||||
|
||||
/** Compares this set to another one.
|
||||
Two sets are considered equal if they both contain the same set of elements.
|
||||
@param other the other set to compare with
|
||||
*/
|
||||
bool operator!= (const SortedSet<ElementType>& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Removes all elements from the set.
|
||||
|
||||
This will remove all the elements, and free any storage that the set is
|
||||
using. To clear it without freeing the storage, use the clearQuick()
|
||||
method instead.
|
||||
|
||||
@see clearQuick
|
||||
*/
|
||||
void clear() noexcept
|
||||
{
|
||||
data.clear();
|
||||
}
|
||||
|
||||
/** Removes all elements from the set without freeing the array's allocated storage.
|
||||
@see clear
|
||||
*/
|
||||
void clearQuick() noexcept
|
||||
{
|
||||
data.clearQuick();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the current number of elements in the set. */
|
||||
inline int size() const noexcept
|
||||
{
|
||||
return data.size();
|
||||
}
|
||||
|
||||
/** Returns true if the set is empty, false otherwise. */
|
||||
inline bool isEmpty() const noexcept
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
/** Returns one of the elements in the set.
|
||||
|
||||
If the index passed in is beyond the range of valid elements, this
|
||||
will return zero.
|
||||
|
||||
If you're certain that the index will always be a valid element, you
|
||||
can call getUnchecked() instead, which is faster.
|
||||
|
||||
@param index the index of the element being requested (0 is the first element in the set)
|
||||
@see getUnchecked, getFirst, getLast
|
||||
*/
|
||||
inline ElementType operator[] (const int index) const noexcept
|
||||
{
|
||||
return data [index];
|
||||
}
|
||||
|
||||
/** Returns one of the elements in the set, without checking the index passed in.
|
||||
Unlike the operator[] method, this will try to return an element without
|
||||
checking that the index is within the bounds of the set, so should only
|
||||
be used when you're confident that it will always be a valid index.
|
||||
|
||||
@param index the index of the element being requested (0 is the first element in the set)
|
||||
@see operator[], getFirst, getLast
|
||||
*/
|
||||
inline ElementType getUnchecked (const int index) const noexcept
|
||||
{
|
||||
return data.getUnchecked (index);
|
||||
}
|
||||
|
||||
/** Returns a direct reference to one of the elements in the set, without checking the index passed in.
|
||||
|
||||
This is like getUnchecked, but returns a direct reference to the element, so that
|
||||
you can alter it directly. Obviously this can be dangerous, so only use it when
|
||||
absolutely necessary.
|
||||
|
||||
@param index the index of the element being requested (0 is the first element in the array)
|
||||
*/
|
||||
inline ElementType& getReference (const int index) noexcept
|
||||
{
|
||||
return data.getReference (index);
|
||||
}
|
||||
|
||||
/** Returns a direct reference to one of the elements in the set, without checking the index passed in.
|
||||
|
||||
@param index the index of the element being requested (0 is the first element in the array)
|
||||
*/
|
||||
inline const ElementType& getReference (const int index) const noexcept
|
||||
{
|
||||
return data.getReference (index);
|
||||
}
|
||||
|
||||
/** Returns the first element in the set, or 0 if the set is empty.
|
||||
@see operator[], getUnchecked, getLast
|
||||
*/
|
||||
inline ElementType getFirst() const noexcept
|
||||
{
|
||||
return data.getFirst();
|
||||
}
|
||||
|
||||
/** Returns the last element in the set, or 0 if the set is empty.
|
||||
@see operator[], getUnchecked, getFirst
|
||||
*/
|
||||
inline ElementType getLast() const noexcept
|
||||
{
|
||||
return data.getLast();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a pointer to the first element in the set.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline const ElementType* begin() const noexcept
|
||||
{
|
||||
return data.begin();
|
||||
}
|
||||
|
||||
/** Returns a pointer to the element which follows the last element in the set.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline const ElementType* end() const noexcept
|
||||
{
|
||||
return data.end();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Finds the index of the first element which matches the value passed in.
|
||||
|
||||
This will search the set for the given object, and return the index
|
||||
of its first occurrence. If the object isn't found, the method will return -1.
|
||||
|
||||
@param elementToLookFor the value or object to look for
|
||||
@returns the index of the object, or -1 if it's not found
|
||||
*/
|
||||
int indexOf (const ElementType& elementToLookFor) const noexcept
|
||||
{
|
||||
const ScopedLockType lock (data.getLock());
|
||||
|
||||
int s = 0;
|
||||
int e = data.size();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (s >= e)
|
||||
return -1;
|
||||
|
||||
if (elementToLookFor == data.getReference (s))
|
||||
return s;
|
||||
|
||||
auto halfway = (s + e) / 2;
|
||||
|
||||
if (halfway == s)
|
||||
return -1;
|
||||
|
||||
if (elementToLookFor < data.getReference (halfway))
|
||||
e = halfway;
|
||||
else
|
||||
s = halfway;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if the set contains at least one occurrence of an object.
|
||||
|
||||
@param elementToLookFor the value or object to look for
|
||||
@returns true if the item is found
|
||||
*/
|
||||
bool contains (const ElementType& elementToLookFor) const noexcept
|
||||
{
|
||||
return indexOf (elementToLookFor) >= 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Adds a new element to the set, (as long as it's not already in there).
|
||||
|
||||
Note that if a matching element already exists, the new value will be assigned
|
||||
to the existing one using operator=, so that if there are any differences between
|
||||
the objects which were not recognised by the object's operator==, then the
|
||||
set will always contain a copy of the most recently added one.
|
||||
|
||||
@param newElement the new object to add to the set
|
||||
@returns true if the value was added, or false if it already existed
|
||||
@see set, insert, addIfNotAlreadyThere, addSorted, addSet, addArray
|
||||
*/
|
||||
bool add (const ElementType& newElement) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
int s = 0;
|
||||
int e = data.size();
|
||||
|
||||
while (s < e)
|
||||
{
|
||||
auto& elem = data.getReference (s);
|
||||
|
||||
if (newElement == elem)
|
||||
{
|
||||
elem = newElement; // force an update in case operator== permits differences.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto halfway = (s + e) / 2;
|
||||
bool isBeforeHalfway = (newElement < data.getReference (halfway));
|
||||
|
||||
if (halfway == s)
|
||||
{
|
||||
if (! isBeforeHalfway)
|
||||
++s;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (isBeforeHalfway)
|
||||
e = halfway;
|
||||
else
|
||||
s = halfway;
|
||||
}
|
||||
|
||||
data.insert (s, newElement);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Adds elements from an array to this set.
|
||||
|
||||
@param elementsToAdd the array of elements to add
|
||||
@param numElementsToAdd how many elements are in this other array
|
||||
@see add
|
||||
*/
|
||||
void addArray (const ElementType* elementsToAdd,
|
||||
int numElementsToAdd) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
while (--numElementsToAdd >= 0)
|
||||
add (*elementsToAdd++);
|
||||
}
|
||||
|
||||
/** Adds elements from another set to this one.
|
||||
|
||||
@param setToAddFrom the set from which to copy the elements
|
||||
@param startIndex the first element of the other set to start copying from
|
||||
@param numElementsToAdd how many elements to add from the other set. If this
|
||||
value is negative or greater than the number of available elements,
|
||||
all available elements will be copied.
|
||||
@see add
|
||||
*/
|
||||
template <class OtherSetType>
|
||||
void addSet (const OtherSetType& setToAddFrom,
|
||||
int startIndex = 0,
|
||||
int numElementsToAdd = -1) noexcept
|
||||
{
|
||||
const typename OtherSetType::ScopedLockType lock1 (setToAddFrom.getLock());
|
||||
const ScopedLockType lock2 (getLock());
|
||||
jassert (this != &setToAddFrom);
|
||||
|
||||
if (this != &setToAddFrom)
|
||||
{
|
||||
if (startIndex < 0)
|
||||
{
|
||||
jassertfalse;
|
||||
startIndex = 0;
|
||||
}
|
||||
|
||||
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > setToAddFrom.size())
|
||||
numElementsToAdd = setToAddFrom.size() - startIndex;
|
||||
|
||||
if (numElementsToAdd > 0)
|
||||
addArray (&setToAddFrom.data.getReference (startIndex), numElementsToAdd);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Removes an element from the set.
|
||||
|
||||
This will remove the element at a given index.
|
||||
If the index passed in is out-of-range, nothing will happen.
|
||||
|
||||
@param indexToRemove the index of the element to remove
|
||||
@returns the element that has been removed
|
||||
@see removeValue, removeRange
|
||||
*/
|
||||
ElementType remove (const int indexToRemove) noexcept
|
||||
{
|
||||
return data.removeAndReturn (indexToRemove);
|
||||
}
|
||||
|
||||
/** Removes an item from the set.
|
||||
|
||||
This will remove the given element from the set, if it's there.
|
||||
|
||||
@param valueToRemove the object to try to remove
|
||||
@see remove, removeRange
|
||||
*/
|
||||
void removeValue (const ElementType& valueToRemove) noexcept
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
data.remove (indexOf (valueToRemove));
|
||||
}
|
||||
|
||||
/** Removes any elements which are also in another set.
|
||||
|
||||
@param otherSet the other set in which to look for elements to remove
|
||||
@see removeValuesNotIn, remove, removeValue, removeRange
|
||||
*/
|
||||
template <class OtherSetType>
|
||||
void removeValuesIn (const OtherSetType& otherSet) noexcept
|
||||
{
|
||||
const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock());
|
||||
const ScopedLockType lock2 (getLock());
|
||||
|
||||
if (this == &otherSet)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
else if (! otherSet.isEmpty())
|
||||
{
|
||||
for (int i = data.size(); --i >= 0;)
|
||||
if (otherSet.contains (data.getReference (i)))
|
||||
remove (i);
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes any elements which are not found in another set.
|
||||
|
||||
Only elements which occur in this other set will be retained.
|
||||
|
||||
@param otherSet the set in which to look for elements NOT to remove
|
||||
@see removeValuesIn, remove, removeValue, removeRange
|
||||
*/
|
||||
template <class OtherSetType>
|
||||
void removeValuesNotIn (const OtherSetType& otherSet) noexcept
|
||||
{
|
||||
const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock());
|
||||
const ScopedLockType lock2 (getLock());
|
||||
|
||||
if (this != &otherSet)
|
||||
{
|
||||
if (otherSet.isEmpty())
|
||||
{
|
||||
clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = data.size(); --i >= 0;)
|
||||
if (! otherSet.contains (data.getReference (i)))
|
||||
remove (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** This swaps the contents of this array with those of another array.
|
||||
|
||||
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
|
||||
because it just swaps their internal pointers.
|
||||
*/
|
||||
template <class OtherSetType>
|
||||
void swapWith (OtherSetType& otherSet) noexcept
|
||||
{
|
||||
data.swapWith (otherSet.data);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Reduces the amount of storage being used by the set.
|
||||
|
||||
Sets typically allocate slightly more storage than they need, and after
|
||||
removing elements, they may have quite a lot of unused space allocated.
|
||||
This method will reduce the amount of allocated storage to a minimum.
|
||||
*/
|
||||
void minimiseStorageOverheads() noexcept
|
||||
{
|
||||
data.minimiseStorageOverheads();
|
||||
}
|
||||
|
||||
/** Increases the set's internal storage to hold a minimum number of elements.
|
||||
|
||||
Calling this before adding a large known number of elements means that
|
||||
the set won't have to keep dynamically resizing itself as the elements
|
||||
are added, and it'll therefore be more efficient.
|
||||
*/
|
||||
void ensureStorageAllocated (const int minNumElements)
|
||||
{
|
||||
data.ensureStorageAllocated (minNumElements);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the CriticalSection that locks this array.
|
||||
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||
an object of ScopedLockType as an RAII lock for it.
|
||||
*/
|
||||
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data.getLock(); }
|
||||
|
||||
/** Returns the type of scoped lock to use for locking this array */
|
||||
using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Array<ElementType, TypeOfCriticalSectionToUse> data;
|
||||
};
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
|
||||
} // namespace juce
|
||||
206
deps/juce/modules/juce_core/containers/juce_SparseSet.cpp
vendored
Normal file
206
deps/juce/modules/juce_core/containers/juce_SparseSet.cpp
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 JUCE_UNIT_TESTS
|
||||
|
||||
class SparseSetTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
SparseSetTests()
|
||||
: UnitTest ("SparseSet class", UnitTestCategories::containers)
|
||||
{}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("basic operations");
|
||||
{
|
||||
SparseSet<int> set;
|
||||
|
||||
expect (set.isEmpty());
|
||||
expectEquals (set.size(), 0);
|
||||
expectEquals (set.getNumRanges(), 0);
|
||||
expect (set.getTotalRange().isEmpty());
|
||||
|
||||
set.addRange ({0, 10});
|
||||
expect (! set.isEmpty());
|
||||
expectEquals (set.size(), 10);
|
||||
expectEquals (set.getNumRanges(), 1);
|
||||
expect (! set.getTotalRange().isEmpty());
|
||||
expect (set.getRange (0) == Range<int> (0, 10));
|
||||
|
||||
expectEquals (set[0], 0);
|
||||
expectEquals (set[5], 5);
|
||||
expectEquals (set[9], 9);
|
||||
// Index out of range yields a default value for a type
|
||||
expectEquals (set[10], 0);
|
||||
expect (set.contains (0));
|
||||
expect (set.contains (9));
|
||||
expect (! set.contains (10));
|
||||
}
|
||||
|
||||
beginTest ("adding ranges");
|
||||
{
|
||||
SparseSet<int> set;
|
||||
|
||||
// Adding same range twice should yield just a single range
|
||||
set.addRange ({0, 10});
|
||||
set.addRange ({0, 10});
|
||||
expectEquals (set.getNumRanges(), 1);
|
||||
expect (set.getRange (0) == Range<int> (0, 10));
|
||||
|
||||
// Adding already included range does not increase num ranges
|
||||
set.addRange ({0, 2});
|
||||
expectEquals (set.getNumRanges(), 1);
|
||||
set.addRange ({8, 10});
|
||||
expectEquals (set.getNumRanges(), 1);
|
||||
set.addRange ({2, 5});
|
||||
expectEquals (set.getNumRanges(), 1);
|
||||
|
||||
// Adding non adjacent range includes total number of ranges
|
||||
set.addRange ({-10, -5});
|
||||
expectEquals (set.getNumRanges(), 2);
|
||||
expect (set.getRange (0) == Range<int> (-10, -5));
|
||||
expect (set.getRange (1) == Range<int> (0, 10));
|
||||
expect (set.getTotalRange() == Range<int> (-10, 10));
|
||||
|
||||
set.addRange ({15, 20});
|
||||
expectEquals (set.getNumRanges(), 3);
|
||||
expect (set.getRange (0) == Range<int> (-10, -5));
|
||||
expect (set.getRange (1) == Range<int> (0, 10));
|
||||
expect (set.getRange (2) == Range<int> (15, 20));
|
||||
expect (set.getTotalRange() == Range<int> (-10, 20));
|
||||
|
||||
// Adding adjacent ranges merges them.
|
||||
set.addRange ({-5, -3});
|
||||
expectEquals (set.getNumRanges(), 3);
|
||||
expect (set.getRange (0) == Range<int> (-10, -3));
|
||||
expect (set.getRange (1) == Range<int> (0, 10));
|
||||
expect (set.getRange (2) == Range<int> (15, 20));
|
||||
expect (set.getTotalRange() == Range<int> (-10, 20));
|
||||
|
||||
set.addRange ({20, 25});
|
||||
expectEquals (set.getNumRanges(), 3);
|
||||
expect (set.getRange (0) == Range<int> (-10, -3));
|
||||
expect (set.getRange (1) == Range<int> (0, 10));
|
||||
expect (set.getRange (2) == Range<int> (15, 25));
|
||||
expect (set.getTotalRange() == Range<int> (-10, 25));
|
||||
|
||||
// Adding range containing other ranges merges them
|
||||
set.addRange ({-50, 50});
|
||||
expectEquals (set.getNumRanges(), 1);
|
||||
expect (set.getRange (0) == Range<int> (-50, 50));
|
||||
expect (set.getTotalRange() == Range<int> (-50, 50));
|
||||
}
|
||||
|
||||
beginTest ("removing ranges");
|
||||
{
|
||||
SparseSet<int> set;
|
||||
|
||||
set.addRange ({-20, -10});
|
||||
set.addRange ({0, 10});
|
||||
set.addRange ({20, 30});
|
||||
expectEquals (set.getNumRanges(), 3);
|
||||
|
||||
// Removing ranges not included in the set has no effect
|
||||
set.removeRange ({-5, 5});
|
||||
expectEquals (set.getNumRanges(), 3);
|
||||
|
||||
// Removing partially overlapping range
|
||||
set.removeRange ({-15, 5});
|
||||
expectEquals (set.getNumRanges(), 3);
|
||||
expect (set.getRange (0) == Range<int> (-20, -15));
|
||||
expect (set.getRange (1) == Range<int> (5, 10));
|
||||
expect (set.getRange (2) == Range<int> (20, 30));
|
||||
|
||||
// Removing subrange of existing range
|
||||
set.removeRange ({20, 22});
|
||||
expectEquals (set.getNumRanges(), 3);
|
||||
expect (set.getRange (2) == Range<int> (22, 30));
|
||||
|
||||
set.removeRange ({28, 30});
|
||||
expectEquals (set.getNumRanges(), 3);
|
||||
expect (set.getRange (2) == Range<int> (22, 28));
|
||||
|
||||
set.removeRange ({24, 26});
|
||||
expectEquals (set.getNumRanges(), 4);
|
||||
expect (set.getRange (0) == Range<int> (-20, -15));
|
||||
expect (set.getRange (1) == Range<int> (5, 10));
|
||||
expect (set.getRange (2) == Range<int> (22, 24));
|
||||
expect (set.getRange (3) == Range<int> (26, 28));
|
||||
}
|
||||
|
||||
beginTest ("XORing ranges");
|
||||
{
|
||||
SparseSet<int> set;
|
||||
set.addRange ({0, 10});
|
||||
|
||||
set.invertRange ({0, 10});
|
||||
expectEquals (set.getNumRanges(), 0);
|
||||
set.invertRange ({0, 10});
|
||||
expectEquals (set.getNumRanges(), 1);
|
||||
|
||||
set.invertRange ({4, 6});
|
||||
expectEquals (set.getNumRanges(), 2);
|
||||
expect (set.getRange (0) == Range<int> (0, 4));
|
||||
expect (set.getRange (1) == Range<int> (6, 10));
|
||||
|
||||
set.invertRange ({-2, 2});
|
||||
expectEquals (set.getNumRanges(), 3);
|
||||
expect (set.getRange (0) == Range<int> (-2, 0));
|
||||
expect (set.getRange (1) == Range<int> (2, 4));
|
||||
expect (set.getRange (2) == Range<int> (6, 10));
|
||||
}
|
||||
|
||||
beginTest ("range contains & overlaps checks");
|
||||
{
|
||||
SparseSet<int> set;
|
||||
set.addRange ({0, 10});
|
||||
|
||||
expect (set.containsRange (Range<int> (0, 2)));
|
||||
expect (set.containsRange (Range<int> (8, 10)));
|
||||
expect (set.containsRange (Range<int> (0, 10)));
|
||||
|
||||
expect (! set.containsRange (Range<int> (-2, 0)));
|
||||
expect (! set.containsRange (Range<int> (-2, 10)));
|
||||
expect (! set.containsRange (Range<int> (10, 12)));
|
||||
expect (! set.containsRange (Range<int> (0, 12)));
|
||||
|
||||
expect (set.overlapsRange (Range<int> (0, 2)));
|
||||
expect (set.overlapsRange (Range<int> (8, 10)));
|
||||
expect (set.overlapsRange (Range<int> (0, 10)));
|
||||
|
||||
expect (! set.overlapsRange (Range<int> (-2, 0)));
|
||||
expect ( set.overlapsRange (Range<int> (-2, 10)));
|
||||
expect (! set.overlapsRange (Range<int> (10, 12)));
|
||||
expect ( set.overlapsRange (Range<int> (0, 12)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static SparseSetTests sparseSetTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
268
deps/juce/modules/juce_core/containers/juce_SparseSet.h
vendored
Normal file
268
deps/juce/modules/juce_core/containers/juce_SparseSet.h
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 set of primitive values, storing them as a set of ranges.
|
||||
|
||||
This container acts like an array, but can efficiently hold large contiguous
|
||||
ranges of values. It's quite a specialised class, mostly useful for things
|
||||
like keeping the set of selected rows in a listbox.
|
||||
|
||||
The type used as a template parameter must be an integer type, such as int, short,
|
||||
int64, etc.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class Type>
|
||||
class SparseSet
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
SparseSet() = default;
|
||||
|
||||
SparseSet (const SparseSet&) = default;
|
||||
SparseSet& operator= (const SparseSet&) = default;
|
||||
|
||||
SparseSet (SparseSet&& other) noexcept : ranges (std::move (other.ranges)) {}
|
||||
SparseSet& operator= (SparseSet&& other) noexcept { ranges = std::move (other.ranges); return *this; }
|
||||
|
||||
//==============================================================================
|
||||
/** Clears the set. */
|
||||
void clear() { ranges.clear(); }
|
||||
|
||||
/** Checks whether the set is empty.
|
||||
This is much quicker than using (size() == 0).
|
||||
*/
|
||||
bool isEmpty() const noexcept { return ranges.isEmpty(); }
|
||||
|
||||
/** Returns the number of values in the set.
|
||||
|
||||
Because of the way the data is stored, this method can take longer if there
|
||||
are a lot of items in the set. Use isEmpty() for a quick test of whether there
|
||||
are any items.
|
||||
*/
|
||||
Type size() const noexcept
|
||||
{
|
||||
Type total = {};
|
||||
|
||||
for (auto& r : ranges)
|
||||
total += r.getLength();
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/** Returns one of the values in the set.
|
||||
|
||||
@param index the index of the value to retrieve, in the range 0 to (size() - 1).
|
||||
@returns the value at this index, or 0 if it's out-of-range
|
||||
*/
|
||||
Type operator[] (Type index) const noexcept
|
||||
{
|
||||
Type total = {};
|
||||
|
||||
for (auto& r : ranges)
|
||||
{
|
||||
auto end = total + r.getLength();
|
||||
|
||||
if (index < end)
|
||||
return r.getStart() + (index - total);
|
||||
|
||||
total = end;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/** Checks whether a particular value is in the set. */
|
||||
bool contains (Type valueToLookFor) const noexcept
|
||||
{
|
||||
for (auto& r : ranges)
|
||||
{
|
||||
if (r.getStart() > valueToLookFor)
|
||||
break;
|
||||
|
||||
if (r.getEnd() > valueToLookFor)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of contiguous blocks of values.
|
||||
@see getRange
|
||||
*/
|
||||
int getNumRanges() const noexcept { return ranges.size(); }
|
||||
|
||||
/** Returns one of the contiguous ranges of values stored.
|
||||
@param rangeIndex the index of the range to look up, between 0
|
||||
and (getNumRanges() - 1)
|
||||
@see getTotalRange
|
||||
*/
|
||||
Range<Type> getRange (int rangeIndex) const noexcept { return ranges[rangeIndex]; }
|
||||
|
||||
/** Returns the range between the lowest and highest values in the set.
|
||||
@see getRange
|
||||
*/
|
||||
Range<Type> getTotalRange() const noexcept
|
||||
{
|
||||
if (ranges.isEmpty())
|
||||
return {};
|
||||
|
||||
return { ranges.getFirst().getStart(),
|
||||
ranges.getLast().getEnd() };
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Adds a range of contiguous values to the set.
|
||||
e.g. addRange (Range \<int\> (10, 14)) will add (10, 11, 12, 13) to the set.
|
||||
*/
|
||||
void addRange (Range<Type> range)
|
||||
{
|
||||
if (! range.isEmpty())
|
||||
{
|
||||
removeRange (range);
|
||||
ranges.add (range);
|
||||
std::sort (ranges.begin(), ranges.end(),
|
||||
[] (Range<Type> a, Range<Type> b) { return a.getStart() < b.getStart(); });
|
||||
simplify();
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes a range of values from the set.
|
||||
e.g. removeRange (Range\<int\> (10, 14)) will remove (10, 11, 12, 13) from the set.
|
||||
*/
|
||||
void removeRange (Range<Type> rangeToRemove)
|
||||
{
|
||||
if (getTotalRange().intersects (rangeToRemove) && ! rangeToRemove.isEmpty())
|
||||
{
|
||||
for (int i = ranges.size(); --i >= 0;)
|
||||
{
|
||||
auto& r = ranges.getReference(i);
|
||||
|
||||
if (r.getEnd() <= rangeToRemove.getStart())
|
||||
break;
|
||||
|
||||
if (r.getStart() >= rangeToRemove.getEnd())
|
||||
continue;
|
||||
|
||||
if (rangeToRemove.contains (r))
|
||||
{
|
||||
ranges.remove (i);
|
||||
}
|
||||
else if (r.contains (rangeToRemove))
|
||||
{
|
||||
auto r1 = r.withEnd (rangeToRemove.getStart());
|
||||
auto r2 = r.withStart (rangeToRemove.getEnd());
|
||||
|
||||
// this should be covered in if (rangeToRemove.contains (r))
|
||||
jassert (! r1.isEmpty() || ! r2.isEmpty());
|
||||
|
||||
r = r1;
|
||||
|
||||
if (r.isEmpty())
|
||||
r = r2;
|
||||
|
||||
if (! r1.isEmpty() && ! r2.isEmpty())
|
||||
ranges.insert (i + 1, r2);
|
||||
}
|
||||
else if (rangeToRemove.getEnd() > r.getEnd())
|
||||
{
|
||||
r.setEnd (rangeToRemove.getStart());
|
||||
}
|
||||
else
|
||||
{
|
||||
r.setStart (rangeToRemove.getEnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Does an XOR of the values in a given range. */
|
||||
void invertRange (Range<Type> range)
|
||||
{
|
||||
SparseSet newItems;
|
||||
newItems.addRange (range);
|
||||
|
||||
for (auto& r : ranges)
|
||||
newItems.removeRange (r);
|
||||
|
||||
removeRange (range);
|
||||
|
||||
for (auto& r : newItems.ranges)
|
||||
addRange (r);
|
||||
}
|
||||
|
||||
/** Checks whether any part of a given range overlaps any part of this set. */
|
||||
bool overlapsRange (Range<Type> range) const noexcept
|
||||
{
|
||||
if (! range.isEmpty())
|
||||
for (auto& r : ranges)
|
||||
if (r.intersects (range))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Checks whether the whole of a given range is contained within this one. */
|
||||
bool containsRange (Range<Type> range) const noexcept
|
||||
{
|
||||
if (! range.isEmpty())
|
||||
for (auto& r : ranges)
|
||||
if (r.contains (range))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns the set as a list of ranges, which you may want to iterate over. */
|
||||
const Array<Range<Type>>& getRanges() const noexcept { return ranges; }
|
||||
|
||||
//==============================================================================
|
||||
bool operator== (const SparseSet& other) const noexcept { return ranges == other.ranges; }
|
||||
bool operator!= (const SparseSet& other) const noexcept { return ranges != other.ranges; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Array<Range<Type>> ranges;
|
||||
|
||||
void simplify()
|
||||
{
|
||||
for (int i = ranges.size(); --i > 0;)
|
||||
{
|
||||
auto& r1 = ranges.getReference (i - 1);
|
||||
auto& r2 = ranges.getReference (i);
|
||||
|
||||
if (r1.getEnd() == r2.getStart())
|
||||
{
|
||||
r1.setEnd (r2.getEnd());
|
||||
ranges.remove (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
909
deps/juce/modules/juce_core/containers/juce_Variant.cpp
vendored
Normal file
909
deps/juce/modules/juce_core/containers/juce_Variant.cpp
vendored
Normal file
@@ -0,0 +1,909 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
enum VariantStreamMarkers
|
||||
{
|
||||
varMarker_Int = 1,
|
||||
varMarker_BoolTrue = 2,
|
||||
varMarker_BoolFalse = 3,
|
||||
varMarker_Double = 4,
|
||||
varMarker_String = 5,
|
||||
varMarker_Int64 = 6,
|
||||
varMarker_Array = 7,
|
||||
varMarker_Binary = 8,
|
||||
varMarker_Undefined = 9
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct var::VariantType
|
||||
{
|
||||
struct VoidTag {};
|
||||
struct UndefinedTag {};
|
||||
struct IntTag {};
|
||||
struct Int64Tag {};
|
||||
struct DoubleTag {};
|
||||
struct BoolTag {};
|
||||
struct StringTag {};
|
||||
struct ObjectTag {};
|
||||
struct ArrayTag {};
|
||||
struct BinaryTag {};
|
||||
struct MethodTag {};
|
||||
|
||||
// members =====================================================================
|
||||
bool isVoid = false;
|
||||
bool isUndefined = false;
|
||||
bool isInt = false;
|
||||
bool isInt64 = false;
|
||||
bool isBool = false;
|
||||
bool isDouble = false;
|
||||
bool isString = false;
|
||||
bool isObject = false;
|
||||
bool isArray = false;
|
||||
bool isBinary = false;
|
||||
bool isMethod = false;
|
||||
bool isComparable = false;
|
||||
|
||||
int (*toInt) (const ValueUnion&) = defaultToInt;
|
||||
int64 (*toInt64) (const ValueUnion&) = defaultToInt64;
|
||||
double (*toDouble) (const ValueUnion&) = defaultToDouble;
|
||||
String (*toString) (const ValueUnion&) = defaultToString;
|
||||
bool (*toBool) (const ValueUnion&) = defaultToBool;
|
||||
ReferenceCountedObject* (*toObject) (const ValueUnion&) = defaultToObject;
|
||||
Array<var>* (*toArray) (const ValueUnion&) = defaultToArray;
|
||||
MemoryBlock* (*toBinary) (const ValueUnion&) = defaultToBinary;
|
||||
var (*clone) (const var&) = defaultClone;
|
||||
void (*cleanUp) (ValueUnion&) = defaultCleanUp;
|
||||
void (*createCopy) (ValueUnion&, const ValueUnion&) = defaultCreateCopy;
|
||||
|
||||
bool (*equals) (const ValueUnion&, const ValueUnion&, const VariantType&) = nullptr;
|
||||
void (*writeToStream) (const ValueUnion&, OutputStream&) = nullptr;
|
||||
|
||||
// defaults ====================================================================
|
||||
static int defaultToInt (const ValueUnion&) { return 0; }
|
||||
static int64 defaultToInt64 (const ValueUnion&) { return 0; }
|
||||
static double defaultToDouble (const ValueUnion&) { return 0; }
|
||||
static String defaultToString (const ValueUnion&) { return {}; }
|
||||
static bool defaultToBool (const ValueUnion&) { return false; }
|
||||
static ReferenceCountedObject* defaultToObject (const ValueUnion&) { return nullptr; }
|
||||
static Array<var>* defaultToArray (const ValueUnion&) { return nullptr; }
|
||||
static MemoryBlock* defaultToBinary (const ValueUnion&) { return nullptr; }
|
||||
static var defaultClone (const var& other) { return other; }
|
||||
static void defaultCleanUp (ValueUnion&) {}
|
||||
static void defaultCreateCopy (ValueUnion& dest, const ValueUnion& source) { dest = source; }
|
||||
|
||||
// void ========================================================================
|
||||
static bool voidEquals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) noexcept
|
||||
{
|
||||
return otherType.isVoid || otherType.isUndefined;
|
||||
}
|
||||
|
||||
static void voidWriteToStream (const ValueUnion&, OutputStream& output)
|
||||
{
|
||||
output.writeCompressedInt (0);
|
||||
}
|
||||
|
||||
constexpr explicit VariantType (VoidTag) noexcept
|
||||
: isVoid (true),
|
||||
isComparable (true),
|
||||
equals (voidEquals),
|
||||
writeToStream (voidWriteToStream) {}
|
||||
|
||||
// undefined ===================================================================
|
||||
static String undefinedToString (const ValueUnion&) { return "undefined"; }
|
||||
|
||||
static bool undefinedEquals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) noexcept
|
||||
{
|
||||
return otherType.isVoid || otherType.isUndefined;
|
||||
}
|
||||
|
||||
static void undefinedWriteToStream (const ValueUnion&, OutputStream& output)
|
||||
{
|
||||
output.writeCompressedInt (1);
|
||||
output.writeByte (varMarker_Undefined);
|
||||
}
|
||||
|
||||
constexpr explicit VariantType (UndefinedTag) noexcept
|
||||
: isUndefined (true),
|
||||
toString (undefinedToString),
|
||||
equals (undefinedEquals),
|
||||
writeToStream (undefinedWriteToStream) {}
|
||||
|
||||
// int =========================================================================
|
||||
static int intToInt (const ValueUnion& data) noexcept { return data.intValue; }
|
||||
static int64 intToInt64 (const ValueUnion& data) noexcept { return (int64) data.intValue; }
|
||||
static double intToDouble (const ValueUnion& data) noexcept { return (double) data.intValue; }
|
||||
static String intToString (const ValueUnion& data) { return String (data.intValue); }
|
||||
static bool intToBool (const ValueUnion& data) noexcept { return data.intValue != 0; }
|
||||
|
||||
static bool intEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
|
||||
{
|
||||
if (otherType.isDouble || otherType.isInt64 || otherType.isString)
|
||||
return otherType.equals (otherData, data, VariantType { IntTag{} });
|
||||
|
||||
return otherType.toInt (otherData) == data.intValue;
|
||||
}
|
||||
|
||||
static void intWriteToStream (const ValueUnion& data, OutputStream& output)
|
||||
{
|
||||
output.writeCompressedInt (5);
|
||||
output.writeByte (varMarker_Int);
|
||||
output.writeInt (data.intValue);
|
||||
}
|
||||
|
||||
constexpr explicit VariantType (IntTag) noexcept
|
||||
: isInt (true),
|
||||
isComparable (true),
|
||||
toInt (intToInt),
|
||||
toInt64 (intToInt64),
|
||||
toDouble (intToDouble),
|
||||
toString (intToString),
|
||||
toBool (intToBool),
|
||||
equals (intEquals),
|
||||
writeToStream (intWriteToStream) {}
|
||||
|
||||
// int64 =======================================================================
|
||||
static int int64ToInt (const ValueUnion& data) noexcept { return (int) data.int64Value; }
|
||||
static int64 int64ToInt64 (const ValueUnion& data) noexcept { return data.int64Value; }
|
||||
static double int64ToDouble (const ValueUnion& data) noexcept { return (double) data.int64Value; }
|
||||
static String int64ToString (const ValueUnion& data) { return String (data.int64Value); }
|
||||
static bool int64ToBool (const ValueUnion& data) noexcept { return data.int64Value != 0; }
|
||||
|
||||
static bool int64Equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
|
||||
{
|
||||
if (otherType.isDouble || otherType.isString)
|
||||
return otherType.equals (otherData, data, VariantType { Int64Tag{} });
|
||||
|
||||
return otherType.toInt64 (otherData) == data.int64Value;
|
||||
}
|
||||
|
||||
static void int64WriteToStream (const ValueUnion& data, OutputStream& output)
|
||||
{
|
||||
output.writeCompressedInt (9);
|
||||
output.writeByte (varMarker_Int64);
|
||||
output.writeInt64 (data.int64Value);
|
||||
}
|
||||
|
||||
constexpr explicit VariantType (Int64Tag) noexcept
|
||||
: isInt64 (true),
|
||||
isComparable (true),
|
||||
toInt (int64ToInt),
|
||||
toInt64 (int64ToInt64),
|
||||
toDouble (int64ToDouble),
|
||||
toString (int64ToString),
|
||||
toBool (int64ToBool),
|
||||
equals (int64Equals),
|
||||
writeToStream (int64WriteToStream) {}
|
||||
|
||||
// double ======================================================================
|
||||
static int doubleToInt (const ValueUnion& data) noexcept { return (int) data.doubleValue; }
|
||||
static int64 doubleToInt64 (const ValueUnion& data) noexcept { return (int64) data.doubleValue; }
|
||||
static double doubleToDouble (const ValueUnion& data) noexcept { return data.doubleValue; }
|
||||
static String doubleToString (const ValueUnion& data) { return serialiseDouble (data.doubleValue); }
|
||||
static bool doubleToBool (const ValueUnion& data) noexcept { return data.doubleValue != 0.0; }
|
||||
|
||||
static bool doubleEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
|
||||
{
|
||||
return std::abs (otherType.toDouble (otherData) - data.doubleValue) < std::numeric_limits<double>::epsilon();
|
||||
}
|
||||
|
||||
static void doubleWriteToStream (const ValueUnion& data, OutputStream& output)
|
||||
{
|
||||
output.writeCompressedInt (9);
|
||||
output.writeByte (varMarker_Double);
|
||||
output.writeDouble (data.doubleValue);
|
||||
}
|
||||
|
||||
constexpr explicit VariantType (DoubleTag) noexcept
|
||||
: isDouble (true),
|
||||
isComparable (true),
|
||||
toInt (doubleToInt),
|
||||
toInt64 (doubleToInt64),
|
||||
toDouble (doubleToDouble),
|
||||
toString (doubleToString),
|
||||
toBool (doubleToBool),
|
||||
equals (doubleEquals),
|
||||
writeToStream (doubleWriteToStream) {}
|
||||
|
||||
// bool ========================================================================
|
||||
static int boolToInt (const ValueUnion& data) noexcept { return data.boolValue ? 1 : 0; }
|
||||
static int64 boolToInt64 (const ValueUnion& data) noexcept { return data.boolValue ? 1 : 0; }
|
||||
static double boolToDouble (const ValueUnion& data) noexcept { return data.boolValue ? 1.0 : 0.0; }
|
||||
static String boolToString (const ValueUnion& data) { return String::charToString (data.boolValue ? (juce_wchar) '1' : (juce_wchar) '0'); }
|
||||
static bool boolToBool (const ValueUnion& data) noexcept { return data.boolValue; }
|
||||
|
||||
static bool boolEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
|
||||
{
|
||||
return otherType.toBool (otherData) == data.boolValue;
|
||||
}
|
||||
|
||||
static void boolWriteToStream (const ValueUnion& data, OutputStream& output)
|
||||
{
|
||||
output.writeCompressedInt (1);
|
||||
output.writeByte (data.boolValue ? (char) varMarker_BoolTrue : (char) varMarker_BoolFalse);
|
||||
}
|
||||
|
||||
constexpr explicit VariantType (BoolTag) noexcept
|
||||
: isBool (true),
|
||||
isComparable (true),
|
||||
toInt (boolToInt),
|
||||
toInt64 (boolToInt64),
|
||||
toDouble (boolToDouble),
|
||||
toString (boolToString),
|
||||
toBool (boolToBool),
|
||||
equals (boolEquals),
|
||||
writeToStream (boolWriteToStream) {}
|
||||
|
||||
// string ======================================================================
|
||||
static const String* getString (const ValueUnion& data) noexcept { return unalignedPointerCast<const String*> (data.stringValue); }
|
||||
static String* getString ( ValueUnion& data) noexcept { return unalignedPointerCast<String*> (data.stringValue); }
|
||||
|
||||
static int stringToInt (const ValueUnion& data) noexcept { return getString (data)->getIntValue(); }
|
||||
static int64 stringToInt64 (const ValueUnion& data) noexcept { return getString (data)->getLargeIntValue(); }
|
||||
static double stringToDouble (const ValueUnion& data) noexcept { return getString (data)->getDoubleValue(); }
|
||||
static String stringToString (const ValueUnion& data) { return *getString (data); }
|
||||
static bool stringToBool (const ValueUnion& data) noexcept
|
||||
{
|
||||
return getString (data)->getIntValue() != 0
|
||||
|| getString (data)->trim().equalsIgnoreCase ("true")
|
||||
|| getString (data)->trim().equalsIgnoreCase ("yes");
|
||||
}
|
||||
|
||||
static void stringCleanUp (ValueUnion& data) noexcept { getString (data)-> ~String(); }
|
||||
static void stringCreateCopy (ValueUnion& dest, const ValueUnion& source) { new (dest.stringValue) String (*getString (source)); }
|
||||
|
||||
static bool stringEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
|
||||
{
|
||||
return otherType.toString (otherData) == *getString (data);
|
||||
}
|
||||
|
||||
static void stringWriteToStream (const ValueUnion& data, OutputStream& output)
|
||||
{
|
||||
auto* s = getString (data);
|
||||
const size_t len = s->getNumBytesAsUTF8() + 1;
|
||||
HeapBlock<char> temp (len);
|
||||
s->copyToUTF8 (temp, len);
|
||||
output.writeCompressedInt ((int) (len + 1));
|
||||
output.writeByte (varMarker_String);
|
||||
output.write (temp, len);
|
||||
}
|
||||
|
||||
constexpr explicit VariantType (StringTag) noexcept
|
||||
: isString (true),
|
||||
isComparable (true),
|
||||
toInt (stringToInt),
|
||||
toInt64 (stringToInt64),
|
||||
toDouble (stringToDouble),
|
||||
toString (stringToString),
|
||||
toBool (stringToBool),
|
||||
cleanUp (stringCleanUp),
|
||||
createCopy (stringCreateCopy),
|
||||
equals (stringEquals),
|
||||
writeToStream (stringWriteToStream) {}
|
||||
|
||||
// object ======================================================================
|
||||
static String objectToString (const ValueUnion& data)
|
||||
{
|
||||
return "Object 0x" + String::toHexString ((int) (pointer_sized_int) data.objectValue);
|
||||
}
|
||||
|
||||
static bool objectToBool (const ValueUnion& data) noexcept { return data.objectValue != nullptr; }
|
||||
static ReferenceCountedObject* objectToObject (const ValueUnion& data) noexcept { return data.objectValue; }
|
||||
|
||||
static var objectClone (const var& original)
|
||||
{
|
||||
if (auto* d = original.getDynamicObject())
|
||||
return d->clone().get();
|
||||
|
||||
jassertfalse; // can only clone DynamicObjects!
|
||||
return {};
|
||||
}
|
||||
|
||||
static void objectCleanUp (ValueUnion& data) noexcept { if (data.objectValue != nullptr) data.objectValue->decReferenceCount(); }
|
||||
|
||||
static void objectCreateCopy (ValueUnion& dest, const ValueUnion& source)
|
||||
{
|
||||
dest.objectValue = source.objectValue;
|
||||
if (dest.objectValue != nullptr)
|
||||
dest.objectValue->incReferenceCount();
|
||||
}
|
||||
|
||||
static bool objectEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
|
||||
{
|
||||
return otherType.toObject (otherData) == data.objectValue;
|
||||
}
|
||||
|
||||
static void objectWriteToStream (const ValueUnion&, OutputStream& output)
|
||||
{
|
||||
jassertfalse; // Can't write an object to a stream!
|
||||
output.writeCompressedInt (0);
|
||||
}
|
||||
|
||||
constexpr explicit VariantType (ObjectTag) noexcept
|
||||
: isObject (true),
|
||||
toString (objectToString),
|
||||
toBool (objectToBool),
|
||||
toObject (objectToObject),
|
||||
clone (objectClone),
|
||||
cleanUp (objectCleanUp),
|
||||
createCopy (objectCreateCopy),
|
||||
equals (objectEquals),
|
||||
writeToStream (objectWriteToStream) {}
|
||||
|
||||
// array =======================================================================
|
||||
static String arrayToString (const ValueUnion&) { return "[Array]"; }
|
||||
static ReferenceCountedObject* arrayToObject (const ValueUnion&) noexcept { return nullptr; }
|
||||
|
||||
static Array<var>* arrayToArray (const ValueUnion& data) noexcept
|
||||
{
|
||||
if (auto* a = dynamic_cast<RefCountedArray*> (data.objectValue))
|
||||
return &(a->array);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool arrayEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
|
||||
{
|
||||
auto* thisArray = arrayToArray (data);
|
||||
auto* otherArray = otherType.toArray (otherData);
|
||||
return thisArray == otherArray || (thisArray != nullptr && otherArray != nullptr && *otherArray == *thisArray);
|
||||
}
|
||||
|
||||
static var arrayClone (const var& original)
|
||||
{
|
||||
Array<var> arrayCopy;
|
||||
|
||||
if (auto* array = arrayToArray (original.value))
|
||||
{
|
||||
arrayCopy.ensureStorageAllocated (array->size());
|
||||
|
||||
for (auto& i : *array)
|
||||
arrayCopy.add (i.clone());
|
||||
}
|
||||
|
||||
return var (arrayCopy);
|
||||
}
|
||||
|
||||
static void arrayWriteToStream (const ValueUnion& data, OutputStream& output)
|
||||
{
|
||||
if (auto* array = arrayToArray (data))
|
||||
{
|
||||
MemoryOutputStream buffer (512);
|
||||
buffer.writeCompressedInt (array->size());
|
||||
|
||||
for (auto& i : *array)
|
||||
i.writeToStream (buffer);
|
||||
|
||||
output.writeCompressedInt (1 + (int) buffer.getDataSize());
|
||||
output.writeByte (varMarker_Array);
|
||||
output << buffer;
|
||||
}
|
||||
}
|
||||
|
||||
struct RefCountedArray : public ReferenceCountedObject
|
||||
{
|
||||
RefCountedArray (const Array<var>& a) : array (a) { incReferenceCount(); }
|
||||
RefCountedArray (Array<var>&& a) : array (std::move (a)) { incReferenceCount(); }
|
||||
Array<var> array;
|
||||
};
|
||||
|
||||
constexpr explicit VariantType (ArrayTag) noexcept
|
||||
: isObject (true),
|
||||
isArray (true),
|
||||
toString (arrayToString),
|
||||
toBool (objectToBool),
|
||||
toObject (arrayToObject),
|
||||
toArray (arrayToArray),
|
||||
clone (arrayClone),
|
||||
cleanUp (objectCleanUp),
|
||||
createCopy (objectCreateCopy),
|
||||
equals (arrayEquals),
|
||||
writeToStream (arrayWriteToStream) {}
|
||||
|
||||
// binary ======================================================================
|
||||
static void binaryCleanUp (ValueUnion& data) noexcept { delete data.binaryValue; }
|
||||
static void binaryCreateCopy (ValueUnion& dest, const ValueUnion& source) { dest.binaryValue = new MemoryBlock (*source.binaryValue); }
|
||||
|
||||
static String binaryToString (const ValueUnion& data) { return data.binaryValue->toBase64Encoding(); }
|
||||
static MemoryBlock* binaryToBinary (const ValueUnion& data) noexcept { return data.binaryValue; }
|
||||
|
||||
static bool binaryEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
|
||||
{
|
||||
const MemoryBlock* const otherBlock = otherType.toBinary (otherData);
|
||||
return otherBlock != nullptr && *otherBlock == *data.binaryValue;
|
||||
}
|
||||
|
||||
static void binaryWriteToStream (const ValueUnion& data, OutputStream& output)
|
||||
{
|
||||
output.writeCompressedInt (1 + (int) data.binaryValue->getSize());
|
||||
output.writeByte (varMarker_Binary);
|
||||
output << *data.binaryValue;
|
||||
}
|
||||
|
||||
constexpr explicit VariantType (BinaryTag) noexcept
|
||||
: isBinary (true),
|
||||
toString (binaryToString),
|
||||
toBinary (binaryToBinary),
|
||||
cleanUp (binaryCleanUp),
|
||||
createCopy (binaryCreateCopy),
|
||||
equals (binaryEquals),
|
||||
writeToStream (binaryWriteToStream) {}
|
||||
|
||||
// method ======================================================================
|
||||
static void methodCleanUp (ValueUnion& data) noexcept { if (data.methodValue != nullptr ) delete data.methodValue; }
|
||||
static void methodCreateCopy (ValueUnion& dest, const ValueUnion& source) { dest.methodValue = new NativeFunction (*source.methodValue); }
|
||||
|
||||
static String methodToString (const ValueUnion&) { return "Method"; }
|
||||
static bool methodToBool (const ValueUnion& data) noexcept { return data.methodValue != nullptr; }
|
||||
|
||||
static bool methodEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept
|
||||
{
|
||||
return otherType.isMethod && otherData.methodValue == data.methodValue;
|
||||
}
|
||||
|
||||
static void methodWriteToStream (const ValueUnion&, OutputStream& output)
|
||||
{
|
||||
jassertfalse; // Can't write a method to a stream!
|
||||
output.writeCompressedInt (0);
|
||||
}
|
||||
|
||||
constexpr explicit VariantType (MethodTag) noexcept
|
||||
: isMethod (true),
|
||||
toString (methodToString),
|
||||
toBool (methodToBool),
|
||||
cleanUp (methodCleanUp),
|
||||
createCopy (methodCreateCopy),
|
||||
equals (methodEquals),
|
||||
writeToStream (methodWriteToStream) {}
|
||||
};
|
||||
|
||||
struct var::Instance
|
||||
{
|
||||
static constexpr VariantType attributesVoid { VariantType::VoidTag{} };
|
||||
static constexpr VariantType attributesUndefined { VariantType::UndefinedTag{} };
|
||||
static constexpr VariantType attributesInt { VariantType::IntTag{} };
|
||||
static constexpr VariantType attributesInt64 { VariantType::Int64Tag{} };
|
||||
static constexpr VariantType attributesBool { VariantType::BoolTag{} };
|
||||
static constexpr VariantType attributesDouble { VariantType::DoubleTag{} };
|
||||
static constexpr VariantType attributesMethod { VariantType::MethodTag{} };
|
||||
static constexpr VariantType attributesArray { VariantType::ArrayTag{} };
|
||||
static constexpr VariantType attributesString { VariantType::StringTag{} };
|
||||
static constexpr VariantType attributesBinary { VariantType::BinaryTag{} };
|
||||
static constexpr VariantType attributesObject { VariantType::ObjectTag{} };
|
||||
};
|
||||
|
||||
constexpr var::VariantType var::Instance::attributesVoid;
|
||||
constexpr var::VariantType var::Instance::attributesUndefined;
|
||||
constexpr var::VariantType var::Instance::attributesInt;
|
||||
constexpr var::VariantType var::Instance::attributesInt64;
|
||||
constexpr var::VariantType var::Instance::attributesBool;
|
||||
constexpr var::VariantType var::Instance::attributesDouble;
|
||||
constexpr var::VariantType var::Instance::attributesMethod;
|
||||
constexpr var::VariantType var::Instance::attributesArray;
|
||||
constexpr var::VariantType var::Instance::attributesString;
|
||||
constexpr var::VariantType var::Instance::attributesBinary;
|
||||
constexpr var::VariantType var::Instance::attributesObject;
|
||||
|
||||
//==============================================================================
|
||||
var::var() noexcept : type (&Instance::attributesVoid) {}
|
||||
var::var (const VariantType& t) noexcept : type (&t) {}
|
||||
var::~var() noexcept { type->cleanUp (value); }
|
||||
|
||||
//==============================================================================
|
||||
var::var (const var& valueToCopy) : type (valueToCopy.type)
|
||||
{
|
||||
type->createCopy (value, valueToCopy.value);
|
||||
}
|
||||
|
||||
var::var (const int v) noexcept : type (&Instance::attributesInt) { value.intValue = v; }
|
||||
var::var (const int64 v) noexcept : type (&Instance::attributesInt64) { value.int64Value = v; }
|
||||
var::var (const bool v) noexcept : type (&Instance::attributesBool) { value.boolValue = v; }
|
||||
var::var (const double v) noexcept : type (&Instance::attributesDouble) { value.doubleValue = v; }
|
||||
var::var (NativeFunction m) noexcept : type (&Instance::attributesMethod) { value.methodValue = new NativeFunction (m); }
|
||||
var::var (const Array<var>& v) : type (&Instance::attributesArray) { value.objectValue = new VariantType::RefCountedArray (v); }
|
||||
var::var (const String& v) : type (&Instance::attributesString) { new (value.stringValue) String (v); }
|
||||
var::var (const char* const v) : type (&Instance::attributesString) { new (value.stringValue) String (v); }
|
||||
var::var (const wchar_t* const v) : type (&Instance::attributesString) { new (value.stringValue) String (v); }
|
||||
var::var (const void* v, size_t sz) : type (&Instance::attributesBinary) { value.binaryValue = new MemoryBlock (v, sz); }
|
||||
var::var (const MemoryBlock& v) : type (&Instance::attributesBinary) { value.binaryValue = new MemoryBlock (v); }
|
||||
|
||||
var::var (const StringArray& v) : type (&Instance::attributesArray)
|
||||
{
|
||||
Array<var> strings;
|
||||
strings.ensureStorageAllocated (v.size());
|
||||
|
||||
for (auto& i : v)
|
||||
strings.add (var (i));
|
||||
|
||||
value.objectValue = new VariantType::RefCountedArray (strings);
|
||||
}
|
||||
|
||||
var::var (ReferenceCountedObject* const object) : type (&Instance::attributesObject)
|
||||
{
|
||||
value.objectValue = object;
|
||||
|
||||
if (object != nullptr)
|
||||
object->incReferenceCount();
|
||||
}
|
||||
|
||||
var var::undefined() noexcept { return var (Instance::attributesUndefined); }
|
||||
|
||||
//==============================================================================
|
||||
bool var::isVoid() const noexcept { return type->isVoid; }
|
||||
bool var::isUndefined() const noexcept { return type->isUndefined; }
|
||||
bool var::isInt() const noexcept { return type->isInt; }
|
||||
bool var::isInt64() const noexcept { return type->isInt64; }
|
||||
bool var::isBool() const noexcept { return type->isBool; }
|
||||
bool var::isDouble() const noexcept { return type->isDouble; }
|
||||
bool var::isString() const noexcept { return type->isString; }
|
||||
bool var::isObject() const noexcept { return type->isObject; }
|
||||
bool var::isArray() const noexcept { return type->isArray; }
|
||||
bool var::isBinaryData() const noexcept { return type->isBinary; }
|
||||
bool var::isMethod() const noexcept { return type->isMethod; }
|
||||
|
||||
var::operator int() const noexcept { return type->toInt (value); }
|
||||
var::operator int64() const noexcept { return type->toInt64 (value); }
|
||||
var::operator bool() const noexcept { return type->toBool (value); }
|
||||
var::operator float() const noexcept { return (float) type->toDouble (value); }
|
||||
var::operator double() const noexcept { return type->toDouble (value); }
|
||||
String var::toString() const { return type->toString (value); }
|
||||
var::operator String() const { return type->toString (value); }
|
||||
ReferenceCountedObject* var::getObject() const noexcept { return type->toObject (value); }
|
||||
Array<var>* var::getArray() const noexcept { return type->toArray (value); }
|
||||
MemoryBlock* var::getBinaryData() const noexcept { return type->toBinary (value); }
|
||||
DynamicObject* var::getDynamicObject() const noexcept { return dynamic_cast<DynamicObject*> (getObject()); }
|
||||
|
||||
//==============================================================================
|
||||
void var::swapWith (var& other) noexcept
|
||||
{
|
||||
std::swap (type, other.type);
|
||||
std::swap (value, other.value);
|
||||
}
|
||||
|
||||
var& var::operator= (const var& v) { type->cleanUp (value); type = v.type; type->createCopy (value, v.value); return *this; }
|
||||
var& var::operator= (const int v) { type->cleanUp (value); type = &Instance::attributesInt; value.intValue = v; return *this; }
|
||||
var& var::operator= (const int64 v) { type->cleanUp (value); type = &Instance::attributesInt64; value.int64Value = v; return *this; }
|
||||
var& var::operator= (const bool v) { type->cleanUp (value); type = &Instance::attributesBool; value.boolValue = v; return *this; }
|
||||
var& var::operator= (const double v) { type->cleanUp (value); type = &Instance::attributesDouble; value.doubleValue = v; return *this; }
|
||||
var& var::operator= (const char* const v) { type->cleanUp (value); type = &Instance::attributesString; new (value.stringValue) String (v); return *this; }
|
||||
var& var::operator= (const wchar_t* const v) { type->cleanUp (value); type = &Instance::attributesString; new (value.stringValue) String (v); return *this; }
|
||||
var& var::operator= (const String& v) { type->cleanUp (value); type = &Instance::attributesString; new (value.stringValue) String (v); return *this; }
|
||||
var& var::operator= (const MemoryBlock& v) { type->cleanUp (value); type = &Instance::attributesBinary; value.binaryValue = new MemoryBlock (v); return *this; }
|
||||
var& var::operator= (const Array<var>& v) { var v2 (v); swapWith (v2); return *this; }
|
||||
var& var::operator= (ReferenceCountedObject* v) { var v2 (v); swapWith (v2); return *this; }
|
||||
var& var::operator= (NativeFunction v) { var v2 (v); swapWith (v2); return *this; }
|
||||
|
||||
var::var (var&& other) noexcept
|
||||
: type (other.type),
|
||||
value (other.value)
|
||||
{
|
||||
other.type = &Instance::attributesVoid;
|
||||
}
|
||||
|
||||
var& var::operator= (var&& other) noexcept
|
||||
{
|
||||
swapWith (other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
var::var (String&& v) : type (&Instance::attributesString)
|
||||
{
|
||||
new (value.stringValue) String (std::move (v));
|
||||
}
|
||||
|
||||
var::var (MemoryBlock&& v) : type (&Instance::attributesBinary)
|
||||
{
|
||||
value.binaryValue = new MemoryBlock (std::move (v));
|
||||
}
|
||||
|
||||
var::var (Array<var>&& v) : type (&Instance::attributesArray)
|
||||
{
|
||||
value.objectValue = new VariantType::RefCountedArray (std::move (v));
|
||||
}
|
||||
|
||||
var& var::operator= (String&& v)
|
||||
{
|
||||
type->cleanUp (value);
|
||||
type = &Instance::attributesString;
|
||||
new (value.stringValue) String (std::move (v));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool var::equals (const var& other) const noexcept
|
||||
{
|
||||
return type->equals (value, other.value, *other.type);
|
||||
}
|
||||
|
||||
bool var::equalsWithSameType (const var& other) const noexcept
|
||||
{
|
||||
return hasSameTypeAs (other) && equals (other);
|
||||
}
|
||||
|
||||
bool var::hasSameTypeAs (const var& other) const noexcept
|
||||
{
|
||||
return type == other.type;
|
||||
}
|
||||
|
||||
bool canCompare (const var& v1, const var& v2)
|
||||
{
|
||||
return v1.type->isComparable && v2.type->isComparable;
|
||||
}
|
||||
|
||||
static int compare (const var& v1, const var& v2)
|
||||
{
|
||||
if (v1.isString() && v2.isString())
|
||||
return v1.toString().compare (v2.toString());
|
||||
|
||||
auto diff = static_cast<double> (v1) - static_cast<double> (v2);
|
||||
return diff == 0 ? 0 : (diff < 0 ? -1 : 1);
|
||||
}
|
||||
|
||||
bool operator== (const var& v1, const var& v2) { return v1.equals (v2); }
|
||||
bool operator!= (const var& v1, const var& v2) { return ! v1.equals (v2); }
|
||||
bool operator< (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) < 0; }
|
||||
bool operator> (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) > 0; }
|
||||
bool operator<= (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) <= 0; }
|
||||
bool operator>= (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) >= 0; }
|
||||
|
||||
bool operator== (const var& v1, const String& v2) { return v1.toString() == v2; }
|
||||
bool operator!= (const var& v1, const String& v2) { return v1.toString() != v2; }
|
||||
bool operator== (const var& v1, const char* v2) { return v1.toString() == v2; }
|
||||
bool operator!= (const var& v1, const char* v2) { return v1.toString() != v2; }
|
||||
|
||||
//==============================================================================
|
||||
var var::clone() const noexcept
|
||||
{
|
||||
return type->clone (*this);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const var& var::operator[] (const Identifier& propertyName) const
|
||||
{
|
||||
if (auto* o = getDynamicObject())
|
||||
return o->getProperty (propertyName);
|
||||
|
||||
return getNullVarRef();
|
||||
}
|
||||
|
||||
const var& var::operator[] (const char* const propertyName) const
|
||||
{
|
||||
return operator[] (Identifier (propertyName));
|
||||
}
|
||||
|
||||
var var::getProperty (const Identifier& propertyName, const var& defaultReturnValue) const
|
||||
{
|
||||
if (auto* o = getDynamicObject())
|
||||
return o->getProperties().getWithDefault (propertyName, defaultReturnValue);
|
||||
|
||||
return defaultReturnValue;
|
||||
}
|
||||
|
||||
bool var::hasProperty (const Identifier& propertyName) const noexcept
|
||||
{
|
||||
if (auto* o = getDynamicObject())
|
||||
return o->hasProperty (propertyName);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var::NativeFunction var::getNativeFunction() const
|
||||
{
|
||||
return isMethod() && (value.methodValue != nullptr) ? *value.methodValue : nullptr;
|
||||
}
|
||||
|
||||
var var::invoke (const Identifier& method, const var* arguments, int numArguments) const
|
||||
{
|
||||
if (auto* o = getDynamicObject())
|
||||
return o->invokeMethod (method, var::NativeFunctionArgs (*this, arguments, numArguments));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
var var::call (const Identifier& method) const
|
||||
{
|
||||
return invoke (method, nullptr, 0);
|
||||
}
|
||||
|
||||
var var::call (const Identifier& method, const var& arg1) const
|
||||
{
|
||||
return invoke (method, &arg1, 1);
|
||||
}
|
||||
|
||||
var var::call (const Identifier& method, const var& arg1, const var& arg2) const
|
||||
{
|
||||
var args[] = { arg1, arg2 };
|
||||
return invoke (method, args, 2);
|
||||
}
|
||||
|
||||
var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3)
|
||||
{
|
||||
var args[] = { arg1, arg2, arg3 };
|
||||
return invoke (method, args, 3);
|
||||
}
|
||||
|
||||
var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const
|
||||
{
|
||||
var args[] = { arg1, arg2, arg3, arg4 };
|
||||
return invoke (method, args, 4);
|
||||
}
|
||||
|
||||
var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const
|
||||
{
|
||||
var args[] = { arg1, arg2, arg3, arg4, arg5 };
|
||||
return invoke (method, args, 5);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int var::size() const
|
||||
{
|
||||
if (auto array = getArray())
|
||||
return array->size();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const var& var::operator[] (int arrayIndex) const
|
||||
{
|
||||
auto array = getArray();
|
||||
|
||||
// When using this method, the var must actually be an array, and the index
|
||||
// must be in-range!
|
||||
jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
|
||||
|
||||
return array->getReference (arrayIndex);
|
||||
}
|
||||
|
||||
var& var::operator[] (int arrayIndex)
|
||||
{
|
||||
auto array = getArray();
|
||||
|
||||
// When using this method, the var must actually be an array, and the index
|
||||
// must be in-range!
|
||||
jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
|
||||
|
||||
return array->getReference (arrayIndex);
|
||||
}
|
||||
|
||||
Array<var>* var::convertToArray()
|
||||
{
|
||||
if (auto array = getArray())
|
||||
return array;
|
||||
|
||||
Array<var> tempVar;
|
||||
|
||||
if (! isVoid())
|
||||
tempVar.add (*this);
|
||||
|
||||
*this = tempVar;
|
||||
return getArray();
|
||||
}
|
||||
|
||||
void var::append (const var& n)
|
||||
{
|
||||
convertToArray()->add (n);
|
||||
}
|
||||
|
||||
void var::remove (const int index)
|
||||
{
|
||||
if (auto array = getArray())
|
||||
array->remove (index);
|
||||
}
|
||||
|
||||
void var::insert (const int index, const var& n)
|
||||
{
|
||||
convertToArray()->insert (index, n);
|
||||
}
|
||||
|
||||
void var::resize (const int numArrayElementsWanted)
|
||||
{
|
||||
convertToArray()->resize (numArrayElementsWanted);
|
||||
}
|
||||
|
||||
int var::indexOf (const var& n) const
|
||||
{
|
||||
if (auto array = getArray())
|
||||
return array->indexOf (n);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void var::writeToStream (OutputStream& output) const
|
||||
{
|
||||
type->writeToStream (value, output);
|
||||
}
|
||||
|
||||
var var::readFromStream (InputStream& input)
|
||||
{
|
||||
const int numBytes = input.readCompressedInt();
|
||||
|
||||
if (numBytes > 0)
|
||||
{
|
||||
switch (input.readByte())
|
||||
{
|
||||
case varMarker_Int: return var (input.readInt());
|
||||
case varMarker_Int64: return var (input.readInt64());
|
||||
case varMarker_BoolTrue: return var (true);
|
||||
case varMarker_BoolFalse: return var (false);
|
||||
case varMarker_Double: return var (input.readDouble());
|
||||
|
||||
case varMarker_String:
|
||||
{
|
||||
MemoryOutputStream mo;
|
||||
mo.writeFromInputStream (input, numBytes - 1);
|
||||
return var (mo.toUTF8());
|
||||
}
|
||||
|
||||
case varMarker_Binary:
|
||||
{
|
||||
MemoryBlock mb ((size_t) numBytes - 1);
|
||||
|
||||
if (numBytes > 1)
|
||||
{
|
||||
const int numRead = input.read (mb.getData(), numBytes - 1);
|
||||
mb.setSize ((size_t) numRead);
|
||||
}
|
||||
|
||||
return var (mb);
|
||||
}
|
||||
|
||||
case varMarker_Array:
|
||||
{
|
||||
var v;
|
||||
auto* destArray = v.convertToArray();
|
||||
|
||||
for (int i = input.readCompressedInt(); --i >= 0;)
|
||||
destArray->add (readFromStream (input));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
default:
|
||||
input.skipNextBytes (numBytes - 1); break;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
var::NativeFunctionArgs::NativeFunctionArgs (const var& t, const var* args, int numArgs) noexcept
|
||||
: thisObject (t), arguments (args), numArguments (numArgs)
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_ALLOW_STATIC_NULL_VARIABLES
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
|
||||
|
||||
const var var::null;
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
354
deps/juce/modules/juce_core/containers/juce_Variant.h
vendored
Normal file
354
deps/juce/modules/juce_core/containers/juce_Variant.h
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 variant class, that can be used to hold a range of primitive values.
|
||||
|
||||
A var object can hold a range of simple primitive values, strings, or
|
||||
any kind of ReferenceCountedObject. The var class is intended to act like
|
||||
the kind of values used in dynamic scripting languages.
|
||||
|
||||
You can save/load var objects either in a small, proprietary binary format
|
||||
using writeToStream()/readFromStream(), or as JSON by using the JSON class.
|
||||
|
||||
@see JSON, DynamicObject
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API var
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** This structure is passed to a NativeFunction callback, and contains invocation
|
||||
details about the function's arguments and context.
|
||||
*/
|
||||
struct JUCE_API NativeFunctionArgs
|
||||
{
|
||||
NativeFunctionArgs (const var& thisObject, const var* args, int numArgs) noexcept;
|
||||
|
||||
const var& thisObject;
|
||||
const var* arguments;
|
||||
int numArguments;
|
||||
};
|
||||
|
||||
using NativeFunction = std::function<var (const NativeFunctionArgs&)>;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a void variant. */
|
||||
var() noexcept;
|
||||
|
||||
/** Destructor. */
|
||||
~var() noexcept;
|
||||
|
||||
var (const var& valueToCopy);
|
||||
var (int value) noexcept;
|
||||
var (int64 value) noexcept;
|
||||
var (bool value) noexcept;
|
||||
var (double value) noexcept;
|
||||
var (const char* value);
|
||||
var (const wchar_t* value);
|
||||
var (const String& value);
|
||||
var (const Array<var>& value);
|
||||
var (const StringArray& value);
|
||||
var (ReferenceCountedObject* object);
|
||||
var (NativeFunction method) noexcept;
|
||||
var (const void* binaryData, size_t dataSize);
|
||||
var (const MemoryBlock& binaryData);
|
||||
|
||||
var& operator= (const var& valueToCopy);
|
||||
var& operator= (int value);
|
||||
var& operator= (int64 value);
|
||||
var& operator= (bool value);
|
||||
var& operator= (double value);
|
||||
var& operator= (const char* value);
|
||||
var& operator= (const wchar_t* value);
|
||||
var& operator= (const String& value);
|
||||
var& operator= (const MemoryBlock& value);
|
||||
var& operator= (const Array<var>& value);
|
||||
var& operator= (ReferenceCountedObject* object);
|
||||
var& operator= (NativeFunction method);
|
||||
|
||||
var (var&&) noexcept;
|
||||
var (String&&);
|
||||
var (MemoryBlock&&);
|
||||
var (Array<var>&&);
|
||||
var& operator= (var&&) noexcept;
|
||||
var& operator= (String&&);
|
||||
|
||||
void swapWith (var& other) noexcept;
|
||||
|
||||
/** Returns a var object that can be used where you need the javascript "undefined" value. */
|
||||
static var undefined() noexcept;
|
||||
|
||||
//==============================================================================
|
||||
operator int() const noexcept;
|
||||
operator int64() const noexcept;
|
||||
operator bool() const noexcept;
|
||||
operator float() const noexcept;
|
||||
operator double() const noexcept;
|
||||
operator String() const;
|
||||
String toString() const;
|
||||
|
||||
/** If this variant holds an array, this provides access to it.
|
||||
NOTE: Beware when you use this - the array pointer is only valid for the lifetime
|
||||
of the variant that returned it, so be very careful not to call this method on temporary
|
||||
var objects that are the return-value of a function, and which may go out of scope before
|
||||
you use the array!
|
||||
*/
|
||||
Array<var>* getArray() const noexcept;
|
||||
|
||||
/** If this variant holds a memory block, this provides access to it.
|
||||
NOTE: Beware when you use this - the MemoryBlock pointer is only valid for the lifetime
|
||||
of the variant that returned it, so be very careful not to call this method on temporary
|
||||
var objects that are the return-value of a function, and which may go out of scope before
|
||||
you use the MemoryBlock!
|
||||
*/
|
||||
MemoryBlock* getBinaryData() const noexcept;
|
||||
|
||||
ReferenceCountedObject* getObject() const noexcept;
|
||||
DynamicObject* getDynamicObject() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
bool isVoid() const noexcept;
|
||||
bool isUndefined() const noexcept;
|
||||
bool isInt() const noexcept;
|
||||
bool isInt64() const noexcept;
|
||||
bool isBool() const noexcept;
|
||||
bool isDouble() const noexcept;
|
||||
bool isString() const noexcept;
|
||||
bool isObject() const noexcept;
|
||||
bool isArray() const noexcept;
|
||||
bool isBinaryData() const noexcept;
|
||||
bool isMethod() const noexcept;
|
||||
|
||||
/** Returns true if this var has the same value as the one supplied.
|
||||
Note that this ignores the type, so a string var "123" and an integer var with the
|
||||
value 123 are considered to be equal.
|
||||
@see equalsWithSameType
|
||||
*/
|
||||
bool equals (const var& other) const noexcept;
|
||||
|
||||
/** Returns true if this var has the same value and type as the one supplied.
|
||||
This differs from equals() because e.g. "123" and 123 will be considered different.
|
||||
@see equals
|
||||
*/
|
||||
bool equalsWithSameType (const var& other) const noexcept;
|
||||
|
||||
/** Returns true if this var has the same type as the one supplied. */
|
||||
bool hasSameTypeAs (const var& other) const noexcept;
|
||||
|
||||
/** Returns a deep copy of this object.
|
||||
For simple types this just returns a copy, but if the object contains any arrays
|
||||
or DynamicObjects, they will be cloned (recursively).
|
||||
*/
|
||||
var clone() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** If the var is an array, this returns the number of elements.
|
||||
If the var isn't actually an array, this will return 0.
|
||||
*/
|
||||
int size() const;
|
||||
|
||||
/** If the var is an array, this can be used to return one of its elements.
|
||||
To call this method, you must make sure that the var is actually an array, and
|
||||
that the index is a valid number. If these conditions aren't met, behaviour is
|
||||
undefined.
|
||||
For more control over the array's contents, you can call getArray() and manipulate
|
||||
it directly as an Array\<var\>.
|
||||
*/
|
||||
const var& operator[] (int arrayIndex) const;
|
||||
|
||||
/** If the var is an array, this can be used to return one of its elements.
|
||||
To call this method, you must make sure that the var is actually an array, and
|
||||
that the index is a valid number. If these conditions aren't met, behaviour is
|
||||
undefined.
|
||||
For more control over the array's contents, you can call getArray() and manipulate
|
||||
it directly as an Array\<var\>.
|
||||
*/
|
||||
var& operator[] (int arrayIndex);
|
||||
|
||||
/** Appends an element to the var, converting it to an array if it isn't already one.
|
||||
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
||||
this value will be kept as the first element of the new array. The parameter value
|
||||
will then be appended to it.
|
||||
For more control over the array's contents, you can call getArray() and manipulate
|
||||
it directly as an Array\<var\>.
|
||||
*/
|
||||
void append (const var& valueToAppend);
|
||||
|
||||
/** Inserts an element to the var, converting it to an array if it isn't already one.
|
||||
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
||||
this value will be kept as the first element of the new array. The parameter value
|
||||
will then be inserted into it.
|
||||
For more control over the array's contents, you can call getArray() and manipulate
|
||||
it directly as an Array\<var\>.
|
||||
*/
|
||||
void insert (int index, const var& value);
|
||||
|
||||
/** If the var is an array, this removes one of its elements.
|
||||
If the index is out-of-range or the var isn't an array, nothing will be done.
|
||||
For more control over the array's contents, you can call getArray() and manipulate
|
||||
it directly as an Array\<var\>.
|
||||
*/
|
||||
void remove (int index);
|
||||
|
||||
/** Treating the var as an array, this resizes it to contain the specified number of elements.
|
||||
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
||||
this value will be kept as the first element of the new array before resizing.
|
||||
For more control over the array's contents, you can call getArray() and manipulate
|
||||
it directly as an Array\<var\>.
|
||||
*/
|
||||
void resize (int numArrayElementsWanted);
|
||||
|
||||
/** If the var is an array, this searches it for the first occurrence of the specified value,
|
||||
and returns its index.
|
||||
If the var isn't an array, or if the value isn't found, this returns -1.
|
||||
*/
|
||||
int indexOf (const var& value) const;
|
||||
|
||||
//==============================================================================
|
||||
/** If this variant is an object, this returns one of its properties. */
|
||||
const var& operator[] (const Identifier& propertyName) const;
|
||||
/** If this variant is an object, this returns one of its properties. */
|
||||
const var& operator[] (const char* propertyName) const;
|
||||
/** If this variant is an object, this returns one of its properties, or a default
|
||||
fallback value if the property is not set. */
|
||||
var getProperty (const Identifier& propertyName, const var& defaultReturnValue) const;
|
||||
/** Returns true if this variant is an object and if it has the given property. */
|
||||
bool hasProperty (const Identifier& propertyName) const noexcept;
|
||||
|
||||
/** Invokes a named method call with no arguments. */
|
||||
var call (const Identifier& method) const;
|
||||
/** Invokes a named method call with one argument. */
|
||||
var call (const Identifier& method, const var& arg1) const;
|
||||
/** Invokes a named method call with 2 arguments. */
|
||||
var call (const Identifier& method, const var& arg1, const var& arg2) const;
|
||||
/** Invokes a named method call with 3 arguments. */
|
||||
var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3);
|
||||
/** Invokes a named method call with 4 arguments. */
|
||||
var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const;
|
||||
/** Invokes a named method call with 5 arguments. */
|
||||
var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const;
|
||||
/** Invokes a named method call with a list of arguments. */
|
||||
var invoke (const Identifier& method, const var* arguments, int numArguments) const;
|
||||
/** If this object is a method, this returns the function pointer. */
|
||||
NativeFunction getNativeFunction() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Writes a binary representation of this value to a stream.
|
||||
The data can be read back later using readFromStream().
|
||||
@see JSON
|
||||
*/
|
||||
void writeToStream (OutputStream& output) const;
|
||||
|
||||
/** Reads back a stored binary representation of a value.
|
||||
The data in the stream must have been written using writeToStream(), or this
|
||||
will have unpredictable results.
|
||||
@see JSON
|
||||
*/
|
||||
static var readFromStream (InputStream& input);
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_ALLOW_STATIC_NULL_VARIABLES && ! defined (DOXYGEN)
|
||||
[[deprecated ("This was a static empty var object, but is now deprecated as it's too easy to accidentally "
|
||||
"use it indirectly during a static constructor leading to hard-to-find order-of-initialisation "
|
||||
"problems. Use var() or {} instead. For returning an empty var from a function by reference, "
|
||||
"use a function-local static var and return that.")]]
|
||||
static const var null;
|
||||
#endif
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct VariantType;
|
||||
struct Instance;
|
||||
|
||||
union ValueUnion
|
||||
{
|
||||
int intValue;
|
||||
int64 int64Value;
|
||||
bool boolValue;
|
||||
double doubleValue;
|
||||
char stringValue[sizeof (String)];
|
||||
ReferenceCountedObject* objectValue;
|
||||
MemoryBlock* binaryValue;
|
||||
NativeFunction* methodValue;
|
||||
};
|
||||
|
||||
friend bool canCompare (const var&, const var&);
|
||||
|
||||
const VariantType* type;
|
||||
ValueUnion value;
|
||||
|
||||
Array<var>* convertToArray();
|
||||
var (const VariantType&) noexcept;
|
||||
|
||||
// This is needed to prevent the wrong constructor/operator being called
|
||||
var (const ReferenceCountedObject*) = delete;
|
||||
var& operator= (const ReferenceCountedObject*) = delete;
|
||||
var (const void*) = delete;
|
||||
var& operator= (const void*) = delete;
|
||||
};
|
||||
|
||||
/** Compares the values of two var objects, using the var::equals() comparison. */
|
||||
JUCE_API bool operator== (const var&, const var&);
|
||||
/** Compares the values of two var objects, using the var::equals() comparison. */
|
||||
JUCE_API bool operator!= (const var&, const var&);
|
||||
/** Compares the values of two var objects, using the var::equals() comparison. */
|
||||
JUCE_API bool operator< (const var&, const var&);
|
||||
/** Compares the values of two var objects, using the var::equals() comparison. */
|
||||
JUCE_API bool operator<= (const var&, const var&);
|
||||
/** Compares the values of two var objects, using the var::equals() comparison. */
|
||||
JUCE_API bool operator> (const var&, const var&);
|
||||
/** Compares the values of two var objects, using the var::equals() comparison. */
|
||||
JUCE_API bool operator>= (const var&, const var&);
|
||||
|
||||
JUCE_API bool operator== (const var&, const String&);
|
||||
JUCE_API bool operator!= (const var&, const String&);
|
||||
JUCE_API bool operator== (const var&, const char*);
|
||||
JUCE_API bool operator!= (const var&, const char*);
|
||||
|
||||
//==============================================================================
|
||||
/** This template-overloaded class can be used to convert between var and custom types.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <typename Type>
|
||||
struct VariantConverter
|
||||
{
|
||||
static Type fromVar (const var& v) { return static_cast<Type> (v); }
|
||||
static var toVar (const Type& t) { return t; }
|
||||
};
|
||||
|
||||
#ifndef DOXYGEN
|
||||
template <>
|
||||
struct VariantConverter<String>
|
||||
{
|
||||
static String fromVar (const var& v) { return v.toString(); }
|
||||
static var toVar (const String& s) { return s; }
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
150
deps/juce/modules/juce_core/files/juce_DirectoryIterator.cpp
vendored
Normal file
150
deps/juce/modules/juce_core/files/juce_DirectoryIterator.cpp
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
StringArray DirectoryIterator::parseWildcards (const String& pattern)
|
||||
{
|
||||
StringArray s;
|
||||
s.addTokens (pattern, ";,", "\"'");
|
||||
s.trim();
|
||||
s.removeEmptyStrings();
|
||||
return s;
|
||||
}
|
||||
|
||||
bool DirectoryIterator::fileMatches (const StringArray& wildcards, const String& filename)
|
||||
{
|
||||
for (auto& w : wildcards)
|
||||
if (filename.matchesWildcard (w, ! File::areFileNamesCaseSensitive()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DirectoryIterator::next()
|
||||
{
|
||||
return next (nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
|
||||
|
||||
bool DirectoryIterator::next (bool* isDirResult, bool* isHiddenResult, int64* fileSize,
|
||||
Time* modTime, Time* creationTime, bool* isReadOnly)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
hasBeenAdvanced = true;
|
||||
|
||||
if (subIterator != nullptr)
|
||||
{
|
||||
if (subIterator->next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly))
|
||||
return true;
|
||||
|
||||
subIterator.reset();
|
||||
}
|
||||
|
||||
String filename;
|
||||
bool isDirectory, isHidden = false, shouldContinue = false;
|
||||
|
||||
while (fileFinder.next (filename, &isDirectory,
|
||||
(isHiddenResult != nullptr || (whatToLookFor & File::ignoreHiddenFiles) != 0) ? &isHidden : nullptr,
|
||||
fileSize, modTime, creationTime, isReadOnly))
|
||||
{
|
||||
++index;
|
||||
|
||||
if (! filename.containsOnly ("."))
|
||||
{
|
||||
bool matches = false;
|
||||
|
||||
if (isDirectory)
|
||||
{
|
||||
if (isRecursive && ((whatToLookFor & File::ignoreHiddenFiles) == 0 || ! isHidden))
|
||||
subIterator.reset (new DirectoryIterator (File::createFileWithoutCheckingPath (path + filename),
|
||||
true, wildCard, whatToLookFor));
|
||||
|
||||
matches = (whatToLookFor & File::findDirectories) != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
matches = (whatToLookFor & File::findFiles) != 0;
|
||||
}
|
||||
|
||||
// if we're not relying on the OS iterator to do the wildcard match, do it now..
|
||||
if (matches && (isRecursive || wildCards.size() > 1))
|
||||
matches = fileMatches (wildCards, filename);
|
||||
|
||||
if (matches && (whatToLookFor & File::ignoreHiddenFiles) != 0)
|
||||
matches = ! isHidden;
|
||||
|
||||
if (matches)
|
||||
{
|
||||
currentFile = File::createFileWithoutCheckingPath (path + filename);
|
||||
if (isHiddenResult != nullptr) *isHiddenResult = isHidden;
|
||||
if (isDirResult != nullptr) *isDirResult = isDirectory;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (subIterator != nullptr)
|
||||
{
|
||||
shouldContinue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! shouldContinue)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
|
||||
const File& DirectoryIterator::getFile() const
|
||||
{
|
||||
if (subIterator != nullptr && subIterator->hasBeenAdvanced)
|
||||
return subIterator->getFile();
|
||||
|
||||
// You need to call DirectoryIterator::next() before asking it for the file that it found!
|
||||
jassert (hasBeenAdvanced);
|
||||
|
||||
return currentFile;
|
||||
}
|
||||
|
||||
float DirectoryIterator::getEstimatedProgress() const
|
||||
{
|
||||
if (totalNumFiles < 0)
|
||||
totalNumFiles = File (path).getNumberOfChildFiles (File::findFilesAndDirectories);
|
||||
|
||||
if (totalNumFiles <= 0)
|
||||
return 0.0f;
|
||||
|
||||
auto detailedIndex = (subIterator != nullptr) ? (float) index + subIterator->getEstimatedProgress()
|
||||
: (float) index;
|
||||
|
||||
return jlimit (0.0f, 1.0f, detailedIndex / (float) totalNumFiles);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
164
deps/juce/modules/juce_core/files/juce_DirectoryIterator.h
vendored
Normal file
164
deps/juce/modules/juce_core/files/juce_DirectoryIterator.h
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
This class is now deprecated in favour of RangedDirectoryIterator.
|
||||
|
||||
Searches through the files in a directory, returning each file that is found.
|
||||
|
||||
A DirectoryIterator will search through a directory and its subdirectories using
|
||||
a wildcard filepattern match.
|
||||
|
||||
If you may be scanning a large number of files, it's usually smarter to use this
|
||||
class than File::findChildFiles() because it allows you to stop at any time, rather
|
||||
than having to wait for the entire scan to finish before getting the results.
|
||||
|
||||
Please note that the order in which files are returned is completely undefined!
|
||||
They'll arrive in whatever order the underlying OS calls provide them, which will
|
||||
depend on the filesystem and other factors. If you need a sorted list, you'll need
|
||||
to manually sort them using your preferred comparator after collecting the list.
|
||||
|
||||
It also provides an estimate of its progress, using a (highly inaccurate!) algorithm.
|
||||
|
||||
@tags{Core}
|
||||
@see RangedDirectoryIterator
|
||||
*/
|
||||
class JUCE_API DirectoryIterator final
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a DirectoryIterator for a given directory.
|
||||
|
||||
After creating one of these, call its next() method to get the
|
||||
first file - e.g. @code
|
||||
|
||||
DirectoryIterator iter (File ("/animals/mooses"), true, "*.moose");
|
||||
|
||||
while (iter.next())
|
||||
{
|
||||
File theFileItFound (iter.getFile());
|
||||
|
||||
... etc
|
||||
}
|
||||
@endcode
|
||||
|
||||
@see RangedDirectoryIterator
|
||||
*/
|
||||
[[deprecated ("This class is now deprecated in favour of RangedDirectoryIterator.")]]
|
||||
DirectoryIterator (const File& directory,
|
||||
bool recursive,
|
||||
const String& pattern = "*",
|
||||
int type = File::findFiles)
|
||||
: wildCards (parseWildcards (pattern)),
|
||||
fileFinder (directory, (recursive || wildCards.size() > 1) ? "*" : pattern),
|
||||
wildCard (pattern),
|
||||
path (File::addTrailingSeparator (directory.getFullPathName())),
|
||||
whatToLookFor (type),
|
||||
isRecursive (recursive)
|
||||
{
|
||||
// you have to specify the type of files you're looking for!
|
||||
jassert ((whatToLookFor & (File::findFiles | File::findDirectories)) != 0);
|
||||
jassert (whatToLookFor > 0 && whatToLookFor <= 7);
|
||||
}
|
||||
|
||||
/** Moves the iterator along to the next file.
|
||||
|
||||
@returns true if a file was found (you can then use getFile() to see what it was) - or
|
||||
false if there are no more matching files.
|
||||
*/
|
||||
bool next();
|
||||
|
||||
/** Moves the iterator along to the next file, and returns various properties of that file.
|
||||
|
||||
If you need to find out details about the file, it's more efficient to call this method than
|
||||
to call the normal next() method and then find out the details afterwards.
|
||||
|
||||
All the parameters are optional, so pass null pointers for any items that you're not
|
||||
interested in.
|
||||
|
||||
@returns true if a file was found (you can then use getFile() to see what it was) - or
|
||||
false if there are no more matching files. If it returns false, then none of the
|
||||
parameters will be filled-in.
|
||||
*/
|
||||
bool next (bool* isDirectory,
|
||||
bool* isHidden,
|
||||
int64* fileSize,
|
||||
Time* modTime,
|
||||
Time* creationTime,
|
||||
bool* isReadOnly);
|
||||
|
||||
/** Returns the file that the iterator is currently pointing at.
|
||||
|
||||
The result of this call is only valid after a call to next() has returned true.
|
||||
*/
|
||||
const File& getFile() const;
|
||||
|
||||
/** Returns a guess of how far through the search the iterator has got.
|
||||
|
||||
@returns a value 0.0 to 1.0 to show the progress, although this won't be
|
||||
very accurate.
|
||||
*/
|
||||
float getEstimatedProgress() const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct NativeIterator
|
||||
{
|
||||
NativeIterator (const File& directory, const String& wildCard);
|
||||
~NativeIterator();
|
||||
|
||||
bool next (String& filenameFound,
|
||||
bool* isDirectory, bool* isHidden, int64* fileSize,
|
||||
Time* modTime, Time* creationTime, bool* isReadOnly);
|
||||
|
||||
class Pimpl;
|
||||
std::unique_ptr<Pimpl> pimpl;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeIterator)
|
||||
};
|
||||
|
||||
StringArray wildCards;
|
||||
NativeIterator fileFinder;
|
||||
String wildCard, path;
|
||||
int index = -1;
|
||||
mutable int totalNumFiles = -1;
|
||||
const int whatToLookFor;
|
||||
const bool isRecursive;
|
||||
bool hasBeenAdvanced = false;
|
||||
std::unique_ptr<DirectoryIterator> subIterator;
|
||||
File currentFile;
|
||||
|
||||
static StringArray parseWildcards (const String& pattern);
|
||||
static bool fileMatches (const StringArray& wildCards, const String& filename);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectoryIterator)
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
1281
deps/juce/modules/juce_core/files/juce_File.cpp
vendored
Normal file
1281
deps/juce/modules/juce_core/files/juce_File.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1137
deps/juce/modules/juce_core/files/juce_File.h
vendored
Normal file
1137
deps/juce/modules/juce_core/files/juce_File.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
40
deps/juce/modules/juce_core/files/juce_FileFilter.cpp
vendored
Normal file
40
deps/juce/modules/juce_core/files/juce_FileFilter.cpp
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
FileFilter::FileFilter (const String& filterDescription)
|
||||
: description (filterDescription)
|
||||
{
|
||||
}
|
||||
|
||||
FileFilter::~FileFilter()
|
||||
{
|
||||
}
|
||||
|
||||
const String& FileFilter::getDescription() const noexcept
|
||||
{
|
||||
return description;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
71
deps/juce/modules/juce_core/files/juce_FileFilter.h
vendored
Normal file
71
deps/juce/modules/juce_core/files/juce_FileFilter.h
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Interface for deciding which files are suitable for something.
|
||||
|
||||
For example, this is used by DirectoryContentsList to select which files
|
||||
go into the list.
|
||||
|
||||
@see WildcardFileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API FileFilter
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a filter with the given description.
|
||||
|
||||
The description can be returned later with the getDescription() method.
|
||||
*/
|
||||
FileFilter (const String& filterDescription);
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~FileFilter();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the description that the filter was created with. */
|
||||
const String& getDescription() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Should return true if this file is suitable for inclusion in whatever context
|
||||
the object is being used.
|
||||
*/
|
||||
virtual bool isFileSuitable (const File& file) const = 0;
|
||||
|
||||
/** Should return true if this directory is suitable for inclusion in whatever context
|
||||
the object is being used.
|
||||
*/
|
||||
virtual bool isDirectorySuitable (const File& file) const = 0;
|
||||
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
String description;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
177
deps/juce/modules/juce_core/files/juce_FileInputStream.cpp
vendored
Normal file
177
deps/juce/modules/juce_core/files/juce_FileInputStream.cpp
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
int64 juce_fileSetPosition (void* handle, int64 pos);
|
||||
|
||||
|
||||
//==============================================================================
|
||||
FileInputStream::FileInputStream (const File& f) : file (f)
|
||||
{
|
||||
openHandle();
|
||||
}
|
||||
|
||||
int64 FileInputStream::getTotalLength()
|
||||
{
|
||||
// You should always check that a stream opened successfully before using it!
|
||||
jassert (openedOk());
|
||||
|
||||
return file.getSize();
|
||||
}
|
||||
|
||||
int FileInputStream::read (void* buffer, int bytesToRead)
|
||||
{
|
||||
// You should always check that a stream opened successfully before using it!
|
||||
jassert (openedOk());
|
||||
|
||||
// The buffer should never be null, and a negative size is probably a
|
||||
// sign that something is broken!
|
||||
jassert (buffer != nullptr && bytesToRead >= 0);
|
||||
|
||||
auto num = readInternal (buffer, (size_t) bytesToRead);
|
||||
currentPosition += (int64) num;
|
||||
|
||||
return (int) num;
|
||||
}
|
||||
|
||||
bool FileInputStream::isExhausted()
|
||||
{
|
||||
return currentPosition >= getTotalLength();
|
||||
}
|
||||
|
||||
int64 FileInputStream::getPosition()
|
||||
{
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
bool FileInputStream::setPosition (int64 pos)
|
||||
{
|
||||
// You should always check that a stream opened successfully before using it!
|
||||
jassert (openedOk());
|
||||
|
||||
if (pos != currentPosition)
|
||||
currentPosition = juce_fileSetPosition (fileHandle, pos);
|
||||
|
||||
return currentPosition == pos;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
struct FileInputStreamTests : public UnitTest
|
||||
{
|
||||
FileInputStreamTests()
|
||||
: UnitTest ("FileInputStream", UnitTestCategories::streams)
|
||||
{}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("Open stream non-existent file");
|
||||
{
|
||||
auto tempFile = File::createTempFile (".txt");
|
||||
expect (! tempFile.exists());
|
||||
|
||||
FileInputStream stream (tempFile);
|
||||
expect (stream.failedToOpen());
|
||||
}
|
||||
|
||||
beginTest ("Open stream existing file");
|
||||
{
|
||||
auto tempFile = File::createTempFile (".txt");
|
||||
tempFile.create();
|
||||
expect (tempFile.exists());
|
||||
|
||||
FileInputStream stream (tempFile);
|
||||
expect (stream.openedOk());
|
||||
}
|
||||
|
||||
const MemoryBlock data ("abcdefghijklmnopqrstuvwxyz", 26);
|
||||
File f (File::createTempFile (".txt"));
|
||||
f.appendData (data.getData(), data.getSize());
|
||||
FileInputStream stream (f);
|
||||
|
||||
beginTest ("Read");
|
||||
{
|
||||
expectEquals (stream.getPosition(), (int64) 0);
|
||||
expectEquals (stream.getTotalLength(), (int64) data.getSize());
|
||||
expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
|
||||
expect (! stream.isExhausted());
|
||||
|
||||
size_t numBytesRead = 0;
|
||||
MemoryBlock readBuffer (data.getSize());
|
||||
|
||||
while (numBytesRead < data.getSize())
|
||||
{
|
||||
numBytesRead += (size_t) stream.read (&readBuffer[numBytesRead], 3);
|
||||
|
||||
expectEquals (stream.getPosition(), (int64) numBytesRead);
|
||||
expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
|
||||
expect (stream.isExhausted() == (numBytesRead == data.getSize()));
|
||||
}
|
||||
|
||||
expectEquals (stream.getPosition(), (int64) data.getSize());
|
||||
expectEquals (stream.getNumBytesRemaining(), (int64) 0);
|
||||
expect (stream.isExhausted());
|
||||
|
||||
expect (readBuffer == data);
|
||||
}
|
||||
|
||||
beginTest ("Skip");
|
||||
{
|
||||
stream.setPosition (0);
|
||||
expectEquals (stream.getPosition(), (int64) 0);
|
||||
expectEquals (stream.getTotalLength(), (int64) data.getSize());
|
||||
expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
|
||||
expect (! stream.isExhausted());
|
||||
|
||||
size_t numBytesRead = 0;
|
||||
const int numBytesToSkip = 5;
|
||||
|
||||
while (numBytesRead < data.getSize())
|
||||
{
|
||||
stream.skipNextBytes (numBytesToSkip);
|
||||
numBytesRead += numBytesToSkip;
|
||||
numBytesRead = std::min (numBytesRead, data.getSize());
|
||||
|
||||
expectEquals (stream.getPosition(), (int64) numBytesRead);
|
||||
expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
|
||||
expect (stream.isExhausted() == (numBytesRead == data.getSize()));
|
||||
}
|
||||
|
||||
expectEquals (stream.getPosition(), (int64) data.getSize());
|
||||
expectEquals (stream.getNumBytesRemaining(), (int64) 0);
|
||||
expect (stream.isExhausted());
|
||||
|
||||
f.deleteFile();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static FileInputStreamTests fileInputStreamTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
90
deps/juce/modules/juce_core/files/juce_FileInputStream.h
vendored
Normal file
90
deps/juce/modules/juce_core/files/juce_FileInputStream.h
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
An input stream that reads from a local file.
|
||||
|
||||
@see InputStream, FileOutputStream, File::createInputStream
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API FileInputStream : public InputStream
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a FileInputStream to read from the given file.
|
||||
|
||||
After creating a FileInputStream, you should use openedOk() or failedToOpen()
|
||||
to make sure that it's OK before trying to read from it! If it failed, you
|
||||
can call getStatus() to get more error information.
|
||||
*/
|
||||
explicit FileInputStream (const File& fileToRead);
|
||||
|
||||
/** Destructor. */
|
||||
~FileInputStream() override;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the file that this stream is reading from. */
|
||||
const File& getFile() const noexcept { return file; }
|
||||
|
||||
/** Returns the status of the file stream.
|
||||
The result will be ok if the file opened successfully. If an error occurs while
|
||||
opening or reading from the file, this will contain an error message.
|
||||
*/
|
||||
const Result& getStatus() const noexcept { return status; }
|
||||
|
||||
/** Returns true if the stream couldn't be opened for some reason.
|
||||
@see getResult()
|
||||
*/
|
||||
bool failedToOpen() const noexcept { return status.failed(); }
|
||||
|
||||
/** Returns true if the stream opened without problems.
|
||||
@see getResult()
|
||||
*/
|
||||
bool openedOk() const noexcept { return status.wasOk(); }
|
||||
|
||||
|
||||
//==============================================================================
|
||||
int64 getTotalLength() override;
|
||||
int read (void*, int) override;
|
||||
bool isExhausted() override;
|
||||
int64 getPosition() override;
|
||||
bool setPosition (int64) override;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
const File file;
|
||||
void* fileHandle = nullptr;
|
||||
int64 currentPosition = 0;
|
||||
Result status { Result::ok() };
|
||||
|
||||
void openHandle();
|
||||
size_t readInternal (void*, size_t);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputStream)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
130
deps/juce/modules/juce_core/files/juce_FileOutputStream.cpp
vendored
Normal file
130
deps/juce/modules/juce_core/files/juce_FileOutputStream.cpp
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
FileOutputStream::FileOutputStream (const File& f, const size_t bufferSizeToUse)
|
||||
: file (f),
|
||||
bufferSize (bufferSizeToUse),
|
||||
buffer (jmax (bufferSizeToUse, (size_t) 16))
|
||||
{
|
||||
openHandle();
|
||||
}
|
||||
|
||||
FileOutputStream::~FileOutputStream()
|
||||
{
|
||||
flushBuffer();
|
||||
closeHandle();
|
||||
}
|
||||
|
||||
int64 FileOutputStream::getPosition()
|
||||
{
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
bool FileOutputStream::setPosition (int64 newPosition)
|
||||
{
|
||||
if (newPosition != currentPosition)
|
||||
{
|
||||
flushBuffer();
|
||||
currentPosition = juce_fileSetPosition (fileHandle, newPosition);
|
||||
}
|
||||
|
||||
return newPosition == currentPosition;
|
||||
}
|
||||
|
||||
bool FileOutputStream::flushBuffer()
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if (bytesInBuffer > 0)
|
||||
{
|
||||
ok = (writeInternal (buffer, bytesInBuffer) == (ssize_t) bytesInBuffer);
|
||||
bytesInBuffer = 0;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void FileOutputStream::flush()
|
||||
{
|
||||
flushBuffer();
|
||||
flushInternal();
|
||||
}
|
||||
|
||||
bool FileOutputStream::write (const void* const src, const size_t numBytes)
|
||||
{
|
||||
jassert (src != nullptr && ((ssize_t) numBytes) >= 0);
|
||||
|
||||
if (! openedOk())
|
||||
return false;
|
||||
|
||||
if (bytesInBuffer + numBytes < bufferSize)
|
||||
{
|
||||
memcpy (buffer + bytesInBuffer, src, numBytes);
|
||||
bytesInBuffer += numBytes;
|
||||
currentPosition += (int64) numBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! flushBuffer())
|
||||
return false;
|
||||
|
||||
if (numBytes < bufferSize)
|
||||
{
|
||||
memcpy (buffer + bytesInBuffer, src, numBytes);
|
||||
bytesInBuffer += numBytes;
|
||||
currentPosition += (int64) numBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto bytesWritten = writeInternal (src, numBytes);
|
||||
|
||||
if (bytesWritten < 0)
|
||||
return false;
|
||||
|
||||
currentPosition += (int64) bytesWritten;
|
||||
return bytesWritten == (ssize_t) numBytes;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileOutputStream::writeRepeatedByte (uint8 byte, size_t numBytes)
|
||||
{
|
||||
jassert (((ssize_t) numBytes) >= 0);
|
||||
|
||||
if (bytesInBuffer + numBytes < bufferSize)
|
||||
{
|
||||
memset (buffer + bytesInBuffer, byte, numBytes);
|
||||
bytesInBuffer += numBytes;
|
||||
currentPosition += (int64) numBytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
return OutputStream::writeRepeatedByte (byte, numBytes);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
126
deps/juce/modules/juce_core/files/juce_FileOutputStream.h
vendored
Normal file
126
deps/juce/modules/juce_core/files/juce_FileOutputStream.h
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
An output stream that writes into a local file.
|
||||
|
||||
@see OutputStream, FileInputStream, File::createOutputStream
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API FileOutputStream : public OutputStream
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a FileOutputStream.
|
||||
|
||||
If the file doesn't exist, it will first be created. If the file can't be
|
||||
created or opened (for example, because the parent directory of the file
|
||||
does not exist), the failedToOpen() method will return true.
|
||||
|
||||
If the file already exists when opened, the stream's write-position will
|
||||
be set to the end of the file. To overwrite an existing file, you can truncate
|
||||
it like this:
|
||||
|
||||
@code
|
||||
FileOutputStream stream (file);
|
||||
|
||||
if (stream.openedOk())
|
||||
{
|
||||
stream.setPosition (0);
|
||||
stream.truncate();
|
||||
...
|
||||
}
|
||||
@endcode
|
||||
|
||||
|
||||
Destroying a FileOutputStream object does not force the operating system
|
||||
to write the buffered data to disk immediately. If this is required you
|
||||
should call flush() before triggering the destructor.
|
||||
|
||||
@see TemporaryFile
|
||||
*/
|
||||
FileOutputStream (const File& fileToWriteTo,
|
||||
size_t bufferSizeToUse = 16384);
|
||||
|
||||
/** Destructor. */
|
||||
~FileOutputStream() override;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the file that this stream is writing to.
|
||||
*/
|
||||
const File& getFile() const { return file; }
|
||||
|
||||
/** Returns the status of the file stream.
|
||||
The result will be ok if the file opened successfully. If an error occurs while
|
||||
opening or writing to the file, this will contain an error message.
|
||||
*/
|
||||
const Result& getStatus() const noexcept { return status; }
|
||||
|
||||
/** Returns true if the stream couldn't be opened for some reason.
|
||||
@see getResult()
|
||||
*/
|
||||
bool failedToOpen() const noexcept { return status.failed(); }
|
||||
|
||||
/** Returns true if the stream opened without problems.
|
||||
@see getResult()
|
||||
*/
|
||||
bool openedOk() const noexcept { return status.wasOk(); }
|
||||
|
||||
/** Attempts to truncate the file to the current write position.
|
||||
To truncate a file to a specific size, first use setPosition() to seek to the
|
||||
appropriate location, and then call this method.
|
||||
*/
|
||||
Result truncate();
|
||||
|
||||
//==============================================================================
|
||||
void flush() override;
|
||||
int64 getPosition() override;
|
||||
bool setPosition (int64) override;
|
||||
bool write (const void*, size_t) override;
|
||||
bool writeRepeatedByte (uint8 byte, size_t numTimesToRepeat) override;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
File file;
|
||||
void* fileHandle = nullptr;
|
||||
Result status { Result::ok() };
|
||||
int64 currentPosition = 0;
|
||||
size_t bufferSize, bytesInBuffer = 0;
|
||||
HeapBlock<char> buffer;
|
||||
|
||||
void openHandle();
|
||||
void closeHandle();
|
||||
void flushInternal();
|
||||
bool flushBuffer();
|
||||
int64 setPositionInternal (int64);
|
||||
ssize_t writeInternal (const void*, size_t);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileOutputStream)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
173
deps/juce/modules/juce_core/files/juce_FileSearchPath.cpp
vendored
Normal file
173
deps/juce/modules/juce_core/files/juce_FileSearchPath.cpp
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
FileSearchPath::FileSearchPath() {}
|
||||
FileSearchPath::~FileSearchPath() {}
|
||||
|
||||
FileSearchPath::FileSearchPath (const String& path)
|
||||
{
|
||||
init (path);
|
||||
}
|
||||
|
||||
FileSearchPath::FileSearchPath (const FileSearchPath& other)
|
||||
: directories (other.directories)
|
||||
{
|
||||
}
|
||||
|
||||
FileSearchPath& FileSearchPath::operator= (const FileSearchPath& other)
|
||||
{
|
||||
directories = other.directories;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FileSearchPath& FileSearchPath::operator= (const String& path)
|
||||
{
|
||||
init (path);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void FileSearchPath::init (const String& path)
|
||||
{
|
||||
directories.clear();
|
||||
directories.addTokens (path, ";", "\"");
|
||||
directories.trim();
|
||||
directories.removeEmptyStrings();
|
||||
|
||||
for (auto& d : directories)
|
||||
d = d.unquoted();
|
||||
}
|
||||
|
||||
int FileSearchPath::getNumPaths() const
|
||||
{
|
||||
return directories.size();
|
||||
}
|
||||
|
||||
File FileSearchPath::operator[] (int index) const
|
||||
{
|
||||
return File (directories[index]);
|
||||
}
|
||||
|
||||
String FileSearchPath::toString() const
|
||||
{
|
||||
auto dirs = directories;
|
||||
|
||||
for (auto& d : dirs)
|
||||
if (d.containsChar (';'))
|
||||
d = d.quoted();
|
||||
|
||||
return dirs.joinIntoString (";");
|
||||
}
|
||||
|
||||
void FileSearchPath::add (const File& dir, int insertIndex)
|
||||
{
|
||||
directories.insert (insertIndex, dir.getFullPathName());
|
||||
}
|
||||
|
||||
bool FileSearchPath::addIfNotAlreadyThere (const File& dir)
|
||||
{
|
||||
for (auto& d : directories)
|
||||
if (File (d) == dir)
|
||||
return false;
|
||||
|
||||
add (dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileSearchPath::remove (int index)
|
||||
{
|
||||
directories.remove (index);
|
||||
}
|
||||
|
||||
void FileSearchPath::addPath (const FileSearchPath& other)
|
||||
{
|
||||
for (int i = 0; i < other.getNumPaths(); ++i)
|
||||
addIfNotAlreadyThere (other[i]);
|
||||
}
|
||||
|
||||
void FileSearchPath::removeRedundantPaths()
|
||||
{
|
||||
for (int i = directories.size(); --i >= 0;)
|
||||
{
|
||||
const File d1 (directories[i]);
|
||||
|
||||
for (int j = directories.size(); --j >= 0;)
|
||||
{
|
||||
const File d2 (directories[j]);
|
||||
|
||||
if (i != j && (d1.isAChildOf (d2) || d1 == d2))
|
||||
{
|
||||
directories.remove (i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileSearchPath::removeNonExistentPaths()
|
||||
{
|
||||
for (int i = directories.size(); --i >= 0;)
|
||||
if (! File (directories[i]).isDirectory())
|
||||
directories.remove (i);
|
||||
}
|
||||
|
||||
Array<File> FileSearchPath::findChildFiles (int whatToLookFor, bool recurse, const String& wildcard) const
|
||||
{
|
||||
Array<File> results;
|
||||
findChildFiles (results, whatToLookFor, recurse, wildcard);
|
||||
return results;
|
||||
}
|
||||
|
||||
int FileSearchPath::findChildFiles (Array<File>& results, int whatToLookFor,
|
||||
bool recurse, const String& wildcard) const
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
for (auto& d : directories)
|
||||
total += File (d).findChildFiles (results, whatToLookFor, recurse, wildcard);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
bool FileSearchPath::isFileInPath (const File& fileToCheck,
|
||||
const bool checkRecursively) const
|
||||
{
|
||||
for (auto& d : directories)
|
||||
{
|
||||
if (checkRecursively)
|
||||
{
|
||||
if (fileToCheck.isAChildOf (File (d)))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fileToCheck.getParentDirectory() == File (d))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
171
deps/juce/modules/juce_core/files/juce_FileSearchPath.h
vendored
Normal file
171
deps/juce/modules/juce_core/files/juce_FileSearchPath.h
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents a set of folders that make up a search path.
|
||||
|
||||
@see File
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API FileSearchPath
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty search path. */
|
||||
FileSearchPath();
|
||||
|
||||
/** Creates a search path from a string of pathnames.
|
||||
|
||||
The path can be semicolon- or comma-separated, e.g.
|
||||
"/foo/bar;/foo/moose;/fish/moose"
|
||||
|
||||
The separate folders are tokenised and added to the search path.
|
||||
*/
|
||||
FileSearchPath (const String& path);
|
||||
|
||||
/** Creates a copy of another search path. */
|
||||
FileSearchPath (const FileSearchPath&);
|
||||
|
||||
/** Copies another search path. */
|
||||
FileSearchPath& operator= (const FileSearchPath&);
|
||||
|
||||
/** Destructor. */
|
||||
~FileSearchPath();
|
||||
|
||||
/** Uses a string containing a list of pathnames to re-initialise this list.
|
||||
|
||||
This search path is cleared and the semicolon- or comma-separated folders
|
||||
in this string are added instead. e.g. "/foo/bar;/foo/moose;/fish/moose"
|
||||
*/
|
||||
FileSearchPath& operator= (const String& path);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of folders in this search path.
|
||||
@see operator[]
|
||||
*/
|
||||
int getNumPaths() const;
|
||||
|
||||
/** Returns one of the folders in this search path.
|
||||
The file returned isn't guaranteed to actually be a valid directory.
|
||||
@see getNumPaths
|
||||
*/
|
||||
File operator[] (int index) const;
|
||||
|
||||
/** Returns the search path as a semicolon-separated list of directories. */
|
||||
String toString() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Adds a new directory to the search path.
|
||||
|
||||
The new directory is added to the end of the list if the insertIndex parameter is
|
||||
less than zero, otherwise it is inserted at the given index.
|
||||
*/
|
||||
void add (const File& directoryToAdd,
|
||||
int insertIndex = -1);
|
||||
|
||||
/** Adds a new directory to the search path if it's not already in there.
|
||||
|
||||
@return true if the directory has been added, false otherwise.
|
||||
*/
|
||||
bool addIfNotAlreadyThere (const File& directoryToAdd);
|
||||
|
||||
/** Removes a directory from the search path. */
|
||||
void remove (int indexToRemove);
|
||||
|
||||
/** Merges another search path into this one.
|
||||
This will remove any duplicate directories.
|
||||
*/
|
||||
void addPath (const FileSearchPath&);
|
||||
|
||||
/** Removes any directories that are actually subdirectories of one of the other directories in the search path.
|
||||
|
||||
If the search is intended to be recursive, there's no point having nested folders in the search
|
||||
path, because they'll just get searched twice and you'll get duplicate results.
|
||||
|
||||
e.g. if the path is "c:\abc\de;c:\abc", this method will simplify it to "c:\abc"
|
||||
*/
|
||||
void removeRedundantPaths();
|
||||
|
||||
/** Removes any directories that don't actually exist. */
|
||||
void removeNonExistentPaths();
|
||||
|
||||
//==============================================================================
|
||||
/** Searches the path for a wildcard.
|
||||
|
||||
This will search all the directories in the search path in order and return
|
||||
an array of the files that were found.
|
||||
|
||||
@param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying whether to
|
||||
return files, directories, or both.
|
||||
@param searchRecursively whether to recursively search the subdirectories too
|
||||
@param wildCardPattern a pattern to match against the filenames
|
||||
@returns the number of files added to the array
|
||||
@see File::findChildFiles
|
||||
*/
|
||||
Array<File> findChildFiles (int whatToLookFor,
|
||||
bool searchRecursively,
|
||||
const String& wildCardPattern = "*") const;
|
||||
|
||||
/** Searches the path for a wildcard.
|
||||
Note that there's a newer, better version of this method which returns the results
|
||||
array, and in almost all cases, you should use that one instead! This one is kept around
|
||||
mainly for legacy code to use.
|
||||
*/
|
||||
int findChildFiles (Array<File>& results,
|
||||
int whatToLookFor,
|
||||
bool searchRecursively,
|
||||
const String& wildCardPattern = "*") const;
|
||||
|
||||
//==============================================================================
|
||||
/** Finds out whether a file is inside one of the path's directories.
|
||||
|
||||
This will return true if the specified file is a child of one of the
|
||||
directories specified by this path. Note that this doesn't actually do any
|
||||
searching or check that the files exist - it just looks at the pathnames
|
||||
to work out whether the file would be inside a directory.
|
||||
|
||||
@param fileToCheck the file to look for
|
||||
@param checkRecursively if true, then this will return true if the file is inside a
|
||||
subfolder of one of the path's directories (at any depth). If false
|
||||
it will only return true if the file is actually a direct child
|
||||
of one of the directories.
|
||||
@see File::isAChildOf
|
||||
|
||||
*/
|
||||
bool isFileInPath (const File& fileToCheck,
|
||||
bool checkRecursively) const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
StringArray directories;
|
||||
|
||||
void init (const String&);
|
||||
|
||||
JUCE_LEAK_DETECTOR (FileSearchPath)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
115
deps/juce/modules/juce_core/files/juce_MemoryMappedFile.h
vendored
Normal file
115
deps/juce/modules/juce_core/files/juce_MemoryMappedFile.h
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Maps a file into virtual memory for easy reading and/or writing.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API MemoryMappedFile
|
||||
{
|
||||
public:
|
||||
/** The read/write flags used when opening a memory mapped file. */
|
||||
enum AccessMode
|
||||
{
|
||||
readOnly, /**< Indicates that the memory can only be read. */
|
||||
readWrite /**< Indicates that the memory can be read and written to - changes that are
|
||||
made will be flushed back to disk at the whim of the OS. */
|
||||
};
|
||||
|
||||
/** Opens a file and maps it to an area of virtual memory.
|
||||
|
||||
The file should already exist, and should already be the size that you want to work with
|
||||
when you call this. If the file is resized after being opened, the behaviour is undefined.
|
||||
|
||||
If the file exists and the operation succeeds, the getData() and getSize() methods will
|
||||
return the location and size of the data that can be read or written. Note that the entire
|
||||
file is not read into memory immediately - the OS simply creates a virtual mapping, which
|
||||
will lazily pull the data into memory when blocks are accessed.
|
||||
|
||||
If the file can't be opened for some reason, the getData() method will return a null pointer.
|
||||
|
||||
If exclusive is false then other apps can also open the same memory mapped file and use this
|
||||
mapping as an effective way of communicating. If exclusive is true then the mapped file will
|
||||
be opened exclusively - preventing other apps to access the file which may improve the
|
||||
performance of accessing the file.
|
||||
*/
|
||||
MemoryMappedFile (const File& file, AccessMode mode, bool exclusive = false);
|
||||
|
||||
/** Opens a section of a file and maps it to an area of virtual memory.
|
||||
|
||||
The file should already exist, and should already be the size that you want to work with
|
||||
when you call this. If the file is resized after being opened, the behaviour is undefined.
|
||||
|
||||
If the file exists and the operation succeeds, the getData() and getSize() methods will
|
||||
return the location and size of the data that can be read or written. Note that the entire
|
||||
file is not read into memory immediately - the OS simply creates a virtual mapping, which
|
||||
will lazily pull the data into memory when blocks are accessed.
|
||||
|
||||
If the file can't be opened for some reason, the getData() method will return a null pointer.
|
||||
|
||||
NOTE: The start of the actual range used may be rounded-down to a multiple of the OS's page-size,
|
||||
so do not assume that the mapped memory will begin at exactly the position you requested - always
|
||||
use getRange() to check the actual range that is being used.
|
||||
*/
|
||||
MemoryMappedFile (const File& file,
|
||||
const Range<int64>& fileRange,
|
||||
AccessMode mode,
|
||||
bool exclusive = false);
|
||||
|
||||
/** Destructor. */
|
||||
~MemoryMappedFile();
|
||||
|
||||
/** Returns the address at which this file has been mapped, or a null pointer if
|
||||
the file couldn't be successfully mapped.
|
||||
*/
|
||||
void* getData() const noexcept { return address; }
|
||||
|
||||
/** Returns the number of bytes of data that are available for reading or writing.
|
||||
This will normally be the size of the file.
|
||||
*/
|
||||
size_t getSize() const noexcept { return (size_t) range.getLength(); }
|
||||
|
||||
/** Returns the section of the file at which the mapped memory represents. */
|
||||
Range<int64> getRange() const noexcept { return range; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void* address = nullptr;
|
||||
Range<int64> range;
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
void* fileHandle = nullptr;
|
||||
#else
|
||||
int fileHandle = 0;
|
||||
#endif
|
||||
|
||||
void openInternal (const File&, AccessMode, bool);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedFile)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
77
deps/juce/modules/juce_core/files/juce_RangedDirectoryIterator.cpp
vendored
Normal file
77
deps/juce/modules/juce_core/files/juce_RangedDirectoryIterator.cpp
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
|
||||
|
||||
float DirectoryEntry::getEstimatedProgress() const
|
||||
{
|
||||
if (auto it = iterator.lock())
|
||||
return it->getEstimatedProgress();
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// We implement this in terms of the deprecated DirectoryIterator,
|
||||
// but the old DirectoryIterator might go away in the future!
|
||||
RangedDirectoryIterator::RangedDirectoryIterator (const File& directory,
|
||||
bool isRecursive,
|
||||
const String& wildCard,
|
||||
int whatToLookFor)
|
||||
: iterator (new DirectoryIterator (directory,
|
||||
isRecursive,
|
||||
wildCard,
|
||||
whatToLookFor))
|
||||
{
|
||||
entry.iterator = iterator;
|
||||
increment();
|
||||
}
|
||||
|
||||
bool RangedDirectoryIterator::next()
|
||||
{
|
||||
const auto result = iterator->next (&entry.directory,
|
||||
&entry.hidden,
|
||||
&entry.fileSize,
|
||||
&entry.modTime,
|
||||
&entry.creationTime,
|
||||
&entry.readOnly);
|
||||
if (result)
|
||||
entry.file = iterator->getFile();
|
||||
else
|
||||
entry = {};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void RangedDirectoryIterator::increment()
|
||||
{
|
||||
if (iterator != nullptr && ! next())
|
||||
iterator = nullptr;
|
||||
}
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
|
||||
} // namespace juce
|
||||
188
deps/juce/modules/juce_core/files/juce_RangedDirectoryIterator.h
vendored
Normal file
188
deps/juce/modules/juce_core/files/juce_RangedDirectoryIterator.h
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
|
||||
|
||||
/**
|
||||
Describes the attributes of a file or folder.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class DirectoryEntry final
|
||||
{
|
||||
public:
|
||||
/** The path to a file or folder. */
|
||||
File getFile() const { return file; }
|
||||
|
||||
/** The time at which the item was last modified. */
|
||||
Time getModificationTime() const { return modTime; }
|
||||
|
||||
/** The time at which the item was created. */
|
||||
Time getCreationTime() const { return creationTime; }
|
||||
|
||||
/** The size of the item. */
|
||||
int64 getFileSize() const { return fileSize; }
|
||||
|
||||
/** True if the item is a directory, false otherwise. */
|
||||
bool isDirectory() const { return directory; }
|
||||
|
||||
/** True if the item is hidden, false otherwise. */
|
||||
bool isHidden() const { return hidden; }
|
||||
|
||||
/** True if the item is read-only, false otherwise. */
|
||||
bool isReadOnly() const { return readOnly; }
|
||||
|
||||
/** The estimated proportion of the range that has been visited
|
||||
by the iterator, from 0.0 to 1.0.
|
||||
*/
|
||||
float getEstimatedProgress() const;
|
||||
|
||||
private:
|
||||
std::weak_ptr<DirectoryIterator> iterator;
|
||||
File file;
|
||||
Time modTime;
|
||||
Time creationTime;
|
||||
int64 fileSize = 0;
|
||||
bool directory = false;
|
||||
bool hidden = false;
|
||||
bool readOnly = false;
|
||||
|
||||
friend class RangedDirectoryIterator;
|
||||
};
|
||||
|
||||
/** A convenience operator so that the expression `*it++` works correctly when
|
||||
`it` is an instance of RangedDirectoryIterator.
|
||||
*/
|
||||
inline const DirectoryEntry& operator* (const DirectoryEntry& e) noexcept { return e; }
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Allows iterating over files and folders using C++11 range-for syntax.
|
||||
|
||||
In the following example, we recursively find all hidden files in a
|
||||
specific directory.
|
||||
|
||||
@code
|
||||
std::vector<File> hiddenFiles;
|
||||
|
||||
for (DirectoryEntry entry : RangedDirectoryIterator (File ("/path/to/folder"), isRecursive))
|
||||
if (entry.isHidden())
|
||||
hiddenFiles.push_back (entry.getFile());
|
||||
@endcode
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class RangedDirectoryIterator final
|
||||
{
|
||||
public:
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = DirectoryEntry;
|
||||
using reference = DirectoryEntry;
|
||||
using pointer = void;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
/** The default-constructed iterator acts as the 'end' sentinel. */
|
||||
RangedDirectoryIterator() = default;
|
||||
|
||||
/** Creates a RangedDirectoryIterator for a given directory.
|
||||
|
||||
The resulting iterator can be used directly in a 'range-for' expression.
|
||||
|
||||
@param directory the directory to search in
|
||||
@param isRecursive whether all the subdirectories should also be searched
|
||||
@param wildCard the file pattern to match. This may contain multiple patterns
|
||||
separated by a semi-colon or comma, e.g. "*.jpg;*.png"
|
||||
@param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying
|
||||
whether to look for files, directories, or both.
|
||||
*/
|
||||
RangedDirectoryIterator (const File& directory,
|
||||
bool isRecursive,
|
||||
const String& wildCard = "*",
|
||||
int whatToLookFor = File::findFiles);
|
||||
|
||||
/** Returns true if both iterators are in their end/sentinel state,
|
||||
otherwise returns false.
|
||||
*/
|
||||
bool operator== (const RangedDirectoryIterator& other) const noexcept
|
||||
{
|
||||
return iterator == nullptr && other.iterator == nullptr;
|
||||
}
|
||||
|
||||
/** Returns the inverse of operator== */
|
||||
bool operator!= (const RangedDirectoryIterator& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
/** Return an object containing metadata about the file or folder to
|
||||
which the iterator is currently pointing.
|
||||
*/
|
||||
const DirectoryEntry& operator* () const noexcept { return entry; }
|
||||
const DirectoryEntry* operator->() const noexcept { return &entry; }
|
||||
|
||||
/** Moves the iterator along to the next file. */
|
||||
RangedDirectoryIterator& operator++()
|
||||
{
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Moves the iterator along to the next file.
|
||||
|
||||
@returns an object containing metadata about the file or folder to
|
||||
to which the iterator was previously pointing.
|
||||
*/
|
||||
DirectoryEntry operator++ (int)
|
||||
{
|
||||
auto result = *(*this);
|
||||
++(*this);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
bool next();
|
||||
void increment();
|
||||
|
||||
std::shared_ptr<DirectoryIterator> iterator;
|
||||
DirectoryEntry entry;
|
||||
};
|
||||
|
||||
/** Returns the iterator that was passed in.
|
||||
Provided for range-for compatibility.
|
||||
*/
|
||||
inline RangedDirectoryIterator begin (const RangedDirectoryIterator& it) { return it; }
|
||||
|
||||
/** Returns a default-constructed sentinel value.
|
||||
Provided for range-for compatibility.
|
||||
*/
|
||||
inline RangedDirectoryIterator end (const RangedDirectoryIterator&) { return {}; }
|
||||
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
} // namespace juce
|
||||
117
deps/juce/modules/juce_core/files/juce_TemporaryFile.cpp
vendored
Normal file
117
deps/juce/modules/juce_core/files/juce_TemporaryFile.cpp
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
static File createTempFile (const File& parentDirectory, String name,
|
||||
const String& suffix, int optionFlags)
|
||||
{
|
||||
if ((optionFlags & TemporaryFile::useHiddenFile) != 0)
|
||||
name = "." + name;
|
||||
|
||||
return parentDirectory.getNonexistentChildFile (name, suffix, (optionFlags & TemporaryFile::putNumbersInBrackets) != 0);
|
||||
}
|
||||
|
||||
TemporaryFile::TemporaryFile (const String& suffix, const int optionFlags)
|
||||
: temporaryFile (createTempFile (File::getSpecialLocation (File::tempDirectory),
|
||||
"temp_" + String::toHexString (Random::getSystemRandom().nextInt()),
|
||||
suffix, optionFlags)),
|
||||
targetFile()
|
||||
{
|
||||
}
|
||||
|
||||
TemporaryFile::TemporaryFile (const File& target, const int optionFlags)
|
||||
: temporaryFile (createTempFile (target.getParentDirectory(),
|
||||
target.getFileNameWithoutExtension()
|
||||
+ "_temp" + String::toHexString (Random::getSystemRandom().nextInt()),
|
||||
target.getFileExtension(), optionFlags)),
|
||||
targetFile (target)
|
||||
{
|
||||
// If you use this constructor, you need to give it a valid target file!
|
||||
jassert (targetFile != File());
|
||||
}
|
||||
|
||||
TemporaryFile::TemporaryFile (const File& target, const File& temporary)
|
||||
: temporaryFile (temporary), targetFile (target)
|
||||
{
|
||||
}
|
||||
|
||||
TemporaryFile::~TemporaryFile()
|
||||
{
|
||||
if (! deleteTemporaryFile())
|
||||
{
|
||||
/* Failed to delete our temporary file! The most likely reason for this would be
|
||||
that you've not closed an output stream that was being used to write to file.
|
||||
|
||||
If you find that something beyond your control is changing permissions on
|
||||
your temporary files and preventing them from being deleted, you may want to
|
||||
call TemporaryFile::deleteTemporaryFile() to detect those error cases and
|
||||
handle them appropriately.
|
||||
*/
|
||||
jassertfalse;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool TemporaryFile::overwriteTargetFileWithTemporary() const
|
||||
{
|
||||
// This method only works if you created this object with the constructor
|
||||
// that takes a target file!
|
||||
jassert (targetFile != File());
|
||||
|
||||
if (temporaryFile.exists())
|
||||
{
|
||||
// Have a few attempts at overwriting the file before giving up..
|
||||
for (int i = 5; --i >= 0;)
|
||||
{
|
||||
if (temporaryFile.replaceFileIn (targetFile))
|
||||
return true;
|
||||
|
||||
Thread::sleep (100);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// There's no temporary file to use. If your write failed, you should
|
||||
// probably check, and not bother calling this method.
|
||||
jassertfalse;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TemporaryFile::deleteTemporaryFile() const
|
||||
{
|
||||
// Have a few attempts at deleting the file before giving up..
|
||||
for (int i = 5; --i >= 0;)
|
||||
{
|
||||
if (temporaryFile.deleteFile())
|
||||
return true;
|
||||
|
||||
Thread::sleep (50);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
162
deps/juce/modules/juce_core/files/juce_TemporaryFile.h
vendored
Normal file
162
deps/juce/modules/juce_core/files/juce_TemporaryFile.h
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Manages a temporary file, which will be deleted when this object is deleted.
|
||||
|
||||
This object is intended to be used as a stack based object, using its scope
|
||||
to make sure the temporary file isn't left lying around.
|
||||
|
||||
For example:
|
||||
|
||||
@code
|
||||
{
|
||||
File myTargetFile ("~/myfile.txt");
|
||||
|
||||
// this will choose a file called something like "~/myfile_temp239348.txt"
|
||||
// which definitely doesn't exist at the time the constructor is called.
|
||||
TemporaryFile temp (myTargetFile);
|
||||
|
||||
// create a stream to the temporary file, and write some data to it...
|
||||
if (auto out = std::unique_ptr<FileOutputStream> (temp.getFile().createOutputStream()))
|
||||
{
|
||||
out->write ( ...etc )
|
||||
out.reset(); // (deletes the stream)
|
||||
|
||||
// ..now we've finished writing, this will rename the temp file to
|
||||
// make it replace the target file we specified above.
|
||||
bool succeeded = temp.overwriteTargetFileWithTemporary();
|
||||
}
|
||||
|
||||
// ..and even if something went wrong and our overwrite failed,
|
||||
// as the TemporaryFile object goes out of scope here, it'll make sure
|
||||
// that the temp file gets deleted.
|
||||
}
|
||||
@endcode
|
||||
|
||||
@see File, FileOutputStream
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API TemporaryFile
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
enum OptionFlags
|
||||
{
|
||||
useHiddenFile = 1, /**< Indicates that the temporary file should be hidden -
|
||||
i.e. its name should start with a dot. */
|
||||
putNumbersInBrackets = 2 /**< Indicates that when numbers are appended to make sure
|
||||
the file is unique, they should go in brackets rather
|
||||
than just being appended (see File::getNonexistentSibling() )*/
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a randomly-named temporary file in the default temp directory.
|
||||
|
||||
@param suffix a file suffix to use for the file
|
||||
@param optionFlags a combination of the values listed in the OptionFlags enum
|
||||
The file will not be created until you write to it. And remember that when
|
||||
this object is deleted, the file will also be deleted!
|
||||
*/
|
||||
TemporaryFile (const String& suffix = String(),
|
||||
int optionFlags = 0);
|
||||
|
||||
/** Creates a temporary file in the same directory as a specified file.
|
||||
|
||||
This is useful if you have a file that you want to overwrite, but don't
|
||||
want to harm the original file if the write operation fails. You can
|
||||
use this to create a temporary file next to the target file, then
|
||||
write to the temporary file, and finally use overwriteTargetFileWithTemporary()
|
||||
to replace the target file with the one you've just written.
|
||||
|
||||
This class won't create any files until you actually write to them. And remember
|
||||
that when this object is deleted, the temporary file will also be deleted!
|
||||
|
||||
@param targetFile the file that you intend to overwrite - the temporary
|
||||
file will be created in the same directory as this
|
||||
@param optionFlags a combination of the values listed in the OptionFlags enum
|
||||
*/
|
||||
TemporaryFile (const File& targetFile,
|
||||
int optionFlags = 0);
|
||||
|
||||
/** Creates a temporary file using an explicit filename.
|
||||
The other constructors are a better choice than this one, unless for some reason
|
||||
you need to explicitly specify the temporary file you want to use.
|
||||
|
||||
@param targetFile the file that you intend to overwrite
|
||||
@param temporaryFile the temporary file to be used
|
||||
*/
|
||||
TemporaryFile (const File& targetFile,
|
||||
const File& temporaryFile);
|
||||
|
||||
/** Destructor.
|
||||
|
||||
When this object is deleted it will make sure that its temporary file is
|
||||
also deleted! If the operation fails, it'll throw an assertion in debug
|
||||
mode.
|
||||
*/
|
||||
~TemporaryFile();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the temporary file. */
|
||||
const File& getFile() const noexcept { return temporaryFile; }
|
||||
|
||||
/** Returns the target file that was specified in the constructor. */
|
||||
const File& getTargetFile() const noexcept { return targetFile; }
|
||||
|
||||
/** Tries to move the temporary file to overwrite the target file that was
|
||||
specified in the constructor.
|
||||
|
||||
If you used the constructor that specified a target file, this will attempt
|
||||
to replace that file with the temporary one.
|
||||
|
||||
Before calling this, make sure:
|
||||
- that you've actually written to the temporary file
|
||||
- that you've closed any open streams that you were using to write to it
|
||||
- and that you don't have any streams open to the target file, which would
|
||||
prevent it being overwritten
|
||||
|
||||
If the file move succeeds, this returns true, and the temporary file will
|
||||
have disappeared. If it fails, the temporary file will probably still exist,
|
||||
but will be deleted when this object is destroyed.
|
||||
*/
|
||||
bool overwriteTargetFileWithTemporary() const;
|
||||
|
||||
/** Attempts to delete the temporary file, if it exists.
|
||||
@returns true if the file is successfully deleted (or if it didn't exist).
|
||||
*/
|
||||
bool deleteTemporaryFile() const;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
const File temporaryFile, targetFile;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemporaryFile)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
74
deps/juce/modules/juce_core/files/juce_WildcardFileFilter.cpp
vendored
Normal file
74
deps/juce/modules/juce_core/files/juce_WildcardFileFilter.cpp
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
static void parseWildcard (const String& pattern, StringArray& result)
|
||||
{
|
||||
result.addTokens (pattern.toLowerCase(), ";,", "\"'");
|
||||
result.trim();
|
||||
result.removeEmptyStrings();
|
||||
|
||||
// special case for *.*, because people use it to mean "any file", but it
|
||||
// would actually ignore files with no extension.
|
||||
for (auto& r : result)
|
||||
if (r == "*.*")
|
||||
r = "*";
|
||||
}
|
||||
|
||||
static bool matchWildcard (const File& file, const StringArray& wildcards)
|
||||
{
|
||||
auto filename = file.getFileName();
|
||||
|
||||
for (auto& w : wildcards)
|
||||
if (filename.matchesWildcard (w, true))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
WildcardFileFilter::WildcardFileFilter (const String& fileWildcardPatterns,
|
||||
const String& directoryWildcardPatterns,
|
||||
const String& desc)
|
||||
: FileFilter (desc.isEmpty() ? fileWildcardPatterns
|
||||
: (desc + " (" + fileWildcardPatterns + ")"))
|
||||
{
|
||||
parseWildcard (fileWildcardPatterns, fileWildcards);
|
||||
parseWildcard (directoryWildcardPatterns, directoryWildcards);
|
||||
}
|
||||
|
||||
WildcardFileFilter::~WildcardFileFilter()
|
||||
{
|
||||
}
|
||||
|
||||
bool WildcardFileFilter::isFileSuitable (const File& file) const
|
||||
{
|
||||
return matchWildcard (file, fileWildcards);
|
||||
}
|
||||
|
||||
bool WildcardFileFilter::isDirectorySuitable (const File& file) const
|
||||
{
|
||||
return matchWildcard (file, directoryWildcards);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
76
deps/juce/modules/juce_core/files/juce_WildcardFileFilter.h
vendored
Normal file
76
deps/juce/modules/juce_core/files/juce_WildcardFileFilter.h
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 type of FileFilter that works by wildcard pattern matching.
|
||||
|
||||
This filter only allows files that match one of the specified patterns, but
|
||||
allows all directories through.
|
||||
|
||||
@see FileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API WildcardFileFilter : public FileFilter
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/**
|
||||
Creates a wildcard filter for one or more patterns.
|
||||
|
||||
The wildcardPatterns parameter is a comma or semicolon-delimited set of
|
||||
patterns, e.g. "*.wav;*.aiff" would look for files ending in either .wav
|
||||
or .aiff.
|
||||
|
||||
Passing an empty string as a pattern will fail to match anything, so by leaving
|
||||
either the file or directory pattern parameter empty means you can control
|
||||
whether files or directories are found.
|
||||
|
||||
The description is a name to show the user in a list of possible patterns, so
|
||||
for the wav/aiff example, your description might be "audio files".
|
||||
*/
|
||||
WildcardFileFilter (const String& fileWildcardPatterns,
|
||||
const String& directoryWildcardPatterns,
|
||||
const String& filterDescription);
|
||||
|
||||
/** Destructor. */
|
||||
~WildcardFileFilter() override;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the filename matches one of the patterns specified. */
|
||||
bool isFileSuitable (const File& file) const override;
|
||||
|
||||
/** This always returns true. */
|
||||
bool isDirectorySuitable (const File& file) const override;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
StringArray fileWildcards, directoryWildcards;
|
||||
|
||||
JUCE_LEAK_DETECTOR (WildcardFileFilter)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
693
deps/juce/modules/juce_core/javascript/juce_JSON.cpp
vendored
Normal file
693
deps/juce/modules/juce_core/javascript/juce_JSON.cpp
vendored
Normal file
@@ -0,0 +1,693 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
struct JSONParser
|
||||
{
|
||||
JSONParser (String::CharPointerType text) : startLocation (text), currentLocation (text) {}
|
||||
|
||||
String::CharPointerType startLocation, currentLocation;
|
||||
|
||||
struct ErrorException
|
||||
{
|
||||
String message;
|
||||
int line = 1, column = 1;
|
||||
|
||||
String getDescription() const { return String (line) + ":" + String (column) + ": error: " + message; }
|
||||
Result getResult() const { return Result::fail (getDescription()); }
|
||||
};
|
||||
|
||||
[[noreturn]] void throwError (juce::String message, String::CharPointerType location)
|
||||
{
|
||||
ErrorException e;
|
||||
e.message = std::move (message);
|
||||
|
||||
for (auto i = startLocation; i < location && ! i.isEmpty(); ++i)
|
||||
{
|
||||
++e.column;
|
||||
if (*i == '\n') { e.column = 1; e.line++; }
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
void skipWhitespace() { currentLocation = currentLocation.findEndOfWhitespace(); }
|
||||
juce_wchar readChar() { return currentLocation.getAndAdvance(); }
|
||||
juce_wchar peekChar() const { return *currentLocation; }
|
||||
bool matchIf (char c) { if (peekChar() == (juce_wchar) c) { ++currentLocation; return true; } return false; }
|
||||
bool isEOF() const { return peekChar() == 0; }
|
||||
|
||||
bool matchString (const char* t)
|
||||
{
|
||||
while (*t != 0)
|
||||
if (! matchIf (*t++))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
var parseObjectOrArray()
|
||||
{
|
||||
skipWhitespace();
|
||||
|
||||
if (matchIf ('{')) return parseObject();
|
||||
if (matchIf ('[')) return parseArray();
|
||||
|
||||
if (! isEOF())
|
||||
throwError ("Expected '{' or '['", currentLocation);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
String parseString (const juce_wchar quoteChar)
|
||||
{
|
||||
MemoryOutputStream buffer (256);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
auto c = readChar();
|
||||
|
||||
if (c == quoteChar)
|
||||
break;
|
||||
|
||||
if (c == '\\')
|
||||
{
|
||||
auto errorLocation = currentLocation;
|
||||
c = readChar();
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
case '\'':
|
||||
case '\\':
|
||||
case '/': break;
|
||||
|
||||
case 'a': c = '\a'; break;
|
||||
case 'b': c = '\b'; break;
|
||||
case 'f': c = '\f'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
case 't': c = '\t'; break;
|
||||
|
||||
case 'u':
|
||||
{
|
||||
c = 0;
|
||||
|
||||
for (int i = 4; --i >= 0;)
|
||||
{
|
||||
auto digitValue = CharacterFunctions::getHexDigitValue (readChar());
|
||||
|
||||
if (digitValue < 0)
|
||||
throwError ("Syntax error in unicode escape sequence", errorLocation);
|
||||
|
||||
c = (juce_wchar) ((c << 4) + static_cast<juce_wchar> (digitValue));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == 0)
|
||||
throwError ("Unexpected EOF in string constant", currentLocation);
|
||||
|
||||
buffer.appendUTF8Char (c);
|
||||
}
|
||||
|
||||
return buffer.toUTF8();
|
||||
}
|
||||
|
||||
var parseAny()
|
||||
{
|
||||
skipWhitespace();
|
||||
auto originalLocation = currentLocation;
|
||||
|
||||
switch (readChar())
|
||||
{
|
||||
case '{': return parseObject();
|
||||
case '[': return parseArray();
|
||||
case '"': return parseString ('"');
|
||||
case '\'': return parseString ('\'');
|
||||
|
||||
case '-':
|
||||
skipWhitespace();
|
||||
return parseNumber (true);
|
||||
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
currentLocation = originalLocation;
|
||||
return parseNumber (false);
|
||||
|
||||
case 't': // "true"
|
||||
if (matchString ("rue"))
|
||||
return var (true);
|
||||
|
||||
break;
|
||||
|
||||
case 'f': // "false"
|
||||
if (matchString ("alse"))
|
||||
return var (false);
|
||||
|
||||
break;
|
||||
|
||||
case 'n': // "null"
|
||||
if (matchString ("ull"))
|
||||
return {};
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
throwError ("Syntax error", originalLocation);
|
||||
}
|
||||
|
||||
var parseNumber (bool isNegative)
|
||||
{
|
||||
auto originalPos = currentLocation;
|
||||
|
||||
int64 intValue = readChar() - '0';
|
||||
jassert (intValue >= 0 && intValue < 10);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
auto lastPos = currentLocation;
|
||||
auto c = readChar();
|
||||
auto digit = ((int) c) - '0';
|
||||
|
||||
if (isPositiveAndBelow (digit, 10))
|
||||
{
|
||||
intValue = intValue * 10 + digit;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == 'e' || c == 'E' || c == '.')
|
||||
{
|
||||
currentLocation = originalPos;
|
||||
auto asDouble = CharacterFunctions::readDoubleValue (currentLocation);
|
||||
return var (isNegative ? -asDouble : asDouble);
|
||||
}
|
||||
|
||||
if (CharacterFunctions::isWhitespace (c)
|
||||
|| c == ',' || c == '}' || c == ']' || c == 0)
|
||||
{
|
||||
currentLocation = lastPos;
|
||||
break;
|
||||
}
|
||||
|
||||
throwError ("Syntax error in number", lastPos);
|
||||
}
|
||||
|
||||
auto correctedValue = isNegative ? -intValue : intValue;
|
||||
|
||||
return (intValue >> 31) != 0 ? var (correctedValue)
|
||||
: var ((int) correctedValue);
|
||||
}
|
||||
|
||||
var parseObject()
|
||||
{
|
||||
auto resultObject = new DynamicObject();
|
||||
var result (resultObject);
|
||||
auto& resultProperties = resultObject->getProperties();
|
||||
auto startOfObjectDecl = currentLocation;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
skipWhitespace();
|
||||
auto errorLocation = currentLocation;
|
||||
auto c = readChar();
|
||||
|
||||
if (c == '}')
|
||||
break;
|
||||
|
||||
if (c == 0)
|
||||
throwError ("Unexpected EOF in object declaration", startOfObjectDecl);
|
||||
|
||||
if (c != '"')
|
||||
throwError ("Expected a property name in double-quotes", errorLocation);
|
||||
|
||||
errorLocation = currentLocation;
|
||||
Identifier propertyName (parseString ('"'));
|
||||
|
||||
if (! propertyName.isValid())
|
||||
throwError ("Invalid property name", errorLocation);
|
||||
|
||||
skipWhitespace();
|
||||
errorLocation = currentLocation;
|
||||
|
||||
if (readChar() != ':')
|
||||
throwError ("Expected ':'", errorLocation);
|
||||
|
||||
resultProperties.set (propertyName, parseAny());
|
||||
|
||||
skipWhitespace();
|
||||
if (matchIf (',')) continue;
|
||||
if (matchIf ('}')) break;
|
||||
|
||||
throwError ("Expected ',' or '}'", currentLocation);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var parseArray()
|
||||
{
|
||||
auto result = var (Array<var>());
|
||||
auto destArray = result.getArray();
|
||||
auto startOfArrayDecl = currentLocation;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
skipWhitespace();
|
||||
|
||||
if (matchIf (']'))
|
||||
break;
|
||||
|
||||
if (isEOF())
|
||||
throwError ("Unexpected EOF in array declaration", startOfArrayDecl);
|
||||
|
||||
destArray->add (parseAny());
|
||||
skipWhitespace();
|
||||
|
||||
if (matchIf (',')) continue;
|
||||
if (matchIf (']')) break;
|
||||
|
||||
throwError ("Expected ',' or ']'", currentLocation);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct JSONFormatter
|
||||
{
|
||||
static void write (OutputStream& out, const var& v,
|
||||
int indentLevel, bool allOnOneLine, int maximumDecimalPlaces)
|
||||
{
|
||||
if (v.isString())
|
||||
{
|
||||
out << '"';
|
||||
writeString (out, v.toString().getCharPointer());
|
||||
out << '"';
|
||||
}
|
||||
else if (v.isVoid())
|
||||
{
|
||||
out << "null";
|
||||
}
|
||||
else if (v.isUndefined())
|
||||
{
|
||||
out << "undefined";
|
||||
}
|
||||
else if (v.isBool())
|
||||
{
|
||||
out << (static_cast<bool> (v) ? "true" : "false");
|
||||
}
|
||||
else if (v.isDouble())
|
||||
{
|
||||
auto d = static_cast<double> (v);
|
||||
|
||||
if (juce_isfinite (d))
|
||||
{
|
||||
out << serialiseDouble (d);
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "null";
|
||||
}
|
||||
}
|
||||
else if (v.isArray())
|
||||
{
|
||||
writeArray (out, *v.getArray(), indentLevel, allOnOneLine, maximumDecimalPlaces);
|
||||
}
|
||||
else if (v.isObject())
|
||||
{
|
||||
if (auto* object = v.getDynamicObject())
|
||||
object->writeAsJSON (out, indentLevel, allOnOneLine, maximumDecimalPlaces);
|
||||
else
|
||||
jassertfalse; // Only DynamicObjects can be converted to JSON!
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can't convert these other types of object to JSON!
|
||||
jassert (! (v.isMethod() || v.isBinaryData()));
|
||||
|
||||
out << v.toString();
|
||||
}
|
||||
}
|
||||
|
||||
static void writeEscapedChar (OutputStream& out, const unsigned short value)
|
||||
{
|
||||
out << "\\u" << String::toHexString ((int) value).paddedLeft ('0', 4);
|
||||
}
|
||||
|
||||
static void writeString (OutputStream& out, String::CharPointerType t)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
auto c = t.getAndAdvance();
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0: return;
|
||||
|
||||
case '\"': out << "\\\""; break;
|
||||
case '\\': out << "\\\\"; break;
|
||||
case '\a': out << "\\a"; break;
|
||||
case '\b': out << "\\b"; break;
|
||||
case '\f': out << "\\f"; break;
|
||||
case '\t': out << "\\t"; break;
|
||||
case '\r': out << "\\r"; break;
|
||||
case '\n': out << "\\n"; break;
|
||||
|
||||
default:
|
||||
if (c >= 32 && c < 127)
|
||||
{
|
||||
out << (char) c;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CharPointer_UTF16::getBytesRequiredFor (c) > 2)
|
||||
{
|
||||
CharPointer_UTF16::CharType chars[2];
|
||||
CharPointer_UTF16 utf16 (chars);
|
||||
utf16.write (c);
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
writeEscapedChar (out, (unsigned short) chars[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeEscapedChar (out, (unsigned short) c);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void writeSpaces (OutputStream& out, int numSpaces)
|
||||
{
|
||||
out.writeRepeatedByte (' ', (size_t) numSpaces);
|
||||
}
|
||||
|
||||
static void writeArray (OutputStream& out, const Array<var>& array,
|
||||
int indentLevel, bool allOnOneLine, int maximumDecimalPlaces)
|
||||
{
|
||||
out << '[';
|
||||
|
||||
if (! array.isEmpty())
|
||||
{
|
||||
if (! allOnOneLine)
|
||||
out << newLine;
|
||||
|
||||
for (int i = 0; i < array.size(); ++i)
|
||||
{
|
||||
if (! allOnOneLine)
|
||||
writeSpaces (out, indentLevel + indentSize);
|
||||
|
||||
write (out, array.getReference(i), indentLevel + indentSize, allOnOneLine, maximumDecimalPlaces);
|
||||
|
||||
if (i < array.size() - 1)
|
||||
{
|
||||
if (allOnOneLine)
|
||||
out << ", ";
|
||||
else
|
||||
out << ',' << newLine;
|
||||
}
|
||||
else if (! allOnOneLine)
|
||||
out << newLine;
|
||||
}
|
||||
|
||||
if (! allOnOneLine)
|
||||
writeSpaces (out, indentLevel);
|
||||
}
|
||||
|
||||
out << ']';
|
||||
}
|
||||
|
||||
enum { indentSize = 2 };
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
var JSON::parse (const String& text)
|
||||
{
|
||||
var result;
|
||||
|
||||
if (parse (text, result))
|
||||
return result;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
var JSON::fromString (StringRef text)
|
||||
{
|
||||
try
|
||||
{
|
||||
return JSONParser (text.text).parseAny();
|
||||
}
|
||||
catch (const JSONParser::ErrorException&) {}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
var JSON::parse (InputStream& input)
|
||||
{
|
||||
return parse (input.readEntireStreamAsString());
|
||||
}
|
||||
|
||||
var JSON::parse (const File& file)
|
||||
{
|
||||
return parse (file.loadFileAsString());
|
||||
}
|
||||
|
||||
Result JSON::parse (const String& text, var& result)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = JSONParser (text.getCharPointer()).parseObjectOrArray();
|
||||
}
|
||||
catch (const JSONParser::ErrorException& error)
|
||||
{
|
||||
return error.getResult();
|
||||
}
|
||||
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
String JSON::toString (const var& data, const bool allOnOneLine, int maximumDecimalPlaces)
|
||||
{
|
||||
MemoryOutputStream mo (1024);
|
||||
JSONFormatter::write (mo, data, 0, allOnOneLine, maximumDecimalPlaces);
|
||||
return mo.toUTF8();
|
||||
}
|
||||
|
||||
void JSON::writeToStream (OutputStream& output, const var& data, const bool allOnOneLine, int maximumDecimalPlaces)
|
||||
{
|
||||
JSONFormatter::write (output, data, 0, allOnOneLine, maximumDecimalPlaces);
|
||||
}
|
||||
|
||||
String JSON::escapeString (StringRef s)
|
||||
{
|
||||
MemoryOutputStream mo;
|
||||
JSONFormatter::writeString (mo, s.text);
|
||||
return mo.toString();
|
||||
}
|
||||
|
||||
Result JSON::parseQuotedString (String::CharPointerType& t, var& result)
|
||||
{
|
||||
try
|
||||
{
|
||||
JSONParser parser (t);
|
||||
auto quote = parser.readChar();
|
||||
|
||||
if (quote != '"' && quote != '\'')
|
||||
return Result::fail ("Not a quoted string!");
|
||||
|
||||
result = parser.parseString (quote);
|
||||
t = parser.currentLocation;
|
||||
}
|
||||
catch (const JSONParser::ErrorException& error)
|
||||
{
|
||||
return error.getResult();
|
||||
}
|
||||
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
class JSONTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
JSONTests()
|
||||
: UnitTest ("JSON", UnitTestCategories::json)
|
||||
{}
|
||||
|
||||
static String createRandomWideCharString (Random& r)
|
||||
{
|
||||
juce_wchar buffer[40] = { 0 };
|
||||
|
||||
for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
|
||||
{
|
||||
if (r.nextBool())
|
||||
{
|
||||
do
|
||||
{
|
||||
buffer[i] = (juce_wchar) (1 + r.nextInt (0x10ffff - 1));
|
||||
}
|
||||
while (! CharPointer_UTF16::canRepresent (buffer[i]));
|
||||
}
|
||||
else
|
||||
buffer[i] = (juce_wchar) (1 + r.nextInt (0xff));
|
||||
}
|
||||
|
||||
return CharPointer_UTF32 (buffer);
|
||||
}
|
||||
|
||||
static String createRandomIdentifier (Random& r)
|
||||
{
|
||||
char buffer[30] = { 0 };
|
||||
|
||||
for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
|
||||
{
|
||||
static const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-:";
|
||||
buffer[i] = chars [r.nextInt (sizeof (chars) - 1)];
|
||||
}
|
||||
|
||||
return CharPointer_ASCII (buffer);
|
||||
}
|
||||
|
||||
// Creates a random double that can be easily stringified, to avoid
|
||||
// false failures when decimal places are rounded or truncated slightly
|
||||
static var createRandomDouble (Random& r)
|
||||
{
|
||||
return var ((r.nextDouble() * 1000.0) + 0.1);
|
||||
}
|
||||
|
||||
static var createRandomVar (Random& r, int depth)
|
||||
{
|
||||
switch (r.nextInt (depth > 3 ? 6 : 8))
|
||||
{
|
||||
case 0: return {};
|
||||
case 1: return r.nextInt();
|
||||
case 2: return r.nextInt64();
|
||||
case 3: return r.nextBool();
|
||||
case 4: return createRandomDouble (r);
|
||||
case 5: return createRandomWideCharString (r);
|
||||
|
||||
case 6:
|
||||
{
|
||||
var v (createRandomVar (r, depth + 1));
|
||||
|
||||
for (int i = 1 + r.nextInt (30); --i >= 0;)
|
||||
v.append (createRandomVar (r, depth + 1));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
case 7:
|
||||
{
|
||||
auto o = new DynamicObject();
|
||||
|
||||
for (int i = r.nextInt (30); --i >= 0;)
|
||||
o->setProperty (createRandomIdentifier (r), createRandomVar (r, depth + 1));
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
{
|
||||
beginTest ("JSON");
|
||||
|
||||
auto r = getRandom();
|
||||
|
||||
expect (JSON::parse (String()) == var());
|
||||
expect (JSON::parse ("{}").isObject());
|
||||
expect (JSON::parse ("[]").isArray());
|
||||
expect (JSON::parse ("[ 1234 ]")[0].isInt());
|
||||
expect (JSON::parse ("[ 12345678901234 ]")[0].isInt64());
|
||||
expect (JSON::parse ("[ 1.123e3 ]")[0].isDouble());
|
||||
expect (JSON::parse ("[ -1234]")[0].isInt());
|
||||
expect (JSON::parse ("[-12345678901234]")[0].isInt64());
|
||||
expect (JSON::parse ("[-1.123e3]")[0].isDouble());
|
||||
|
||||
for (int i = 100; --i >= 0;)
|
||||
{
|
||||
var v;
|
||||
|
||||
if (i > 0)
|
||||
v = createRandomVar (r, 0);
|
||||
|
||||
const bool oneLine = r.nextBool();
|
||||
String asString (JSON::toString (v, oneLine));
|
||||
var parsed = JSON::parse ("[" + asString + "]")[0];
|
||||
String parsedString (JSON::toString (parsed, oneLine));
|
||||
expect (asString.isNotEmpty() && parsedString == asString);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
beginTest ("Float formatting");
|
||||
|
||||
std::map<double, String> tests;
|
||||
tests[1] = "1.0";
|
||||
tests[1.1] = "1.1";
|
||||
tests[1.01] = "1.01";
|
||||
tests[0.76378] = "0.76378";
|
||||
tests[-10] = "-10.0";
|
||||
tests[10.01] = "10.01";
|
||||
tests[0.0123] = "0.0123";
|
||||
tests[-3.7e-27] = "-3.7e-27";
|
||||
tests[1e+40] = "1.0e40";
|
||||
tests[-12345678901234567.0] = "-1.234567890123457e16";
|
||||
tests[192000] = "192000.0";
|
||||
tests[1234567] = "1.234567e6";
|
||||
tests[0.00006] = "0.00006";
|
||||
tests[0.000006] = "6.0e-6";
|
||||
|
||||
for (auto& test : tests)
|
||||
expectEquals (JSON::toString (test.first), test.second);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static JSONTests JSONUnitTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
136
deps/juce/modules/juce_core/javascript/juce_JSON.h
vendored
Normal file
136
deps/juce/modules/juce_core/javascript/juce_JSON.h
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 JSON-formatted text to and from var objects.
|
||||
|
||||
The var class is structurally compatible with JSON-formatted data, so these
|
||||
functions allow you to parse JSON into a var object, and to convert a var
|
||||
object to JSON-formatted text.
|
||||
|
||||
@see var
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API JSON
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Parses a string of JSON-formatted text, and returns a result code containing
|
||||
any parse errors.
|
||||
|
||||
This will return the parsed structure in the parsedResult parameter, and will
|
||||
return a Result object to indicate whether parsing was successful, and if not,
|
||||
it will contain an error message.
|
||||
|
||||
If you're not interested in the error message, you can use one of the other
|
||||
shortcut parse methods, which simply return a var() if the parsing fails.
|
||||
|
||||
Note that this will only parse valid JSON, which means that the item given must
|
||||
be either an object or an array definition. If you want to also be able to parse
|
||||
any kind of primitive JSON object, use the fromString() method.
|
||||
*/
|
||||
static Result parse (const String& text, var& parsedResult);
|
||||
|
||||
/** Attempts to parse some JSON-formatted text, and returns the result as a var object.
|
||||
|
||||
If the parsing fails, this simply returns var() - if you need to find out more
|
||||
detail about the parse error, use the alternative parse() method which returns a Result.
|
||||
|
||||
Note that this will only parse valid JSON, which means that the item given must
|
||||
be either an object or an array definition. If you want to also be able to parse
|
||||
any kind of primitive JSON object, use the fromString() method.
|
||||
*/
|
||||
static var parse (const String& text);
|
||||
|
||||
/** Attempts to parse some JSON-formatted text from a file, and returns the result
|
||||
as a var object.
|
||||
|
||||
Note that this is just a short-cut for reading the entire file into a string and
|
||||
parsing the result.
|
||||
|
||||
If the parsing fails, this simply returns var() - if you need to find out more
|
||||
detail about the parse error, use the alternative parse() method which returns a Result.
|
||||
*/
|
||||
static var parse (const File& file);
|
||||
|
||||
/** Attempts to parse some JSON-formatted text from a stream, and returns the result
|
||||
as a var object.
|
||||
|
||||
Note that this is just a short-cut for reading the entire stream into a string and
|
||||
parsing the result.
|
||||
|
||||
If the parsing fails, this simply returns var() - if you need to find out more
|
||||
detail about the parse error, use the alternative parse() method which returns a Result.
|
||||
*/
|
||||
static var parse (InputStream& input);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a string which contains a JSON-formatted representation of the var object.
|
||||
If allOnOneLine is true, the result will be compacted into a single line of text
|
||||
with no carriage-returns. If false, it will be laid-out in a more human-readable format.
|
||||
The maximumDecimalPlaces parameter determines the precision of floating point numbers
|
||||
in scientific notation.
|
||||
@see writeToStream
|
||||
*/
|
||||
static String toString (const var& objectToFormat,
|
||||
bool allOnOneLine = false,
|
||||
int maximumDecimalPlaces = 15);
|
||||
|
||||
/** Parses a string that was created with the toString() method.
|
||||
This is slightly different to the parse() methods because they will reject primitive
|
||||
values and only accept array or object definitions, whereas this method will handle
|
||||
either.
|
||||
*/
|
||||
static var fromString (StringRef);
|
||||
|
||||
/** Writes a JSON-formatted representation of the var object to the given stream.
|
||||
If allOnOneLine is true, the result will be compacted into a single line of text
|
||||
with no carriage-returns. If false, it will be laid-out in a more human-readable format.
|
||||
The maximumDecimalPlaces parameter determines the precision of floating point numbers
|
||||
in scientific notation.
|
||||
@see toString
|
||||
*/
|
||||
static void writeToStream (OutputStream& output,
|
||||
const var& objectToFormat,
|
||||
bool allOnOneLine = false,
|
||||
int maximumDecimalPlaces = 15);
|
||||
|
||||
/** Returns a version of a string with any extended characters escaped. */
|
||||
static String escapeString (StringRef);
|
||||
|
||||
/** Parses a quoted string-literal in JSON format, returning the un-escaped result in the
|
||||
result parameter, and an error message in case the content was illegal.
|
||||
This advances the text parameter, leaving it positioned after the closing quote.
|
||||
*/
|
||||
static Result parseQuotedString (String::CharPointerType& text, var& result);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
JSON() = delete; // This class can't be instantiated - just use its static methods.
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
1919
deps/juce/modules/juce_core/javascript/juce_Javascript.cpp
vendored
Normal file
1919
deps/juce/modules/juce_core/javascript/juce_Javascript.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
122
deps/juce/modules/juce_core/javascript/juce_Javascript.h
vendored
Normal file
122
deps/juce/modules/juce_core/javascript/juce_Javascript.h
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 simple javascript interpreter!
|
||||
|
||||
It's not fully standards-compliant, and won't be as fast as the fancy JIT-compiled
|
||||
engines that you get in browsers, but this is an extremely compact, low-overhead javascript
|
||||
interpreter, which is integrated with the juce var and DynamicObject classes. If you need
|
||||
a few simple bits of scripting in your app, and want to be able to easily let the JS
|
||||
work with native objects defined as DynamicObject subclasses, then this might do the job.
|
||||
|
||||
To use, simply create an instance of this class and call execute() to run your code.
|
||||
Variables that the script sets can be retrieved with evaluate(), and if you need to provide
|
||||
native objects for the script to use, you can add them with registerNativeObject().
|
||||
|
||||
One caveat: Because the values and objects that the engine works with are DynamicObject
|
||||
and var objects, they use reference-counting rather than garbage-collection, so if your
|
||||
script creates complex connections between objects, you run the risk of creating cyclic
|
||||
dependencies and hence leaking.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API JavascriptEngine final
|
||||
{
|
||||
public:
|
||||
/** Creates an instance of the engine.
|
||||
This creates a root namespace and defines some basic Object, String, Array
|
||||
and Math library methods.
|
||||
*/
|
||||
JavascriptEngine();
|
||||
|
||||
/** Destructor. */
|
||||
~JavascriptEngine();
|
||||
|
||||
/** Attempts to parse and run a block of javascript code.
|
||||
If there's a parse or execution error, the error description is returned in
|
||||
the result.
|
||||
You can specify a maximum time for which the program is allowed to run, and
|
||||
it'll return with an error message if this time is exceeded.
|
||||
*/
|
||||
Result execute (const String& javascriptCode);
|
||||
|
||||
/** Attempts to parse and run a javascript expression, and returns the result.
|
||||
If there's a syntax error, or the expression can't be evaluated, the return value
|
||||
will be var::undefined(). The errorMessage parameter gives you a way to find out
|
||||
any parsing errors.
|
||||
You can specify a maximum time for which the program is allowed to run, and
|
||||
it'll return with an error message if this time is exceeded.
|
||||
*/
|
||||
var evaluate (const String& javascriptCode,
|
||||
Result* errorMessage = nullptr);
|
||||
|
||||
/** Calls a function in the root namespace, and returns the result.
|
||||
The function arguments are passed in the same format as used by native
|
||||
methods in the var class.
|
||||
*/
|
||||
var callFunction (const Identifier& function,
|
||||
const var::NativeFunctionArgs& args,
|
||||
Result* errorMessage = nullptr);
|
||||
|
||||
/** Calls a function object in the namespace of a dynamic object, and returns the result.
|
||||
The function arguments are passed in the same format as used by native
|
||||
methods in the var class.
|
||||
*/
|
||||
var callFunctionObject (DynamicObject* objectScope,
|
||||
const var& functionObject,
|
||||
const var::NativeFunctionArgs& args,
|
||||
Result* errorMessage = nullptr);
|
||||
|
||||
/** Adds a native object to the root namespace.
|
||||
The object passed-in is reference-counted, and will be retained by the
|
||||
engine until the engine is deleted. The name must be a simple JS identifier,
|
||||
without any dots.
|
||||
*/
|
||||
void registerNativeObject (const Identifier& objectName, DynamicObject* object);
|
||||
|
||||
/** This value indicates how long a call to one of the evaluate methods is permitted
|
||||
to run before timing-out and failing.
|
||||
The default value is a number of seconds, but you can change this to whatever value
|
||||
suits your application.
|
||||
*/
|
||||
RelativeTime maximumExecutionTime;
|
||||
|
||||
/** When called from another thread, causes the interpreter to time-out as soon as possible */
|
||||
void stop() noexcept;
|
||||
|
||||
/** Provides access to the set of properties of the root namespace object. */
|
||||
const NamedValueSet& getRootObjectProperties() const noexcept;
|
||||
|
||||
private:
|
||||
JUCE_PUBLIC_IN_DLL_BUILD (struct RootObject)
|
||||
const ReferenceCountedObjectPtr<RootObject> root;
|
||||
void prepareTimeout() const noexcept;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JavascriptEngine)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
284
deps/juce/modules/juce_core/juce_core.cpp
vendored
Normal file
284
deps/juce/modules/juce_core/juce_core.cpp
vendored
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifdef JUCE_CORE_H_INCLUDED
|
||||
/* When you add this cpp file to your project, you mustn't include it in a file where you've
|
||||
already included any other headers - just put it inside a file on its own, possibly with your config
|
||||
flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix
|
||||
header files that the compiler may be using.
|
||||
*/
|
||||
#error "Incorrect use of JUCE cpp file"
|
||||
#endif
|
||||
|
||||
#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1
|
||||
#define JUCE_CORE_INCLUDE_COM_SMART_PTR 1
|
||||
#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1
|
||||
#define JUCE_CORE_INCLUDE_JNI_HELPERS 1
|
||||
|
||||
#include "juce_core.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdarg>
|
||||
#include <locale>
|
||||
#include <thread>
|
||||
|
||||
#if ! JUCE_ANDROID
|
||||
#include <sys/timeb.h>
|
||||
#include <cwctype>
|
||||
#endif
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
#include <ctime>
|
||||
|
||||
#if JUCE_MINGW
|
||||
#include <ws2spi.h>
|
||||
#include <cstdio>
|
||||
#include <locale.h>
|
||||
#else
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4091)
|
||||
#include <Dbghelp.h>
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
|
||||
#if ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
#pragma comment (lib, "DbgHelp.lib")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
#if JUCE_LINUX || JUCE_BSD || JUCE_ANDROID
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/errno.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#if JUCE_WASM
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#if JUCE_LINUX || JUCE_BSD
|
||||
#include <stdio.h>
|
||||
#include <langinfo.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#if JUCE_USE_CURL
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <pwd.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/time.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if ! (JUCE_ANDROID || JUCE_WASM)
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if JUCE_MAC || JUCE_IOS
|
||||
#include <xlocale.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
#if JUCE_ANDROID
|
||||
#include <ifaddrs.h>
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
#undef check
|
||||
|
||||
//==============================================================================
|
||||
#ifndef JUCE_STANDALONE_APPLICATION
|
||||
JUCE_COMPILER_WARNING ("Please re-save your project with the latest Projucer version to avoid this warning")
|
||||
#define JUCE_STANDALONE_APPLICATION 0
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#include "containers/juce_AbstractFifo.cpp"
|
||||
#include "containers/juce_ArrayBase.cpp"
|
||||
#include "containers/juce_NamedValueSet.cpp"
|
||||
#include "containers/juce_OwnedArray.cpp"
|
||||
#include "containers/juce_PropertySet.cpp"
|
||||
#include "containers/juce_ReferenceCountedArray.cpp"
|
||||
#include "containers/juce_SparseSet.cpp"
|
||||
#include "files/juce_DirectoryIterator.cpp"
|
||||
#include "files/juce_RangedDirectoryIterator.cpp"
|
||||
#include "files/juce_File.cpp"
|
||||
#include "files/juce_FileInputStream.cpp"
|
||||
#include "files/juce_FileOutputStream.cpp"
|
||||
#include "files/juce_FileSearchPath.cpp"
|
||||
#include "files/juce_TemporaryFile.cpp"
|
||||
#include "logging/juce_FileLogger.cpp"
|
||||
#include "logging/juce_Logger.cpp"
|
||||
#include "maths/juce_BigInteger.cpp"
|
||||
#include "maths/juce_Expression.cpp"
|
||||
#include "maths/juce_Random.cpp"
|
||||
#include "memory/juce_MemoryBlock.cpp"
|
||||
#include "memory/juce_AllocationHooks.cpp"
|
||||
#include "misc/juce_RuntimePermissions.cpp"
|
||||
#include "misc/juce_Result.cpp"
|
||||
#include "misc/juce_Uuid.cpp"
|
||||
#include "misc/juce_ConsoleApplication.cpp"
|
||||
#include "network/juce_MACAddress.cpp"
|
||||
#include "network/juce_NamedPipe.cpp"
|
||||
#include "network/juce_Socket.cpp"
|
||||
#include "network/juce_IPAddress.cpp"
|
||||
#include "streams/juce_BufferedInputStream.cpp"
|
||||
#include "streams/juce_FileInputSource.cpp"
|
||||
#include "streams/juce_InputStream.cpp"
|
||||
#include "streams/juce_MemoryInputStream.cpp"
|
||||
#include "streams/juce_MemoryOutputStream.cpp"
|
||||
#include "streams/juce_SubregionStream.cpp"
|
||||
#include "system/juce_SystemStats.cpp"
|
||||
#include "text/juce_CharacterFunctions.cpp"
|
||||
#include "text/juce_Identifier.cpp"
|
||||
#include "text/juce_LocalisedStrings.cpp"
|
||||
#include "text/juce_String.cpp"
|
||||
#include "streams/juce_OutputStream.cpp"
|
||||
#include "text/juce_StringArray.cpp"
|
||||
#include "text/juce_StringPairArray.cpp"
|
||||
#include "text/juce_StringPool.cpp"
|
||||
#include "text/juce_TextDiff.cpp"
|
||||
#include "text/juce_Base64.cpp"
|
||||
#include "threads/juce_ReadWriteLock.cpp"
|
||||
#include "threads/juce_Thread.cpp"
|
||||
#include "threads/juce_ThreadPool.cpp"
|
||||
#include "threads/juce_TimeSliceThread.cpp"
|
||||
#include "time/juce_PerformanceCounter.cpp"
|
||||
#include "time/juce_RelativeTime.cpp"
|
||||
#include "time/juce_Time.cpp"
|
||||
#include "unit_tests/juce_UnitTest.cpp"
|
||||
#include "containers/juce_Variant.cpp"
|
||||
#include "javascript/juce_JSON.cpp"
|
||||
#include "javascript/juce_Javascript.cpp"
|
||||
#include "containers/juce_DynamicObject.cpp"
|
||||
#include "xml/juce_XmlDocument.cpp"
|
||||
#include "xml/juce_XmlElement.cpp"
|
||||
#include "zip/juce_GZIPDecompressorInputStream.cpp"
|
||||
#include "zip/juce_GZIPCompressorOutputStream.cpp"
|
||||
#include "zip/juce_ZipFile.cpp"
|
||||
#include "files/juce_FileFilter.cpp"
|
||||
#include "files/juce_WildcardFileFilter.cpp"
|
||||
|
||||
//==============================================================================
|
||||
#if ! JUCE_WINDOWS
|
||||
#include "native/juce_posix_SharedCode.h"
|
||||
#include "native/juce_posix_NamedPipe.cpp"
|
||||
#if ! JUCE_ANDROID || __ANDROID_API__ >= 24
|
||||
#include "native/juce_posix_IPAddress.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MAC || JUCE_IOS
|
||||
#include "native/juce_mac_Files.mm"
|
||||
#include "native/juce_mac_Network.mm"
|
||||
#include "native/juce_mac_Strings.mm"
|
||||
#include "native/juce_intel_SharedCode.h"
|
||||
#include "native/juce_mac_SystemStats.mm"
|
||||
#include "native/juce_mac_Threads.mm"
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_WINDOWS
|
||||
#include "native/juce_win32_Files.cpp"
|
||||
#include "native/juce_win32_Network.cpp"
|
||||
#include "native/juce_win32_Registry.cpp"
|
||||
#include "native/juce_win32_SystemStats.cpp"
|
||||
#include "native/juce_win32_Threads.cpp"
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_LINUX || JUCE_BSD
|
||||
#include "native/juce_linux_CommonFile.cpp"
|
||||
#include "native/juce_linux_Files.cpp"
|
||||
#include "native/juce_linux_Network.cpp"
|
||||
#if JUCE_USE_CURL
|
||||
#include "native/juce_curl_Network.cpp"
|
||||
#endif
|
||||
#if JUCE_BSD
|
||||
#include "native/juce_intel_SharedCode.h"
|
||||
#endif
|
||||
#include "native/juce_linux_SystemStats.cpp"
|
||||
#include "native/juce_linux_Threads.cpp"
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_ANDROID
|
||||
#include "native/juce_linux_CommonFile.cpp"
|
||||
#include "native/juce_android_JNIHelpers.cpp"
|
||||
#include "native/juce_android_Files.cpp"
|
||||
#include "native/juce_android_Misc.cpp"
|
||||
#include "native/juce_android_Network.cpp"
|
||||
#include "native/juce_android_SystemStats.cpp"
|
||||
#include "native/juce_android_Threads.cpp"
|
||||
#include "native/juce_android_RuntimePermissions.cpp"
|
||||
|
||||
#elif JUCE_WASM
|
||||
#include "native/juce_wasm_SystemStats.cpp"
|
||||
|
||||
#endif
|
||||
|
||||
#include "threads/juce_HighResolutionTimer.cpp"
|
||||
#include "threads/juce_WaitableEvent.cpp"
|
||||
#include "network/juce_URL.cpp"
|
||||
|
||||
#if ! JUCE_WASM
|
||||
#include "threads/juce_ChildProcess.cpp"
|
||||
#include "network/juce_WebInputStream.cpp"
|
||||
#include "streams/juce_URLInputSource.cpp"
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
#include "containers/juce_HashMap_test.cpp"
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
namespace juce
|
||||
{
|
||||
/*
|
||||
As the very long class names here try to explain, the purpose of this code is to cause
|
||||
a linker error if not all of your compile units are consistent in the options that they
|
||||
enable before including JUCE headers. The reason this is important is that if you have
|
||||
two cpp files, and one includes the juce headers with debug enabled, and the other doesn't,
|
||||
then each will be generating code with different memory layouts for the classes, and
|
||||
you'll get subtle and hard-to-track-down memory corruption bugs!
|
||||
*/
|
||||
#if JUCE_DEBUG
|
||||
this_will_fail_to_link_if_some_of_your_compile_units_are_built_in_debug_mode
|
||||
::this_will_fail_to_link_if_some_of_your_compile_units_are_built_in_debug_mode() noexcept {}
|
||||
#else
|
||||
this_will_fail_to_link_if_some_of_your_compile_units_are_built_in_release_mode
|
||||
::this_will_fail_to_link_if_some_of_your_compile_units_are_built_in_release_mode() noexcept {}
|
||||
#endif
|
||||
}
|
||||
391
deps/juce/modules/juce_core/juce_core.h
vendored
Normal file
391
deps/juce/modules/juce_core/juce_core.h
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
The block below describes the properties of this module, and is read by
|
||||
the Projucer to automatically generate project code that uses it.
|
||||
For details about the syntax and how to create or use a module, see the
|
||||
JUCE Module Format.md file.
|
||||
|
||||
|
||||
BEGIN_JUCE_MODULE_DECLARATION
|
||||
|
||||
ID: juce_core
|
||||
vendor: juce
|
||||
version: 6.1.2
|
||||
name: JUCE core classes
|
||||
description: The essential set of basic JUCE classes, as required by all the other JUCE modules. Includes text, container, memory, threading and i/o functionality.
|
||||
website: http://www.juce.com/juce
|
||||
license: ISC
|
||||
minimumCppStandard: 14
|
||||
|
||||
dependencies:
|
||||
OSXFrameworks: Cocoa Foundation IOKit
|
||||
iOSFrameworks: Foundation
|
||||
linuxLibs: rt dl pthread
|
||||
mingwLibs: uuid wsock32 wininet version ole32 ws2_32 oleaut32 imm32 comdlg32 shlwapi rpcrt4 winmm
|
||||
|
||||
END_JUCE_MODULE_DECLARATION
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#pragma once
|
||||
#define JUCE_CORE_H_INCLUDED
|
||||
|
||||
//==============================================================================
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
// Disable warnings for long class names, padding, and undefined preprocessor definitions.
|
||||
#pragma warning (disable: 4251 4786 4668 4820)
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning (disable: 1125)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "system/juce_TargetPlatform.h"
|
||||
|
||||
//==============================================================================
|
||||
/** Config: JUCE_FORCE_DEBUG
|
||||
|
||||
Normally, JUCE_DEBUG is set to 1 or 0 based on compiler and project settings,
|
||||
but if you define this value, you can override this to force it to be true or false.
|
||||
*/
|
||||
#ifndef JUCE_FORCE_DEBUG
|
||||
//#define JUCE_FORCE_DEBUG 0
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/** Config: JUCE_LOG_ASSERTIONS
|
||||
|
||||
If this flag is enabled, the jassert and jassertfalse macros will always use Logger::writeToLog()
|
||||
to write a message when an assertion happens.
|
||||
|
||||
Enabling it will also leave this turned on in release builds. When it's disabled,
|
||||
however, the jassert and jassertfalse macros will not be compiled in a
|
||||
release build.
|
||||
|
||||
@see jassert, jassertfalse, Logger
|
||||
*/
|
||||
#ifndef JUCE_LOG_ASSERTIONS
|
||||
#if JUCE_ANDROID
|
||||
#define JUCE_LOG_ASSERTIONS 1
|
||||
#else
|
||||
#define JUCE_LOG_ASSERTIONS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/** Config: JUCE_CHECK_MEMORY_LEAKS
|
||||
|
||||
Enables a memory-leak check for certain objects when the app terminates. See the LeakedObjectDetector
|
||||
class and the JUCE_LEAK_DETECTOR macro for more details about enabling leak checking for specific classes.
|
||||
*/
|
||||
#if JUCE_DEBUG && ! defined (JUCE_CHECK_MEMORY_LEAKS)
|
||||
#define JUCE_CHECK_MEMORY_LEAKS 1
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/** Config: JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
|
||||
In a Windows build, this can be used to stop the required system libs being
|
||||
automatically added to the link stage.
|
||||
*/
|
||||
#ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES 0
|
||||
#endif
|
||||
|
||||
/** Config: JUCE_INCLUDE_ZLIB_CODE
|
||||
This can be used to disable Juce's embedded 3rd-party zlib code.
|
||||
You might need to tweak this if you're linking to an external zlib library in your app,
|
||||
but for normal apps, this option should be left alone.
|
||||
|
||||
If you disable this, you might also want to set a value for JUCE_ZLIB_INCLUDE_PATH, to
|
||||
specify the path where your zlib headers live.
|
||||
*/
|
||||
#ifndef JUCE_INCLUDE_ZLIB_CODE
|
||||
#define JUCE_INCLUDE_ZLIB_CODE 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_ZLIB_INCLUDE_PATH
|
||||
#define JUCE_ZLIB_INCLUDE_PATH <zlib.h>
|
||||
#endif
|
||||
|
||||
/** Config: JUCE_USE_CURL
|
||||
Enables http/https support via libcurl (Linux only). Enabling this will add an additional
|
||||
run-time dynamic dependency to libcurl.
|
||||
|
||||
If you disable this then https/ssl support will not be available on Linux.
|
||||
*/
|
||||
#ifndef JUCE_USE_CURL
|
||||
#define JUCE_USE_CURL 1
|
||||
#endif
|
||||
|
||||
/** Config: JUCE_LOAD_CURL_SYMBOLS_LAZILY
|
||||
If enabled, JUCE will load libcurl lazily when required (for example, when WebInputStream
|
||||
is used). Enabling this flag may also help with library dependency errors as linking
|
||||
libcurl at compile-time may instruct the linker to hard depend on a specific version
|
||||
of libcurl. It's also useful if you want to limit the amount of JUCE dependencies and
|
||||
you are not using WebInputStream or the URL classes.
|
||||
*/
|
||||
#ifndef JUCE_LOAD_CURL_SYMBOLS_LAZILY
|
||||
#define JUCE_LOAD_CURL_SYMBOLS_LAZILY 0
|
||||
#endif
|
||||
|
||||
/** Config: JUCE_CATCH_UNHANDLED_EXCEPTIONS
|
||||
If enabled, this will add some exception-catching code to forward unhandled exceptions
|
||||
to your JUCEApplicationBase::unhandledException() callback.
|
||||
*/
|
||||
#ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS
|
||||
#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 0
|
||||
#endif
|
||||
|
||||
/** Config: JUCE_ALLOW_STATIC_NULL_VARIABLES
|
||||
If disabled, this will turn off dangerous static globals like String::empty, var::null, etc
|
||||
which can cause nasty order-of-initialisation problems if they are referenced during static
|
||||
constructor code.
|
||||
*/
|
||||
#ifndef JUCE_ALLOW_STATIC_NULL_VARIABLES
|
||||
#define JUCE_ALLOW_STATIC_NULL_VARIABLES 0
|
||||
#endif
|
||||
|
||||
/** Config: JUCE_STRICT_REFCOUNTEDPOINTER
|
||||
If enabled, this will make the ReferenceCountedObjectPtr class stricter about allowing
|
||||
itself to be cast directly to a raw pointer. By default this is disabled, for compatibility
|
||||
with old code, but if possible, you should always enable it to improve code safety!
|
||||
*/
|
||||
#ifndef JUCE_STRICT_REFCOUNTEDPOINTER
|
||||
#define JUCE_STRICT_REFCOUNTEDPOINTER 0
|
||||
#endif
|
||||
|
||||
/** Config: JUCE_ENABLE_ALLOCATION_HOOKS
|
||||
If enabled, this will add global allocation functions with built-in assertions, which may
|
||||
help when debugging allocations in unit tests.
|
||||
*/
|
||||
#ifndef JUCE_ENABLE_ALLOCATION_HOOKS
|
||||
#define JUCE_ENABLE_ALLOCATION_HOOKS 0
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_STRING_UTF_TYPE
|
||||
#define JUCE_STRING_UTF_TYPE 8
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
|
||||
#if JUCE_CORE_INCLUDE_NATIVE_HEADERS
|
||||
#include "native/juce_BasicNativeHeaders.h"
|
||||
#endif
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
#undef small
|
||||
#endif
|
||||
|
||||
#include "system/juce_StandardHeader.h"
|
||||
|
||||
namespace juce
|
||||
{
|
||||
class StringRef;
|
||||
class MemoryBlock;
|
||||
class File;
|
||||
class InputStream;
|
||||
class OutputStream;
|
||||
class DynamicObject;
|
||||
class FileInputStream;
|
||||
class FileOutputStream;
|
||||
class XmlElement;
|
||||
|
||||
extern JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept;
|
||||
extern JUCE_API void JUCE_CALLTYPE logAssertion (const char* file, int line) noexcept;
|
||||
}
|
||||
|
||||
#include "memory/juce_Memory.h"
|
||||
#include "maths/juce_MathsFunctions.h"
|
||||
#include "memory/juce_ByteOrder.h"
|
||||
#include "memory/juce_Atomic.h"
|
||||
#include "text/juce_CharacterFunctions.h"
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4514 4996)
|
||||
|
||||
#include "text/juce_CharPointer_UTF8.h"
|
||||
#include "text/juce_CharPointer_UTF16.h"
|
||||
#include "text/juce_CharPointer_UTF32.h"
|
||||
#include "text/juce_CharPointer_ASCII.h"
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
|
||||
#include "text/juce_String.h"
|
||||
#include "text/juce_StringRef.h"
|
||||
#include "logging/juce_Logger.h"
|
||||
#include "memory/juce_LeakedObjectDetector.h"
|
||||
#include "memory/juce_ContainerDeletePolicy.h"
|
||||
#include "memory/juce_HeapBlock.h"
|
||||
#include "memory/juce_MemoryBlock.h"
|
||||
#include "memory/juce_ReferenceCountedObject.h"
|
||||
#include "memory/juce_ScopedPointer.h"
|
||||
#include "memory/juce_OptionalScopedPointer.h"
|
||||
#include "memory/juce_Singleton.h"
|
||||
#include "memory/juce_WeakReference.h"
|
||||
#include "threads/juce_ScopedLock.h"
|
||||
#include "threads/juce_CriticalSection.h"
|
||||
#include "maths/juce_Range.h"
|
||||
#include "maths/juce_NormalisableRange.h"
|
||||
#include "maths/juce_StatisticsAccumulator.h"
|
||||
#include "containers/juce_ElementComparator.h"
|
||||
#include "containers/juce_ArrayAllocationBase.h"
|
||||
#include "containers/juce_ArrayBase.h"
|
||||
#include "containers/juce_Array.h"
|
||||
#include "containers/juce_LinkedListPointer.h"
|
||||
#include "containers/juce_ListenerList.h"
|
||||
#include "containers/juce_OwnedArray.h"
|
||||
#include "containers/juce_ReferenceCountedArray.h"
|
||||
#include "containers/juce_ScopedValueSetter.h"
|
||||
#include "containers/juce_SortedSet.h"
|
||||
#include "containers/juce_SparseSet.h"
|
||||
#include "containers/juce_AbstractFifo.h"
|
||||
#include "containers/juce_SingleThreadedAbstractFifo.h"
|
||||
#include "text/juce_NewLine.h"
|
||||
#include "text/juce_StringPool.h"
|
||||
#include "text/juce_Identifier.h"
|
||||
#include "text/juce_StringArray.h"
|
||||
#include "system/juce_SystemStats.h"
|
||||
#include "memory/juce_HeavyweightLeakedObjectDetector.h"
|
||||
#include "text/juce_StringPairArray.h"
|
||||
#include "text/juce_TextDiff.h"
|
||||
#include "text/juce_LocalisedStrings.h"
|
||||
#include "text/juce_Base64.h"
|
||||
#include "misc/juce_Functional.h"
|
||||
#include "misc/juce_Result.h"
|
||||
#include "misc/juce_Uuid.h"
|
||||
#include "misc/juce_ConsoleApplication.h"
|
||||
#include "containers/juce_Variant.h"
|
||||
#include "containers/juce_NamedValueSet.h"
|
||||
#include "containers/juce_DynamicObject.h"
|
||||
#include "containers/juce_HashMap.h"
|
||||
#include "time/juce_RelativeTime.h"
|
||||
#include "time/juce_Time.h"
|
||||
#include "streams/juce_InputStream.h"
|
||||
#include "streams/juce_OutputStream.h"
|
||||
#include "streams/juce_BufferedInputStream.h"
|
||||
#include "streams/juce_MemoryInputStream.h"
|
||||
#include "streams/juce_MemoryOutputStream.h"
|
||||
#include "streams/juce_SubregionStream.h"
|
||||
#include "streams/juce_InputSource.h"
|
||||
#include "files/juce_File.h"
|
||||
#include "files/juce_DirectoryIterator.h"
|
||||
#include "files/juce_RangedDirectoryIterator.h"
|
||||
#include "files/juce_FileInputStream.h"
|
||||
#include "files/juce_FileOutputStream.h"
|
||||
#include "files/juce_FileSearchPath.h"
|
||||
#include "files/juce_MemoryMappedFile.h"
|
||||
#include "files/juce_TemporaryFile.h"
|
||||
#include "files/juce_FileFilter.h"
|
||||
#include "files/juce_WildcardFileFilter.h"
|
||||
#include "streams/juce_FileInputSource.h"
|
||||
#include "logging/juce_FileLogger.h"
|
||||
#include "javascript/juce_JSON.h"
|
||||
#include "javascript/juce_Javascript.h"
|
||||
#include "maths/juce_BigInteger.h"
|
||||
#include "maths/juce_Expression.h"
|
||||
#include "maths/juce_Random.h"
|
||||
#include "misc/juce_RuntimePermissions.h"
|
||||
#include "misc/juce_WindowsRegistry.h"
|
||||
#include "threads/juce_ChildProcess.h"
|
||||
#include "threads/juce_DynamicLibrary.h"
|
||||
#include "threads/juce_HighResolutionTimer.h"
|
||||
#include "threads/juce_InterProcessLock.h"
|
||||
#include "threads/juce_Process.h"
|
||||
#include "threads/juce_SpinLock.h"
|
||||
#include "threads/juce_WaitableEvent.h"
|
||||
#include "threads/juce_Thread.h"
|
||||
#include "threads/juce_ThreadLocalValue.h"
|
||||
#include "threads/juce_ThreadPool.h"
|
||||
#include "threads/juce_TimeSliceThread.h"
|
||||
#include "threads/juce_ReadWriteLock.h"
|
||||
#include "threads/juce_ScopedReadLock.h"
|
||||
#include "threads/juce_ScopedWriteLock.h"
|
||||
#include "network/juce_IPAddress.h"
|
||||
#include "network/juce_MACAddress.h"
|
||||
#include "network/juce_NamedPipe.h"
|
||||
#include "network/juce_Socket.h"
|
||||
#include "network/juce_URL.h"
|
||||
#include "network/juce_WebInputStream.h"
|
||||
#include "streams/juce_URLInputSource.h"
|
||||
#include "time/juce_PerformanceCounter.h"
|
||||
#include "unit_tests/juce_UnitTest.h"
|
||||
#include "xml/juce_XmlDocument.h"
|
||||
#include "xml/juce_XmlElement.h"
|
||||
#include "zip/juce_GZIPCompressorOutputStream.h"
|
||||
#include "zip/juce_GZIPDecompressorInputStream.h"
|
||||
#include "zip/juce_ZipFile.h"
|
||||
#include "containers/juce_PropertySet.h"
|
||||
#include "memory/juce_SharedResourcePointer.h"
|
||||
#include "memory/juce_AllocationHooks.h"
|
||||
#include "memory/juce_Reservoir.h"
|
||||
|
||||
#if JUCE_CORE_INCLUDE_OBJC_HELPERS && (JUCE_MAC || JUCE_IOS)
|
||||
#include "native/juce_mac_ObjCHelpers.h"
|
||||
#endif
|
||||
|
||||
#if JUCE_CORE_INCLUDE_COM_SMART_PTR && JUCE_WINDOWS
|
||||
#include "native/juce_win32_ComSmartPtr.h"
|
||||
#endif
|
||||
|
||||
#if JUCE_CORE_INCLUDE_JNI_HELPERS && JUCE_ANDROID
|
||||
#include <jni.h>
|
||||
#include "native/juce_android_JNIHelpers.h"
|
||||
#endif
|
||||
|
||||
#if JUCE_UNIT_TESTS
|
||||
#include "unit_tests/juce_UnitTestCategories.h"
|
||||
#endif
|
||||
|
||||
#ifndef DOXYGEN
|
||||
namespace juce
|
||||
{
|
||||
/*
|
||||
As the very long class names here try to explain, the purpose of this code is to cause
|
||||
a linker error if not all of your compile units are consistent in the options that they
|
||||
enable before including JUCE headers. The reason this is important is that if you have
|
||||
two cpp files, and one includes the juce headers with debug enabled, and another does so
|
||||
without that, then each will be generating code with different class layouts, and you'll
|
||||
get subtle and hard-to-track-down memory corruption!
|
||||
*/
|
||||
#if JUCE_DEBUG
|
||||
struct JUCE_API this_will_fail_to_link_if_some_of_your_compile_units_are_built_in_debug_mode
|
||||
{ this_will_fail_to_link_if_some_of_your_compile_units_are_built_in_debug_mode() noexcept; };
|
||||
static this_will_fail_to_link_if_some_of_your_compile_units_are_built_in_debug_mode compileUnitMismatchSentinel;
|
||||
#else
|
||||
struct JUCE_API this_will_fail_to_link_if_some_of_your_compile_units_are_built_in_release_mode
|
||||
{ this_will_fail_to_link_if_some_of_your_compile_units_are_built_in_release_mode() noexcept; };
|
||||
static this_will_fail_to_link_if_some_of_your_compile_units_are_built_in_release_mode compileUnitMismatchSentinel;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
|
||||
// In DLL builds, need to disable this warnings for other modules
|
||||
#if defined (JUCE_DLL_BUILD) || defined (JUCE_DLL)
|
||||
JUCE_IGNORE_MSVC (4251)
|
||||
#endif
|
||||
23
deps/juce/modules/juce_core/juce_core.mm
vendored
Normal file
23
deps/juce/modules/juce_core/juce_core.mm
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "juce_core.cpp"
|
||||
133
deps/juce/modules/juce_core/logging/juce_FileLogger.cpp
vendored
Normal file
133
deps/juce/modules/juce_core/logging/juce_FileLogger.cpp
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
FileLogger::FileLogger (const File& file,
|
||||
const String& welcomeMessage,
|
||||
const int64 maxInitialFileSizeBytes)
|
||||
: logFile (file)
|
||||
{
|
||||
if (maxInitialFileSizeBytes >= 0)
|
||||
trimFileSize (logFile, maxInitialFileSizeBytes);
|
||||
|
||||
if (! file.exists())
|
||||
file.create(); // (to create the parent directories)
|
||||
|
||||
String welcome;
|
||||
welcome << newLine
|
||||
<< "**********************************************************" << newLine
|
||||
<< welcomeMessage << newLine
|
||||
<< "Log started: " << Time::getCurrentTime().toString (true, true) << newLine;
|
||||
|
||||
FileLogger::logMessage (welcome);
|
||||
}
|
||||
|
||||
FileLogger::~FileLogger() {}
|
||||
|
||||
//==============================================================================
|
||||
void FileLogger::logMessage (const String& message)
|
||||
{
|
||||
const ScopedLock sl (logLock);
|
||||
DBG (message);
|
||||
FileOutputStream out (logFile, 256);
|
||||
out << message << newLine;
|
||||
}
|
||||
|
||||
void FileLogger::trimFileSize (const File& file, int64 maxFileSizeBytes)
|
||||
{
|
||||
if (maxFileSizeBytes <= 0)
|
||||
{
|
||||
file.deleteFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
const int64 fileSize = file.getSize();
|
||||
|
||||
if (fileSize > maxFileSizeBytes)
|
||||
{
|
||||
TemporaryFile tempFile (file);
|
||||
|
||||
{
|
||||
FileOutputStream out (tempFile.getFile());
|
||||
FileInputStream in (file);
|
||||
|
||||
if (! (out.openedOk() && in.openedOk()))
|
||||
return;
|
||||
|
||||
in.setPosition (fileSize - maxFileSizeBytes);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const char c = in.readByte();
|
||||
if (c == 0)
|
||||
return;
|
||||
|
||||
if (c == '\n' || c == '\r')
|
||||
{
|
||||
out << c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out.writeFromInputStream (in, -1);
|
||||
}
|
||||
|
||||
tempFile.overwriteTargetFileWithTemporary();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
File FileLogger::getSystemLogFileFolder()
|
||||
{
|
||||
#if JUCE_MAC
|
||||
return File ("~/Library/Logs");
|
||||
#else
|
||||
return File::getSpecialLocation (File::userApplicationDataDirectory);
|
||||
#endif
|
||||
}
|
||||
|
||||
FileLogger* FileLogger::createDefaultAppLogger (const String& logFileSubDirectoryName,
|
||||
const String& logFileName,
|
||||
const String& welcomeMessage,
|
||||
const int64 maxInitialFileSizeBytes)
|
||||
{
|
||||
return new FileLogger (getSystemLogFileFolder().getChildFile (logFileSubDirectoryName)
|
||||
.getChildFile (logFileName),
|
||||
welcomeMessage, maxInitialFileSizeBytes);
|
||||
}
|
||||
|
||||
FileLogger* FileLogger::createDateStampedLogger (const String& logFileSubDirectoryName,
|
||||
const String& logFileNameRoot,
|
||||
const String& logFileNameSuffix,
|
||||
const String& welcomeMessage)
|
||||
{
|
||||
return new FileLogger (getSystemLogFileFolder().getChildFile (logFileSubDirectoryName)
|
||||
.getChildFile (logFileNameRoot + Time::getCurrentTime().formatted ("%Y-%m-%d_%H-%M-%S"))
|
||||
.withFileExtension (logFileNameSuffix)
|
||||
.getNonexistentSibling(),
|
||||
welcomeMessage, 0);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
133
deps/juce/modules/juce_core/logging/juce_FileLogger.h
vendored
Normal file
133
deps/juce/modules/juce_core/logging/juce_FileLogger.h
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 simple implementation of a Logger that writes to a file.
|
||||
|
||||
@see Logger
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API FileLogger : public Logger
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a FileLogger for a given file.
|
||||
|
||||
@param fileToWriteTo the file that to use - new messages will be appended
|
||||
to the file. If the file doesn't exist, it will be created,
|
||||
along with any parent directories that are needed.
|
||||
@param welcomeMessage when opened, the logger will write a header to the log, along
|
||||
with the current date and time, and this welcome message
|
||||
@param maxInitialFileSizeBytes if this is zero or greater, then if the file already exists
|
||||
but is larger than this number of bytes, then the start of the
|
||||
file will be truncated to keep the size down. This prevents a log
|
||||
file getting ridiculously large over time. The file will be truncated
|
||||
at a new-line boundary. If this value is less than zero, no size limit
|
||||
will be imposed; if it's zero, the file will always be deleted. Note that
|
||||
the size is only checked once when this object is created - any logging
|
||||
that is done later will be appended without any checking
|
||||
*/
|
||||
FileLogger (const File& fileToWriteTo,
|
||||
const String& welcomeMessage,
|
||||
const int64 maxInitialFileSizeBytes = 128 * 1024);
|
||||
|
||||
/** Destructor. */
|
||||
~FileLogger() override;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the file that this logger is writing to. */
|
||||
const File& getLogFile() const noexcept { return logFile; }
|
||||
|
||||
//==============================================================================
|
||||
/** Helper function to create a log file in the correct place for this platform.
|
||||
|
||||
The method might return nullptr if the file can't be created for some reason.
|
||||
|
||||
@param logFileSubDirectoryName the name of the subdirectory to create inside the logs folder (as
|
||||
returned by getSystemLogFileFolder). It's best to use something
|
||||
like the name of your application here.
|
||||
@param logFileName the name of the file to create, e.g. "MyAppLog.txt".
|
||||
@param welcomeMessage a message that will be written to the log when it's opened.
|
||||
@param maxInitialFileSizeBytes (see the FileLogger constructor for more info on this)
|
||||
*/
|
||||
static FileLogger* createDefaultAppLogger (const String& logFileSubDirectoryName,
|
||||
const String& logFileName,
|
||||
const String& welcomeMessage,
|
||||
const int64 maxInitialFileSizeBytes = 128 * 1024);
|
||||
|
||||
/** Helper function to create a log file in the correct place for this platform.
|
||||
|
||||
The filename used is based on the root and suffix strings provided, along with a
|
||||
time and date string, meaning that a new, empty log file will be always be created
|
||||
rather than appending to an existing one.
|
||||
|
||||
The method might return nullptr if the file can't be created for some reason.
|
||||
|
||||
@param logFileSubDirectoryName the name of the subdirectory to create inside the logs folder (as
|
||||
returned by getSystemLogFileFolder). It's best to use something
|
||||
like the name of your application here.
|
||||
@param logFileNameRoot the start of the filename to use, e.g. "MyAppLog_". This will have
|
||||
a timestamp and the logFileNameSuffix appended to it
|
||||
@param logFileNameSuffix the file suffix to use, e.g. ".txt"
|
||||
@param welcomeMessage a message that will be written to the log when it's opened.
|
||||
*/
|
||||
static FileLogger* createDateStampedLogger (const String& logFileSubDirectoryName,
|
||||
const String& logFileNameRoot,
|
||||
const String& logFileNameSuffix,
|
||||
const String& welcomeMessage);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns an OS-specific folder where log-files should be stored.
|
||||
|
||||
On Windows this will return a logger with a path such as:
|
||||
c:\\Documents and Settings\\username\\Application Data\\[logFileSubDirectoryName]\\[logFileName]
|
||||
|
||||
On the Mac it'll create something like:
|
||||
~/Library/Logs/[logFileSubDirectoryName]/[logFileName]
|
||||
|
||||
@see createDefaultAppLogger
|
||||
*/
|
||||
static File getSystemLogFileFolder();
|
||||
|
||||
// (implementation of the Logger virtual method)
|
||||
void logMessage (const String&) override;
|
||||
|
||||
//==============================================================================
|
||||
/** This is a utility function which removes lines from the start of a text
|
||||
file to make sure that its total size is below the given size.
|
||||
*/
|
||||
static void trimFileSize (const File& file, int64 maxFileSize);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
File logFile;
|
||||
CriticalSection logLock;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileLogger)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
62
deps/juce/modules/juce_core/logging/juce_Logger.cpp
vendored
Normal file
62
deps/juce/modules/juce_core/logging/juce_Logger.cpp
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
Logger::Logger() {}
|
||||
|
||||
Logger::~Logger()
|
||||
{
|
||||
// You're deleting this logger while it's still being used!
|
||||
// Always call Logger::setCurrentLogger (nullptr) before deleting the active logger.
|
||||
jassert (currentLogger != this);
|
||||
}
|
||||
|
||||
Logger* Logger::currentLogger = nullptr;
|
||||
|
||||
void Logger::setCurrentLogger (Logger* const newLogger) noexcept { currentLogger = newLogger; }
|
||||
Logger* Logger::getCurrentLogger() noexcept { return currentLogger; }
|
||||
|
||||
void Logger::writeToLog (const String& message)
|
||||
{
|
||||
if (currentLogger != nullptr)
|
||||
currentLogger->logMessage (message);
|
||||
else
|
||||
outputDebugString (message);
|
||||
}
|
||||
|
||||
#if JUCE_LOG_ASSERTIONS || JUCE_DEBUG
|
||||
void JUCE_API JUCE_CALLTYPE logAssertion (const char* const filename, const int lineNum) noexcept
|
||||
{
|
||||
String m ("JUCE Assertion failure in ");
|
||||
m << File::createFileWithoutCheckingPath (CharPointer_UTF8 (filename)).getFileName() << ':' << lineNum;
|
||||
|
||||
#if JUCE_LOG_ASSERTIONS
|
||||
Logger::writeToLog (m);
|
||||
#else
|
||||
DBG (m);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
91
deps/juce/modules/juce_core/logging/juce_Logger.h
vendored
Normal file
91
deps/juce/modules/juce_core/logging/juce_Logger.h
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Acts as an application-wide logging class.
|
||||
|
||||
A subclass of Logger can be created and passed into the Logger::setCurrentLogger
|
||||
method and this will then be used by all calls to writeToLog.
|
||||
|
||||
The logger class also contains methods for writing messages to the debugger's
|
||||
output stream.
|
||||
|
||||
@see FileLogger
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API Logger
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Destructor. */
|
||||
virtual ~Logger();
|
||||
|
||||
//==============================================================================
|
||||
/** Sets the current logging class to use.
|
||||
|
||||
Note that the object passed in will not be owned or deleted by the logger, so
|
||||
the caller must make sure that it is not deleted while still being used.
|
||||
A null pointer can be passed-in to reset the system to the default logger.
|
||||
*/
|
||||
static void JUCE_CALLTYPE setCurrentLogger (Logger* newLogger) noexcept;
|
||||
|
||||
/** Returns the current logger, or nullptr if no custom logger has been set. */
|
||||
static Logger* JUCE_CALLTYPE getCurrentLogger() noexcept;
|
||||
|
||||
/** Writes a string to the current logger.
|
||||
|
||||
This will pass the string to the logger's logMessage() method if a logger
|
||||
has been set.
|
||||
|
||||
@see logMessage
|
||||
*/
|
||||
static void JUCE_CALLTYPE writeToLog (const String& message);
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** Writes a message to the standard error stream.
|
||||
|
||||
This can be called directly, or by using the DBG() macro in
|
||||
juce_PlatformDefs.h (which will avoid calling the method in non-debug builds).
|
||||
*/
|
||||
static void JUCE_CALLTYPE outputDebugString (const String& text);
|
||||
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
Logger();
|
||||
|
||||
/** This is overloaded by subclasses to implement custom logging behaviour.
|
||||
@see setCurrentLogger
|
||||
*/
|
||||
virtual void logMessage (const String& message) = 0;
|
||||
|
||||
private:
|
||||
static Logger* currentLogger;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
1371
deps/juce/modules/juce_core/maths/juce_BigInteger.cpp
vendored
Normal file
1371
deps/juce/modules/juce_core/maths/juce_BigInteger.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
342
deps/juce/modules/juce_core/maths/juce_BigInteger.h
vendored
Normal file
342
deps/juce/modules/juce_core/maths/juce_BigInteger.h
vendored
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
An arbitrarily large integer class.
|
||||
|
||||
A BigInteger can be used in a similar way to a normal integer, but has no size
|
||||
limit (except for memory and performance constraints).
|
||||
|
||||
Negative values are possible, but the value isn't stored as 2s-complement, so
|
||||
be careful if you use negative values and look at the values of individual bits.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API BigInteger
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty BigInteger */
|
||||
BigInteger();
|
||||
|
||||
/** Creates a BigInteger containing an integer value in its low bits.
|
||||
The low 32 bits of the number are initialised with this value.
|
||||
*/
|
||||
BigInteger (uint32 value);
|
||||
|
||||
/** Creates a BigInteger containing an integer value in its low bits.
|
||||
The low 32 bits of the number are initialised with the absolute value
|
||||
passed in, and its sign is set to reflect the sign of the number.
|
||||
*/
|
||||
BigInteger (int32 value);
|
||||
|
||||
/** Creates a BigInteger containing an integer value in its low bits.
|
||||
The low 64 bits of the number are initialised with the absolute value
|
||||
passed in, and its sign is set to reflect the sign of the number.
|
||||
*/
|
||||
BigInteger (int64 value);
|
||||
|
||||
/** Creates a copy of another BigInteger. */
|
||||
BigInteger (const BigInteger&);
|
||||
|
||||
/** Move constructor */
|
||||
BigInteger (BigInteger&&) noexcept;
|
||||
|
||||
/** Move assignment operator */
|
||||
BigInteger& operator= (BigInteger&&) noexcept;
|
||||
|
||||
/** Destructor. */
|
||||
~BigInteger();
|
||||
|
||||
//==============================================================================
|
||||
/** Copies another BigInteger onto this one. */
|
||||
BigInteger& operator= (const BigInteger&);
|
||||
|
||||
/** Swaps the internal contents of this with another object. */
|
||||
void swapWith (BigInteger&) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the value of a specified bit in the number.
|
||||
If the index is out-of-range, the result will be false.
|
||||
*/
|
||||
bool operator[] (int bit) const noexcept;
|
||||
|
||||
/** Returns true if no bits are set. */
|
||||
bool isZero() const noexcept;
|
||||
|
||||
/** Returns true if the value is 1. */
|
||||
bool isOne() const noexcept;
|
||||
|
||||
/** Attempts to get the lowest 32 bits of the value as an integer.
|
||||
If the value is bigger than the integer limits, this will return only the lower bits.
|
||||
*/
|
||||
int toInteger() const noexcept;
|
||||
|
||||
/** Attempts to get the lowest 64 bits of the value as an integer.
|
||||
If the value is bigger than the integer limits, this will return only the lower bits.
|
||||
*/
|
||||
int64 toInt64() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Resets the value to 0. */
|
||||
void clear() noexcept;
|
||||
|
||||
/** Clears a particular bit in the number. */
|
||||
void clearBit (int bitNumber) noexcept;
|
||||
|
||||
/** Sets a specified bit to 1. */
|
||||
void setBit (int bitNumber);
|
||||
|
||||
/** Sets or clears a specified bit. */
|
||||
void setBit (int bitNumber, bool shouldBeSet);
|
||||
|
||||
/** Sets a range of bits to be either on or off.
|
||||
|
||||
@param startBit the first bit to change
|
||||
@param numBits the number of bits to change
|
||||
@param shouldBeSet whether to turn these bits on or off
|
||||
*/
|
||||
void setRange (int startBit, int numBits, bool shouldBeSet);
|
||||
|
||||
/** Inserts a bit an a given position, shifting up any bits above it. */
|
||||
void insertBit (int bitNumber, bool shouldBeSet);
|
||||
|
||||
/** Returns a range of bits as a new BigInteger.
|
||||
|
||||
e.g. getBitRangeAsInt (0, 64) would return the lowest 64 bits.
|
||||
@see getBitRangeAsInt
|
||||
*/
|
||||
BigInteger getBitRange (int startBit, int numBits) const;
|
||||
|
||||
/** Returns a range of bits as an integer value.
|
||||
|
||||
e.g. getBitRangeAsInt (0, 32) would return the lowest 32 bits.
|
||||
|
||||
Asking for more than 32 bits isn't allowed (obviously) - for that, use
|
||||
getBitRange().
|
||||
*/
|
||||
uint32 getBitRangeAsInt (int startBit, int numBits) const noexcept;
|
||||
|
||||
/** Sets a range of bits to an integer value.
|
||||
|
||||
Copies the given integer onto a range of bits, starting at startBit,
|
||||
and using up to numBits of the available bits.
|
||||
*/
|
||||
void setBitRangeAsInt (int startBit, int numBits, uint32 valueToSet);
|
||||
|
||||
/** Shifts a section of bits left or right.
|
||||
|
||||
@param howManyBitsLeft how far to move the bits (+ve numbers shift it left, -ve numbers shift it right).
|
||||
@param startBit the first bit to affect - if this is > 0, only bits above that index will be affected.
|
||||
*/
|
||||
void shiftBits (int howManyBitsLeft, int startBit);
|
||||
|
||||
/** Returns the total number of set bits in the value. */
|
||||
int countNumberOfSetBits() const noexcept;
|
||||
|
||||
/** Looks for the index of the next set bit after a given starting point.
|
||||
|
||||
This searches from startIndex (inclusive) upwards for the first set bit,
|
||||
and returns its index. If no set bits are found, it returns -1.
|
||||
*/
|
||||
int findNextSetBit (int startIndex) const noexcept;
|
||||
|
||||
/** Looks for the index of the next clear bit after a given starting point.
|
||||
|
||||
This searches from startIndex (inclusive) upwards for the first clear bit,
|
||||
and returns its index.
|
||||
*/
|
||||
int findNextClearBit (int startIndex) const noexcept;
|
||||
|
||||
/** Returns the index of the highest set bit in the number.
|
||||
If the value is zero, this will return -1.
|
||||
*/
|
||||
int getHighestBit() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the value is less than zero.
|
||||
@see setNegative, negate
|
||||
*/
|
||||
bool isNegative() const noexcept;
|
||||
|
||||
/** Changes the sign of the number to be positive or negative.
|
||||
@see isNegative, negate
|
||||
*/
|
||||
void setNegative (bool shouldBeNegative) noexcept;
|
||||
|
||||
/** Inverts the sign of the number.
|
||||
@see isNegative, setNegative
|
||||
*/
|
||||
void negate() noexcept;
|
||||
|
||||
//==============================================================================
|
||||
// All the standard arithmetic ops...
|
||||
|
||||
BigInteger& operator+= (const BigInteger&);
|
||||
BigInteger& operator-= (const BigInteger&);
|
||||
BigInteger& operator*= (const BigInteger&);
|
||||
BigInteger& operator/= (const BigInteger&);
|
||||
BigInteger& operator|= (const BigInteger&);
|
||||
BigInteger& operator&= (const BigInteger&);
|
||||
BigInteger& operator^= (const BigInteger&);
|
||||
BigInteger& operator%= (const BigInteger&);
|
||||
BigInteger& operator<<= (int numBitsToShift);
|
||||
BigInteger& operator>>= (int numBitsToShift);
|
||||
BigInteger& operator++();
|
||||
BigInteger& operator--();
|
||||
BigInteger operator++ (int);
|
||||
BigInteger operator-- (int);
|
||||
|
||||
BigInteger operator-() const;
|
||||
BigInteger operator+ (const BigInteger&) const;
|
||||
BigInteger operator- (const BigInteger&) const;
|
||||
BigInteger operator* (const BigInteger&) const;
|
||||
BigInteger operator/ (const BigInteger&) const;
|
||||
BigInteger operator| (const BigInteger&) const;
|
||||
BigInteger operator& (const BigInteger&) const;
|
||||
BigInteger operator^ (const BigInteger&) const;
|
||||
BigInteger operator% (const BigInteger&) const;
|
||||
BigInteger operator<< (int numBitsToShift) const;
|
||||
BigInteger operator>> (int numBitsToShift) const;
|
||||
|
||||
bool operator== (const BigInteger&) const noexcept;
|
||||
bool operator!= (const BigInteger&) const noexcept;
|
||||
bool operator< (const BigInteger&) const noexcept;
|
||||
bool operator<= (const BigInteger&) const noexcept;
|
||||
bool operator> (const BigInteger&) const noexcept;
|
||||
bool operator>= (const BigInteger&) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Does a signed comparison of two BigIntegers.
|
||||
|
||||
Return values are:
|
||||
- 0 if the numbers are the same
|
||||
- < 0 if this number is smaller than the other
|
||||
- > 0 if this number is bigger than the other
|
||||
*/
|
||||
int compare (const BigInteger& other) const noexcept;
|
||||
|
||||
/** Compares the magnitudes of two BigIntegers, ignoring their signs.
|
||||
|
||||
Return values are:
|
||||
- 0 if the numbers are the same
|
||||
- < 0 if this number is smaller than the other
|
||||
- > 0 if this number is bigger than the other
|
||||
*/
|
||||
int compareAbsolute (const BigInteger& other) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Divides this value by another one and returns the remainder.
|
||||
|
||||
This number is divided by other, leaving the quotient in this number,
|
||||
with the remainder being copied to the other BigInteger passed in.
|
||||
*/
|
||||
void divideBy (const BigInteger& divisor, BigInteger& remainder);
|
||||
|
||||
/** Returns the largest value that will divide both this value and the argument. */
|
||||
BigInteger findGreatestCommonDivisor (BigInteger other) const;
|
||||
|
||||
/** Performs a combined exponent and modulo operation.
|
||||
This BigInteger's value becomes (this ^ exponent) % modulus.
|
||||
*/
|
||||
void exponentModulo (const BigInteger& exponent, const BigInteger& modulus);
|
||||
|
||||
/** Performs an inverse modulo on the value.
|
||||
i.e. the result is (this ^ -1) mod (modulus).
|
||||
*/
|
||||
void inverseModulo (const BigInteger& modulus);
|
||||
|
||||
/** Performs the Montgomery Multiplication with modulo.
|
||||
This object is left containing the result value: ((this * other) * R1) % modulus.
|
||||
To get this result, we need modulus, modulusp and k such as R = 2^k, with
|
||||
modulus * modulusp - R * R1 = GCD(modulus, R) = 1
|
||||
*/
|
||||
void montgomeryMultiplication (const BigInteger& other, const BigInteger& modulus,
|
||||
const BigInteger& modulusp, int k);
|
||||
|
||||
/** Performs the Extended Euclidean algorithm.
|
||||
This method will set the xOut and yOut arguments such that (a * xOut) - (b * yOut) = GCD (a, b).
|
||||
On return, this object is left containing the value of the GCD.
|
||||
*/
|
||||
void extendedEuclidean (const BigInteger& a, const BigInteger& b,
|
||||
BigInteger& xOut, BigInteger& yOut);
|
||||
|
||||
//==============================================================================
|
||||
/** Converts the number to a string.
|
||||
|
||||
Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex).
|
||||
If minimumNumCharacters is greater than 0, the returned string will be
|
||||
padded with leading zeros to reach at least that length.
|
||||
*/
|
||||
String toString (int base, int minimumNumCharacters = 1) const;
|
||||
|
||||
/** Reads the numeric value from a string.
|
||||
|
||||
Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex).
|
||||
Any invalid characters will be ignored.
|
||||
*/
|
||||
void parseString (StringRef text, int base);
|
||||
|
||||
//==============================================================================
|
||||
/** Turns the number into a block of binary data.
|
||||
|
||||
The data is arranged as little-endian, so the first byte of data is the low 8 bits
|
||||
of the number, and so on.
|
||||
|
||||
@see loadFromMemoryBlock
|
||||
*/
|
||||
MemoryBlock toMemoryBlock() const;
|
||||
|
||||
/** Converts a block of raw data into a number.
|
||||
|
||||
The data is arranged as little-endian, so the first byte of data is the low 8 bits
|
||||
of the number, and so on.
|
||||
|
||||
@see toMemoryBlock
|
||||
*/
|
||||
void loadFromMemoryBlock (const MemoryBlock& data);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
enum { numPreallocatedInts = 4 };
|
||||
HeapBlock<uint32> heapAllocation;
|
||||
uint32 preallocated[numPreallocatedInts];
|
||||
size_t allocatedSize;
|
||||
int highestBit = -1;
|
||||
bool negative = false;
|
||||
|
||||
uint32* getValues() const noexcept;
|
||||
uint32* ensureSize (size_t);
|
||||
void shiftLeft (int bits, int startBit);
|
||||
void shiftRight (int bits, int startBit);
|
||||
|
||||
JUCE_LEAK_DETECTOR (BigInteger)
|
||||
};
|
||||
|
||||
/** Writes a BigInteger to an OutputStream as a UTF8 decimal string. */
|
||||
OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const BigInteger& value);
|
||||
|
||||
} // namespace juce
|
||||
1175
deps/juce/modules/juce_core/maths/juce_Expression.cpp
vendored
Normal file
1175
deps/juce/modules/juce_core/maths/juce_Expression.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
251
deps/juce/modules/juce_core/maths/juce_Expression.h
vendored
Normal file
251
deps/juce/modules/juce_core/maths/juce_Expression.h
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 for dynamically evaluating simple numeric expressions.
|
||||
|
||||
This class can parse a simple C-style string expression involving floating point
|
||||
numbers, named symbols and functions. The basic arithmetic operations of +, -, *, /
|
||||
are supported, as well as parentheses, and any alphanumeric identifiers are
|
||||
assumed to be named symbols which will be resolved when the expression is
|
||||
evaluated.
|
||||
|
||||
Expressions which use identifiers and functions require a subclass of
|
||||
Expression::Scope to be supplied when evaluating them, and this object
|
||||
is expected to be able to resolve the symbol names and perform the functions that
|
||||
are used.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API Expression
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a simple expression with a value of 0. */
|
||||
Expression();
|
||||
|
||||
/** Destructor. */
|
||||
~Expression();
|
||||
|
||||
/** Creates a copy of an expression. */
|
||||
Expression (const Expression&);
|
||||
|
||||
/** Copies another expression. */
|
||||
Expression& operator= (const Expression&);
|
||||
|
||||
/** Move constructor */
|
||||
Expression (Expression&&) noexcept;
|
||||
|
||||
/** Move assignment operator */
|
||||
Expression& operator= (Expression&&) noexcept;
|
||||
|
||||
/** Creates a simple expression with a specified constant value. */
|
||||
explicit Expression (double constant);
|
||||
|
||||
/** Attempts to create an expression by parsing a string.
|
||||
Any errors are returned in the parseError argument provided.
|
||||
*/
|
||||
Expression (const String& stringToParse, String& parseError);
|
||||
|
||||
/** Returns a string version of the expression. */
|
||||
String toString() const;
|
||||
|
||||
/** Returns an expression which is an addition operation of two existing expressions. */
|
||||
Expression operator+ (const Expression&) const;
|
||||
/** Returns an expression which is a subtraction operation of two existing expressions. */
|
||||
Expression operator- (const Expression&) const;
|
||||
/** Returns an expression which is a multiplication operation of two existing expressions. */
|
||||
Expression operator* (const Expression&) const;
|
||||
/** Returns an expression which is a division operation of two existing expressions. */
|
||||
Expression operator/ (const Expression&) const;
|
||||
/** Returns an expression which performs a negation operation on an existing expression. */
|
||||
Expression operator-() const;
|
||||
|
||||
/** Returns an Expression which is an identifier reference. */
|
||||
static Expression symbol (const String& symbol);
|
||||
|
||||
/** Returns an Expression which is a function call. */
|
||||
static Expression function (const String& functionName, const Array<Expression>& parameters);
|
||||
|
||||
/** Returns an Expression which parses a string from a character pointer, and updates the pointer
|
||||
to indicate where it finished.
|
||||
|
||||
The pointer is incremented so that on return, it indicates the character that follows
|
||||
the end of the expression that was parsed.
|
||||
|
||||
If there's a syntax error in parsing, the parseError argument will be set
|
||||
to a description of the problem.
|
||||
*/
|
||||
static Expression parse (String::CharPointerType& stringToParse, String& parseError);
|
||||
|
||||
//==============================================================================
|
||||
/** When evaluating an Expression object, this class is used to resolve symbols and
|
||||
perform functions that the expression uses.
|
||||
*/
|
||||
class JUCE_API Scope
|
||||
{
|
||||
public:
|
||||
Scope();
|
||||
virtual ~Scope();
|
||||
|
||||
/** Returns some kind of globally unique ID that identifies this scope. */
|
||||
virtual String getScopeUID() const;
|
||||
|
||||
/** Returns the value of a symbol.
|
||||
If the symbol is unknown, this can throw an Expression::EvaluationError exception.
|
||||
The member value is set to the part of the symbol that followed the dot, if there is
|
||||
one, e.g. for "foo.bar", symbol = "foo" and member = "bar".
|
||||
@throws Expression::EvaluationError
|
||||
*/
|
||||
virtual Expression getSymbolValue (const String& symbol) const;
|
||||
|
||||
/** Executes a named function.
|
||||
If the function name is unknown, this can throw an Expression::EvaluationError exception.
|
||||
@throws Expression::EvaluationError
|
||||
*/
|
||||
virtual double evaluateFunction (const String& functionName,
|
||||
const double* parameters, int numParameters) const;
|
||||
|
||||
/** Used as a callback by the Scope::visitRelativeScope() method.
|
||||
You should never create an instance of this class yourself, it's used by the
|
||||
expression evaluation code.
|
||||
*/
|
||||
class Visitor
|
||||
{
|
||||
public:
|
||||
virtual ~Visitor() = default;
|
||||
virtual void visit (const Scope&) = 0;
|
||||
};
|
||||
|
||||
/** Creates a Scope object for a named scope, and then calls a visitor
|
||||
to do some kind of processing with this new scope.
|
||||
|
||||
If the name is valid, this method must create a suitable (temporary) Scope
|
||||
object to represent it, and must call the Visitor::visit() method with this
|
||||
new scope.
|
||||
*/
|
||||
virtual void visitRelativeScope (const String& scopeName, Visitor& visitor) const;
|
||||
};
|
||||
|
||||
/** Evaluates this expression, without using a Scope.
|
||||
Without a Scope, no symbols can be used, and only basic functions such as sin, cos, tan,
|
||||
min, max are available.
|
||||
To find out about any errors during evaluation, use the other version of this method which
|
||||
takes a String parameter.
|
||||
*/
|
||||
double evaluate() const;
|
||||
|
||||
/** Evaluates this expression, providing a scope that should be able to evaluate any symbols
|
||||
or functions that it uses.
|
||||
To find out about any errors during evaluation, use the other version of this method which
|
||||
takes a String parameter.
|
||||
*/
|
||||
double evaluate (const Scope& scope) const;
|
||||
|
||||
/** Evaluates this expression, providing a scope that should be able to evaluate any symbols
|
||||
or functions that it uses.
|
||||
*/
|
||||
double evaluate (const Scope& scope, String& evaluationError) const;
|
||||
|
||||
/** Attempts to return an expression which is a copy of this one, but with a constant adjusted
|
||||
to make the expression resolve to a target value.
|
||||
|
||||
E.g. if the expression is "x + 10" and x is 5, then asking for a target value of 8 will return
|
||||
the expression "x + 3". Obviously some expressions can't be reversed in this way, in which
|
||||
case they might just be adjusted by adding a constant to the original expression.
|
||||
|
||||
@throws Expression::EvaluationError
|
||||
*/
|
||||
Expression adjustedToGiveNewResult (double targetValue, const Scope& scope) const;
|
||||
|
||||
/** Represents a symbol that is used in an Expression. */
|
||||
struct Symbol
|
||||
{
|
||||
Symbol (const String& scopeUID, const String& symbolName);
|
||||
bool operator== (const Symbol&) const noexcept;
|
||||
bool operator!= (const Symbol&) const noexcept;
|
||||
|
||||
String scopeUID; /**< The unique ID of the Scope that contains this symbol. */
|
||||
String symbolName; /**< The name of the symbol. */
|
||||
};
|
||||
|
||||
/** Returns a copy of this expression in which all instances of a given symbol have been renamed. */
|
||||
Expression withRenamedSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope) const;
|
||||
|
||||
/** Returns true if this expression makes use of the specified symbol.
|
||||
If a suitable scope is supplied, the search will dereference and recursively check
|
||||
all symbols, so that it can be determined whether this expression relies on the given
|
||||
symbol at any level in its evaluation. If the scope parameter is null, this just checks
|
||||
whether the expression contains any direct references to the symbol.
|
||||
|
||||
@throws Expression::EvaluationError
|
||||
*/
|
||||
bool referencesSymbol (const Symbol& symbol, const Scope& scope) const;
|
||||
|
||||
/** Returns true if this expression contains any symbols. */
|
||||
bool usesAnySymbols() const;
|
||||
|
||||
/** Returns a list of all symbols that may be needed to resolve this expression in the given scope. */
|
||||
void findReferencedSymbols (Array<Symbol>& results, const Scope& scope) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Expression type.
|
||||
@see Expression::getType()
|
||||
*/
|
||||
enum Type
|
||||
{
|
||||
constantType,
|
||||
functionType,
|
||||
operatorType,
|
||||
symbolType
|
||||
};
|
||||
|
||||
/** Returns the type of this expression. */
|
||||
Type getType() const noexcept;
|
||||
|
||||
/** If this expression is a symbol, function or operator, this returns its identifier. */
|
||||
String getSymbolOrFunction() const;
|
||||
|
||||
/** Returns the number of inputs to this expression.
|
||||
@see getInput
|
||||
*/
|
||||
int getNumInputs() const;
|
||||
|
||||
/** Retrieves one of the inputs to this expression.
|
||||
@see getNumInputs
|
||||
*/
|
||||
Expression getInput (int index) const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class Term;
|
||||
struct Helpers;
|
||||
ReferenceCountedObjectPtr<Term> term;
|
||||
|
||||
explicit Expression (Term*);
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
685
deps/juce/modules/juce_core/maths/juce_MathsFunctions.h
vendored
Normal file
685
deps/juce/modules/juce_core/maths/juce_MathsFunctions.h
vendored
Normal file
@@ -0,0 +1,685 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 file sets up some handy mathematical typdefs and functions.
|
||||
*/
|
||||
|
||||
//==============================================================================
|
||||
// Definitions for the int8, int16, int32, int64 and pointer_sized_int types.
|
||||
|
||||
/** A platform-independent 8-bit signed integer type. */
|
||||
using int8 = signed char;
|
||||
/** A platform-independent 8-bit unsigned integer type. */
|
||||
using uint8 = unsigned char;
|
||||
/** A platform-independent 16-bit signed integer type. */
|
||||
using int16 = signed short;
|
||||
/** A platform-independent 16-bit unsigned integer type. */
|
||||
using uint16 = unsigned short;
|
||||
/** A platform-independent 32-bit signed integer type. */
|
||||
using int32 = signed int;
|
||||
/** A platform-independent 32-bit unsigned integer type. */
|
||||
using uint32 = unsigned int;
|
||||
|
||||
#if JUCE_MSVC
|
||||
/** A platform-independent 64-bit integer type. */
|
||||
using int64 = __int64;
|
||||
/** A platform-independent 64-bit unsigned integer type. */
|
||||
using uint64 = unsigned __int64;
|
||||
#else
|
||||
/** A platform-independent 64-bit integer type. */
|
||||
using int64 = long long;
|
||||
/** A platform-independent 64-bit unsigned integer type. */
|
||||
using uint64 = unsigned long long;
|
||||
#endif
|
||||
|
||||
#ifndef DOXYGEN
|
||||
/** A macro for creating 64-bit literals.
|
||||
Historically, this was needed to support portability with MSVC6, and is kept here
|
||||
so that old code will still compile, but nowadays every compiler will support the
|
||||
LL and ULL suffixes, so you should use those in preference to this macro.
|
||||
*/
|
||||
#define literal64bit(longLiteral) (longLiteral##LL)
|
||||
#endif
|
||||
|
||||
#if JUCE_64BIT
|
||||
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||
using pointer_sized_int = int64;
|
||||
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||
using pointer_sized_uint = uint64;
|
||||
#elif JUCE_MSVC
|
||||
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||
using pointer_sized_int = _W64 int;
|
||||
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||
using pointer_sized_uint = _W64 unsigned int;
|
||||
#else
|
||||
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||
using pointer_sized_int = int;
|
||||
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||
using pointer_sized_uint = unsigned int;
|
||||
#endif
|
||||
|
||||
#if JUCE_WINDOWS && ! JUCE_MINGW
|
||||
using ssize_t = pointer_sized_int;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// Some indispensable min/max functions
|
||||
|
||||
/** Returns the larger of two values. */
|
||||
template <typename Type>
|
||||
constexpr Type jmax (Type a, Type b) { return a < b ? b : a; }
|
||||
|
||||
/** Returns the larger of three values. */
|
||||
template <typename Type>
|
||||
constexpr Type jmax (Type a, Type b, Type c) { return a < b ? (b < c ? c : b) : (a < c ? c : a); }
|
||||
|
||||
/** Returns the larger of four values. */
|
||||
template <typename Type>
|
||||
constexpr Type jmax (Type a, Type b, Type c, Type d) { return jmax (a, jmax (b, c, d)); }
|
||||
|
||||
/** Returns the smaller of two values. */
|
||||
template <typename Type>
|
||||
constexpr Type jmin (Type a, Type b) { return b < a ? b : a; }
|
||||
|
||||
/** Returns the smaller of three values. */
|
||||
template <typename Type>
|
||||
constexpr Type jmin (Type a, Type b, Type c) { return b < a ? (c < b ? c : b) : (c < a ? c : a); }
|
||||
|
||||
/** Returns the smaller of four values. */
|
||||
template <typename Type>
|
||||
constexpr Type jmin (Type a, Type b, Type c, Type d) { return jmin (a, jmin (b, c, d)); }
|
||||
|
||||
/** Remaps a normalised value (between 0 and 1) to a target range.
|
||||
This effectively returns (targetRangeMin + value0To1 * (targetRangeMax - targetRangeMin)).
|
||||
*/
|
||||
template <typename Type>
|
||||
constexpr Type jmap (Type value0To1, Type targetRangeMin, Type targetRangeMax)
|
||||
{
|
||||
return targetRangeMin + value0To1 * (targetRangeMax - targetRangeMin);
|
||||
}
|
||||
|
||||
/** Remaps a value from a source range to a target range. */
|
||||
template <typename Type>
|
||||
Type jmap (Type sourceValue, Type sourceRangeMin, Type sourceRangeMax, Type targetRangeMin, Type targetRangeMax)
|
||||
{
|
||||
jassert (sourceRangeMax != sourceRangeMin); // mapping from a range of zero will produce NaN!
|
||||
return targetRangeMin + ((targetRangeMax - targetRangeMin) * (sourceValue - sourceRangeMin)) / (sourceRangeMax - sourceRangeMin);
|
||||
}
|
||||
|
||||
/** Remaps a normalised value (between 0 and 1) to a logarithmic target range.
|
||||
|
||||
The entire target range must be greater than zero.
|
||||
|
||||
@see mapFromLog10
|
||||
|
||||
@code
|
||||
mapToLog10 (0.5, 0.4, 40.0) == 4.0
|
||||
@endcode
|
||||
*/
|
||||
template <typename Type>
|
||||
Type mapToLog10 (Type value0To1, Type logRangeMin, Type logRangeMax)
|
||||
{
|
||||
jassert (logRangeMin > 0);
|
||||
jassert (logRangeMax > 0);
|
||||
|
||||
auto logMin = std::log10 (logRangeMin);
|
||||
auto logMax = std::log10 (logRangeMax);
|
||||
|
||||
return std::pow ((Type) 10.0, value0To1 * (logMax - logMin) + logMin);
|
||||
}
|
||||
|
||||
/** Remaps a logarithmic value in a target range to a normalised value (between 0 and 1).
|
||||
|
||||
The entire target range must be greater than zero.
|
||||
|
||||
@see mapToLog10
|
||||
|
||||
@code
|
||||
mapFromLog10 (4.0, 0.4, 40.0) == 0.5
|
||||
@endcode
|
||||
*/
|
||||
template <typename Type>
|
||||
Type mapFromLog10 (Type valueInLogRange, Type logRangeMin, Type logRangeMax)
|
||||
{
|
||||
jassert (logRangeMin > 0);
|
||||
jassert (logRangeMax > 0);
|
||||
|
||||
auto logMin = std::log10 (logRangeMin);
|
||||
auto logMax = std::log10 (logRangeMax);
|
||||
|
||||
return (std::log10 (valueInLogRange) - logMin) / (logMax - logMin);
|
||||
}
|
||||
|
||||
/** Scans an array of values, returning the minimum value that it contains. */
|
||||
template <typename Type>
|
||||
Type findMinimum (const Type* data, int numValues)
|
||||
{
|
||||
if (numValues <= 0)
|
||||
return Type (0);
|
||||
|
||||
auto result = *data++;
|
||||
|
||||
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||
{
|
||||
auto v = *data++;
|
||||
|
||||
if (v < result)
|
||||
result = v;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Scans an array of values, returning the maximum value that it contains. */
|
||||
template <typename Type>
|
||||
Type findMaximum (const Type* values, int numValues)
|
||||
{
|
||||
if (numValues <= 0)
|
||||
return Type (0);
|
||||
|
||||
auto result = *values++;
|
||||
|
||||
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||
{
|
||||
auto v = *values++;
|
||||
|
||||
if (result < v)
|
||||
result = v;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Scans an array of values, returning the minimum and maximum values that it contains. */
|
||||
template <typename Type>
|
||||
void findMinAndMax (const Type* values, int numValues, Type& lowest, Type& highest)
|
||||
{
|
||||
if (numValues <= 0)
|
||||
{
|
||||
lowest = Type (0);
|
||||
highest = Type (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto mn = *values++;
|
||||
auto mx = mn;
|
||||
|
||||
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||
{
|
||||
auto v = *values++;
|
||||
|
||||
if (mx < v) mx = v;
|
||||
if (v < mn) mn = v;
|
||||
}
|
||||
|
||||
lowest = mn;
|
||||
highest = mx;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Constrains a value to keep it within a given range.
|
||||
|
||||
This will check that the specified value lies between the lower and upper bounds
|
||||
specified, and if not, will return the nearest value that would be in-range. Effectively,
|
||||
it's like calling jmax (lowerLimit, jmin (upperLimit, value)).
|
||||
|
||||
Note that it expects that lowerLimit <= upperLimit. If this isn't true,
|
||||
the results will be unpredictable.
|
||||
|
||||
@param lowerLimit the minimum value to return
|
||||
@param upperLimit the maximum value to return
|
||||
@param valueToConstrain the value to try to return
|
||||
@returns the closest value to valueToConstrain which lies between lowerLimit
|
||||
and upperLimit (inclusive)
|
||||
@see jmin, jmax, jmap
|
||||
*/
|
||||
template <typename Type>
|
||||
Type jlimit (Type lowerLimit,
|
||||
Type upperLimit,
|
||||
Type valueToConstrain) noexcept
|
||||
{
|
||||
jassert (lowerLimit <= upperLimit); // if these are in the wrong order, results are unpredictable..
|
||||
|
||||
return valueToConstrain < lowerLimit ? lowerLimit
|
||||
: (upperLimit < valueToConstrain ? upperLimit
|
||||
: valueToConstrain);
|
||||
}
|
||||
|
||||
/** Returns true if a value is at least zero, and also below a specified upper limit.
|
||||
This is basically a quicker way to write:
|
||||
@code valueToTest >= 0 && valueToTest < upperLimit
|
||||
@endcode
|
||||
*/
|
||||
template <typename Type1, typename Type2>
|
||||
bool isPositiveAndBelow (Type1 valueToTest, Type2 upperLimit) noexcept
|
||||
{
|
||||
jassert (Type1() <= static_cast<Type1> (upperLimit)); // makes no sense to call this if the upper limit is itself below zero..
|
||||
return Type1() <= valueToTest && valueToTest < static_cast<Type1> (upperLimit);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
bool isPositiveAndBelow (int valueToTest, Type upperLimit) noexcept
|
||||
{
|
||||
jassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
|
||||
return static_cast<unsigned int> (valueToTest) < static_cast<unsigned int> (upperLimit);
|
||||
}
|
||||
|
||||
/** Returns true if a value is at least zero, and also less than or equal to a specified upper limit.
|
||||
This is basically a quicker way to write:
|
||||
@code valueToTest >= 0 && valueToTest <= upperLimit
|
||||
@endcode
|
||||
*/
|
||||
template <typename Type1, typename Type2>
|
||||
bool isPositiveAndNotGreaterThan (Type1 valueToTest, Type2 upperLimit) noexcept
|
||||
{
|
||||
jassert (Type1() <= static_cast<Type1> (upperLimit)); // makes no sense to call this if the upper limit is itself below zero..
|
||||
return Type1() <= valueToTest && valueToTest <= static_cast<Type1> (upperLimit);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
bool isPositiveAndNotGreaterThan (int valueToTest, Type upperLimit) noexcept
|
||||
{
|
||||
jassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
|
||||
return static_cast<unsigned int> (valueToTest) <= static_cast<unsigned int> (upperLimit);
|
||||
}
|
||||
|
||||
/** Computes the absolute difference between two values and returns true if it is less than or equal
|
||||
to a given tolerance, otherwise it returns false.
|
||||
*/
|
||||
template <typename Type>
|
||||
bool isWithin (Type a, Type b, Type tolerance) noexcept
|
||||
{
|
||||
return std::abs (a - b) <= tolerance;
|
||||
}
|
||||
|
||||
/** Returns true if the two numbers are approximately equal. This is useful for floating-point
|
||||
and double comparisons.
|
||||
*/
|
||||
template <typename Type>
|
||||
bool approximatelyEqual (Type a, Type b) noexcept
|
||||
{
|
||||
return std::abs (a - b) <= (std::numeric_limits<Type>::epsilon() * std::max (a, b))
|
||||
|| std::abs (a - b) < std::numeric_limits<Type>::min();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Handy function for avoiding unused variables warning. */
|
||||
template <typename... Types>
|
||||
void ignoreUnused (Types&&...) noexcept {}
|
||||
|
||||
/** Handy function for getting the number of elements in a simple const C array.
|
||||
E.g.
|
||||
@code
|
||||
static int myArray[] = { 1, 2, 3 };
|
||||
|
||||
int numElements = numElementsInArray (myArray) // returns 3
|
||||
@endcode
|
||||
*/
|
||||
template <typename Type, size_t N>
|
||||
constexpr int numElementsInArray (Type (&)[N]) noexcept { return N; }
|
||||
|
||||
//==============================================================================
|
||||
// Some useful maths functions that aren't always present with all compilers and build settings.
|
||||
|
||||
/** Using juce_hypot is easier than dealing with the different types of hypot function
|
||||
that are provided by the various platforms and compilers. */
|
||||
template <typename Type>
|
||||
Type juce_hypot (Type a, Type b) noexcept
|
||||
{
|
||||
#if JUCE_MSVC
|
||||
return static_cast<Type> (_hypot (a, b));
|
||||
#else
|
||||
return static_cast<Type> (hypot (a, b));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef DOXYGEN
|
||||
template <>
|
||||
inline float juce_hypot (float a, float b) noexcept
|
||||
{
|
||||
#if JUCE_MSVC
|
||||
return _hypotf (a, b);
|
||||
#else
|
||||
return hypotf (a, b);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/** Commonly used mathematical constants
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <typename FloatType>
|
||||
struct MathConstants
|
||||
{
|
||||
/** A predefined value for Pi */
|
||||
static constexpr FloatType pi = static_cast<FloatType> (3.141592653589793238L);
|
||||
|
||||
/** A predefined value for 2 * Pi */
|
||||
static constexpr FloatType twoPi = static_cast<FloatType> (2 * 3.141592653589793238L);
|
||||
|
||||
/** A predefined value for Pi / 2 */
|
||||
static constexpr FloatType halfPi = static_cast<FloatType> (3.141592653589793238L / 2);
|
||||
|
||||
/** A predefined value for Euler's number */
|
||||
static constexpr FloatType euler = static_cast<FloatType> (2.71828182845904523536L);
|
||||
|
||||
/** A predefined value for sqrt(2) */
|
||||
static constexpr FloatType sqrt2 = static_cast<FloatType> (1.4142135623730950488L);
|
||||
};
|
||||
|
||||
#ifndef DOXYGEN
|
||||
/** A double-precision constant for pi. */
|
||||
[[deprecated ("This is deprecated in favour of MathConstants<double>::pi.")]]
|
||||
const constexpr double double_Pi = MathConstants<double>::pi;
|
||||
|
||||
/** A single-precision constant for pi. */
|
||||
[[deprecated ("This is deprecated in favour of MathConstants<double>::pi.")]]
|
||||
const constexpr float float_Pi = MathConstants<float>::pi;
|
||||
#endif
|
||||
|
||||
/** Converts an angle in degrees to radians. */
|
||||
template <typename FloatType>
|
||||
constexpr FloatType degreesToRadians (FloatType degrees) noexcept { return degrees * (MathConstants<FloatType>::pi / FloatType (180)); }
|
||||
|
||||
/** Converts an angle in radians to degrees. */
|
||||
template <typename FloatType>
|
||||
constexpr FloatType radiansToDegrees (FloatType radians) noexcept { return radians * (FloatType (180) / MathConstants<FloatType>::pi); }
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** The isfinite() method seems to vary between platforms, so this is a
|
||||
platform-independent function for it.
|
||||
*/
|
||||
template <typename NumericType>
|
||||
bool juce_isfinite (NumericType) noexcept
|
||||
{
|
||||
return true; // Integer types are always finite
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool juce_isfinite (float value) noexcept
|
||||
{
|
||||
#if JUCE_WINDOWS && ! JUCE_MINGW
|
||||
return _finite (value) != 0;
|
||||
#else
|
||||
return std::isfinite (value);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool juce_isfinite (double value) noexcept
|
||||
{
|
||||
#if JUCE_WINDOWS && ! JUCE_MINGW
|
||||
return _finite (value) != 0;
|
||||
#else
|
||||
return std::isfinite (value);
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MSVC
|
||||
#pragma optimize ("t", off)
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma float_control (precise, on, push)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** Fast floating-point-to-integer conversion.
|
||||
|
||||
This is faster than using the normal c++ cast to convert a float to an int, and
|
||||
it will round the value to the nearest integer, rather than rounding it down
|
||||
like the normal cast does.
|
||||
|
||||
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||
even numbers will be rounded up or down differently.
|
||||
*/
|
||||
template <typename FloatType>
|
||||
int roundToInt (const FloatType value) noexcept
|
||||
{
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma float_control (precise, on, push)
|
||||
#endif
|
||||
|
||||
union { int asInt[2]; double asDouble; } n;
|
||||
n.asDouble = ((double) value) + 6755399441055744.0;
|
||||
|
||||
#if JUCE_BIG_ENDIAN
|
||||
return n.asInt [1];
|
||||
#else
|
||||
return n.asInt [0];
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int roundToInt (int value) noexcept
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
#if JUCE_MSVC
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma float_control (pop)
|
||||
#endif
|
||||
#pragma optimize ("", on) // resets optimisations to the project defaults
|
||||
#endif
|
||||
|
||||
/** Fast floating-point-to-integer conversion.
|
||||
|
||||
This is a slightly slower and slightly more accurate version of roundToInt(). It works
|
||||
fine for values above zero, but negative numbers are rounded the wrong way.
|
||||
*/
|
||||
inline int roundToIntAccurate (double value) noexcept
|
||||
{
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma float_control (pop)
|
||||
#endif
|
||||
|
||||
return roundToInt (value + 1.5e-8);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Truncates a positive floating-point number to an unsigned int.
|
||||
|
||||
This is generally faster than static_cast<unsigned int> (std::floor (x))
|
||||
but it only works for positive numbers small enough to be represented as an
|
||||
unsigned int.
|
||||
*/
|
||||
template <typename FloatType>
|
||||
unsigned int truncatePositiveToUnsignedInt (FloatType value) noexcept
|
||||
{
|
||||
jassert (value >= static_cast<FloatType> (0));
|
||||
jassert (static_cast<FloatType> (value)
|
||||
<= static_cast<FloatType> (std::numeric_limits<unsigned int>::max()));
|
||||
|
||||
return static_cast<unsigned int> (value);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the specified integer is a power-of-two. */
|
||||
template <typename IntegerType>
|
||||
constexpr bool isPowerOfTwo (IntegerType value)
|
||||
{
|
||||
return (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
/** Returns the smallest power-of-two which is equal to or greater than the given integer. */
|
||||
inline int nextPowerOfTwo (int n) noexcept
|
||||
{
|
||||
--n;
|
||||
n |= (n >> 1);
|
||||
n |= (n >> 2);
|
||||
n |= (n >> 4);
|
||||
n |= (n >> 8);
|
||||
n |= (n >> 16);
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
/** Returns the index of the highest set bit in a (non-zero) number.
|
||||
So for n=3 this would return 1, for n=7 it returns 2, etc.
|
||||
An input value of 0 is illegal!
|
||||
*/
|
||||
int findHighestSetBit (uint32 n) noexcept;
|
||||
|
||||
/** Returns the number of bits in a 32-bit integer. */
|
||||
inline int countNumberOfBits (uint32 n) noexcept
|
||||
{
|
||||
n -= ((n >> 1) & 0x55555555);
|
||||
n = (((n >> 2) & 0x33333333) + (n & 0x33333333));
|
||||
n = (((n >> 4) + n) & 0x0f0f0f0f);
|
||||
n += (n >> 8);
|
||||
n += (n >> 16);
|
||||
return (int) (n & 0x3f);
|
||||
}
|
||||
|
||||
/** Returns the number of bits in a 64-bit integer. */
|
||||
inline int countNumberOfBits (uint64 n) noexcept
|
||||
{
|
||||
return countNumberOfBits ((uint32) n) + countNumberOfBits ((uint32) (n >> 32));
|
||||
}
|
||||
|
||||
/** Performs a modulo operation, but can cope with the dividend being negative.
|
||||
The divisor must be greater than zero.
|
||||
*/
|
||||
template <typename IntegerType>
|
||||
IntegerType negativeAwareModulo (IntegerType dividend, const IntegerType divisor) noexcept
|
||||
{
|
||||
jassert (divisor > 0);
|
||||
dividend %= divisor;
|
||||
return (dividend < 0) ? (dividend + divisor) : dividend;
|
||||
}
|
||||
|
||||
/** Returns the square of its argument. */
|
||||
template <typename NumericType>
|
||||
inline constexpr NumericType square (NumericType n) noexcept
|
||||
{
|
||||
return n * n;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Writes a number of bits into a memory buffer at a given bit index.
|
||||
The buffer is treated as a sequence of 8-bit bytes, and the value is encoded in little-endian order,
|
||||
so for example if startBit = 10, and numBits = 11 then the lower 6 bits of the value would be written
|
||||
into bits 2-8 of targetBuffer[1], and the upper 5 bits of value into bits 0-5 of targetBuffer[2].
|
||||
|
||||
@see readLittleEndianBitsInBuffer
|
||||
*/
|
||||
void writeLittleEndianBitsInBuffer (void* targetBuffer, uint32 startBit, uint32 numBits, uint32 value) noexcept;
|
||||
|
||||
/** Reads a number of bits from a buffer at a given bit index.
|
||||
The buffer is treated as a sequence of 8-bit bytes, and the value is encoded in little-endian order,
|
||||
so for example if startBit = 10, and numBits = 11 then the lower 6 bits of the result would be read
|
||||
from bits 2-8 of sourceBuffer[1], and the upper 5 bits of the result from bits 0-5 of sourceBuffer[2].
|
||||
|
||||
@see writeLittleEndianBitsInBuffer
|
||||
*/
|
||||
uint32 readLittleEndianBitsInBuffer (const void* sourceBuffer, uint32 startBit, uint32 numBits) noexcept;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_INTEL || DOXYGEN
|
||||
/** This macro can be applied to a float variable to check whether it contains a denormalised
|
||||
value, and to normalise it if necessary.
|
||||
On CPUs that aren't vulnerable to denormalisation problems, this will have no effect.
|
||||
*/
|
||||
#define JUCE_UNDENORMALISE(x) { (x) += 0.1f; (x) -= 0.1f; }
|
||||
#else
|
||||
#define JUCE_UNDENORMALISE(x)
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/** This namespace contains a few template classes for helping work out class type variations.
|
||||
*/
|
||||
namespace TypeHelpers
|
||||
{
|
||||
/** The ParameterType struct is used to find the best type to use when passing some kind
|
||||
of object as a parameter.
|
||||
|
||||
Of course, this is only likely to be useful in certain esoteric template situations.
|
||||
|
||||
E.g. "myFunction (typename TypeHelpers::ParameterType<int>::type, typename TypeHelpers::ParameterType<MyObject>::type)"
|
||||
would evaluate to "myfunction (int, const MyObject&)", keeping any primitive types as
|
||||
pass-by-value, but passing objects as a const reference, to avoid copying.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <typename Type> struct ParameterType { using type = const Type&; };
|
||||
|
||||
#ifndef DOXYGEN
|
||||
template <typename Type> struct ParameterType <Type&> { using type = Type&; };
|
||||
template <typename Type> struct ParameterType <Type*> { using type = Type*; };
|
||||
template <> struct ParameterType <char> { using type = char; };
|
||||
template <> struct ParameterType <unsigned char> { using type = unsigned char; };
|
||||
template <> struct ParameterType <short> { using type = short; };
|
||||
template <> struct ParameterType <unsigned short> { using type = unsigned short; };
|
||||
template <> struct ParameterType <int> { using type = int; };
|
||||
template <> struct ParameterType <unsigned int> { using type = unsigned int; };
|
||||
template <> struct ParameterType <long> { using type = long; };
|
||||
template <> struct ParameterType <unsigned long> { using type = unsigned long; };
|
||||
template <> struct ParameterType <int64> { using type = int64; };
|
||||
template <> struct ParameterType <uint64> { using type = uint64; };
|
||||
template <> struct ParameterType <bool> { using type = bool; };
|
||||
template <> struct ParameterType <float> { using type = float; };
|
||||
template <> struct ParameterType <double> { using type = double; };
|
||||
#endif
|
||||
|
||||
/** These templates are designed to take a type, and if it's a double, they return a double
|
||||
type; for anything else, they return a float type.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <typename Type> struct SmallestFloatType { using type = float; };
|
||||
|
||||
#ifndef DOXYGEN
|
||||
template <> struct SmallestFloatType <double> { using type = double; };
|
||||
#endif
|
||||
|
||||
/** These templates are designed to take an integer type, and return an unsigned int
|
||||
version with the same size.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <int bytes> struct UnsignedTypeWithSize {};
|
||||
|
||||
#ifndef DOXYGEN
|
||||
template <> struct UnsignedTypeWithSize<1> { using type = uint8; };
|
||||
template <> struct UnsignedTypeWithSize<2> { using type = uint16; };
|
||||
template <> struct UnsignedTypeWithSize<4> { using type = uint32; };
|
||||
template <> struct UnsignedTypeWithSize<8> { using type = uint64; };
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
[[deprecated ("Use roundToInt instead.")]] inline int roundDoubleToInt (double value) noexcept { return roundToInt (value); }
|
||||
[[deprecated ("Use roundToInt instead.")]] inline int roundFloatToInt (float value) noexcept { return roundToInt (value); }
|
||||
[[deprecated ("Use std::abs() instead.")]] inline int64 abs64 (int64 n) noexcept { return std::abs (n); }
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
261
deps/juce/modules/juce_core/maths/juce_NormalisableRange.h
vendored
Normal file
261
deps/juce/modules/juce_core/maths/juce_NormalisableRange.h
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents a mapping between an arbitrary range of values and a
|
||||
normalised 0->1 range.
|
||||
|
||||
The properties of the mapping also include an optional snapping interval
|
||||
and skew-factor.
|
||||
|
||||
@see Range
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <typename ValueType>
|
||||
class NormalisableRange
|
||||
{
|
||||
public:
|
||||
/** Creates a continuous range that performs a dummy mapping. */
|
||||
NormalisableRange() = default;
|
||||
|
||||
NormalisableRange (const NormalisableRange&) = default;
|
||||
NormalisableRange& operator= (const NormalisableRange&) = default;
|
||||
NormalisableRange (NormalisableRange&&) = default;
|
||||
NormalisableRange& operator= (NormalisableRange&&) = default;
|
||||
|
||||
/** Creates a NormalisableRange with a given range, interval and skew factor. */
|
||||
NormalisableRange (ValueType rangeStart,
|
||||
ValueType rangeEnd,
|
||||
ValueType intervalValue,
|
||||
ValueType skewFactor,
|
||||
bool useSymmetricSkew = false) noexcept
|
||||
: start (rangeStart), end (rangeEnd), interval (intervalValue),
|
||||
skew (skewFactor), symmetricSkew (useSymmetricSkew)
|
||||
{
|
||||
checkInvariants();
|
||||
}
|
||||
|
||||
/** Creates a NormalisableRange with a given range, continuous interval, but a dummy skew-factor. */
|
||||
NormalisableRange (ValueType rangeStart,
|
||||
ValueType rangeEnd) noexcept
|
||||
: start (rangeStart), end (rangeEnd)
|
||||
{
|
||||
checkInvariants();
|
||||
}
|
||||
|
||||
/** Creates a NormalisableRange with a given range and interval, but a dummy skew-factor. */
|
||||
NormalisableRange (ValueType rangeStart,
|
||||
ValueType rangeEnd,
|
||||
ValueType intervalValue) noexcept
|
||||
: start (rangeStart), end (rangeEnd), interval (intervalValue)
|
||||
{
|
||||
checkInvariants();
|
||||
}
|
||||
|
||||
/** Creates a NormalisableRange with a given range, continuous interval, but a dummy skew-factor. */
|
||||
NormalisableRange (Range<ValueType> range) noexcept
|
||||
: NormalisableRange (range.getStart(), range.getEnd())
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a NormalisableRange with a given range and interval, but a dummy skew-factor. */
|
||||
NormalisableRange (Range<ValueType> range, ValueType intervalValue) noexcept
|
||||
: NormalisableRange (range.getStart(), range.getEnd(), intervalValue)
|
||||
{
|
||||
}
|
||||
|
||||
/** A function object which can remap a value in some way based on the start and end of a range. */
|
||||
using ValueRemapFunction = std::function<ValueType(ValueType rangeStart,
|
||||
ValueType rangeEnd,
|
||||
ValueType valueToRemap)>;
|
||||
|
||||
/** Creates a NormalisableRange with a given range and an injective mapping function.
|
||||
|
||||
@param rangeStart The minimum value in the range.
|
||||
@param rangeEnd The maximum value in the range.
|
||||
@param convertFrom0To1Func A function which uses the current start and end of this NormalisableRange
|
||||
and produces a mapped value from a normalised value.
|
||||
@param convertTo0To1Func A function which uses the current start and end of this NormalisableRange
|
||||
and produces a normalised value from a mapped value.
|
||||
@param snapToLegalValueFunc A function which uses the current start and end of this NormalisableRange
|
||||
to take a mapped value and snap it to the nearest legal value.
|
||||
*/
|
||||
NormalisableRange (ValueType rangeStart,
|
||||
ValueType rangeEnd,
|
||||
ValueRemapFunction convertFrom0To1Func,
|
||||
ValueRemapFunction convertTo0To1Func,
|
||||
ValueRemapFunction snapToLegalValueFunc = {}) noexcept
|
||||
: start (rangeStart),
|
||||
end (rangeEnd),
|
||||
convertFrom0To1Function (std::move (convertFrom0To1Func)),
|
||||
convertTo0To1Function (std::move (convertTo0To1Func)),
|
||||
snapToLegalValueFunction (std::move (snapToLegalValueFunc))
|
||||
{
|
||||
checkInvariants();
|
||||
}
|
||||
|
||||
/** Uses the properties of this mapping to convert a non-normalised value to
|
||||
its 0->1 representation.
|
||||
*/
|
||||
ValueType convertTo0to1 (ValueType v) const noexcept
|
||||
{
|
||||
if (convertTo0To1Function != nullptr)
|
||||
return clampTo0To1 (convertTo0To1Function (start, end, v));
|
||||
|
||||
auto proportion = clampTo0To1 ((v - start) / (end - start));
|
||||
|
||||
if (skew == static_cast<ValueType> (1))
|
||||
return proportion;
|
||||
|
||||
if (! symmetricSkew)
|
||||
return std::pow (proportion, skew);
|
||||
|
||||
auto distanceFromMiddle = static_cast<ValueType> (2) * proportion - static_cast<ValueType> (1);
|
||||
|
||||
return (static_cast<ValueType> (1) + std::pow (std::abs (distanceFromMiddle), skew)
|
||||
* (distanceFromMiddle < ValueType() ? static_cast<ValueType> (-1)
|
||||
: static_cast<ValueType> (1)))
|
||||
/ static_cast<ValueType> (2);
|
||||
}
|
||||
|
||||
/** Uses the properties of this mapping to convert a normalised 0->1 value to
|
||||
its full-range representation.
|
||||
*/
|
||||
ValueType convertFrom0to1 (ValueType proportion) const noexcept
|
||||
{
|
||||
proportion = clampTo0To1 (proportion);
|
||||
|
||||
if (convertFrom0To1Function != nullptr)
|
||||
return convertFrom0To1Function (start, end, proportion);
|
||||
|
||||
if (! symmetricSkew)
|
||||
{
|
||||
if (skew != static_cast<ValueType> (1) && proportion > ValueType())
|
||||
proportion = std::exp (std::log (proportion) / skew);
|
||||
|
||||
return start + (end - start) * proportion;
|
||||
}
|
||||
|
||||
auto distanceFromMiddle = static_cast<ValueType> (2) * proportion - static_cast<ValueType> (1);
|
||||
|
||||
if (skew != static_cast<ValueType> (1) && distanceFromMiddle != static_cast<ValueType> (0))
|
||||
distanceFromMiddle = std::exp (std::log (std::abs (distanceFromMiddle)) / skew)
|
||||
* (distanceFromMiddle < ValueType() ? static_cast<ValueType> (-1)
|
||||
: static_cast<ValueType> (1));
|
||||
|
||||
return start + (end - start) / static_cast<ValueType> (2) * (static_cast<ValueType> (1) + distanceFromMiddle);
|
||||
}
|
||||
|
||||
/** Takes a non-normalised value and snaps it based on either the interval property of
|
||||
this NormalisableRange or the lambda function supplied to the constructor.
|
||||
*/
|
||||
ValueType snapToLegalValue (ValueType v) const noexcept
|
||||
{
|
||||
if (snapToLegalValueFunction != nullptr)
|
||||
return snapToLegalValueFunction (start, end, v);
|
||||
|
||||
if (interval > ValueType())
|
||||
v = start + interval * std::floor ((v - start) / interval + static_cast<ValueType> (0.5));
|
||||
|
||||
return (v <= start || end <= start) ? start : (v >= end ? end : v);
|
||||
}
|
||||
|
||||
/** Returns the extent of the normalisable range. */
|
||||
Range<ValueType> getRange() const noexcept { return { start, end }; }
|
||||
|
||||
/** Given a value which is between the start and end points, this sets the skew
|
||||
such that convertFrom0to1 (0.5) will return this value.
|
||||
|
||||
If you have used lambda functions for convertFrom0to1Func and convertFrom0to1Func in the
|
||||
constructor of this class then the skew value is ignored.
|
||||
|
||||
@param centrePointValue this must be greater than the start of the range and less than the end.
|
||||
*/
|
||||
void setSkewForCentre (ValueType centrePointValue) noexcept
|
||||
{
|
||||
jassert (centrePointValue > start);
|
||||
jassert (centrePointValue < end);
|
||||
|
||||
symmetricSkew = false;
|
||||
skew = std::log (static_cast<ValueType> (0.5)) / std::log ((centrePointValue - start) / (end - start));
|
||||
checkInvariants();
|
||||
}
|
||||
|
||||
/** The minimum value of the non-normalised range. */
|
||||
ValueType start = 0;
|
||||
|
||||
/** The maximum value of the non-normalised range. */
|
||||
ValueType end = 1;
|
||||
|
||||
/** The snapping interval that should be used (for a non-normalised value). Use 0 for a
|
||||
continuous range.
|
||||
|
||||
If you have used a lambda function for snapToLegalValueFunction in the constructor of
|
||||
this class then the interval is ignored.
|
||||
*/
|
||||
ValueType interval = 0;
|
||||
|
||||
/** An optional skew factor that alters the way values are distribute across the range.
|
||||
|
||||
The skew factor lets you skew the mapping logarithmically so that larger or smaller
|
||||
values are given a larger proportion of the available space.
|
||||
|
||||
A factor of 1.0 has no skewing effect at all. If the factor is < 1.0, the lower end
|
||||
of the range will fill more of the slider's length; if the factor is > 1.0, the upper
|
||||
end of the range will be expanded.
|
||||
|
||||
If you have used lambda functions for convertFrom0to1Func and convertFrom0to1Func in the
|
||||
constructor of this class then the skew value is ignored.
|
||||
*/
|
||||
ValueType skew = 1;
|
||||
|
||||
/** If true, the skew factor applies from the middle of the slider to each of its ends. */
|
||||
bool symmetricSkew = false;
|
||||
|
||||
private:
|
||||
void checkInvariants() const
|
||||
{
|
||||
jassert (end > start);
|
||||
jassert (interval >= ValueType());
|
||||
jassert (skew > ValueType());
|
||||
}
|
||||
|
||||
static ValueType clampTo0To1 (ValueType value)
|
||||
{
|
||||
auto clampedValue = jlimit (static_cast<ValueType> (0), static_cast<ValueType> (1), value);
|
||||
|
||||
// If you hit this assertion then either your normalisation function is not working
|
||||
// correctly or your input is out of the expected bounds.
|
||||
jassert (clampedValue == value);
|
||||
|
||||
return clampedValue;
|
||||
}
|
||||
|
||||
ValueRemapFunction convertFrom0To1Function, convertTo0To1Function, snapToLegalValueFunction;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
204
deps/juce/modules/juce_core/maths/juce_Random.cpp
vendored
Normal file
204
deps/juce/modules/juce_core/maths/juce_Random.cpp
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
Random::Random (int64 seedValue) noexcept : seed (seedValue)
|
||||
{
|
||||
}
|
||||
|
||||
Random::Random() : seed (1)
|
||||
{
|
||||
setSeedRandomly();
|
||||
}
|
||||
|
||||
Random::~Random() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void Random::setSeed (const int64 newSeed) noexcept
|
||||
{
|
||||
if (this == &getSystemRandom())
|
||||
{
|
||||
// Resetting the system Random risks messing up
|
||||
// JUCE's internal state. If you need a predictable
|
||||
// stream of random numbers you should use a local
|
||||
// Random object.
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
seed = newSeed;
|
||||
}
|
||||
|
||||
void Random::combineSeed (const int64 seedValue) noexcept
|
||||
{
|
||||
seed ^= nextInt64() ^ seedValue;
|
||||
}
|
||||
|
||||
void Random::setSeedRandomly()
|
||||
{
|
||||
static std::atomic<int64> globalSeed { 0 };
|
||||
|
||||
combineSeed (globalSeed ^ (int64) (pointer_sized_int) this);
|
||||
combineSeed (Time::getMillisecondCounter());
|
||||
combineSeed (Time::getHighResolutionTicks());
|
||||
combineSeed (Time::getHighResolutionTicksPerSecond());
|
||||
combineSeed (Time::currentTimeMillis());
|
||||
globalSeed ^= seed;
|
||||
}
|
||||
|
||||
Random& Random::getSystemRandom() noexcept
|
||||
{
|
||||
static Random sysRand;
|
||||
return sysRand;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int Random::nextInt() noexcept
|
||||
{
|
||||
seed = (int64) (((((uint64) seed) * 0x5deece66dLL) + 11) & 0xffffffffffffLL);
|
||||
|
||||
return (int) (seed >> 16);
|
||||
}
|
||||
|
||||
int Random::nextInt (const int maxValue) noexcept
|
||||
{
|
||||
jassert (maxValue > 0);
|
||||
return (int) ((((unsigned int) nextInt()) * (uint64) maxValue) >> 32);
|
||||
}
|
||||
|
||||
int Random::nextInt (Range<int> range) noexcept
|
||||
{
|
||||
return range.getStart() + nextInt (range.getLength());
|
||||
}
|
||||
|
||||
int64 Random::nextInt64() noexcept
|
||||
{
|
||||
return (int64) ((((uint64) (unsigned int) nextInt()) << 32) | (uint64) (unsigned int) nextInt());
|
||||
}
|
||||
|
||||
bool Random::nextBool() noexcept
|
||||
{
|
||||
return (nextInt() & 0x40000000) != 0;
|
||||
}
|
||||
|
||||
float Random::nextFloat() noexcept
|
||||
{
|
||||
auto result = static_cast<float> (static_cast<uint32> (nextInt()))
|
||||
/ (static_cast<float> (std::numeric_limits<uint32>::max()) + 1.0f);
|
||||
return result == 1.0f ? 1.0f - std::numeric_limits<float>::epsilon() : result;
|
||||
}
|
||||
|
||||
double Random::nextDouble() noexcept
|
||||
{
|
||||
return static_cast<uint32> (nextInt()) / (std::numeric_limits<uint32>::max() + 1.0);
|
||||
}
|
||||
|
||||
BigInteger Random::nextLargeNumber (const BigInteger& maximumValue)
|
||||
{
|
||||
BigInteger n;
|
||||
|
||||
do
|
||||
{
|
||||
fillBitsRandomly (n, 0, maximumValue.getHighestBit() + 1);
|
||||
}
|
||||
while (n >= maximumValue);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void Random::fillBitsRandomly (void* const buffer, size_t bytes)
|
||||
{
|
||||
int* d = static_cast<int*> (buffer);
|
||||
|
||||
for (; bytes >= sizeof (int); bytes -= sizeof (int))
|
||||
*d++ = nextInt();
|
||||
|
||||
if (bytes > 0)
|
||||
{
|
||||
const int lastBytes = nextInt();
|
||||
memcpy (d, &lastBytes, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
void Random::fillBitsRandomly (BigInteger& arrayToChange, int startBit, int numBits)
|
||||
{
|
||||
arrayToChange.setBit (startBit + numBits - 1, true); // to force the array to pre-allocate space
|
||||
|
||||
while ((startBit & 31) != 0 && numBits > 0)
|
||||
{
|
||||
arrayToChange.setBit (startBit++, nextBool());
|
||||
--numBits;
|
||||
}
|
||||
|
||||
while (numBits >= 32)
|
||||
{
|
||||
arrayToChange.setBitRangeAsInt (startBit, 32, (unsigned int) nextInt());
|
||||
startBit += 32;
|
||||
numBits -= 32;
|
||||
}
|
||||
|
||||
while (--numBits >= 0)
|
||||
arrayToChange.setBit (startBit + numBits, nextBool());
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
class RandomTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
RandomTests()
|
||||
: UnitTest ("Random", UnitTestCategories::maths)
|
||||
{}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("Random");
|
||||
|
||||
Random r = getRandom();
|
||||
|
||||
for (int i = 2000; --i >= 0;)
|
||||
{
|
||||
expect (r.nextDouble() >= 0.0 && r.nextDouble() < 1.0);
|
||||
expect (r.nextFloat() >= 0.0f && r.nextFloat() < 1.0f);
|
||||
expect (r.nextInt (5) >= 0 && r.nextInt (5) < 5);
|
||||
expect (r.nextInt (1) == 0);
|
||||
|
||||
int n = r.nextInt (50) + 1;
|
||||
expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
|
||||
|
||||
n = r.nextInt (0x7ffffffe) + 1;
|
||||
expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static RandomTests randomTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
137
deps/juce/modules/juce_core/maths/juce_Random.h
vendored
Normal file
137
deps/juce/modules/juce_core/maths/juce_Random.h
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 random number generator.
|
||||
|
||||
You can create a Random object and use it to generate a sequence of random numbers.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API Random final
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a Random object based on a seed value.
|
||||
|
||||
For a given seed value, the subsequent numbers generated by this object
|
||||
will be predictable, so a good idea is to set this value based
|
||||
on the time, e.g.
|
||||
|
||||
new Random (Time::currentTimeMillis())
|
||||
*/
|
||||
explicit Random (int64 seedValue) noexcept;
|
||||
|
||||
/** Creates a Random object using a random seed value.
|
||||
Internally, this calls setSeedRandomly() to randomise the seed.
|
||||
*/
|
||||
Random();
|
||||
|
||||
/** Destructor. */
|
||||
~Random() noexcept;
|
||||
|
||||
/** Returns the next random 32 bit integer.
|
||||
@returns a random integer from the full range 0x80000000 to 0x7fffffff
|
||||
*/
|
||||
int nextInt() noexcept;
|
||||
|
||||
/** Returns the next random number, limited to a given range.
|
||||
The maxValue parameter may not be negative, or zero.
|
||||
@returns a random integer between 0 (inclusive) and maxValue (exclusive).
|
||||
*/
|
||||
int nextInt (int maxValue) noexcept;
|
||||
|
||||
/** Returns the next random number, limited to a given range.
|
||||
@returns a random integer between the range start (inclusive) and its end (exclusive).
|
||||
*/
|
||||
int nextInt (Range<int> range) noexcept;
|
||||
|
||||
/** Returns the next 64-bit random number.
|
||||
@returns a random integer from the full range 0x8000000000000000 to 0x7fffffffffffffff
|
||||
*/
|
||||
int64 nextInt64() noexcept;
|
||||
|
||||
/** Returns the next random floating-point number.
|
||||
@returns a random value in the range 0 (inclusive) to 1.0 (exclusive)
|
||||
*/
|
||||
float nextFloat() noexcept;
|
||||
|
||||
/** Returns the next random floating-point number.
|
||||
@returns a random value in the range 0 (inclusive) to 1.0 (exclusive)
|
||||
*/
|
||||
double nextDouble() noexcept;
|
||||
|
||||
/** Returns the next random boolean value. */
|
||||
bool nextBool() noexcept;
|
||||
|
||||
/** Returns a BigInteger containing a random number.
|
||||
@returns a random value in the range 0 to (maximumValue - 1).
|
||||
*/
|
||||
BigInteger nextLargeNumber (const BigInteger& maximumValue);
|
||||
|
||||
/** Fills a block of memory with random values. */
|
||||
void fillBitsRandomly (void* bufferToFill, size_t sizeInBytes);
|
||||
|
||||
/** Sets a range of bits in a BigInteger to random values. */
|
||||
void fillBitsRandomly (BigInteger& arrayToChange, int startBit, int numBits);
|
||||
|
||||
//==============================================================================
|
||||
/** Resets this Random object to a given seed value. */
|
||||
void setSeed (int64 newSeed) noexcept;
|
||||
|
||||
/** Returns the RNG's current seed. */
|
||||
int64 getSeed() const noexcept { return seed; }
|
||||
|
||||
/** Merges this object's seed with another value.
|
||||
This sets the seed to be a value created by combining the current seed and this
|
||||
new value.
|
||||
*/
|
||||
void combineSeed (int64 seedValue) noexcept;
|
||||
|
||||
/** Reseeds this generator using a value generated from various semi-random system
|
||||
properties like the current time, etc.
|
||||
|
||||
Because this function convolves the time with the last seed value, calling
|
||||
it repeatedly will increase the randomness of the final result.
|
||||
*/
|
||||
void setSeedRandomly();
|
||||
|
||||
/** The overhead of creating a new Random object is fairly small, but if you want to avoid
|
||||
it, you can call this method to get a global shared Random object.
|
||||
|
||||
It's not thread-safe though, so threads should use their own Random object, otherwise
|
||||
you run the risk of your random numbers becoming.. erm.. randomly corrupted..
|
||||
*/
|
||||
static Random& getSystemRandom() noexcept;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
int64 seed;
|
||||
|
||||
JUCE_LEAK_DETECTOR (Random)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
297
deps/juce/modules/juce_core/maths/juce_Range.h
vendored
Normal file
297
deps/juce/modules/juce_core/maths/juce_Range.h
vendored
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 general-purpose range object, that simply represents any linear range with
|
||||
a start and end point.
|
||||
|
||||
Note that when checking whether values fall within the range, the start value is
|
||||
considered to be inclusive, and the end of the range exclusive.
|
||||
|
||||
The templated parameter is expected to be a primitive integer or floating point
|
||||
type, though class types could also be used if they behave in a number-like way.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <typename ValueType>
|
||||
class Range
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Constructs an empty range. */
|
||||
constexpr Range() = default;
|
||||
|
||||
/** Constructs a range with given start and end values. */
|
||||
constexpr Range (const ValueType startValue, const ValueType endValue) noexcept
|
||||
: start (startValue), end (jmax (startValue, endValue))
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructs a copy of another range. */
|
||||
constexpr Range (const Range&) = default;
|
||||
|
||||
/** Copies another range object. */
|
||||
Range& operator= (const Range&) = default;
|
||||
|
||||
/** Returns the range that lies between two positions (in either order). */
|
||||
constexpr static Range between (const ValueType position1, const ValueType position2) noexcept
|
||||
{
|
||||
return position1 < position2 ? Range (position1, position2)
|
||||
: Range (position2, position1);
|
||||
}
|
||||
|
||||
/** Returns a range with a given start and length. */
|
||||
static Range withStartAndLength (const ValueType startValue, const ValueType length) noexcept
|
||||
{
|
||||
jassert (length >= ValueType());
|
||||
return Range (startValue, startValue + length);
|
||||
}
|
||||
|
||||
/** Returns a range with the specified start position and a length of zero. */
|
||||
constexpr static Range emptyRange (const ValueType start) noexcept
|
||||
{
|
||||
return Range (start, start);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the start of the range. */
|
||||
constexpr inline ValueType getStart() const noexcept { return start; }
|
||||
|
||||
/** Returns the length of the range. */
|
||||
constexpr inline ValueType getLength() const noexcept { return end - start; }
|
||||
|
||||
/** Returns the end of the range. */
|
||||
constexpr inline ValueType getEnd() const noexcept { return end; }
|
||||
|
||||
/** Returns true if the range has a length of zero. */
|
||||
constexpr inline bool isEmpty() const noexcept { return start == end; }
|
||||
|
||||
//==============================================================================
|
||||
/** Changes the start position of the range, leaving the end position unchanged.
|
||||
If the new start position is higher than the current end of the range, the end point
|
||||
will be pushed along to equal it, leaving an empty range at the new position.
|
||||
*/
|
||||
void setStart (const ValueType newStart) noexcept
|
||||
{
|
||||
start = newStart;
|
||||
if (end < newStart)
|
||||
end = newStart;
|
||||
}
|
||||
|
||||
/** Returns a range with the same end as this one, but a different start.
|
||||
If the new start position is higher than the current end of the range, the end point
|
||||
will be pushed along to equal it, returning an empty range at the new position.
|
||||
*/
|
||||
constexpr Range withStart (const ValueType newStart) const noexcept
|
||||
{
|
||||
return Range (newStart, jmax (newStart, end));
|
||||
}
|
||||
|
||||
/** Returns a range with the same length as this one, but moved to have the given start position. */
|
||||
constexpr Range movedToStartAt (const ValueType newStart) const noexcept
|
||||
{
|
||||
return Range (newStart, end + (newStart - start));
|
||||
}
|
||||
|
||||
/** Changes the end position of the range, leaving the start unchanged.
|
||||
If the new end position is below the current start of the range, the start point
|
||||
will be pushed back to equal the new end point.
|
||||
*/
|
||||
void setEnd (const ValueType newEnd) noexcept
|
||||
{
|
||||
end = newEnd;
|
||||
if (newEnd < start)
|
||||
start = newEnd;
|
||||
}
|
||||
|
||||
/** Returns a range with the same start position as this one, but a different end.
|
||||
If the new end position is below the current start of the range, the start point
|
||||
will be pushed back to equal the new end point.
|
||||
*/
|
||||
constexpr Range withEnd (const ValueType newEnd) const noexcept
|
||||
{
|
||||
return Range (jmin (start, newEnd), newEnd);
|
||||
}
|
||||
|
||||
/** Returns a range with the same length as this one, but moved to have the given end position. */
|
||||
constexpr Range movedToEndAt (const ValueType newEnd) const noexcept
|
||||
{
|
||||
return Range (start + (newEnd - end), newEnd);
|
||||
}
|
||||
|
||||
/** Changes the length of the range.
|
||||
Lengths less than zero are treated as zero.
|
||||
*/
|
||||
void setLength (const ValueType newLength) noexcept
|
||||
{
|
||||
end = start + jmax (ValueType(), newLength);
|
||||
}
|
||||
|
||||
/** Returns a range with the same start as this one, but a different length.
|
||||
Lengths less than zero are treated as zero.
|
||||
*/
|
||||
constexpr Range withLength (const ValueType newLength) const noexcept
|
||||
{
|
||||
return Range (start, start + newLength);
|
||||
}
|
||||
|
||||
/** Returns a range which has its start moved down and its end moved up by the
|
||||
given amount.
|
||||
@returns The returned range will be (start - amount, end + amount)
|
||||
*/
|
||||
constexpr Range expanded (ValueType amount) const noexcept
|
||||
{
|
||||
return Range (start - amount, end + amount);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Adds an amount to the start and end of the range. */
|
||||
inline Range operator+= (const ValueType amountToAdd) noexcept
|
||||
{
|
||||
start += amountToAdd;
|
||||
end += amountToAdd;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Subtracts an amount from the start and end of the range. */
|
||||
inline Range operator-= (const ValueType amountToSubtract) noexcept
|
||||
{
|
||||
start -= amountToSubtract;
|
||||
end -= amountToSubtract;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Returns a range that is equal to this one with an amount added to its
|
||||
start and end.
|
||||
*/
|
||||
constexpr Range operator+ (const ValueType amountToAdd) const noexcept
|
||||
{
|
||||
return Range (start + amountToAdd, end + amountToAdd);
|
||||
}
|
||||
|
||||
/** Returns a range that is equal to this one with the specified amount
|
||||
subtracted from its start and end. */
|
||||
constexpr Range operator- (const ValueType amountToSubtract) const noexcept
|
||||
{
|
||||
return Range (start - amountToSubtract, end - amountToSubtract);
|
||||
}
|
||||
|
||||
constexpr bool operator== (Range other) const noexcept { return start == other.start && end == other.end; }
|
||||
constexpr bool operator!= (Range other) const noexcept { return start != other.start || end != other.end; }
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the given position lies inside this range.
|
||||
When making this comparison, the start value is considered to be inclusive,
|
||||
and the end of the range exclusive.
|
||||
*/
|
||||
constexpr bool contains (const ValueType position) const noexcept
|
||||
{
|
||||
return start <= position && position < end;
|
||||
}
|
||||
|
||||
/** Returns the nearest value to the one supplied, which lies within the range. */
|
||||
ValueType clipValue (const ValueType value) const noexcept
|
||||
{
|
||||
return jlimit (start, end, value);
|
||||
}
|
||||
|
||||
/** Returns true if the given range lies entirely inside this range. */
|
||||
constexpr bool contains (Range other) const noexcept
|
||||
{
|
||||
return start <= other.start && end >= other.end;
|
||||
}
|
||||
|
||||
/** Returns true if the given range intersects this one. */
|
||||
constexpr bool intersects (Range other) const noexcept
|
||||
{
|
||||
return other.start < end && start < other.end;
|
||||
}
|
||||
|
||||
/** Returns the range that is the intersection of the two ranges, or an empty range
|
||||
with an undefined start position if they don't overlap. */
|
||||
constexpr Range getIntersectionWith (Range other) const noexcept
|
||||
{
|
||||
return Range (jmax (start, other.start),
|
||||
jmin (end, other.end));
|
||||
}
|
||||
|
||||
/** Returns the smallest range that contains both this one and the other one. */
|
||||
constexpr Range getUnionWith (Range other) const noexcept
|
||||
{
|
||||
return Range (jmin (start, other.start),
|
||||
jmax (end, other.end));
|
||||
}
|
||||
|
||||
/** Returns the smallest range that contains both this one and the given value. */
|
||||
constexpr Range getUnionWith (const ValueType valueToInclude) const noexcept
|
||||
{
|
||||
return Range (jmin (valueToInclude, start),
|
||||
jmax (valueToInclude, end));
|
||||
}
|
||||
|
||||
/** Returns a given range, after moving it forwards or backwards to fit it
|
||||
within this range.
|
||||
|
||||
If the supplied range has a greater length than this one, the return value
|
||||
will be this range.
|
||||
|
||||
Otherwise, if the supplied range is smaller than this one, the return value
|
||||
will be the new range, shifted forwards or backwards so that it doesn't extend
|
||||
beyond this one, but keeping its original length.
|
||||
*/
|
||||
Range constrainRange (Range rangeToConstrain) const noexcept
|
||||
{
|
||||
const ValueType otherLen = rangeToConstrain.getLength();
|
||||
return getLength() <= otherLen
|
||||
? *this
|
||||
: rangeToConstrain.movedToStartAt (jlimit (start, end - otherLen, rangeToConstrain.getStart()));
|
||||
}
|
||||
|
||||
/** Scans an array of values for its min and max, and returns these as a Range. */
|
||||
static Range findMinAndMax (const ValueType* values, int numValues) noexcept
|
||||
{
|
||||
if (numValues <= 0)
|
||||
return Range();
|
||||
|
||||
const ValueType first (*values++);
|
||||
Range r (first, first);
|
||||
|
||||
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||
{
|
||||
const ValueType v (*values++);
|
||||
|
||||
if (r.end < v) r.end = v;
|
||||
if (v < r.start) r.start = v;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ValueType start{}, end{};
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
136
deps/juce/modules/juce_core/maths/juce_StatisticsAccumulator.h
vendored
Normal file
136
deps/juce/modules/juce_core/maths/juce_StatisticsAccumulator.h
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 that measures various statistics about a series of floating point
|
||||
values that it is given.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <typename FloatType>
|
||||
class StatisticsAccumulator
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Constructs a new StatisticsAccumulator. */
|
||||
StatisticsAccumulator() = default;
|
||||
|
||||
//==============================================================================
|
||||
/** Add a new value to the accumulator.
|
||||
This will update all running statistics accordingly.
|
||||
*/
|
||||
void addValue (FloatType v) noexcept
|
||||
{
|
||||
jassert (juce_isfinite (v));
|
||||
|
||||
sum += v;
|
||||
sumSquares += v * v;
|
||||
++count;
|
||||
|
||||
if (v > maximum) maximum = v;
|
||||
if (v < minimum) minimum = v;
|
||||
}
|
||||
|
||||
/** Reset the accumulator.
|
||||
This will reset all currently saved statistcs.
|
||||
*/
|
||||
void reset() noexcept { *this = StatisticsAccumulator<FloatType>(); }
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the average (arithmetic mean) of all previously added values.
|
||||
If no values have been added yet, this will return zero.
|
||||
*/
|
||||
FloatType getAverage() const noexcept
|
||||
{
|
||||
return count > 0 ? sum / (FloatType) count
|
||||
: FloatType();
|
||||
}
|
||||
|
||||
/** Returns the variance of all previously added values.
|
||||
If no values have been added yet, this will return zero.
|
||||
*/
|
||||
FloatType getVariance() const noexcept
|
||||
{
|
||||
return count > 0 ? (sumSquares - sum * sum / (FloatType) count) / (FloatType) count
|
||||
: FloatType();
|
||||
}
|
||||
|
||||
/** Returns the standard deviation of all previously added values.
|
||||
If no values have been added yet, this will return zero.
|
||||
*/
|
||||
FloatType getStandardDeviation() const noexcept
|
||||
{
|
||||
return std::sqrt (getVariance());
|
||||
}
|
||||
|
||||
/** Returns the smallest of all previously added values.
|
||||
If no values have been added yet, this will return positive infinity.
|
||||
*/
|
||||
FloatType getMinValue() const noexcept
|
||||
{
|
||||
return minimum;
|
||||
}
|
||||
|
||||
/** Returns the largest of all previously added values.
|
||||
If no values have been added yet, this will return negative infinity.
|
||||
*/
|
||||
FloatType getMaxValue() const noexcept
|
||||
{
|
||||
return maximum;
|
||||
}
|
||||
|
||||
/** Returns how many values have been added to this accumulator. */
|
||||
size_t getCount() const noexcept
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct KahanSum
|
||||
{
|
||||
KahanSum() = default;
|
||||
operator FloatType() const noexcept { return sum; }
|
||||
|
||||
void JUCE_NO_ASSOCIATIVE_MATH_OPTIMISATIONS operator+= (FloatType value) noexcept
|
||||
{
|
||||
FloatType correctedValue = value - error;
|
||||
FloatType newSum = sum + correctedValue;
|
||||
error = (newSum - sum) - correctedValue;
|
||||
sum = newSum;
|
||||
}
|
||||
|
||||
FloatType sum{}, error{};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
size_t count { 0 };
|
||||
KahanSum sum, sumSquares;
|
||||
FloatType minimum { std::numeric_limits<FloatType>::infinity() },
|
||||
maximum { -std::numeric_limits<FloatType>::infinity() };
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
100
deps/juce/modules/juce_core/memory/juce_AllocationHooks.cpp
vendored
Normal file
100
deps/juce/modules/juce_core/memory/juce_AllocationHooks.cpp
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#if JUCE_ENABLE_ALLOCATION_HOOKS
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
static AllocationHooks& getAllocationHooksForThread()
|
||||
{
|
||||
thread_local AllocationHooks hooks;
|
||||
return hooks;
|
||||
}
|
||||
|
||||
void notifyAllocationHooksForThread()
|
||||
{
|
||||
getAllocationHooksForThread().listenerList.call ([] (AllocationHooks::Listener& l)
|
||||
{
|
||||
l.newOrDeleteCalled();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void* operator new (size_t s)
|
||||
{
|
||||
juce::notifyAllocationHooksForThread();
|
||||
return std::malloc (s);
|
||||
}
|
||||
|
||||
void* operator new[] (size_t s)
|
||||
{
|
||||
juce::notifyAllocationHooksForThread();
|
||||
return std::malloc (s);
|
||||
}
|
||||
|
||||
void operator delete (void* p) noexcept
|
||||
{
|
||||
juce::notifyAllocationHooksForThread();
|
||||
std::free (p);
|
||||
}
|
||||
|
||||
void operator delete[] (void* p) noexcept
|
||||
{
|
||||
juce::notifyAllocationHooksForThread();
|
||||
std::free (p);
|
||||
}
|
||||
|
||||
void operator delete (void* p, size_t) noexcept
|
||||
{
|
||||
juce::notifyAllocationHooksForThread();
|
||||
std::free (p);
|
||||
}
|
||||
|
||||
void operator delete[] (void* p, size_t) noexcept
|
||||
{
|
||||
juce::notifyAllocationHooksForThread();
|
||||
std::free (p);
|
||||
}
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
UnitTestAllocationChecker::UnitTestAllocationChecker (UnitTest& test)
|
||||
: unitTest (test)
|
||||
{
|
||||
getAllocationHooksForThread().addListener (this);
|
||||
}
|
||||
|
||||
UnitTestAllocationChecker::~UnitTestAllocationChecker() noexcept
|
||||
{
|
||||
getAllocationHooksForThread().removeListener (this);
|
||||
unitTest.expectEquals ((int) calls, 0, "new or delete was incorrectly called while allocation checker was active");
|
||||
}
|
||||
|
||||
void UnitTestAllocationChecker::newOrDeleteCalled() noexcept { ++calls; }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
73
deps/juce/modules/juce_core/memory/juce_AllocationHooks.h
vendored
Normal file
73
deps/juce/modules/juce_core/memory/juce_AllocationHooks.h
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#if JUCE_ENABLE_ALLOCATION_HOOKS
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class AllocationHooks
|
||||
{
|
||||
public:
|
||||
struct Listener
|
||||
{
|
||||
virtual ~Listener() noexcept = default;
|
||||
virtual void newOrDeleteCalled() noexcept = 0;
|
||||
};
|
||||
|
||||
void addListener (Listener* l) { listenerList.add (l); }
|
||||
void removeListener (Listener* l) noexcept { listenerList.remove (l); }
|
||||
|
||||
private:
|
||||
friend void notifyAllocationHooksForThread();
|
||||
ListenerList<Listener> listenerList;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Scoped checker which will cause a unit test failure if any new/delete calls
|
||||
are made during the lifetime of the UnitTestAllocationChecker.
|
||||
*/
|
||||
class UnitTestAllocationChecker : private AllocationHooks::Listener
|
||||
{
|
||||
public:
|
||||
/** Create a checker which will log a failure to the passed test if
|
||||
any calls to new/delete are made.
|
||||
|
||||
Remember to call `UnitTest::beginTest` before constructing this checker!
|
||||
*/
|
||||
explicit UnitTestAllocationChecker (UnitTest& test);
|
||||
|
||||
/** Will add a failure to the test if the number of new/delete calls during
|
||||
this object's lifetime was greater than zero.
|
||||
*/
|
||||
~UnitTestAllocationChecker() noexcept override;
|
||||
|
||||
private:
|
||||
void newOrDeleteCalled() noexcept override;
|
||||
|
||||
UnitTest& unitTest;
|
||||
size_t calls = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
145
deps/juce/modules/juce_core/memory/juce_Atomic.h
vendored
Normal file
145
deps/juce/modules/juce_core/memory/juce_Atomic.h
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
using DiffType = typename AtomicHelpers::DiffTypeHelper<Type>::Type;
|
||||
|
||||
/** Creates a new value, initialised to zero. */
|
||||
Atomic() noexcept : value (Type()) {}
|
||||
|
||||
/** 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
|
||||
[[deprecated ("This method has been deprecated as there is no equivalent method in "
|
||||
"std::atomic. Use compareAndSetBool instead.")]]
|
||||
Type compareAndSetValue (Type, Type) noexcept;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
224
deps/juce/modules/juce_core/memory/juce_ByteOrder.h
vendored
Normal file
224
deps/juce/modules/juce_core/memory/juce_ByteOrder.h
vendored
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#if ! defined (DOXYGEN) && (JUCE_MAC || JUCE_IOS)
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#endif
|
||||
|
||||
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. */
|
||||
constexpr static uint16 swap (uint16 value) noexcept;
|
||||
|
||||
/** Swaps the upper and lower bytes of a 16-bit integer. */
|
||||
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. */
|
||||
constexpr static uint32 littleEndianInt (const void* bytes) noexcept;
|
||||
|
||||
/** Turns 8 bytes into a little-endian integer. */
|
||||
constexpr static uint64 littleEndianInt64 (const void* bytes) noexcept;
|
||||
|
||||
/** Turns 2 bytes into a little-endian integer. */
|
||||
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). */
|
||||
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. */
|
||||
constexpr static uint32 bigEndianInt (const void* bytes) noexcept;
|
||||
|
||||
/** Turns 8 bytes into a big-endian integer. */
|
||||
constexpr static uint64 bigEndianInt64 (const void* bytes) noexcept;
|
||||
|
||||
/** Turns 2 bytes into a big-endian integer. */
|
||||
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). */
|
||||
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. */
|
||||
constexpr static uint16 makeInt (uint8 leastSig, uint8 mostSig) noexcept;
|
||||
|
||||
/** Constructs a 32-bit integer from its constituent bytes, in order of significance. */
|
||||
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. */
|
||||
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. */
|
||||
constexpr static bool isBigEndian() noexcept
|
||||
{
|
||||
#if JUCE_LITTLE_ENDIAN
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
ByteOrder() = delete;
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
constexpr inline uint16 ByteOrder::swap (uint16 v) noexcept { return static_cast<uint16> ((v << 8) | (v >> 8)); }
|
||||
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
|
||||
}
|
||||
|
||||
constexpr inline uint16 ByteOrder::makeInt (uint8 b0, uint8 b1) noexcept
|
||||
{
|
||||
return static_cast<uint16> (static_cast<uint16> (b0) | (static_cast<uint16> (b1) << 8));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
constexpr inline uint16 ByteOrder::littleEndianShort (const void* bytes) noexcept { return makeInt (static_cast<const uint8*> (bytes)[0], static_cast<const uint8*> (bytes)[1]); }
|
||||
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]); }
|
||||
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]); }
|
||||
|
||||
constexpr inline uint16 ByteOrder::bigEndianShort (const void* bytes) noexcept { return makeInt (static_cast<const uint8*> (bytes)[1], static_cast<const uint8*> (bytes)[0]); }
|
||||
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]); }
|
||||
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]); }
|
||||
|
||||
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])); }
|
||||
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
|
||||
58
deps/juce/modules/juce_core/memory/juce_ContainerDeletePolicy.h
vendored
Normal file
58
deps/juce/modules/juce_core/memory/juce_ContainerDeletePolicy.h
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 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 OwnedArray of a forward-declared type, move the
|
||||
// implementation of all methods trying to use the OwnedArray (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
|
||||
350
deps/juce/modules/juce_core/memory/juce_HeapBlock.h
vendored
Normal file
350
deps/juce/modules/juce_core/memory/juce_HeapBlock.h
vendored
Normal file
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 ! (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
|
||||
{
|
||||
private:
|
||||
template <class OtherElementType>
|
||||
using AllowConversion = typename std::enable_if<std::is_base_of<typename std::remove_pointer<ElementType>::type,
|
||||
typename std::remove_pointer<OtherElementType>::type>::value>::type;
|
||||
|
||||
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() = default;
|
||||
|
||||
/** 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, std::enable_if_t<std::is_integral<SizeType>::value, int> = 0>
|
||||
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, std::enable_if_t<std::is_integral<SizeType>::value, int> = 0>
|
||||
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;
|
||||
}
|
||||
|
||||
/** Converting move constructor.
|
||||
Only enabled if this is a HeapBlock<Base*> and the other object is a HeapBlock<Derived*>,
|
||||
where std::is_base_of<Base, Derived>::value == true.
|
||||
*/
|
||||
template <class OtherElementType, bool otherThrowOnFailure, typename = AllowConversion<OtherElementType>>
|
||||
HeapBlock (HeapBlock<OtherElementType, otherThrowOnFailure>&& other) noexcept
|
||||
: data (reinterpret_cast<ElementType*> (other.data))
|
||||
{
|
||||
other.data = nullptr;
|
||||
}
|
||||
|
||||
/** Converting move assignment operator.
|
||||
Only enabled if this is a HeapBlock<Base*> and the other object is a HeapBlock<Derived*>,
|
||||
where std::is_base_of<Base, Derived>::value == true.
|
||||
*/
|
||||
template <class OtherElementType, bool otherThrowOnFailure, typename = AllowConversion<OtherElementType>>
|
||||
HeapBlock& operator= (HeapBlock<OtherElementType, otherThrowOnFailure>&& other) noexcept
|
||||
{
|
||||
free();
|
||||
data = reinterpret_cast<ElementType*> (other.data);
|
||||
other.data = nullptr;
|
||||
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. */
|
||||
using Type = ElementType;
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
template <class OtherElementType, bool otherThrowOnFailure>
|
||||
friend class HeapBlock;
|
||||
|
||||
#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
|
||||
144
deps/juce/modules/juce_core/memory/juce_HeavyweightLeakedObjectDetector.h
vendored
Normal file
144
deps/juce/modules/juce_core/memory/juce_HeavyweightLeakedObjectDetector.h
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 a useful way of tracking down hard to find memory leaks when the
|
||||
regular LeakedObjectDetector isn't enough.
|
||||
|
||||
As well as firing when any instances of the OwnerClass type are leaked, it will
|
||||
print out a stack trace showing where the leaked object was created. This is obviously
|
||||
quite a heavyweight task so, unlike the LeakedObjectDetector which should be always
|
||||
be added to your classes, you should only use this object temporarily when you are
|
||||
debugging and remove it when finished.
|
||||
|
||||
To use it, use the JUCE_HEAVYWEIGHT_LEAK_DETECTOR macro as a simple way to put
|
||||
one in your class declaration.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class OwnerClass>
|
||||
class HeavyweightLeakedObjectDetector
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
HeavyweightLeakedObjectDetector() noexcept { getBacktraceMap()[this] = SystemStats::getStackBacktrace(); }
|
||||
HeavyweightLeakedObjectDetector (const HeavyweightLeakedObjectDetector&) noexcept { getBacktraceMap()[this] = SystemStats::getStackBacktrace(); }
|
||||
|
||||
~HeavyweightLeakedObjectDetector() { getBacktraceMap().erase (this); }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
typedef std::map<HeavyweightLeakedObjectDetector<OwnerClass>*, String> BacktraceMap;
|
||||
|
||||
//==============================================================================
|
||||
struct BacktraceMapHolder
|
||||
{
|
||||
BacktraceMapHolder() = default;
|
||||
|
||||
~BacktraceMapHolder()
|
||||
{
|
||||
if (map.size() > 0)
|
||||
{
|
||||
DBG ("*** Leaked objects detected: " << map.size() << " instance(s) of class " << getLeakedObjectClassName());
|
||||
DBG (getFormattedBacktracesString());
|
||||
|
||||
/** If you hit this, then you've leaked one or more objects of the type specified by
|
||||
the 'OwnerClass' template parameter - the name and stack trace of its creation should
|
||||
have been printed by the lines 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;
|
||||
}
|
||||
}
|
||||
|
||||
String getFormattedBacktracesString() const
|
||||
{
|
||||
String str;
|
||||
|
||||
int counter = 1;
|
||||
for (auto& bt : map)
|
||||
{
|
||||
str << "\nBacktrace " << String (counter++) << "\n"
|
||||
<< "-----------------------------------------------------------------" << "\n"
|
||||
<< bt.second;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
BacktraceMap map;
|
||||
};
|
||||
|
||||
static BacktraceMap& getBacktraceMap()
|
||||
{
|
||||
static BacktraceMapHolder holder;
|
||||
return holder.map;
|
||||
}
|
||||
|
||||
static const char* getLeakedObjectClassName()
|
||||
{
|
||||
return OwnerClass::getLeakedObjectClassName();
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#if DOXYGEN || ! defined (JUCE_HEAVYWEIGHT_LEAK_DETECTOR)
|
||||
#if (DOXYGEN || JUCE_CHECK_MEMORY_LEAKS)
|
||||
/** This macro lets you embed a heavyweight leak-detecting object inside a class.
|
||||
|
||||
To use it, simply declare a JUCE_HEAVYWEIGHT_LEAK_DETECTOR (YourClassName) inside a private section
|
||||
of the class declaration. E.g.
|
||||
|
||||
@code
|
||||
class MyClass
|
||||
{
|
||||
public:
|
||||
MyClass();
|
||||
void blahBlah();
|
||||
|
||||
private:
|
||||
JUCE_HEAVYWEIGHT_LEAK_DETECTOR (MyClass)
|
||||
};
|
||||
@endcode
|
||||
|
||||
NB: you should only use this when you really need to track down a tricky memory leak, and
|
||||
should never leave one of these inside a class!
|
||||
|
||||
@see HeavyweightLeakedObjectDetector, JUCE_LEAK_DETECTOR, LeakedObjectDetector
|
||||
*/
|
||||
#define JUCE_HEAVYWEIGHT_LEAK_DETECTOR(OwnerClass) \
|
||||
friend class juce::HeavyweightLeakedObjectDetector<OwnerClass>; \
|
||||
static const char* getLeakedObjectClassName() noexcept { return #OwnerClass; } \
|
||||
juce::HeavyweightLeakedObjectDetector<OwnerClass> JUCE_JOIN_MACRO (leakDetector, __LINE__);
|
||||
#else
|
||||
#define JUCE_HEAVYWEIGHT_LEAK_DETECTOR(OwnerClass)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
142
deps/juce/modules/juce_core/memory/juce_LeakedObjectDetector.h
vendored
Normal file
142
deps/juce/modules/juce_core/memory/juce_LeakedObjectDetector.h
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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& operator= (const LeakedObjectDetector&) noexcept = default;
|
||||
|
||||
~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() = default;
|
||||
|
||||
~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
|
||||
200
deps/juce/modules/juce_core/memory/juce_Memory.h
vendored
Normal file
200
deps/juce/modules/juce_core/memory/juce_Memory.h
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 ((void*) &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 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));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Casts a pointer to another type via `void*`, which suppresses the cast-align
|
||||
warning which sometimes arises when casting pointers to types with different
|
||||
alignment.
|
||||
You should only use this when you know for a fact that the input pointer points
|
||||
to a region that has suitable alignment for `Type`, e.g. regions returned from
|
||||
malloc/calloc that should be suitable for any non-over-aligned type.
|
||||
*/
|
||||
template <typename Type, typename std::enable_if<std::is_pointer<Type>::value, int>::type = 0>
|
||||
inline Type unalignedPointerCast (void* ptr) noexcept
|
||||
{
|
||||
return reinterpret_cast<Type> (ptr);
|
||||
}
|
||||
|
||||
/** Casts a pointer to another type via `void*`, which suppresses the cast-align
|
||||
warning which sometimes arises when casting pointers to types with different
|
||||
alignment.
|
||||
You should only use this when you know for a fact that the input pointer points
|
||||
to a region that has suitable alignment for `Type`, e.g. regions returned from
|
||||
malloc/calloc that should be suitable for any non-over-aligned type.
|
||||
*/
|
||||
template <typename Type, typename std::enable_if<std::is_pointer<Type>::value, int>::type = 0>
|
||||
inline Type unalignedPointerCast (const void* ptr) noexcept
|
||||
{
|
||||
return reinterpret_cast<Type> (ptr);
|
||||
}
|
||||
|
||||
/** 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 unalignedPointerCast<Type*> (reinterpret_cast<char*> (basePointer) + bytes);
|
||||
}
|
||||
|
||||
/** 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 const Type* addBytesToPointer (const Type* basePointer, IntegerType bytes) noexcept
|
||||
{
|
||||
return unalignedPointerCast<const Type*> (reinterpret_cast<const char*> (basePointer) + bytes);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#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
|
||||
|
||||
/** Converts an owning raw pointer into a unique_ptr, deriving the
|
||||
type of the unique_ptr automatically.
|
||||
|
||||
This should only be used with pointers to single objects.
|
||||
Do NOT pass a pointer to an array to this function, as the
|
||||
destructor of the unique_ptr will incorrectly call `delete`
|
||||
instead of `delete[]` on the pointer.
|
||||
*/
|
||||
template <typename T>
|
||||
std::unique_ptr<T> rawToUniquePtr (T* ptr)
|
||||
{
|
||||
return std::unique_ptr<T> (ptr);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
413
deps/juce/modules/juce_core/memory/juce_MemoryBlock.cpp
vendored
Normal file
413
deps/juce/modules/juce_core/memory/juce_MemoryBlock.cpp
vendored
Normal file
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 (std::move (other.data)),
|
||||
size (other.size)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryBlock& MemoryBlock::operator= (MemoryBlock&& other) noexcept
|
||||
{
|
||||
data = std::move (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::replaceAll (const void* srcData, size_t numBytes)
|
||||
{
|
||||
if (numBytes <= 0)
|
||||
{
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
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 (;;)
|
||||
{
|
||||
juce_wchar 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 ((size_t) initialLen * sizeof (String::CharPointerType::CharType) + 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
|
||||
290
deps/juce/modules/juce_core/memory/juce_MemoryBlock.h
vendored
Normal file
290
deps/juce/modules/juce_core/memory/juce_MemoryBlock.h
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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() noexcept { return data; }
|
||||
|
||||
/** Returns a void pointer to the data.
|
||||
|
||||
Note that the pointer returned will probably become invalid when the
|
||||
block is resized.
|
||||
*/
|
||||
const 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) noexcept { return data [offset]; }
|
||||
|
||||
/** Returns a byte from the memory block. */
|
||||
template <typename Type>
|
||||
const char& operator[] (const Type offset) const noexcept { return data [offset]; }
|
||||
|
||||
/** Returns an iterator for the data. */
|
||||
char* begin() noexcept { return data; }
|
||||
|
||||
/** Returns an iterator for the data. */
|
||||
const char* begin() const noexcept { return data; }
|
||||
|
||||
/** Returns an end-iterator for the data. */
|
||||
char* end() noexcept { return begin() + getSize(); }
|
||||
|
||||
/** Returns an end-iterator for the data. */
|
||||
const char* end() const noexcept { return begin() + getSize(); }
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the memory block has zero size. */
|
||||
bool isEmpty() const noexcept { return getSize() == 0; }
|
||||
|
||||
/** 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 replaceAll (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);
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
[[deprecated ("Use the replaceAll method instead, which will also replace the data when numBytes == 0.")]]
|
||||
void replaceWith (const void* srcData, size_t numBytes)
|
||||
{
|
||||
if (numBytes > 0)
|
||||
replaceAll (srcData, numBytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
using HeapBlockType = HeapBlock<char, true>;
|
||||
HeapBlockType data;
|
||||
size_t size = 0;
|
||||
|
||||
JUCE_LEAK_DETECTOR (MemoryBlock)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
191
deps/juce/modules/juce_core/memory/juce_OptionalScopedPointer.h
vendored
Normal file
191
deps/juce/modules/juce_core/memory/juce_OptionalScopedPointer.h
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 std::unique_ptr, but allows you to specify whether or
|
||||
not the object is deleted.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class ObjectType>
|
||||
class OptionalScopedPointer
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty OptionalScopedPointer. */
|
||||
OptionalScopedPointer() = default;
|
||||
|
||||
/** 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 std::unique_ptr,
|
||||
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 std::unique_ptr, 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&& other) noexcept
|
||||
: object (std::move (other.object)),
|
||||
shouldDelete (std::move (other.shouldDelete))
|
||||
{
|
||||
}
|
||||
|
||||
/** Takes ownership of the object owned by `ptr`. */
|
||||
explicit OptionalScopedPointer (std::unique_ptr<ObjectType>&& ptr) noexcept
|
||||
: OptionalScopedPointer (ptr.release(), true)
|
||||
{
|
||||
}
|
||||
|
||||
/** Points to the same object as `ref`, but does not take ownership. */
|
||||
explicit OptionalScopedPointer (ObjectType& ref) noexcept
|
||||
: OptionalScopedPointer (std::addressof (ref), false)
|
||||
{
|
||||
}
|
||||
|
||||
/** Takes ownership of the object that another OptionalScopedPointer holds.
|
||||
|
||||
Like a normal std::unique_ptr, 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&& other) noexcept
|
||||
{
|
||||
swapWith (other);
|
||||
other.reset();
|
||||
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() noexcept
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the object that this pointer is managing. */
|
||||
operator ObjectType*() const noexcept { return object.get(); }
|
||||
|
||||
/** Returns the object that this pointer is managing. */
|
||||
ObjectType* get() const noexcept { return object.get(); }
|
||||
|
||||
/** Returns the object that this pointer is managing. */
|
||||
ObjectType& operator*() const noexcept { return *object; }
|
||||
|
||||
/** Lets you access methods and properties of the object that this pointer is holding. */
|
||||
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() noexcept
|
||||
{
|
||||
if (! shouldDelete)
|
||||
object.release();
|
||||
else
|
||||
object.reset();
|
||||
}
|
||||
|
||||
/** 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 std::unique_ptr,
|
||||
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
|
||||
{
|
||||
std::swap (other.object, object);
|
||||
std::swap (other.shouldDelete, shouldDelete);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
std::unique_ptr<ObjectType> object;
|
||||
bool shouldDelete = false;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
469
deps/juce/modules/juce_core/memory/juce_ReferenceCountedObject.h
vendored
Normal file
469
deps/juce/modules/juce_core/memory/juce_ReferenceCountedObject.h
vendored
Normal file
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
the reference count can be updated on multiple threads. Note that
|
||||
whilst it's thread-safe to create and delete a ReferenceCountedObjectPtr
|
||||
to a ReferenceCountedObject shared between threads, it's not thread-safe
|
||||
to modify or swap the ReferenceCountedObject.
|
||||
|
||||
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() = default;
|
||||
|
||||
/** 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() = default;
|
||||
|
||||
/** 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() = default;
|
||||
|
||||
/** 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);
|
||||
}
|
||||
|
||||
/** Creates a pointer to an object.
|
||||
This will increment the object's reference-count.
|
||||
*/
|
||||
ReferenceCountedObjectPtr (ReferencedType& refCountedObject) noexcept
|
||||
: referencedObject (&refCountedObject)
|
||||
{
|
||||
refCountedObject.incReferenceCount();
|
||||
}
|
||||
|
||||
/** Copies another pointer.
|
||||
This will increment the object's reference-count.
|
||||
*/
|
||||
ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept
|
||||
: referencedObject (other.referencedObject)
|
||||
{
|
||||
incIfNotNull (referencedObject);
|
||||
}
|
||||
|
||||
/** Takes-over the object from another pointer. */
|
||||
ReferenceCountedObjectPtr (ReferenceCountedObjectPtr&& other) noexcept
|
||||
: referencedObject (other.referencedObject)
|
||||
{
|
||||
other.referencedObject = nullptr;
|
||||
}
|
||||
|
||||
/** 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 (newObject != nullptr)
|
||||
return operator= (*newObject);
|
||||
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** 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)
|
||||
{
|
||||
newObject.incReferenceCount();
|
||||
auto* oldObject = referencedObject;
|
||||
referencedObject = &newObject;
|
||||
decIfNotNull (oldObject);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Resets this pointer to a null pointer. */
|
||||
ReferenceCountedObjectPtr& operator= (decltype (nullptr))
|
||||
{
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Takes-over the object from another pointer. */
|
||||
ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectPtr&& other) noexcept
|
||||
{
|
||||
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.
|
||||
*/
|
||||
ReferencedType* get() const noexcept { return referencedObject; }
|
||||
|
||||
/** Resets this object to a null pointer. */
|
||||
void reset() noexcept
|
||||
{
|
||||
auto oldObject = referencedObject; // need to null the pointer before deleting the object
|
||||
referencedObject = nullptr; // in case this ptr is itself deleted as a side-effect
|
||||
decIfNotNull (oldObject); // of the destructor
|
||||
}
|
||||
|
||||
// the -> operator is called on the referenced object
|
||||
ReferencedType* operator->() const noexcept
|
||||
{
|
||||
jassert (referencedObject != nullptr); // null pointer method call!
|
||||
return referencedObject;
|
||||
}
|
||||
|
||||
/** Dereferences the object that this pointer references.
|
||||
The pointer returned may be null, of course.
|
||||
*/
|
||||
ReferencedType& operator*() const noexcept { jassert (referencedObject != nullptr); return *referencedObject; }
|
||||
|
||||
/** Checks whether this pointer is null */
|
||||
bool operator== (decltype (nullptr)) const noexcept { return referencedObject == nullptr; }
|
||||
/** Checks whether this pointer is null */
|
||||
bool operator!= (decltype (nullptr)) const noexcept { return referencedObject != nullptr; }
|
||||
|
||||
/** Compares two ReferenceCountedObjectPtrs. */
|
||||
bool operator== (const ObjectType* other) const noexcept { return referencedObject == other; }
|
||||
/** Compares two ReferenceCountedObjectPtrs. */
|
||||
bool operator== (const ReferenceCountedObjectPtr& other) const noexcept { return referencedObject == other.get(); }
|
||||
/** Compares two ReferenceCountedObjectPtrs. */
|
||||
bool operator!= (const ObjectType* other) const noexcept { return referencedObject != other; }
|
||||
/** Compares two ReferenceCountedObjectPtrs. */
|
||||
bool operator!= (const ReferenceCountedObjectPtr& other) const noexcept { return referencedObject != other.get(); }
|
||||
|
||||
#if JUCE_STRICT_REFCOUNTEDPOINTER
|
||||
/** Checks whether this pointer is null */
|
||||
explicit operator bool() const noexcept { return referencedObject != nullptr; }
|
||||
|
||||
#else
|
||||
/** Returns the object that this pointer references.
|
||||
The pointer returned may be null, of course.
|
||||
Note that this methods allows the compiler to be very lenient with what it allows you to do
|
||||
with the pointer, it's safer to disable this by setting JUCE_STRICT_REFCOUNTEDPOINTER=1, which
|
||||
increased type safety and can prevent some common slip-ups.
|
||||
*/
|
||||
operator ReferencedType*() const noexcept { return referencedObject; }
|
||||
#endif
|
||||
|
||||
#ifndef DOXYGEN
|
||||
[[deprecated ("Use the get method instead.")]]
|
||||
ReferencedType* getObject() const { return get(); }
|
||||
#endif
|
||||
|
||||
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 Type>
|
||||
bool operator== (const Type* object1, const ReferenceCountedObjectPtr<Type>& object2) noexcept
|
||||
{
|
||||
return object1 == object2.get();
|
||||
}
|
||||
|
||||
/** Compares two ReferenceCountedObjectPtrs. */
|
||||
template <typename Type>
|
||||
bool operator!= (const Type* object1, const ReferenceCountedObjectPtr<Type>& object2) noexcept
|
||||
{
|
||||
return object1 != object2.get();
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
100
deps/juce/modules/juce_core/memory/juce_Reservoir.h
vendored
Normal file
100
deps/juce/modules/juce_core/memory/juce_Reservoir.h
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
/**
|
||||
Helper functions for managing buffered readers.
|
||||
*/
|
||||
struct Reservoir
|
||||
{
|
||||
/** Attempts to read the requested range from some kind of input stream,
|
||||
with intermediate buffering in a 'reservoir'.
|
||||
|
||||
While there are still samples in the requested range left to read, this
|
||||
function will check whether the next part of the requested range is
|
||||
already loaded into the reservoir. If the range is available, then
|
||||
doBufferedRead will call readFromReservoir with the range that should
|
||||
be copied to the output buffer. If the range is not available,
|
||||
doBufferedRead will call fillReservoir to request that a new region is
|
||||
loaded into the reservoir. It will repeat these steps until either the
|
||||
entire requested region has been read, or the stream ends.
|
||||
|
||||
This will return the range that could not be read successfully, if any.
|
||||
An empty range implies that the entire read was successful.
|
||||
|
||||
Note that all ranges, including those provided as arguments to the
|
||||
callbacks, are relative to the original unbuffered input. That is, if
|
||||
getBufferedRange returns the range [200, 300), then readFromReservoir
|
||||
might be passed the range [250, 300) in order to copy the final 50
|
||||
samples from the reservoir.
|
||||
|
||||
@param rangeToRead the absolute position of the range that should
|
||||
be read
|
||||
@param getBufferedRange a function void -> Range<Index> that returns
|
||||
the region currently held in the reservoir
|
||||
@param readFromReservoir a function Range<Index> -> void that can be
|
||||
used to copy samples from the region in the
|
||||
reservoir specified in the input range
|
||||
@param fillReservoir a function Index -> void that is given a
|
||||
requested read location, and that should
|
||||
attempt to fill the reservoir starting at this
|
||||
location. After this function,
|
||||
getBufferedRange should return the new region
|
||||
contained in the managed buffer
|
||||
*/
|
||||
template <typename Index, typename GetBufferedRange, typename ReadFromReservoir, typename FillReservoir>
|
||||
static Range<Index> doBufferedRead (Range<Index> rangeToRead,
|
||||
GetBufferedRange&& getBufferedRange,
|
||||
ReadFromReservoir&& readFromReservoir,
|
||||
FillReservoir&& fillReservoir)
|
||||
{
|
||||
while (! rangeToRead.isEmpty())
|
||||
{
|
||||
const auto rangeToReadInBuffer = rangeToRead.getIntersectionWith (getBufferedRange());
|
||||
|
||||
if (rangeToReadInBuffer.isEmpty())
|
||||
{
|
||||
fillReservoir (rangeToRead.getStart());
|
||||
|
||||
const auto newRange = getBufferedRange();
|
||||
|
||||
if (newRange.isEmpty() || ! newRange.contains (rangeToRead.getStart()))
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
readFromReservoir (rangeToReadInBuffer);
|
||||
|
||||
rangeToRead.setStart (rangeToReadInBuffer.getEnd());
|
||||
}
|
||||
}
|
||||
|
||||
return rangeToRead;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
224
deps/juce/modules/juce_core/memory/juce_ScopedPointer.h
vendored
Normal file
224
deps/juce/modules/juce_core/memory/juce_ScopedPointer.h
vendored
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef DOXYGEN
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
This class is deprecated. You should use std::unique_ptr instead.
|
||||
*/
|
||||
template <class ObjectType>
|
||||
class [[deprecated]] ScopedPointer
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
|
||||
|
||||
inline ScopedPointer() {}
|
||||
|
||||
inline ScopedPointer (decltype (nullptr)) noexcept {}
|
||||
|
||||
inline ScopedPointer (ObjectType* objectToTakePossessionOf) noexcept
|
||||
: object (objectToTakePossessionOf)
|
||||
{
|
||||
}
|
||||
|
||||
ScopedPointer (ScopedPointer& objectToTransferFrom) noexcept
|
||||
: object (objectToTransferFrom.release())
|
||||
{
|
||||
}
|
||||
|
||||
inline ~ScopedPointer() { reset(); }
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ScopedPointer& operator= (ObjectType* newObjectToTakePossessionOf)
|
||||
{
|
||||
reset (newObjectToTakePossessionOf);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ScopedPointer (ScopedPointer&& other) noexcept : object (other.object)
|
||||
{
|
||||
other.object = nullptr;
|
||||
}
|
||||
|
||||
ScopedPointer& operator= (ScopedPointer&& other) noexcept
|
||||
{
|
||||
reset (other.release());
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
inline operator ObjectType*() const noexcept { return object; }
|
||||
inline ObjectType* get() const noexcept { return object; }
|
||||
inline ObjectType& operator*() const noexcept { return *object; }
|
||||
inline ObjectType* operator->() const noexcept { return object; }
|
||||
|
||||
void reset()
|
||||
{
|
||||
auto* oldObject = object;
|
||||
object = {};
|
||||
ContainerDeletePolicy<ObjectType>::destroy (oldObject);
|
||||
}
|
||||
|
||||
void reset (ObjectType* newObject)
|
||||
{
|
||||
if (object != newObject)
|
||||
{
|
||||
auto* oldObject = object;
|
||||
object = newObject;
|
||||
ContainerDeletePolicy<ObjectType>::destroy (oldObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
// You're trying to reset this ScopedPointer to itself! This will work here as ScopedPointer does an equality check
|
||||
// but be aware that std::unique_ptr won't do this and you could end up with some nasty, subtle bugs!
|
||||
jassert (newObject == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void reset (ScopedPointer& newObject)
|
||||
{
|
||||
reset (newObject.release());
|
||||
}
|
||||
|
||||
ObjectType* release() noexcept { auto* o = object; object = {}; return o; }
|
||||
|
||||
//==============================================================================
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
|
||||
|
||||
template <typename ObjectType1, typename ObjectType2>
|
||||
bool operator== (ObjectType1* pointer1, const ScopedPointer<ObjectType2>& pointer2) noexcept
|
||||
{
|
||||
return pointer1 == pointer2.get();
|
||||
}
|
||||
|
||||
template <typename ObjectType1, typename ObjectType2>
|
||||
bool operator!= (ObjectType1* pointer1, const ScopedPointer<ObjectType2>& pointer2) noexcept
|
||||
{
|
||||
return pointer1 != pointer2.get();
|
||||
}
|
||||
|
||||
template <typename ObjectType1, typename ObjectType2>
|
||||
bool operator== (const ScopedPointer<ObjectType1>& pointer1, ObjectType2* pointer2) noexcept
|
||||
{
|
||||
return pointer1.get() == pointer2;
|
||||
}
|
||||
|
||||
template <typename ObjectType1, typename ObjectType2>
|
||||
bool operator!= (const ScopedPointer<ObjectType1>& pointer1, ObjectType2* pointer2) noexcept
|
||||
{
|
||||
return pointer1.get() != pointer2;
|
||||
}
|
||||
|
||||
template <typename ObjectType1, typename ObjectType2>
|
||||
bool operator== (const ScopedPointer<ObjectType1>& pointer1, const ScopedPointer<ObjectType2>& pointer2) noexcept
|
||||
{
|
||||
return pointer1.get() == pointer2.get();
|
||||
}
|
||||
|
||||
template <typename ObjectType1, typename ObjectType2>
|
||||
bool operator!= (const ScopedPointer<ObjectType1>& pointer1, const ScopedPointer<ObjectType2>& pointer2) noexcept
|
||||
{
|
||||
return pointer1.get() != pointer2.get();
|
||||
}
|
||||
|
||||
template <class ObjectType>
|
||||
bool operator== (decltype (nullptr), const ScopedPointer<ObjectType>& pointer) noexcept
|
||||
{
|
||||
return pointer.get() == nullptr;
|
||||
}
|
||||
|
||||
template <class ObjectType>
|
||||
bool operator!= (decltype (nullptr), const ScopedPointer<ObjectType>& pointer) noexcept
|
||||
{
|
||||
return pointer.get() != nullptr;
|
||||
}
|
||||
|
||||
template <class ObjectType>
|
||||
bool operator== (const ScopedPointer<ObjectType>& pointer, decltype (nullptr)) noexcept
|
||||
{
|
||||
return pointer.get() == nullptr;
|
||||
}
|
||||
|
||||
template <class ObjectType>
|
||||
bool operator!= (const ScopedPointer<ObjectType>& pointer, decltype (nullptr)) noexcept
|
||||
{
|
||||
return pointer.get() != nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// 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"); }
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
|
||||
} // namespace juce
|
||||
|
||||
#endif
|
||||
162
deps/juce/modules/juce_core/memory/juce_SharedResourcePointer.h
vendored
Normal file
162
deps/juce/modules/juce_core/memory/juce_SharedResourcePointer.h
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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. */
|
||||
SharedObjectType& getObject() const noexcept { return *sharedObject; }
|
||||
|
||||
/** Returns the shared object pointer. */
|
||||
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*)] = { nullptr };
|
||||
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
|
||||
280
deps/juce/modules/juce_core/memory/juce_Singleton.h
vendored
Normal file
280
deps/juce/modules/juce_core/memory/juce_Singleton.h
vendored
Normal file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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() = default;
|
||||
|
||||
~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
|
||||
240
deps/juce/modules/juce_core/memory/juce_WeakReference.h
vendored
Normal file
240
deps/juce/modules/juce_core/memory/juce_WeakReference.h
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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.
|
||||
|
||||
Note that WeakReference is not designed to be thread-safe, so if you're accessing it from
|
||||
different threads, you'll need to do your own locking around all uses of the pointer and
|
||||
the object it refers to.
|
||||
|
||||
E.g.
|
||||
@code
|
||||
class MyObject
|
||||
{
|
||||
public:
|
||||
MyObject() {}
|
||||
|
||||
~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..
|
||||
|
||||
auto* n = new MyObject();
|
||||
WeakReference<MyObject> myObjectRef = n;
|
||||
|
||||
auto pointer1 = myObjectRef.get(); // returns a valid pointer to 'n'
|
||||
delete n;
|
||||
auto pointer2 = myObjectRef.get(); // now returns nullptr
|
||||
@endcode
|
||||
|
||||
@see WeakReference::Master
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class ObjectType, class ReferenceCountingType = ReferenceCountedObject>
|
||||
class WeakReference
|
||||
{
|
||||
public:
|
||||
/** Creates a null WeakReference. */
|
||||
inline WeakReference() = default;
|
||||
|
||||
/** 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 (std::move (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 = std::move (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->() 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)
|
||||
};
|
||||
|
||||
using SharedRef = ReferenceCountedObjectPtr<SharedPointer>;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
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() = default;
|
||||
|
||||
~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.
|
||||
*/
|
||||
SharedRef 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 SharedRef getRef (ObjectType* o)
|
||||
{
|
||||
if (o != nullptr)
|
||||
return o->masterReference.getSharedPointer (o);
|
||||
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
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 juce::WeakReference<Class>::Master { ~WeakRefMaster() { this->clear(); } }; \
|
||||
WeakRefMaster masterReference; \
|
||||
friend class juce::WeakReference<Class>; \
|
||||
|
||||
|
||||
} // namespace juce
|
||||
439
deps/juce/modules/juce_core/misc/juce_ConsoleApplication.cpp
vendored
Normal file
439
deps/juce/modules/juce_core/misc/juce_ConsoleApplication.cpp
vendored
Normal file
@@ -0,0 +1,439 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
static File resolveFilename (const String& name)
|
||||
{
|
||||
return File::getCurrentWorkingDirectory().getChildFile (name.unquoted());
|
||||
}
|
||||
|
||||
static File checkFileExists (const File& f)
|
||||
{
|
||||
if (! f.exists())
|
||||
ConsoleApplication::fail ("Could not find file: " + f.getFullPathName());
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static File checkFolderExists (const File& f)
|
||||
{
|
||||
if (! f.isDirectory())
|
||||
ConsoleApplication::fail ("Could not find folder: " + f.getFullPathName());
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static File resolveFilenameForOption (const ArgumentList& args, StringRef option, const String& filename)
|
||||
{
|
||||
if (filename.isEmpty())
|
||||
{
|
||||
args.failIfOptionIsMissing (option);
|
||||
ConsoleApplication::fail ("Expected a filename after the " + option + " option");
|
||||
}
|
||||
|
||||
return resolveFilename (filename);
|
||||
}
|
||||
|
||||
File ArgumentList::Argument::resolveAsFile() const
|
||||
{
|
||||
return resolveFilename (text);
|
||||
}
|
||||
|
||||
File ArgumentList::Argument::resolveAsExistingFile() const
|
||||
{
|
||||
return checkFileExists (resolveAsFile());
|
||||
}
|
||||
|
||||
File ArgumentList::Argument::resolveAsExistingFolder() const
|
||||
{
|
||||
auto f = resolveAsFile();
|
||||
|
||||
if (! f.isDirectory())
|
||||
ConsoleApplication::fail ("Could not find folder: " + f.getFullPathName());
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static bool isShortOptionFormat (StringRef s) { return s[0] == '-' && s[1] != '-'; }
|
||||
static bool isLongOptionFormat (StringRef s) { return s[0] == '-' && s[1] == '-' && s[2] != '-'; }
|
||||
static bool isOptionFormat (StringRef s) { return s[0] == '-'; }
|
||||
|
||||
bool ArgumentList::Argument::isLongOption() const { return isLongOptionFormat (text); }
|
||||
bool ArgumentList::Argument::isShortOption() const { return isShortOptionFormat (text); }
|
||||
bool ArgumentList::Argument::isOption() const { return isOptionFormat (text); }
|
||||
|
||||
bool ArgumentList::Argument::isLongOption (const String& option) const
|
||||
{
|
||||
if (! isLongOptionFormat (option))
|
||||
{
|
||||
jassert (! isShortOptionFormat (option)); // this will always fail to match
|
||||
return isLongOption ("--" + option);
|
||||
}
|
||||
|
||||
return text.upToFirstOccurrenceOf ("=", false, false) == option;
|
||||
}
|
||||
|
||||
String ArgumentList::Argument::getLongOptionValue() const
|
||||
{
|
||||
if (isLongOption())
|
||||
{
|
||||
auto equalsIndex = text.indexOfChar ('=');
|
||||
|
||||
if (equalsIndex > 0)
|
||||
return text.substring (equalsIndex + 1);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ArgumentList::Argument::isShortOption (char option) const
|
||||
{
|
||||
jassert (option != '-'); // this is probably not what you intended to pass in
|
||||
|
||||
return isShortOption() && text.containsChar (String (option)[0]);
|
||||
}
|
||||
|
||||
bool ArgumentList::Argument::operator== (StringRef wildcard) const
|
||||
{
|
||||
for (auto& o : StringArray::fromTokens (wildcard, "|", {}))
|
||||
{
|
||||
if (text == o)
|
||||
return true;
|
||||
|
||||
if (isShortOptionFormat (o) && o.length() == 2 && isShortOption ((char) o[1]))
|
||||
return true;
|
||||
|
||||
if (isLongOptionFormat (o) && isLongOption (o))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ArgumentList::Argument::operator!= (StringRef s) const { return ! operator== (s); }
|
||||
|
||||
//==============================================================================
|
||||
ArgumentList::ArgumentList (String exeName, StringArray args)
|
||||
: executableName (std::move (exeName))
|
||||
{
|
||||
args.trim();
|
||||
args.removeEmptyStrings();
|
||||
|
||||
for (auto& a : args)
|
||||
arguments.add ({ a.unquoted() });
|
||||
}
|
||||
|
||||
ArgumentList::ArgumentList (int argc, char* argv[])
|
||||
: ArgumentList (argv[0], StringArray (argv + 1, argc - 1))
|
||||
{
|
||||
}
|
||||
|
||||
ArgumentList::ArgumentList (const String& exeName, const String& args)
|
||||
: ArgumentList (exeName, StringArray::fromTokens (args, true))
|
||||
{
|
||||
}
|
||||
|
||||
int ArgumentList::size() const { return arguments.size(); }
|
||||
ArgumentList::Argument ArgumentList::operator[] (int index) const { return arguments[index]; }
|
||||
|
||||
void ArgumentList::checkMinNumArguments (int expectedMinNumberOfArgs) const
|
||||
{
|
||||
if (size() < expectedMinNumberOfArgs)
|
||||
ConsoleApplication::fail ("Not enough arguments!");
|
||||
}
|
||||
|
||||
int ArgumentList::indexOfOption (StringRef option) const
|
||||
{
|
||||
jassert (option == String (option).trim()); // passing non-trimmed strings will always fail to find a match!
|
||||
|
||||
for (int i = 0; i < arguments.size(); ++i)
|
||||
if (arguments.getReference (i) == option)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ArgumentList::containsOption (StringRef option) const
|
||||
{
|
||||
return indexOfOption (option) >= 0;
|
||||
}
|
||||
|
||||
bool ArgumentList::removeOptionIfFound (StringRef option)
|
||||
{
|
||||
auto i = indexOfOption (option);
|
||||
|
||||
if (i >= 0)
|
||||
arguments.remove (i);
|
||||
|
||||
return i >= 0;
|
||||
}
|
||||
|
||||
void ArgumentList::failIfOptionIsMissing (StringRef option) const
|
||||
{
|
||||
if (indexOfOption (option) < 0)
|
||||
ConsoleApplication::fail ("Expected the option " + option);
|
||||
}
|
||||
|
||||
String ArgumentList::getValueForOption (StringRef option) const
|
||||
{
|
||||
jassert (isOptionFormat (option)); // the thing you're searching for must be an option
|
||||
|
||||
for (int i = 0; i < arguments.size(); ++i)
|
||||
{
|
||||
auto& arg = arguments.getReference(i);
|
||||
|
||||
if (arg == option)
|
||||
{
|
||||
if (arg.isShortOption())
|
||||
{
|
||||
if (i < arguments.size() - 1 && ! arguments.getReference (i + 1).isOption())
|
||||
return arguments.getReference (i + 1).text;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (arg.isLongOption())
|
||||
return arg.getLongOptionValue();
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
String ArgumentList::removeValueForOption (StringRef option)
|
||||
{
|
||||
jassert (isOptionFormat (option)); // the thing you're searching for must be an option
|
||||
|
||||
for (int i = 0; i < arguments.size(); ++i)
|
||||
{
|
||||
auto& arg = arguments.getReference(i);
|
||||
|
||||
if (arg == option)
|
||||
{
|
||||
if (arg.isShortOption())
|
||||
{
|
||||
if (i < arguments.size() - 1 && ! arguments.getReference (i + 1).isOption())
|
||||
{
|
||||
auto result = arguments.getReference (i + 1).text;
|
||||
arguments.removeRange (i, 2);
|
||||
return result;
|
||||
}
|
||||
|
||||
arguments.remove (i);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (arg.isLongOption())
|
||||
{
|
||||
auto result = arg.getLongOptionValue();
|
||||
arguments.remove (i);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
File ArgumentList::getFileForOption (StringRef option) const
|
||||
{
|
||||
return resolveFilenameForOption (*this, option, getValueForOption (option));
|
||||
}
|
||||
|
||||
File ArgumentList::getFileForOptionAndRemove (StringRef option)
|
||||
{
|
||||
return resolveFilenameForOption (*this, option, removeValueForOption (option));
|
||||
}
|
||||
|
||||
File ArgumentList::getExistingFileForOption (StringRef option) const
|
||||
{
|
||||
return checkFileExists (getFileForOption (option));
|
||||
}
|
||||
|
||||
File ArgumentList::getExistingFileForOptionAndRemove (StringRef option)
|
||||
{
|
||||
return checkFileExists (getFileForOptionAndRemove (option));
|
||||
}
|
||||
|
||||
File ArgumentList::getExistingFolderForOption (StringRef option) const
|
||||
{
|
||||
return checkFolderExists (getFileForOption (option));
|
||||
}
|
||||
|
||||
File ArgumentList::getExistingFolderForOptionAndRemove (StringRef option)
|
||||
{
|
||||
return checkFolderExists (getFileForOptionAndRemove (option));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct ConsoleAppFailureCode
|
||||
{
|
||||
String errorMessage;
|
||||
int returnCode;
|
||||
};
|
||||
|
||||
void ConsoleApplication::fail (String errorMessage, int returnCode)
|
||||
{
|
||||
throw ConsoleAppFailureCode { std::move (errorMessage), returnCode };
|
||||
}
|
||||
|
||||
int ConsoleApplication::invokeCatchingFailures (std::function<int()>&& f)
|
||||
{
|
||||
int returnCode = 0;
|
||||
|
||||
try
|
||||
{
|
||||
returnCode = f();
|
||||
}
|
||||
catch (const ConsoleAppFailureCode& error)
|
||||
{
|
||||
std::cerr << error.errorMessage << std::endl;
|
||||
returnCode = error.returnCode;
|
||||
}
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
const ConsoleApplication::Command* ConsoleApplication::findCommand (const ArgumentList& args, bool optionMustBeFirstArg) const
|
||||
{
|
||||
for (auto& c : commands)
|
||||
{
|
||||
auto index = args.indexOfOption (c.commandOption);
|
||||
|
||||
if (optionMustBeFirstArg ? (index == 0) : (index >= 0))
|
||||
return &c;
|
||||
}
|
||||
|
||||
if (commandIfNoOthersRecognised >= 0)
|
||||
return &commands[(size_t) commandIfNoOthersRecognised];
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
int ConsoleApplication::findAndRunCommand (const ArgumentList& args, bool optionMustBeFirstArg) const
|
||||
{
|
||||
return invokeCatchingFailures ([&args, optionMustBeFirstArg, this]
|
||||
{
|
||||
if (auto c = findCommand (args, optionMustBeFirstArg))
|
||||
c->command (args);
|
||||
else
|
||||
fail ("Unrecognised arguments");
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
int ConsoleApplication::findAndRunCommand (int argc, char* argv[]) const
|
||||
{
|
||||
return findAndRunCommand (ArgumentList (argc, argv));
|
||||
}
|
||||
|
||||
void ConsoleApplication::addCommand (Command c)
|
||||
{
|
||||
commands.emplace_back (std::move (c));
|
||||
}
|
||||
|
||||
void ConsoleApplication::addDefaultCommand (Command c)
|
||||
{
|
||||
commandIfNoOthersRecognised = (int) commands.size();
|
||||
addCommand (std::move (c));
|
||||
}
|
||||
|
||||
void ConsoleApplication::addHelpCommand (String arg, String helpMessage, bool makeDefaultCommand)
|
||||
{
|
||||
Command c { arg, arg, "Prints the list of commands", {},
|
||||
[this, helpMessage] (const ArgumentList& args)
|
||||
{
|
||||
std::cout << helpMessage << std::endl;
|
||||
printCommandList (args);
|
||||
}};
|
||||
|
||||
if (makeDefaultCommand)
|
||||
addDefaultCommand (std::move (c));
|
||||
else
|
||||
addCommand (std::move (c));
|
||||
}
|
||||
|
||||
void ConsoleApplication::addVersionCommand (String arg, String versionText)
|
||||
{
|
||||
addCommand ({ arg, arg, "Prints the current version number", {},
|
||||
[versionText] (const ArgumentList&)
|
||||
{
|
||||
std::cout << versionText << std::endl;
|
||||
}});
|
||||
}
|
||||
|
||||
const std::vector<ConsoleApplication::Command>& ConsoleApplication::getCommands() const
|
||||
{
|
||||
return commands;
|
||||
}
|
||||
|
||||
static String getExeNameAndArgs (const ArgumentList& args, const ConsoleApplication::Command& command)
|
||||
{
|
||||
auto exeName = args.executableName.fromLastOccurrenceOf ("/", false, false)
|
||||
.fromLastOccurrenceOf ("\\", false, false);
|
||||
|
||||
return " " + exeName + " " + command.argumentDescription;
|
||||
}
|
||||
|
||||
static void printCommandDescription (const ArgumentList& args, const ConsoleApplication::Command& command,
|
||||
int descriptionIndent)
|
||||
{
|
||||
auto nameAndArgs = getExeNameAndArgs (args, command);
|
||||
|
||||
if (nameAndArgs.length() > descriptionIndent)
|
||||
std::cout << nameAndArgs << std::endl << String().paddedRight (' ', descriptionIndent);
|
||||
else
|
||||
std::cout << nameAndArgs.paddedRight (' ', descriptionIndent);
|
||||
|
||||
std::cout << command.shortDescription << std::endl;
|
||||
}
|
||||
|
||||
void ConsoleApplication::printCommandList (const ArgumentList& args) const
|
||||
{
|
||||
int descriptionIndent = 0;
|
||||
|
||||
for (auto& c : commands)
|
||||
descriptionIndent = std::max (descriptionIndent, getExeNameAndArgs (args, c).length());
|
||||
|
||||
descriptionIndent = std::min (descriptionIndent + 2, 40);
|
||||
|
||||
for (auto& c : commands)
|
||||
printCommandDescription (args, c, descriptionIndent);
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void ConsoleApplication::printCommandDetails (const ArgumentList& args, const Command& command) const
|
||||
{
|
||||
auto len = getExeNameAndArgs (args, command).length();
|
||||
|
||||
printCommandDescription (args, command, std::min (len + 3, 40));
|
||||
|
||||
if (command.longDescription.isNotEmpty())
|
||||
std::cout << std::endl << command.longDescription << std::endl;
|
||||
}
|
||||
|
||||
|
||||
} // namespace juce
|
||||
353
deps/juce/modules/juce_core/misc/juce_ConsoleApplication.h
vendored
Normal file
353
deps/juce/modules/juce_core/misc/juce_ConsoleApplication.h
vendored
Normal file
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 list of command-line arguments, and provides useful methods for searching
|
||||
and operating on them.
|
||||
|
||||
You can create an ArgumentList manually, or give it some argv/argc values from a
|
||||
main() function to parse.
|
||||
|
||||
@see ConsoleApplication
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
struct ArgumentList
|
||||
{
|
||||
/** Creates an argument list for a given executable. */
|
||||
ArgumentList (String executable, StringArray arguments);
|
||||
|
||||
/** Parses a standard argv/argc pair to create an argument list. */
|
||||
ArgumentList (int argc, char* argv[]);
|
||||
|
||||
/** Tokenises a string containing all the arguments to create an argument list. */
|
||||
ArgumentList (const String& executable, const String& arguments);
|
||||
|
||||
ArgumentList (const ArgumentList&) = default;
|
||||
ArgumentList& operator= (const ArgumentList&) = default;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
One of the arguments in an ArgumentList.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
struct Argument
|
||||
{
|
||||
/** The original text of this argument. */
|
||||
String text;
|
||||
|
||||
/** Resolves this argument as an absolute File, using the current working
|
||||
directory as a base for resolving relative paths, and stripping quotes, etc.
|
||||
*/
|
||||
File resolveAsFile() const;
|
||||
|
||||
/** Resolves this argument as an absolute File, using the current working
|
||||
directory as a base for resolving relative paths, and also doing a check to
|
||||
make sure the file exists.
|
||||
If the file doesn't exist, this will call fail() with a suitable error.
|
||||
@see resolveAsFile, resolveAsExistingFolder
|
||||
*/
|
||||
File resolveAsExistingFile() const;
|
||||
|
||||
/** Resolves a user-supplied folder name into an absolute File, using the current working
|
||||
directory as a base for resolving relative paths, and also doing a check to make
|
||||
sure the folder exists.
|
||||
If the folder doesn't exist, this will call fail() with a suitable error.
|
||||
@see resolveAsFile, resolveAsExistingFile
|
||||
*/
|
||||
File resolveAsExistingFolder() const;
|
||||
|
||||
/** Returns true if this argument starts with a double dash. */
|
||||
bool isLongOption() const;
|
||||
|
||||
/** Returns true if this argument starts with a single dash. */
|
||||
bool isShortOption() const;
|
||||
|
||||
/** Returns true if this argument starts with a double dash, followed by the given string. */
|
||||
bool isLongOption (const String& optionRoot) const;
|
||||
|
||||
/** If this argument is a long option with a value, this returns the value.
|
||||
e.g. for "--foo=bar", this would return 'bar'.
|
||||
*/
|
||||
String getLongOptionValue() const;
|
||||
|
||||
/** Returns true if this argument starts with a single dash and then contains the given character somewhere inside it. */
|
||||
bool isShortOption (char shortOptionCharacter) const;
|
||||
|
||||
/** Returns true if this argument starts with one or more dashes. */
|
||||
bool isOption() const;
|
||||
|
||||
/** Compares this argument against a string.
|
||||
The string may be a pipe-separated list of options, e.g. "--help|-h"
|
||||
*/
|
||||
bool operator== (StringRef stringToCompare) const;
|
||||
|
||||
/** Compares this argument against a string.
|
||||
The string may be a pipe-separated list of options, e.g. "--help|-h"
|
||||
*/
|
||||
bool operator!= (StringRef stringToCompare) const;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of arguments in the list. */
|
||||
int size() const;
|
||||
|
||||
/** Returns one of the arguments */
|
||||
Argument operator[] (int index) const;
|
||||
|
||||
/** Throws an error unless there are at least the given number of arguments. */
|
||||
void checkMinNumArguments (int expectedMinNumberOfArgs) const;
|
||||
|
||||
/** Returns true if the given string matches one of the arguments.
|
||||
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
|
||||
@see removeOptionIfFound
|
||||
*/
|
||||
bool containsOption (StringRef option) const;
|
||||
|
||||
/** Returns true if the given string matches one of the arguments, and also removes the
|
||||
argument from the list if found.
|
||||
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
|
||||
@see containsOption
|
||||
*/
|
||||
bool removeOptionIfFound (StringRef option);
|
||||
|
||||
/** Returns the index of the given string if it matches one of the arguments, or -1 if it doesn't.
|
||||
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
|
||||
*/
|
||||
int indexOfOption (StringRef option) const;
|
||||
|
||||
/** Throws an error unless the given option is found in the argument list. */
|
||||
void failIfOptionIsMissing (StringRef option) const;
|
||||
|
||||
/** Looks for a given argument and returns either its assigned value (for long options) or the
|
||||
string that follows it (for short options).
|
||||
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
|
||||
If it finds a long option, it will look for an assignment with a '=' sign, e.g. "--file=foo.txt",
|
||||
and will return the string following the '='. If there's no '=', it will return an empty string.
|
||||
If it finds a short option, it will attempt to return the argument that follows it, unless
|
||||
it's another option.
|
||||
If the argument isn't found, this returns an empty string.
|
||||
*/
|
||||
String getValueForOption (StringRef option) const;
|
||||
|
||||
/** Looks for a given argument and returns either its assigned value (for long options) or the
|
||||
string that follows it (for short options).
|
||||
This works like getValueForOption() but also removes the option argument (and any value arguments)
|
||||
from the list if they are found.
|
||||
*/
|
||||
String removeValueForOption (StringRef option);
|
||||
|
||||
/** Looks for the value of argument using getValueForOption() and tries to parse that value as a file.
|
||||
If the option isn't found, or if the value can't be parsed as a filename, it will throw an error.
|
||||
*/
|
||||
File getFileForOption (StringRef option) const;
|
||||
|
||||
/** Looks for the value of argument using getValueForOption() and tries to parse that value as a file.
|
||||
This works like getFileForOption() but also removes the option argument (and any value arguments)
|
||||
from the list if they are found.
|
||||
*/
|
||||
File getFileForOptionAndRemove (StringRef option);
|
||||
|
||||
/** Looks for a file argument using getFileForOption() and fails with a suitable error if
|
||||
the file doesn't exist.
|
||||
*/
|
||||
File getExistingFileForOption (StringRef option) const;
|
||||
|
||||
/** Looks for a file argument using getFileForOption() and fails with a suitable error if
|
||||
the file doesn't exist.
|
||||
This works like getExistingFileForOption() but also removes the option argument (and any
|
||||
value arguments) from the list if they are found.
|
||||
*/
|
||||
File getExistingFileForOptionAndRemove (StringRef option);
|
||||
|
||||
/** Looks for a filename argument using getFileForOption() and fails with a suitable error if
|
||||
the file isn't a folder that exists.
|
||||
*/
|
||||
File getExistingFolderForOption (StringRef option) const;
|
||||
|
||||
/** Looks for a filename argument using getFileForOption() and fails with a suitable error if
|
||||
the file isn't a folder that exists.
|
||||
This works like getExistingFolderForOption() but also removes the option argument (and any
|
||||
value arguments) from the list if they are found.
|
||||
*/
|
||||
File getExistingFolderForOptionAndRemove (StringRef option);
|
||||
|
||||
/** The name or path of the executable that was invoked, as it was specified on the command-line. */
|
||||
String executableName;
|
||||
|
||||
/** The list of arguments (not including the name of the executable that was invoked). */
|
||||
Array<Argument> arguments;
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents a the set of commands that a console app can perform, and provides
|
||||
helper functions for performing them.
|
||||
|
||||
When using these helper classes to implement a console app, you probably want to
|
||||
do something along these lines:
|
||||
|
||||
@code
|
||||
int main (int argc, char* argv[])
|
||||
{
|
||||
ConsoleApplication app;
|
||||
|
||||
app.addHelpCommand ("--help|-h", "Usage:", true);
|
||||
app.addVersionCommand ("--version|-v", "MyApp version 1.2.3");
|
||||
|
||||
app.addCommand ({ "--foo",
|
||||
"--foo filename",
|
||||
"Performs a foo operation on the given file",
|
||||
[] (const auto& args) { doFoo (args); }});
|
||||
|
||||
return app.findAndRunCommand (argc, argv);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@see ArgumentList
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
struct ConsoleApplication
|
||||
{
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents a command that can be executed if its command-line arguments are matched.
|
||||
|
||||
@see ConsoleApplication::addCommand(), ConsoleApplication::findAndRunCommand()
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
struct Command
|
||||
{
|
||||
/** The option string that must appear in the argument list for this command to be invoked.
|
||||
This can also be a list of different versions separated by pipes, e.g. "--help|-h"
|
||||
*/
|
||||
String commandOption;
|
||||
|
||||
/** A description of the command-line arguments needed for this command, which will be
|
||||
printed as part of the help text.
|
||||
*/
|
||||
String argumentDescription;
|
||||
|
||||
/** A short (one line) description of this command, which can be printed by
|
||||
ConsoleApplication::printCommandList().
|
||||
*/
|
||||
String shortDescription;
|
||||
|
||||
/** A longer description of this command, for use in extended help. */
|
||||
String longDescription;
|
||||
|
||||
/** The actual command that should be invoked to perform this action. */
|
||||
std::function<void (const ArgumentList&)> command;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Adds a command to the list. */
|
||||
void addCommand (Command);
|
||||
|
||||
/** Adds a command to the list, and marks it as one which is invoked if no other
|
||||
command matches.
|
||||
*/
|
||||
void addDefaultCommand (Command);
|
||||
|
||||
/** Adds a command that will print the given text in response to the "--version" option. */
|
||||
void addVersionCommand (String versionArgument, String versionText);
|
||||
|
||||
/** Adds a help command to the list.
|
||||
This command will print the user-supplied message that's passed in here as an
|
||||
argument, followed by a list of all the registered commands.
|
||||
*/
|
||||
void addHelpCommand (String helpArgument, String helpMessage, bool makeDefaultCommand);
|
||||
|
||||
/** Prints out the list of commands and their short descriptions in a format that's
|
||||
suitable for use as help.
|
||||
*/
|
||||
void printCommandList (const ArgumentList&) const;
|
||||
|
||||
/** Prints out a longer description of a particular command, based on its
|
||||
longDescription member.
|
||||
*/
|
||||
void printCommandDetails (const ArgumentList&, const Command&) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Throws a failure exception to cause a command-line app to terminate.
|
||||
This is intended to be called from code in a Command, so that the
|
||||
exception will be automatically caught and turned into a printed error message
|
||||
and a return code which will be returned from main().
|
||||
@see ConsoleApplication::invokeCatchingFailures()
|
||||
*/
|
||||
static void fail (String errorMessage, int returnCode = 1);
|
||||
|
||||
/** Invokes a function, catching any fail() calls that it might trigger, and handling
|
||||
them by printing their error message and returning their error code.
|
||||
@see ConsoleApplication::fail()
|
||||
*/
|
||||
static int invokeCatchingFailures (std::function<int()>&& functionToCall);
|
||||
|
||||
//==============================================================================
|
||||
/** Looks for the first command in the list which matches the given arguments, and
|
||||
tries to invoke it.
|
||||
|
||||
If no command is found, and if there is no default command to run, it fails with
|
||||
a suitable error message.
|
||||
If the command calls the fail() function, this will throw an exception that gets
|
||||
automatically caught and handled, and this method will return the error code that
|
||||
was passed into the fail() call.
|
||||
|
||||
If optionMustBeFirstArg is true, then only the first argument will be looked at
|
||||
when searching the available commands - this lets you do 'git' style commands where
|
||||
the executable name is followed by a verb.
|
||||
*/
|
||||
int findAndRunCommand (const ArgumentList&,
|
||||
bool optionMustBeFirstArg = false) const;
|
||||
|
||||
/** Creates an ArgumentList object from the argc and argv variablrs, and invokes
|
||||
findAndRunCommand() using it.
|
||||
*/
|
||||
int findAndRunCommand (int argc, char* argv[]) const;
|
||||
|
||||
/** Looks for the first command in the list which matches the given arguments.
|
||||
If none is found, this returns either the default command (if one is set)
|
||||
or nullptr.
|
||||
If optionMustBeFirstArg is true, then only the first argument will be looked at
|
||||
when searching the available commands - this lets you do 'git' style commands where
|
||||
the executable name is followed by a verb.
|
||||
*/
|
||||
const Command* findCommand (const ArgumentList&, bool optionMustBeFirstArg) const;
|
||||
|
||||
/** Gives read-only access to the list of registered commands. */
|
||||
const std::vector<Command>& getCommands() const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
std::vector<Command> commands;
|
||||
int commandIfNoOthersRecognised = -1;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
53
deps/juce/modules/juce_core/misc/juce_Functional.h
vendored
Normal file
53
deps/juce/modules/juce_core/misc/juce_Functional.h
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
/** Some helper methods for checking a callable object before invoking with
|
||||
the specified arguments.
|
||||
|
||||
If the object is a std::function it will check for nullptr before
|
||||
calling. For a callable object it will invoke the function call operator.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
struct NullCheckedInvocation
|
||||
{
|
||||
template <typename... Signature, typename... Args>
|
||||
static void invoke (std::function<Signature...>&& fn, Args&&... args)
|
||||
{
|
||||
if (fn != nullptr)
|
||||
fn (std::forward<Args> (args)...);
|
||||
}
|
||||
|
||||
template <typename Callable, typename... Args>
|
||||
static void invoke (Callable&& fn, Args&&... args)
|
||||
{
|
||||
fn (std::forward<Args> (args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static void invoke (std::nullptr_t, Args&&...) {}
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
80
deps/juce/modules/juce_core/misc/juce_Result.cpp
vendored
Normal file
80
deps/juce/modules/juce_core/misc/juce_Result.cpp
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
Result::Result() noexcept {}
|
||||
|
||||
Result::Result (const String& message) noexcept
|
||||
: errorMessage (message)
|
||||
{
|
||||
}
|
||||
|
||||
Result::Result (const Result& other)
|
||||
: errorMessage (other.errorMessage)
|
||||
{
|
||||
}
|
||||
|
||||
Result& Result::operator= (const Result& other)
|
||||
{
|
||||
errorMessage = other.errorMessage;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Result::Result (Result&& other) noexcept
|
||||
: errorMessage (std::move (other.errorMessage))
|
||||
{
|
||||
}
|
||||
|
||||
Result& Result::operator= (Result&& other) noexcept
|
||||
{
|
||||
errorMessage = std::move (other.errorMessage);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Result::operator== (const Result& other) const noexcept
|
||||
{
|
||||
return errorMessage == other.errorMessage;
|
||||
}
|
||||
|
||||
bool Result::operator!= (const Result& other) const noexcept
|
||||
{
|
||||
return errorMessage != other.errorMessage;
|
||||
}
|
||||
|
||||
Result Result::fail (const String& errorMessage) noexcept
|
||||
{
|
||||
return Result (errorMessage.isEmpty() ? "Unknown Error" : errorMessage);
|
||||
}
|
||||
|
||||
const String& Result::getErrorMessage() const noexcept
|
||||
{
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
bool Result::wasOk() const noexcept { return errorMessage.isEmpty(); }
|
||||
Result::operator bool() const noexcept { return errorMessage.isEmpty(); }
|
||||
bool Result::failed() const noexcept { return errorMessage.isNotEmpty(); }
|
||||
bool Result::operator!() const noexcept { return errorMessage.isNotEmpty(); }
|
||||
|
||||
} // namespace juce
|
||||
116
deps/juce/modules/juce_core/misc/juce_Result.h
vendored
Normal file
116
deps/juce/modules/juce_core/misc/juce_Result.h
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents the 'success' or 'failure' of an operation, and holds an associated
|
||||
error message to describe the error when there's a failure.
|
||||
|
||||
E.g.
|
||||
@code
|
||||
Result myOperation()
|
||||
{
|
||||
if (doSomeKindOfFoobar())
|
||||
return Result::ok();
|
||||
else
|
||||
return Result::fail ("foobar didn't work!");
|
||||
}
|
||||
|
||||
const Result result (myOperation());
|
||||
|
||||
if (result.wasOk())
|
||||
{
|
||||
...it's all good...
|
||||
}
|
||||
else
|
||||
{
|
||||
warnUserAboutFailure ("The foobar operation failed! Error message was: "
|
||||
+ result.getErrorMessage());
|
||||
}
|
||||
@endcode
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API Result
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates and returns a 'successful' result. */
|
||||
static Result ok() noexcept { return Result(); }
|
||||
|
||||
/** Creates a 'failure' result.
|
||||
If you pass a blank error message in here, a default "Unknown Error" message
|
||||
will be used instead.
|
||||
*/
|
||||
static Result fail (const String& errorMessage) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if this result indicates a success. */
|
||||
bool wasOk() const noexcept;
|
||||
|
||||
/** Returns true if this result indicates a failure.
|
||||
You can use getErrorMessage() to retrieve the error message associated
|
||||
with the failure.
|
||||
*/
|
||||
bool failed() const noexcept;
|
||||
|
||||
/** Returns true if this result indicates a success.
|
||||
This is equivalent to calling wasOk().
|
||||
*/
|
||||
operator bool() const noexcept;
|
||||
|
||||
/** Returns true if this result indicates a failure.
|
||||
This is equivalent to calling failed().
|
||||
*/
|
||||
bool operator!() const noexcept;
|
||||
|
||||
/** Returns the error message that was set when this result was created.
|
||||
For a successful result, this will be an empty string;
|
||||
*/
|
||||
const String& getErrorMessage() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
Result (const Result&);
|
||||
Result& operator= (const Result&);
|
||||
Result (Result&&) noexcept;
|
||||
Result& operator= (Result&&) noexcept;
|
||||
|
||||
bool operator== (const Result& other) const noexcept;
|
||||
bool operator!= (const Result& other) const noexcept;
|
||||
|
||||
private:
|
||||
String errorMessage;
|
||||
|
||||
// The default constructor is not for public use!
|
||||
// Instead, use Result::ok() or Result::fail()
|
||||
Result() noexcept;
|
||||
explicit Result (const String&) noexcept;
|
||||
|
||||
// These casts are private to prevent people trying to use the Result object in numeric contexts
|
||||
operator int() const;
|
||||
operator void*() const;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
36
deps/juce/modules/juce_core/misc/juce_RuntimePermissions.cpp
vendored
Normal file
36
deps/juce/modules/juce_core/misc/juce_RuntimePermissions.cpp
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 ! JUCE_ANDROID // We currently don't request runtime permissions on any other platform
|
||||
// than Android, so this file contains a dummy implementation for those.
|
||||
// This may change in the future.
|
||||
|
||||
void RuntimePermissions::request (PermissionID, Callback callback) { callback (true); }
|
||||
bool RuntimePermissions::isRequired (PermissionID) { return false; }
|
||||
bool RuntimePermissions::isGranted (PermissionID) { return true; }
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
131
deps/juce/modules/juce_core/misc/juce_RuntimePermissions.h
vendored
Normal file
131
deps/juce/modules/juce_core/misc/juce_RuntimePermissions.h
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Class to handle app runtime permissions for certain functionality on some platforms.
|
||||
|
||||
The use of this class is currently only required if the app should run on
|
||||
Android API level 23 and higher.
|
||||
|
||||
On lower API levels, the permissions are specified in the app manifest. On iOS,
|
||||
runtime permission requests are handled automatically by the Apple APIs and not
|
||||
manually in the app code. On Windows, OS X, and Linux, runtime permissions are not
|
||||
used at all. In all these cases, request() will simply call through to the
|
||||
callback with no overhead and pass true (making it safe to use on all platforms).
|
||||
|
||||
For example, to enable audio recording on Android in your cross-platform app,
|
||||
you could modify your code as follows:
|
||||
|
||||
Old code:
|
||||
|
||||
audioDeviceManager.initialise (2, 2, nullptr, true, String(), nullptr);
|
||||
|
||||
New code:
|
||||
|
||||
RuntimePermissions::request (
|
||||
RuntimePermissions::audioRecording,
|
||||
[this] (bool wasGranted)
|
||||
{
|
||||
if (! wasGranted)
|
||||
{
|
||||
// e.g. display an error or initialise with 0 input channels
|
||||
return;
|
||||
}
|
||||
|
||||
audioDeviceManager.initialise (2, 2, nullptr, true, String(), nullptr);
|
||||
}
|
||||
);
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API RuntimePermissions
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
enum PermissionID
|
||||
{
|
||||
/** Permission to access the microphone (required on Android).
|
||||
You need to request this, for example, to initialise an AudioDeviceManager with
|
||||
a non-zero number of input channels, and to open the default audio input device.
|
||||
*/
|
||||
recordAudio = 1,
|
||||
|
||||
/** Permission to scan for and pair to Bluetooth MIDI devices (required on Android).
|
||||
You need to request this before calling BluetoothMidiDevicePairingDialogue::open(),
|
||||
otherwise no devices will be found.
|
||||
*/
|
||||
bluetoothMidi = 2,
|
||||
|
||||
/** Permission to read from external storage such as SD cards */
|
||||
readExternalStorage = 3,
|
||||
|
||||
/** Permission to write to external storage such as SD cards */
|
||||
writeExternalStorage = 4,
|
||||
|
||||
/** Permission to use camera */
|
||||
camera = 5
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Function type of runtime permission request callbacks. */
|
||||
using Callback = std::function<void (bool)>;
|
||||
|
||||
//==============================================================================
|
||||
/** Call this method to request a runtime permission.
|
||||
|
||||
@param permission The PermissionID of the permission you want to request.
|
||||
|
||||
@param callback The callback to be called after the request has been granted
|
||||
or denied; the argument passed will be true if the permission
|
||||
has been granted and false otherwise.
|
||||
|
||||
If no runtime request is required or possible to obtain the permission, the
|
||||
callback will be called immediately. The argument passed in will be true
|
||||
if the permission is granted or no permission is required on this platform,
|
||||
and false otherwise.
|
||||
|
||||
If a runtime request is required to obtain the permission, the callback
|
||||
will be called asynchronously after the OS has granted or denied the requested
|
||||
permission (typically by displaying a dialog box to the user and waiting until
|
||||
the user has responded).
|
||||
*/
|
||||
static void request (PermissionID permission, Callback callback);
|
||||
|
||||
/** Returns whether a runtime request is required to obtain the permission
|
||||
on the current platform.
|
||||
*/
|
||||
static bool isRequired (PermissionID permission);
|
||||
|
||||
/** Returns true if the app has been already granted this permission, either
|
||||
via a previous runtime request or otherwise, or no permission is necessary.
|
||||
|
||||
Note that this can be false even if isRequired returns false. In this case,
|
||||
the permission can not be obtained at all at runtime.
|
||||
*/
|
||||
static bool isGranted (PermissionID permission);
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
147
deps/juce/modules/juce_core/misc/juce_Uuid.cpp
vendored
Normal file
147
deps/juce/modules/juce_core/misc/juce_Uuid.cpp
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
Uuid::Uuid()
|
||||
{
|
||||
Random r;
|
||||
|
||||
for (size_t i = 0; i < sizeof (uuid); ++i)
|
||||
uuid[i] = (uint8) (r.nextInt (256));
|
||||
|
||||
// To make it RFC 4122 compliant, need to force a few bits...
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x40;
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80;
|
||||
}
|
||||
|
||||
Uuid::~Uuid() noexcept {}
|
||||
|
||||
Uuid::Uuid (const Uuid& other) noexcept
|
||||
{
|
||||
memcpy (uuid, other.uuid, sizeof (uuid));
|
||||
}
|
||||
|
||||
Uuid& Uuid::operator= (const Uuid& other) noexcept
|
||||
{
|
||||
memcpy (uuid, other.uuid, sizeof (uuid));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Uuid::operator== (const Uuid& other) const noexcept { return memcmp (uuid, other.uuid, sizeof (uuid)) == 0; }
|
||||
bool Uuid::operator!= (const Uuid& other) const noexcept { return ! operator== (other); }
|
||||
|
||||
bool Uuid::operator< (const Uuid& other) const noexcept { return compare (other) < 0; }
|
||||
bool Uuid::operator> (const Uuid& other) const noexcept { return compare (other) > 0; }
|
||||
bool Uuid::operator<= (const Uuid& other) const noexcept { return compare (other) <= 0; }
|
||||
bool Uuid::operator>= (const Uuid& other) const noexcept { return compare (other) >= 0; }
|
||||
|
||||
int Uuid::compare (Uuid other) const noexcept
|
||||
{
|
||||
for (size_t i = 0; i < sizeof (uuid); ++i)
|
||||
if (int diff = uuid[i] - (int) other.uuid[i])
|
||||
return diff > 0 ? 1 : -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Uuid Uuid::null() noexcept
|
||||
{
|
||||
return Uuid ((const uint8*) nullptr);
|
||||
}
|
||||
|
||||
bool Uuid::isNull() const noexcept
|
||||
{
|
||||
for (auto i : uuid)
|
||||
if (i != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String Uuid::getHexRegion (int start, int length) const
|
||||
{
|
||||
return String::toHexString (uuid + start, length, 0);
|
||||
}
|
||||
|
||||
String Uuid::toString() const
|
||||
{
|
||||
return getHexRegion (0, 16);
|
||||
}
|
||||
|
||||
String Uuid::toDashedString() const
|
||||
{
|
||||
return getHexRegion (0, 4)
|
||||
+ "-" + getHexRegion (4, 2)
|
||||
+ "-" + getHexRegion (6, 2)
|
||||
+ "-" + getHexRegion (8, 2)
|
||||
+ "-" + getHexRegion (10, 6);
|
||||
}
|
||||
|
||||
Uuid::Uuid (const String& uuidString)
|
||||
{
|
||||
operator= (uuidString);
|
||||
}
|
||||
|
||||
Uuid& Uuid::operator= (const String& uuidString)
|
||||
{
|
||||
MemoryBlock mb;
|
||||
mb.loadFromHexString (uuidString);
|
||||
mb.ensureSize (sizeof (uuid), true);
|
||||
mb.copyTo (uuid, 0, sizeof (uuid));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Uuid::Uuid (const uint8* const rawData) noexcept
|
||||
{
|
||||
operator= (rawData);
|
||||
}
|
||||
|
||||
Uuid& Uuid::operator= (const uint8* const rawData) noexcept
|
||||
{
|
||||
if (rawData != nullptr)
|
||||
memcpy (uuid, rawData, sizeof (uuid));
|
||||
else
|
||||
zeromem (uuid, sizeof (uuid));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint32 Uuid::getTimeLow() const noexcept { return ByteOrder::bigEndianInt (uuid); }
|
||||
uint16 Uuid::getTimeMid() const noexcept { return ByteOrder::bigEndianShort (uuid + 4); }
|
||||
uint16 Uuid::getTimeHighAndVersion() const noexcept { return ByteOrder::bigEndianShort (uuid + 6); }
|
||||
uint8 Uuid::getClockSeqAndReserved() const noexcept { return uuid[8]; }
|
||||
uint8 Uuid::getClockSeqLow() const noexcept { return uuid[9]; }
|
||||
uint64 Uuid::getNode() const noexcept { return (((uint64) ByteOrder::bigEndianShort (uuid + 10)) << 32) + ByteOrder::bigEndianInt (uuid + 12); }
|
||||
|
||||
uint64 Uuid::hash() const noexcept
|
||||
{
|
||||
uint64 result = 0;
|
||||
|
||||
for (auto n : uuid)
|
||||
result = ((uint64) 101) * result + n;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
147
deps/juce/modules/juce_core/misc/juce_Uuid.h
vendored
Normal file
147
deps/juce/modules/juce_core/misc/juce_Uuid.h
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 universally unique 128-bit identifier.
|
||||
|
||||
This class generates very random unique numbers. It's vanishingly unlikely
|
||||
that two identical UUIDs would ever be created by chance. The values are
|
||||
formatted to meet the RFC 4122 version 4 standard.
|
||||
|
||||
The class includes methods for saving the ID as a string or as raw binary data.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API Uuid
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a new unique ID, compliant with RFC 4122 version 4. */
|
||||
Uuid();
|
||||
|
||||
/** Destructor. */
|
||||
~Uuid() noexcept;
|
||||
|
||||
/** Creates a copy of another UUID. */
|
||||
Uuid (const Uuid&) noexcept;
|
||||
|
||||
/** Copies another UUID. */
|
||||
Uuid& operator= (const Uuid&) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the ID is zero. */
|
||||
bool isNull() const noexcept;
|
||||
|
||||
/** Returns a null Uuid object. */
|
||||
static Uuid null() noexcept;
|
||||
|
||||
bool operator== (const Uuid&) const noexcept;
|
||||
bool operator!= (const Uuid&) const noexcept;
|
||||
bool operator< (const Uuid&) const noexcept;
|
||||
bool operator> (const Uuid&) const noexcept;
|
||||
bool operator<= (const Uuid&) const noexcept;
|
||||
bool operator>= (const Uuid&) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a stringified version of this UUID.
|
||||
|
||||
A Uuid object can later be reconstructed from this string using operator= or
|
||||
the constructor that takes a string parameter.
|
||||
|
||||
@returns a 32 character hex string.
|
||||
*/
|
||||
String toString() const;
|
||||
|
||||
/** Returns a stringified version of this UUID, separating it into sections with dashes.
|
||||
@returns a string in the format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
*/
|
||||
String toDashedString() const;
|
||||
|
||||
/** Creates an ID from an encoded string version.
|
||||
@see toString
|
||||
*/
|
||||
Uuid (const String& uuidString);
|
||||
|
||||
/** Copies from a stringified UUID.
|
||||
The string passed in should be one that was created with the toString() method.
|
||||
*/
|
||||
Uuid& operator= (const String& uuidString);
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the time-low section of the UUID. */
|
||||
uint32 getTimeLow() const noexcept;
|
||||
/** Returns the time-mid section of the UUID. */
|
||||
uint16 getTimeMid() const noexcept;
|
||||
/** Returns the time-high-and-version section of the UUID. */
|
||||
uint16 getTimeHighAndVersion() const noexcept;
|
||||
/** Returns the clock-seq-and-reserved section of the UUID. */
|
||||
uint8 getClockSeqAndReserved() const noexcept;
|
||||
/** Returns the clock-seq-low section of the UUID. */
|
||||
uint8 getClockSeqLow() const noexcept;
|
||||
/** Returns the node section of the UUID. */
|
||||
uint64 getNode() const noexcept;
|
||||
|
||||
/** Returns a hash of the UUID. */
|
||||
uint64 hash() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a pointer to the internal binary representation of the ID.
|
||||
|
||||
This is an array of 16 bytes. To reconstruct a Uuid from its data, use
|
||||
the constructor or operator= method that takes an array of uint8s.
|
||||
*/
|
||||
const uint8* getRawData() const noexcept { return uuid; }
|
||||
|
||||
/** Creates a UUID from a 16-byte array.
|
||||
@see getRawData
|
||||
*/
|
||||
Uuid (const uint8* rawData) noexcept;
|
||||
|
||||
/** Sets this UUID from 16-bytes of raw data. */
|
||||
Uuid& operator= (const uint8* rawData) noexcept;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
uint8 uuid[16];
|
||||
String getHexRegion (int, int) const;
|
||||
int compare (Uuid) const noexcept;
|
||||
|
||||
JUCE_LEAK_DETECTOR (Uuid)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
||||
#ifndef DOXYGEN
|
||||
namespace std
|
||||
{
|
||||
template <> struct hash<juce::Uuid>
|
||||
{
|
||||
size_t operator() (const juce::Uuid& u) const noexcept { return (size_t) u.hash(); }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
140
deps/juce/modules/juce_core/misc/juce_WindowsRegistry.h
vendored
Normal file
140
deps/juce/modules/juce_core/misc/juce_WindowsRegistry.h
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 JUCE_WINDOWS || DOXYGEN
|
||||
|
||||
/**
|
||||
Contains some static helper functions for manipulating the MS Windows registry
|
||||
(Only available on Windows, of course!)
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API WindowsRegistry
|
||||
{
|
||||
public:
|
||||
/** These values can be used to specify whether the 32- or 64-bit registry should be used.
|
||||
When running on a 32-bit OS, there is no 64-bit registry, so the mode will be ignored.
|
||||
*/
|
||||
enum WoW64Mode
|
||||
{
|
||||
/** Default handling: 32-bit apps will use the 32-bit registry, and 64-bit apps
|
||||
will use the 64-bit registry. */
|
||||
WoW64_Default = 0,
|
||||
|
||||
/** Always use the 64-bit registry store. (KEY_WOW64_64KEY). */
|
||||
WoW64_64bit = 0x100,
|
||||
|
||||
/** Always use the 32-bit registry store. (KEY_WOW64_32KEY). */
|
||||
WoW64_32bit = 0x200
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a string from the registry.
|
||||
The path is a string for the entire path of a value in the registry,
|
||||
e.g. "HKEY_CURRENT_USER\Software\foo\bar"
|
||||
*/
|
||||
static String JUCE_CALLTYPE getValue (const String& regValuePath,
|
||||
const String& defaultValue = String(),
|
||||
WoW64Mode mode = WoW64_Default);
|
||||
|
||||
/** Reads a binary block from the registry.
|
||||
The path is a string for the entire path of a value in the registry,
|
||||
e.g. "HKEY_CURRENT_USER\Software\foo\bar"
|
||||
@returns a DWORD indicating the type of the key.
|
||||
*/
|
||||
static uint32 JUCE_CALLTYPE getBinaryValue (const String& regValuePath, MemoryBlock& resultData, WoW64Mode mode = WoW64_Default);
|
||||
|
||||
/** Sets a registry value as a string.
|
||||
This will take care of creating any groups needed to get to the given registry value.
|
||||
*/
|
||||
static bool JUCE_CALLTYPE setValue (const String& regValuePath, const String& value, WoW64Mode mode = WoW64_Default);
|
||||
|
||||
/** Sets a registry value as a DWORD.
|
||||
This will take care of creating any groups needed to get to the given registry value.
|
||||
*/
|
||||
static bool JUCE_CALLTYPE setValue (const String& regValuePath, uint32 value, WoW64Mode mode = WoW64_Default);
|
||||
|
||||
/** Sets a registry value as a QWORD.
|
||||
This will take care of creating any groups needed to get to the given registry value.
|
||||
*/
|
||||
static bool JUCE_CALLTYPE setValue (const String& regValuePath, uint64 value, WoW64Mode mode = WoW64_Default);
|
||||
|
||||
/** Sets a registry value as a binary block.
|
||||
This will take care of creating any groups needed to get to the given registry value.
|
||||
*/
|
||||
static bool JUCE_CALLTYPE setValue (const String& regValuePath, const MemoryBlock& value, WoW64Mode mode = WoW64_Default);
|
||||
|
||||
/** Returns true if the given value exists in the registry. */
|
||||
static bool JUCE_CALLTYPE valueExists (const String& regValuePath, WoW64Mode mode = WoW64_Default);
|
||||
|
||||
/** Returns true if the given key exists in the registry. */
|
||||
static bool JUCE_CALLTYPE keyExists (const String& regKeyPath, WoW64Mode mode = WoW64_Default);
|
||||
|
||||
/** Deletes a registry value. */
|
||||
static bool JUCE_CALLTYPE deleteValue (const String& regValuePath, WoW64Mode mode = WoW64_Default);
|
||||
|
||||
/** Deletes a registry key (which is registry-talk for 'folder'). */
|
||||
static bool JUCE_CALLTYPE deleteKey (const String& regKeyPath, WoW64Mode mode = WoW64_Default);
|
||||
|
||||
/** Creates a file association in the registry.
|
||||
|
||||
This lets you set the executable that should be launched by a given file extension.
|
||||
@param fileExtension the file extension to associate, including the
|
||||
initial dot, e.g. ".txt"
|
||||
@param symbolicDescription a space-free short token to identify the file type
|
||||
@param fullDescription a human-readable description of the file type
|
||||
@param targetExecutable the executable that should be launched
|
||||
@param iconResourceNumber the icon that gets displayed for the file type will be
|
||||
found by looking up this resource number in the
|
||||
executable. Pass 0 here to not use an icon
|
||||
@param registerForCurrentUserOnly if false, this will try to register the association
|
||||
for all users (you might not have permission to do this
|
||||
unless running in an installer). If true, it will register the
|
||||
association in HKEY_CURRENT_USER.
|
||||
@param mode the WoW64 mode to use for choosing the database
|
||||
*/
|
||||
static bool JUCE_CALLTYPE registerFileAssociation (const String& fileExtension,
|
||||
const String& symbolicDescription,
|
||||
const String& fullDescription,
|
||||
const File& targetExecutable,
|
||||
int iconResourceNumber,
|
||||
bool registerForCurrentUserOnly,
|
||||
WoW64Mode mode = WoW64_Default);
|
||||
|
||||
#ifndef DOXYGEN
|
||||
// DEPRECATED: use the other methods with a WoW64Mode parameter of WoW64_64bit instead.
|
||||
[[deprecated]] static String getValueWow64 (const String&, const String& defaultValue = String());
|
||||
[[deprecated]] static bool valueExistsWow64 (const String&);
|
||||
[[deprecated]] static bool keyExistsWow64 (const String&);
|
||||
#endif
|
||||
|
||||
private:
|
||||
WindowsRegistry() = delete;
|
||||
JUCE_DECLARE_NON_COPYABLE (WindowsRegistry)
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
43
deps/juce/modules/juce_core/native/java/README.txt
vendored
Normal file
43
deps/juce/modules/juce_core/native/java/README.txt
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
The Java code in the module's native/java subfolders have been used to generate
|
||||
dex byte-code in various places in the JUCE framework. These are the steps
|
||||
required to re-generate the dex byte-code from any Java source code inside the
|
||||
native/java subfolders:
|
||||
|
||||
1. Create a new JUCE android project with the minimal sdk version which is
|
||||
required for the Java source code you wish to compile.
|
||||
|
||||
2. If you are creating byte-code for new .java files, move the new files into
|
||||
the native/javacore/app folder of the module, or create one if it doesn't
|
||||
exist. Remember that .java files need to be in nested sub-folders which
|
||||
resemble their package, i.e. a Java class com.rmsl.juce.HelloWorld.java should
|
||||
be in the module's native/javacore/app/com/rmsl/juce folder. If you wish to
|
||||
modify existing .java files in the JUCE modules then just rename native/java to
|
||||
native/javacore.
|
||||
|
||||
3. Build your project with Android Studio and run. The app will now use the
|
||||
source code in the folder created in step 2 so you can debug your Java code
|
||||
this way.
|
||||
|
||||
4. Once everything is working rebuild your app in release mode.
|
||||
|
||||
5. Go to your app's Builds/Android folder. Inside there you will find
|
||||
build/intermediates/javac/release_Release/compileRelease_ReleaseJavaWithJavac/classes.
|
||||
Inside of that folder, you will find all your Java byte-code compiled classes.
|
||||
Remove any classes that you are not interested in (typically you'll find
|
||||
Java.class and JuceApp.class which you will probably want to remove).
|
||||
|
||||
6. Inside of
|
||||
build/intermediates/javac/release_Release/compileRelease_ReleaseJavaWithJavac/classes
|
||||
execute the following dx command:
|
||||
|
||||
<path-to-your-android-sdk>/build-tools/<latest-build-tool-version>/dx --dex --verbose --min-sdk-version=<your-min-sdk-of-your-classes> --output /tmp/JavaDexByteCode.dex .
|
||||
|
||||
(Replace <your-min-sdk-of-your-classes> with the minimal sdk version you used in step 1.)
|
||||
|
||||
7. gzip the output:
|
||||
|
||||
gzip /tmp/JavaDexByteCode.dex
|
||||
|
||||
8. The output /tmp/JavaDexByteCode.dex.gz is now the byte code that can be
|
||||
included into JUCE. You can use the Projucer's BinaryData generator
|
||||
functionality to get this into a convenient char array like form.
|
||||
80
deps/juce/modules/juce_core/native/java/app/com/rmsl/juce/FragmentOverlay.java
vendored
Normal file
80
deps/juce/modules/juce_core/native/java/app/com/rmsl/juce/FragmentOverlay.java
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
package com.rmsl.juce;
|
||||
|
||||
import android.app.DialogFragment;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class FragmentOverlay extends DialogFragment
|
||||
{
|
||||
@Override
|
||||
public void onCreate (Bundle state)
|
||||
{
|
||||
super.onCreate (state);
|
||||
cppThis = getArguments ().getLong ("cppThis");
|
||||
|
||||
if (cppThis != 0)
|
||||
onCreateNative (cppThis, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart ()
|
||||
{
|
||||
super.onStart ();
|
||||
|
||||
if (cppThis != 0)
|
||||
onStartNative (cppThis);
|
||||
}
|
||||
|
||||
public void onRequestPermissionsResult (int requestCode,
|
||||
String[] permissions,
|
||||
int[] grantResults)
|
||||
{
|
||||
if (cppThis != 0)
|
||||
onRequestPermissionsResultNative (cppThis, requestCode,
|
||||
permissions, grantResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult (int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
if (cppThis != 0)
|
||||
onActivityResultNative (cppThis, requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
public void close ()
|
||||
{
|
||||
cppThis = 0;
|
||||
dismiss ();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private long cppThis = 0;
|
||||
|
||||
private native void onActivityResultNative (long myself, int requestCode, int resultCode, Intent data);
|
||||
private native void onCreateNative (long myself, Bundle state);
|
||||
private native void onStartNative (long myself);
|
||||
private native void onRequestPermissionsResultNative (long myself, int requestCode,
|
||||
String[] permissions, int[] grantResults);
|
||||
}
|
||||
429
deps/juce/modules/juce_core/native/java/app/com/rmsl/juce/JuceHTTPStream.java
vendored
Normal file
429
deps/juce/modules/juce_core/native/java/app/com/rmsl/juce/JuceHTTPStream.java
vendored
Normal file
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
package com.rmsl.juce;
|
||||
|
||||
import java.lang.Runnable;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.atomic.*;
|
||||
|
||||
public class JuceHTTPStream
|
||||
{
|
||||
public JuceHTTPStream(String address, boolean isPostToUse, byte[] postDataToUse,
|
||||
String headersToUse, int timeOutMsToUse,
|
||||
int[] statusCodeToUse, StringBuffer responseHeadersToUse,
|
||||
int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException
|
||||
{
|
||||
isPost = isPostToUse;
|
||||
postData = postDataToUse;
|
||||
headers = headersToUse;
|
||||
timeOutMs = timeOutMsToUse;
|
||||
statusCode = statusCodeToUse;
|
||||
responseHeaders = responseHeadersToUse;
|
||||
totalLength = -1;
|
||||
numRedirectsToFollow = numRedirectsToFollowToUse;
|
||||
httpRequestCmd = httpRequestCmdToUse;
|
||||
|
||||
connection = createConnection(address, isPost, postData, headers, timeOutMs, httpRequestCmd);
|
||||
}
|
||||
|
||||
public static final JuceHTTPStream createHTTPStream(String address, boolean isPost, byte[] postData,
|
||||
String headers, int timeOutMs, int[] statusCode,
|
||||
StringBuffer responseHeaders, int numRedirectsToFollow,
|
||||
String httpRequestCmd)
|
||||
{
|
||||
// timeout parameter of zero for HttpUrlConnection is a blocking connect (negative value for juce::URL)
|
||||
if (timeOutMs < 0)
|
||||
timeOutMs = 0;
|
||||
else if (timeOutMs == 0)
|
||||
timeOutMs = 30000;
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
try
|
||||
{
|
||||
JuceHTTPStream httpStream = new JuceHTTPStream(address, isPost, postData, headers,
|
||||
timeOutMs, statusCode, responseHeaders,
|
||||
numRedirectsToFollow, httpRequestCmd);
|
||||
|
||||
return httpStream;
|
||||
} catch (Throwable e)
|
||||
{
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private final HttpURLConnection createConnection(String address, boolean isPost, byte[] postData,
|
||||
String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException
|
||||
{
|
||||
HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection());
|
||||
|
||||
try
|
||||
{
|
||||
newConnection.setInstanceFollowRedirects(false);
|
||||
newConnection.setConnectTimeout(timeOutMs);
|
||||
newConnection.setReadTimeout(timeOutMs);
|
||||
|
||||
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
|
||||
// So convert headers string to an array, with an element for each line
|
||||
String headerLines[] = headers.split("\\n");
|
||||
|
||||
// Set request headers
|
||||
for (int i = 0; i < headerLines.length; ++i)
|
||||
{
|
||||
int pos = headerLines[i].indexOf(":");
|
||||
|
||||
if (pos > 0 && pos < headerLines[i].length())
|
||||
{
|
||||
String field = headerLines[i].substring(0, pos);
|
||||
String value = headerLines[i].substring(pos + 1);
|
||||
|
||||
if (value.length() > 0)
|
||||
newConnection.setRequestProperty(field, value);
|
||||
}
|
||||
}
|
||||
|
||||
newConnection.setRequestMethod(httpRequestCmd);
|
||||
|
||||
if (isPost)
|
||||
{
|
||||
newConnection.setDoOutput(true);
|
||||
|
||||
if (postData != null)
|
||||
{
|
||||
OutputStream out = newConnection.getOutputStream();
|
||||
out.write(postData);
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
|
||||
return newConnection;
|
||||
} catch (Throwable e)
|
||||
{
|
||||
newConnection.disconnect();
|
||||
throw new IOException("Connection error");
|
||||
}
|
||||
}
|
||||
|
||||
private final InputStream getCancellableStream(final boolean isInput) throws ExecutionException
|
||||
{
|
||||
synchronized (createFutureLock)
|
||||
{
|
||||
if (hasBeenCancelled.get())
|
||||
return null;
|
||||
|
||||
streamFuture = executor.submit(new Callable<BufferedInputStream>()
|
||||
{
|
||||
@Override
|
||||
public BufferedInputStream call() throws IOException
|
||||
{
|
||||
return new BufferedInputStream(isInput ? connection.getInputStream()
|
||||
: connection.getErrorStream());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return streamFuture.get();
|
||||
} catch (InterruptedException e)
|
||||
{
|
||||
return null;
|
||||
} catch (CancellationException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public final boolean connect()
|
||||
{
|
||||
boolean result = false;
|
||||
int numFollowedRedirects = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
result = doConnect();
|
||||
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
if (++numFollowedRedirects > numRedirectsToFollow)
|
||||
break;
|
||||
|
||||
int status = statusCode[0];
|
||||
|
||||
if (status == 301 || status == 302 || status == 303 || status == 307)
|
||||
{
|
||||
// Assumes only one occurrence of "Location"
|
||||
int pos1 = responseHeaders.indexOf("Location:") + 10;
|
||||
int pos2 = responseHeaders.indexOf("\n", pos1);
|
||||
|
||||
if (pos2 > pos1)
|
||||
{
|
||||
String currentLocation = connection.getURL().toString();
|
||||
String newLocation = responseHeaders.substring(pos1, pos2);
|
||||
|
||||
try
|
||||
{
|
||||
// Handle newLocation whether it's absolute or relative
|
||||
URL baseUrl = new URL(currentLocation);
|
||||
URL newUrl = new URL(baseUrl, newLocation);
|
||||
String transformedNewLocation = newUrl.toString();
|
||||
|
||||
if (transformedNewLocation != currentLocation)
|
||||
{
|
||||
// Clear responseHeaders before next iteration
|
||||
responseHeaders.delete(0, responseHeaders.length());
|
||||
|
||||
synchronized (createStreamLock)
|
||||
{
|
||||
if (hasBeenCancelled.get())
|
||||
return false;
|
||||
|
||||
connection.disconnect();
|
||||
|
||||
try
|
||||
{
|
||||
connection = createConnection(transformedNewLocation, isPost,
|
||||
postData, headers, timeOutMs,
|
||||
httpRequestCmd);
|
||||
} catch (Throwable e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} catch (Throwable e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private final boolean doConnect()
|
||||
{
|
||||
synchronized (createStreamLock)
|
||||
{
|
||||
if (hasBeenCancelled.get())
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
inputStream = getCancellableStream(true);
|
||||
} catch (ExecutionException e)
|
||||
{
|
||||
if (connection.getResponseCode() < 400)
|
||||
{
|
||||
statusCode[0] = connection.getResponseCode();
|
||||
connection.disconnect();
|
||||
return false;
|
||||
}
|
||||
} finally
|
||||
{
|
||||
statusCode[0] = connection.getResponseCode();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (statusCode[0] >= 400)
|
||||
inputStream = getCancellableStream(false);
|
||||
else
|
||||
inputStream = getCancellableStream(true);
|
||||
} catch (ExecutionException e)
|
||||
{
|
||||
}
|
||||
|
||||
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet())
|
||||
{
|
||||
if (entry.getKey() != null && entry.getValue() != null)
|
||||
{
|
||||
responseHeaders.append(entry.getKey() + ": "
|
||||
+ android.text.TextUtils.join(",", entry.getValue()) + "\n");
|
||||
|
||||
if (entry.getKey().compareTo("Content-Length") == 0)
|
||||
totalLength = Integer.decode(entry.getValue().get(0));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (IOException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class DisconnectionRunnable implements Runnable
|
||||
{
|
||||
public DisconnectionRunnable(HttpURLConnection theConnection,
|
||||
InputStream theInputStream,
|
||||
ReentrantLock theCreateStreamLock,
|
||||
Object theCreateFutureLock,
|
||||
Future<BufferedInputStream> theStreamFuture)
|
||||
{
|
||||
connectionToDisconnect = theConnection;
|
||||
inputStream = theInputStream;
|
||||
createStreamLock = theCreateStreamLock;
|
||||
createFutureLock = theCreateFutureLock;
|
||||
streamFuture = theStreamFuture;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!createStreamLock.tryLock())
|
||||
{
|
||||
synchronized (createFutureLock)
|
||||
{
|
||||
if (streamFuture != null)
|
||||
streamFuture.cancel(true);
|
||||
}
|
||||
|
||||
createStreamLock.lock();
|
||||
}
|
||||
|
||||
if (connectionToDisconnect != null)
|
||||
connectionToDisconnect.disconnect();
|
||||
|
||||
if (inputStream != null)
|
||||
inputStream.close();
|
||||
} catch (IOException e)
|
||||
{
|
||||
} finally
|
||||
{
|
||||
createStreamLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private HttpURLConnection connectionToDisconnect;
|
||||
private InputStream inputStream;
|
||||
private ReentrantLock createStreamLock;
|
||||
private Object createFutureLock;
|
||||
Future<BufferedInputStream> streamFuture;
|
||||
}
|
||||
|
||||
public final void release()
|
||||
{
|
||||
DisconnectionRunnable disconnectionRunnable = new DisconnectionRunnable(connection,
|
||||
inputStream,
|
||||
createStreamLock,
|
||||
createFutureLock,
|
||||
streamFuture);
|
||||
|
||||
synchronized (createStreamLock)
|
||||
{
|
||||
hasBeenCancelled.set(true);
|
||||
|
||||
connection = null;
|
||||
}
|
||||
|
||||
Thread disconnectionThread = new Thread(disconnectionRunnable);
|
||||
disconnectionThread.start();
|
||||
}
|
||||
|
||||
public final int read(byte[] buffer, int numBytes)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
try
|
||||
{
|
||||
synchronized (createStreamLock)
|
||||
{
|
||||
if (inputStream != null)
|
||||
num = inputStream.read(buffer, 0, numBytes);
|
||||
}
|
||||
} catch (IOException e)
|
||||
{
|
||||
}
|
||||
|
||||
if (num > 0)
|
||||
position += num;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
public final long getPosition()
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
public final long getTotalLength()
|
||||
{
|
||||
return totalLength;
|
||||
}
|
||||
|
||||
public final boolean isExhausted()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public final boolean setPosition(long newPos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isPost;
|
||||
private byte[] postData;
|
||||
private String headers;
|
||||
private int timeOutMs;
|
||||
String httpRequestCmd;
|
||||
private HttpURLConnection connection;
|
||||
private int[] statusCode;
|
||||
private StringBuffer responseHeaders;
|
||||
private int totalLength;
|
||||
private int numRedirectsToFollow;
|
||||
private InputStream inputStream;
|
||||
private long position;
|
||||
private final ReentrantLock createStreamLock = new ReentrantLock();
|
||||
private final Object createFutureLock = new Object();
|
||||
private AtomicBoolean hasBeenCancelled = new AtomicBoolean();
|
||||
|
||||
private final ExecutorService executor = Executors.newCachedThreadPool(Executors.defaultThreadFactory());
|
||||
Future<BufferedInputStream> streamFuture;
|
||||
}
|
||||
60
deps/juce/modules/juce_core/native/java/app/com/rmsl/juce/JuceInvocationHandler.java
vendored
Normal file
60
deps/juce/modules/juce_core/native/java/app/com/rmsl/juce/JuceInvocationHandler.java
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
package com.rmsl.juce;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
|
||||
public class JuceInvocationHandler implements InvocationHandler
|
||||
{
|
||||
public JuceInvocationHandler (long nativeContextRef)
|
||||
{
|
||||
nativeContext = nativeContextRef;
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
nativeContext = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalize()
|
||||
{
|
||||
if (nativeContext != 0)
|
||||
dispatchFinalize (nativeContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable
|
||||
{
|
||||
if (nativeContext != 0)
|
||||
return dispatchInvoke (nativeContext, proxy, method, args);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private long nativeContext = 0;
|
||||
|
||||
private native void dispatchFinalize (long nativeContextRef);
|
||||
private native Object dispatchInvoke (long nativeContextRef, Object proxy, Method method, Object[] args);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user