| @@ -20,6 +20,8 @@ | |||
| #include "CarlaPluginInternal.hpp" | |||
| #include "juce_gui_basics.h" | |||
| #if 0 | |||
| #include <QtGui/QCloseEvent> | |||
| @@ -482,17 +482,16 @@ public: | |||
| template <class F1, class E1, class F2, class E2> | |||
| struct Test5 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| static void test (UnitTest& unitTest, Random& r) | |||
| { | |||
| test (unitTest, false); | |||
| test (unitTest, true); | |||
| test (unitTest, false, r); | |||
| test (unitTest, true, r); | |||
| } | |||
| static void test (UnitTest& unitTest, bool inPlace) | |||
| static void test (UnitTest& unitTest, bool inPlace, Random& r) | |||
| { | |||
| const int numSamples = 2048; | |||
| int32 original [numSamples], converted [numSamples], reversed [numSamples]; | |||
| Random r; | |||
| { | |||
| AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst> d (original); | |||
| @@ -549,49 +548,50 @@ public: | |||
| template <class F1, class E1, class FormatType> | |||
| struct Test3 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| static void test (UnitTest& unitTest, Random& r) | |||
| { | |||
| Test5 <F1, E1, FormatType, AudioData::BigEndian>::test (unitTest); | |||
| Test5 <F1, E1, FormatType, AudioData::LittleEndian>::test (unitTest); | |||
| Test5 <F1, E1, FormatType, AudioData::BigEndian>::test (unitTest, r); | |||
| Test5 <F1, E1, FormatType, AudioData::LittleEndian>::test (unitTest, r); | |||
| } | |||
| }; | |||
| template <class FormatType, class Endianness> | |||
| struct Test2 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| static void test (UnitTest& unitTest, Random& r) | |||
| { | |||
| Test3 <FormatType, Endianness, AudioData::Int8>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::UInt8>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int16>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int24>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int32>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Float32>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int8>::test (unitTest, r); | |||
| Test3 <FormatType, Endianness, AudioData::UInt8>::test (unitTest, r); | |||
| Test3 <FormatType, Endianness, AudioData::Int16>::test (unitTest, r); | |||
| Test3 <FormatType, Endianness, AudioData::Int24>::test (unitTest, r); | |||
| Test3 <FormatType, Endianness, AudioData::Int32>::test (unitTest, r); | |||
| Test3 <FormatType, Endianness, AudioData::Float32>::test (unitTest, r); | |||
| } | |||
| }; | |||
| template <class FormatType> | |||
| struct Test1 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| static void test (UnitTest& unitTest, Random& r) | |||
| { | |||
| Test2 <FormatType, AudioData::BigEndian>::test (unitTest); | |||
| Test2 <FormatType, AudioData::LittleEndian>::test (unitTest); | |||
| Test2 <FormatType, AudioData::BigEndian>::test (unitTest, r); | |||
| Test2 <FormatType, AudioData::LittleEndian>::test (unitTest, r); | |||
| } | |||
| }; | |||
| void runTest() | |||
| { | |||
| Random r = getRandom(); | |||
| beginTest ("Round-trip conversion: Int8"); | |||
| Test1 <AudioData::Int8>::test (*this); | |||
| Test1 <AudioData::Int8>::test (*this, r); | |||
| beginTest ("Round-trip conversion: Int16"); | |||
| Test1 <AudioData::Int16>::test (*this); | |||
| Test1 <AudioData::Int16>::test (*this, r); | |||
| beginTest ("Round-trip conversion: Int24"); | |||
| Test1 <AudioData::Int24>::test (*this); | |||
| Test1 <AudioData::Int24>::test (*this, r); | |||
| beginTest ("Round-trip conversion: Int32"); | |||
| Test1 <AudioData::Int32>::test (*this); | |||
| Test1 <AudioData::Int32>::test (*this, r); | |||
| beginTest ("Round-trip conversion: Float32"); | |||
| Test1 <AudioData::Float32>::test (*this); | |||
| Test1 <AudioData::Float32>::test (*this, r); | |||
| } | |||
| }; | |||
| @@ -285,9 +285,7 @@ void AudioSampleBuffer::applyGainRamp (const int channel, | |||
| } | |||
| } | |||
| void AudioSampleBuffer::applyGain (const int startSample, | |||
| const int numSamples, | |||
| const float gain) noexcept | |||
| void AudioSampleBuffer::applyGain (int startSample, int numSamples, float gain) noexcept | |||
| { | |||
| for (int i = 0; i < numChannels; ++i) | |||
| applyGain (i, startSample, numSamples, gain); | |||
| @@ -298,10 +296,8 @@ void AudioSampleBuffer::applyGain (const float gain) noexcept | |||
| applyGain (0, size, gain); | |||
| } | |||
| void AudioSampleBuffer::applyGainRamp (const int startSample, | |||
| const int numSamples, | |||
| const float startGain, | |||
| const float endGain) noexcept | |||
| void AudioSampleBuffer::applyGainRamp (int startSample, int numSamples, | |||
| float startGain, float endGain) noexcept | |||
| { | |||
| for (int i = 0; i < numChannels; ++i) | |||
| applyGainRamp (i, startSample, numSamples, startGain, endGain); | |||
| @@ -399,11 +395,9 @@ void AudioSampleBuffer::copyFrom (const int destChannel, | |||
| jassert (sourceStartSample >= 0 && sourceStartSample + numSamples <= source.size); | |||
| if (numSamples > 0) | |||
| { | |||
| FloatVectorOperations::copy (channels [destChannel] + destStartSample, | |||
| source.channels [sourceChannel] + sourceStartSample, | |||
| numSamples); | |||
| } | |||
| } | |||
| void AudioSampleBuffer::copyFrom (const int destChannel, | |||
| @@ -416,11 +410,7 @@ void AudioSampleBuffer::copyFrom (const int destChannel, | |||
| jassert (source != nullptr); | |||
| if (numSamples > 0) | |||
| { | |||
| FloatVectorOperations::copy (channels [destChannel] + destStartSample, | |||
| source, | |||
| numSamples); | |||
| } | |||
| FloatVectorOperations::copy (channels [destChannel] + destStartSample, source, numSamples); | |||
| } | |||
| void AudioSampleBuffer::copyFrom (const int destChannel, | |||
| @@ -482,6 +472,21 @@ void AudioSampleBuffer::copyFromWithRamp (const int destChannel, | |||
| } | |||
| } | |||
| void AudioSampleBuffer::reverse (int channel, int startSample, int numSamples) const noexcept | |||
| { | |||
| jassert (isPositiveAndBelow (channel, numChannels)); | |||
| jassert (startSample >= 0 && startSample + numSamples <= size); | |||
| std::reverse (channels[channel] + startSample, | |||
| channels[channel] + startSample + numSamples); | |||
| } | |||
| void AudioSampleBuffer::reverse (int startSample, int numSamples) const noexcept | |||
| { | |||
| for (int i = 0; i < numChannels; ++i) | |||
| reverse (i, startSample, numSamples); | |||
| } | |||
| void AudioSampleBuffer::findMinMax (const int channel, | |||
| const int startSample, | |||
| int numSamples, | |||
| @@ -508,8 +513,7 @@ float AudioSampleBuffer::getMagnitude (const int channel, | |||
| return jmax (mn, -mn, mx, -mx); | |||
| } | |||
| float AudioSampleBuffer::getMagnitude (const int startSample, | |||
| const int numSamples) const noexcept | |||
| float AudioSampleBuffer::getMagnitude (int startSample, int numSamples) const noexcept | |||
| { | |||
| float mag = 0.0f; | |||
| @@ -107,19 +107,16 @@ public: | |||
| //============================================================================== | |||
| /** Returns the number of channels of audio data that this buffer contains. | |||
| @see getSampleData | |||
| */ | |||
| int getNumChannels() const noexcept { return numChannels; } | |||
| /** Returns the number of samples allocated in each of the buffer's channels. | |||
| @see getSampleData | |||
| */ | |||
| int getNumSamples() const noexcept { return size; } | |||
| /** Returns a pointer one of the buffer's channels. | |||
| For speed, this doesn't check whether the channel number is out of range, | |||
| so be careful when using it! | |||
| */ | |||
| @@ -409,23 +406,26 @@ public: | |||
| float& minVal, | |||
| float& maxVal) const noexcept; | |||
| /** Finds the highest absolute sample value within a region of a channel. | |||
| */ | |||
| /** Finds the highest absolute sample value within a region of a channel. */ | |||
| float getMagnitude (int channel, | |||
| int startSample, | |||
| int numSamples) const noexcept; | |||
| /** Finds the highest absolute sample value within a region on all channels. | |||
| */ | |||
| /** Finds the highest absolute sample value within a region on all channels. */ | |||
| float getMagnitude (int startSample, | |||
| int numSamples) const noexcept; | |||
| /** Returns the root mean squared level for a region of a channel. | |||
| */ | |||
| /** Returns the root mean squared level for a region of a channel. */ | |||
| float getRMSLevel (int channel, | |||
| int startSample, | |||
| int numSamples) const noexcept; | |||
| /** Reverses a part of a channel. */ | |||
| void reverse (int channel, int startSample, int numSamples) const noexcept; | |||
| /** Reverses a part of the buffer. */ | |||
| void reverse (int startSample, int numSamples) const noexcept; | |||
| private: | |||
| //============================================================================== | |||
| int numChannels, size; | |||
| @@ -42,13 +42,6 @@ namespace FloatVectorHelpers | |||
| return (((pointer_sized_int) p) & 15) == 0; | |||
| } | |||
| inline static void mmEmpty() noexcept | |||
| { | |||
| #if ! JUCE_64BIT | |||
| _mm_empty(); | |||
| #endif | |||
| } | |||
| static inline float findMinimumOrMaximum (const float* src, int num, const bool isMinimum) noexcept | |||
| { | |||
| #if JUCE_USE_SSE_INTRINSICS | |||
| @@ -84,7 +77,6 @@ namespace FloatVectorHelpers | |||
| { | |||
| float vals[4]; | |||
| _mm_storeu_ps (vals, val); | |||
| FloatVectorHelpers::mmEmpty(); | |||
| localVal = isMinimum ? jmin (vals[0], vals[1], vals[2], vals[3]) | |||
| : jmax (vals[0], vals[1], vals[2], vals[3]); | |||
| @@ -111,7 +103,6 @@ namespace FloatVectorHelpers | |||
| const int numLongOps = num / 4; | |||
| #define JUCE_FINISH_SSE_OP(normalOp) \ | |||
| FloatVectorHelpers::mmEmpty(); \ | |||
| num &= 3; \ | |||
| if (num == 0) return; \ | |||
| } \ | |||
| @@ -301,7 +292,6 @@ void JUCE_CALLTYPE FloatVectorOperations::findMinAndMax (const float* src, int n | |||
| float mns[4], mxs[4]; | |||
| _mm_storeu_ps (mns, mn); | |||
| _mm_storeu_ps (mxs, mx); | |||
| FloatVectorHelpers::mmEmpty(); | |||
| localMin = jmin (mns[0], mns[1], mns[2], mns[3]); | |||
| localMax = jmax (mxs[0], mxs[1], mxs[2], mxs[3]); | |||
| @@ -0,0 +1,239 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2013 - Raw Material Software Ltd. | |||
| Permission is granted to use this software under the terms of either: | |||
| a) the GPL v2 (or any later version) | |||
| b) the Affero GPL v3 | |||
| Details of these licenses can be found at: www.gnu.org/licenses | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.juce.com for more information. | |||
| ============================================================================== | |||
| */ | |||
| #if JUCE_INTEL | |||
| #define JUCE_SNAP_TO_ZERO(n) if (! (n < -1.0e-8 || n > 1.0e-8)) n = 0; | |||
| #else | |||
| #define JUCE_SNAP_TO_ZERO(n) | |||
| #endif | |||
| //============================================================================== | |||
| IIRFilterOld::IIRFilterOld() | |||
| : active (false), v1 (0), v2 (0) | |||
| { | |||
| zeromem (coefficients, sizeof (coefficients)); | |||
| } | |||
| IIRFilterOld::IIRFilterOld (const IIRFilterOld& other) | |||
| : active (other.active), v1 (0), v2 (0) | |||
| { | |||
| const SpinLock::ScopedLockType sl (other.processLock); | |||
| memcpy (coefficients, other.coefficients, sizeof (coefficients)); | |||
| } | |||
| IIRFilterOld::~IIRFilterOld() | |||
| { | |||
| } | |||
| //============================================================================== | |||
| void IIRFilterOld::reset() noexcept | |||
| { | |||
| const SpinLock::ScopedLockType sl (processLock); | |||
| v1 = v2 = 0; | |||
| } | |||
| float IIRFilterOld::processSingleSampleRaw (const float in) noexcept | |||
| { | |||
| float out = coefficients[0] * in + v1; | |||
| JUCE_SNAP_TO_ZERO (out); | |||
| v1 = coefficients[1] * in - coefficients[3] * out + v2; | |||
| v2 = coefficients[2] * in - coefficients[4] * out; | |||
| return out; | |||
| } | |||
| void IIRFilterOld::processSamples (float* const samples, | |||
| const int numSamples) noexcept | |||
| { | |||
| const SpinLock::ScopedLockType sl (processLock); | |||
| if (active) | |||
| { | |||
| const float c0 = coefficients[0]; | |||
| const float c1 = coefficients[1]; | |||
| const float c2 = coefficients[2]; | |||
| const float c3 = coefficients[3]; | |||
| const float c4 = coefficients[4]; | |||
| float lv1 = v1, lv2 = v2; | |||
| for (int i = 0; i < numSamples; ++i) | |||
| { | |||
| const float in = samples[i]; | |||
| const float out = c0 * in + lv1; | |||
| samples[i] = out; | |||
| lv1 = c1 * in - c3 * out + lv2; | |||
| lv2 = c2 * in - c4 * out; | |||
| } | |||
| JUCE_SNAP_TO_ZERO (lv1); v1 = lv1; | |||
| JUCE_SNAP_TO_ZERO (lv2); v2 = lv2; | |||
| } | |||
| } | |||
| //============================================================================== | |||
| void IIRFilterOld::makeLowPass (const double sampleRate, | |||
| const double frequency) noexcept | |||
| { | |||
| jassert (sampleRate > 0); | |||
| const double n = 1.0 / tan (double_Pi * frequency / sampleRate); | |||
| const double nSquared = n * n; | |||
| const double c1 = 1.0 / (1.0 + std::sqrt (2.0) * n + nSquared); | |||
| setCoefficients (c1, | |||
| c1 * 2.0f, | |||
| c1, | |||
| 1.0, | |||
| c1 * 2.0 * (1.0 - nSquared), | |||
| c1 * (1.0 - std::sqrt (2.0) * n + nSquared)); | |||
| } | |||
| void IIRFilterOld::makeHighPass (const double sampleRate, | |||
| const double frequency) noexcept | |||
| { | |||
| const double n = tan (double_Pi * frequency / sampleRate); | |||
| const double nSquared = n * n; | |||
| const double c1 = 1.0 / (1.0 + std::sqrt (2.0) * n + nSquared); | |||
| setCoefficients (c1, | |||
| c1 * -2.0f, | |||
| c1, | |||
| 1.0, | |||
| c1 * 2.0 * (nSquared - 1.0), | |||
| c1 * (1.0 - std::sqrt (2.0) * n + nSquared)); | |||
| } | |||
| void IIRFilterOld::makeLowShelf (const double sampleRate, | |||
| const double cutOffFrequency, | |||
| const double Q, | |||
| const float gainFactor) noexcept | |||
| { | |||
| jassert (sampleRate > 0); | |||
| jassert (Q > 0); | |||
| const double A = jmax (0.0f, gainFactor); | |||
| const double aminus1 = A - 1.0; | |||
| const double aplus1 = A + 1.0; | |||
| const double omega = (double_Pi * 2.0 * jmax (cutOffFrequency, 2.0)) / sampleRate; | |||
| const double coso = std::cos (omega); | |||
| const double beta = std::sin (omega) * std::sqrt (A) / Q; | |||
| const double aminus1TimesCoso = aminus1 * coso; | |||
| setCoefficients (A * (aplus1 - aminus1TimesCoso + beta), | |||
| A * 2.0 * (aminus1 - aplus1 * coso), | |||
| A * (aplus1 - aminus1TimesCoso - beta), | |||
| aplus1 + aminus1TimesCoso + beta, | |||
| -2.0 * (aminus1 + aplus1 * coso), | |||
| aplus1 + aminus1TimesCoso - beta); | |||
| } | |||
| void IIRFilterOld::makeHighShelf (const double sampleRate, | |||
| const double cutOffFrequency, | |||
| const double Q, | |||
| const float gainFactor) noexcept | |||
| { | |||
| jassert (sampleRate > 0); | |||
| jassert (Q > 0); | |||
| const double A = jmax (0.0f, gainFactor); | |||
| const double aminus1 = A - 1.0; | |||
| const double aplus1 = A + 1.0; | |||
| const double omega = (double_Pi * 2.0 * jmax (cutOffFrequency, 2.0)) / sampleRate; | |||
| const double coso = std::cos (omega); | |||
| const double beta = std::sin (omega) * std::sqrt (A) / Q; | |||
| const double aminus1TimesCoso = aminus1 * coso; | |||
| setCoefficients (A * (aplus1 + aminus1TimesCoso + beta), | |||
| A * -2.0 * (aminus1 + aplus1 * coso), | |||
| A * (aplus1 + aminus1TimesCoso - beta), | |||
| aplus1 - aminus1TimesCoso + beta, | |||
| 2.0 * (aminus1 - aplus1 * coso), | |||
| aplus1 - aminus1TimesCoso - beta); | |||
| } | |||
| void IIRFilterOld::makeBandPass (const double sampleRate, | |||
| const double centreFrequency, | |||
| const double Q, | |||
| const float gainFactor) noexcept | |||
| { | |||
| jassert (sampleRate > 0); | |||
| jassert (Q > 0); | |||
| const double A = jmax (0.0f, gainFactor); | |||
| const double omega = (double_Pi * 2.0 * jmax (centreFrequency, 2.0)) / sampleRate; | |||
| const double alpha = 0.5 * std::sin (omega) / Q; | |||
| const double c2 = -2.0 * std::cos (omega); | |||
| const double alphaTimesA = alpha * A; | |||
| const double alphaOverA = alpha / A; | |||
| setCoefficients (1.0 + alphaTimesA, | |||
| c2, | |||
| 1.0 - alphaTimesA, | |||
| 1.0 + alphaOverA, | |||
| c2, | |||
| 1.0 - alphaOverA); | |||
| } | |||
| void IIRFilterOld::makeInactive() noexcept | |||
| { | |||
| const SpinLock::ScopedLockType sl (processLock); | |||
| active = false; | |||
| } | |||
| //============================================================================== | |||
| void IIRFilterOld::copyCoefficientsFrom (const IIRFilterOld& other) noexcept | |||
| { | |||
| const SpinLock::ScopedLockType sl (processLock); | |||
| memcpy (coefficients, other.coefficients, sizeof (coefficients)); | |||
| active = other.active; | |||
| } | |||
| //============================================================================== | |||
| void IIRFilterOld::setCoefficients (double c1, double c2, double c3, | |||
| double c4, double c5, double c6) noexcept | |||
| { | |||
| const double a = 1.0 / c4; | |||
| c1 *= a; | |||
| c2 *= a; | |||
| c3 *= a; | |||
| c5 *= a; | |||
| c6 *= a; | |||
| const SpinLock::ScopedLockType sl (processLock); | |||
| coefficients[0] = (float) c1; | |||
| coefficients[1] = (float) c2; | |||
| coefficients[2] = (float) c3; | |||
| coefficients[3] = (float) c5; | |||
| coefficients[4] = (float) c6; | |||
| active = true; | |||
| } | |||
| #undef JUCE_SNAP_TO_ZERO | |||
| @@ -0,0 +1,148 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2013 - Raw Material Software Ltd. | |||
| Permission is granted to use this software under the terms of either: | |||
| a) the GPL v2 (or any later version) | |||
| b) the Affero GPL v3 | |||
| Details of these licenses can be found at: www.gnu.org/licenses | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.juce.com for more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_IIRFILTER_OLD_JUCEHEADER__ | |||
| #define __JUCE_IIRFILTER_OLD_JUCEHEADER__ | |||
| //============================================================================== | |||
| /** | |||
| An IIR filter that can perform low, high, or band-pass filtering on an | |||
| audio signal. | |||
| @see IIRFilterAudioSource | |||
| */ | |||
| class JUCE_API IIRFilterOld | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Creates a filter. | |||
| Initially the filter is inactive, so will have no effect on samples that | |||
| you process with it. Use the appropriate method to turn it into the type | |||
| of filter needed. | |||
| */ | |||
| IIRFilterOld(); | |||
| /** Creates a copy of another filter. */ | |||
| IIRFilterOld (const IIRFilterOld& other); | |||
| /** Destructor. */ | |||
| ~IIRFilterOld(); | |||
| //============================================================================== | |||
| /** Resets the filter's processing pipeline, ready to start a new stream of data. | |||
| Note that this clears the processing state, but the type of filter and | |||
| its coefficients aren't changed. To put a filter into an inactive state, use | |||
| the makeInactive() method. | |||
| */ | |||
| void reset() noexcept; | |||
| /** Performs the filter operation on the given set of samples. | |||
| */ | |||
| void processSamples (float* samples, | |||
| int numSamples) noexcept; | |||
| /** Processes a single sample, without any locking or checking. | |||
| Use this if you need fast processing of a single value, but be aware that | |||
| this isn't thread-safe in the way that processSamples() is. | |||
| */ | |||
| float processSingleSampleRaw (float sample) noexcept; | |||
| //============================================================================== | |||
| /** Sets the filter up to act as a low-pass filter. | |||
| */ | |||
| void makeLowPass (double sampleRate, | |||
| double frequency) noexcept; | |||
| /** Sets the filter up to act as a high-pass filter. | |||
| */ | |||
| void makeHighPass (double sampleRate, | |||
| double frequency) noexcept; | |||
| //============================================================================== | |||
| /** Sets the filter up to act as a low-pass shelf filter with variable Q and gain. | |||
| The gain is a scale factor that the low frequencies are multiplied by, so values | |||
| greater than 1.0 will boost the low frequencies, values less than 1.0 will | |||
| attenuate them. | |||
| */ | |||
| void makeLowShelf (double sampleRate, | |||
| double cutOffFrequency, | |||
| double Q, | |||
| float gainFactor) noexcept; | |||
| /** Sets the filter up to act as a high-pass shelf filter with variable Q and gain. | |||
| The gain is a scale factor that the high frequencies are multiplied by, so values | |||
| greater than 1.0 will boost the high frequencies, values less than 1.0 will | |||
| attenuate them. | |||
| */ | |||
| void makeHighShelf (double sampleRate, | |||
| double cutOffFrequency, | |||
| double Q, | |||
| float gainFactor) noexcept; | |||
| /** Sets the filter up to act as a band pass filter centred around a | |||
| frequency, with a variable Q and gain. | |||
| The gain is a scale factor that the centre frequencies are multiplied by, so | |||
| values greater than 1.0 will boost the centre frequencies, values less than | |||
| 1.0 will attenuate them. | |||
| */ | |||
| void makeBandPass (double sampleRate, | |||
| double centreFrequency, | |||
| double Q, | |||
| float gainFactor) noexcept; | |||
| /** Clears the filter's coefficients so that it becomes inactive. | |||
| */ | |||
| void makeInactive() noexcept; | |||
| //============================================================================== | |||
| /** Makes this filter duplicate the set-up of another one. | |||
| */ | |||
| void copyCoefficientsFrom (const IIRFilterOld& other) noexcept; | |||
| protected: | |||
| //============================================================================== | |||
| SpinLock processLock; | |||
| void setCoefficients (double c1, double c2, double c3, | |||
| double c4, double c5, double c6) noexcept; | |||
| bool active; | |||
| float coefficients[5]; | |||
| float v1, v2; | |||
| // (use the copyCoefficientsFrom() method instead of this operator) | |||
| IIRFilterOld& operator= (const IIRFilterOld&); | |||
| JUCE_LEAK_DETECTOR (IIRFilterOld) | |||
| }; | |||
| #endif // __JUCE_IIRFILTER_OLD_JUCEHEADER__ | |||
| @@ -65,6 +65,7 @@ namespace juce | |||
| #include "buffers/juce_AudioSampleBuffer.cpp" | |||
| #include "buffers/juce_FloatVectorOperations.cpp" | |||
| #include "effects/juce_IIRFilter.cpp" | |||
| #include "effects/juce_IIRFilterOld.cpp" | |||
| #include "effects/juce_LagrangeInterpolator.cpp" | |||
| #include "midi/juce_MidiBuffer.cpp" | |||
| #include "midi/juce_MidiFile.cpp" | |||
| @@ -36,6 +36,7 @@ namespace juce | |||
| #include "buffers/juce_FloatVectorOperations.h" | |||
| #include "effects/juce_Decibels.h" | |||
| #include "effects/juce_IIRFilter.h" | |||
| #include "effects/juce_IIRFilterOld.h" | |||
| #include "effects/juce_LagrangeInterpolator.h" | |||
| #include "effects/juce_Reverb.h" | |||
| #include "midi/juce_MidiMessage.h" | |||
| @@ -1,7 +1,7 @@ | |||
| { | |||
| "id": "juce_audio_basics", | |||
| "name": "JUCE audio and midi data classes", | |||
| "version": "2.1.2", | |||
| "version": "2.1.3", | |||
| "description": "Classes for audio buffer manipulation, midi message handling, synthesis, etc", | |||
| "website": "http://www.juce.com/juce", | |||
| "license": "GPL/Commercial", | |||
| @@ -240,9 +240,8 @@ uint8* MidiBuffer::findEventAfter (uint8* d, const int samplePosition) const noe | |||
| } | |||
| //============================================================================== | |||
| MidiBuffer::Iterator::Iterator (const MidiBuffer& buffer_) noexcept | |||
| : buffer (buffer_), | |||
| data (buffer_.getData()) | |||
| MidiBuffer::Iterator::Iterator (const MidiBuffer& b) noexcept | |||
| : buffer (b), data (b.getData()) | |||
| { | |||
| } | |||
| @@ -250,7 +249,6 @@ MidiBuffer::Iterator::~Iterator() noexcept | |||
| { | |||
| } | |||
| //============================================================================== | |||
| void MidiBuffer::Iterator::setNextSamplePosition (const int samplePosition) noexcept | |||
| { | |||
| data = buffer.getData(); | |||
| @@ -51,10 +51,10 @@ public: | |||
| explicit MidiBuffer (const MidiMessage& message) noexcept; | |||
| /** Creates a copy of another MidiBuffer. */ | |||
| MidiBuffer (const MidiBuffer& other) noexcept; | |||
| MidiBuffer (const MidiBuffer&) noexcept; | |||
| /** Makes a copy of another MidiBuffer. */ | |||
| MidiBuffer& operator= (const MidiBuffer& other) noexcept; | |||
| MidiBuffer& operator= (const MidiBuffer&) noexcept; | |||
| /** Destructor */ | |||
| ~MidiBuffer(); | |||
| @@ -176,7 +176,7 @@ public: | |||
| public: | |||
| //============================================================================== | |||
| /** Creates an Iterator for this MidiBuffer. */ | |||
| Iterator (const MidiBuffer& buffer) noexcept; | |||
| Iterator (const MidiBuffer&) noexcept; | |||
| /** Destructor. */ | |||
| ~Iterator() noexcept; | |||
| @@ -146,6 +146,26 @@ namespace MidiFileHelpers | |||
| return 0; | |||
| } | |||
| }; | |||
| template <typename MethodType> | |||
| static void findAllMatchingEvents (const OwnedArray<MidiMessageSequence>& tracks, | |||
| MidiMessageSequence& results, | |||
| MethodType method) | |||
| { | |||
| for (int i = 0; i < tracks.size(); ++i) | |||
| { | |||
| const MidiMessageSequence& track = *tracks.getUnchecked(i); | |||
| const int numEvents = track.getNumEvents(); | |||
| for (int j = 0; j < numEvents; ++j) | |||
| { | |||
| const MidiMessage& m = track.getEventPointer(j)->message; | |||
| if ((m.*method)()) | |||
| results.addEvent (m); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| //============================================================================== | |||
| @@ -197,36 +217,19 @@ void MidiFile::setSmpteTimeFormat (const int framesPerSecond, | |||
| } | |||
| //============================================================================== | |||
| void MidiFile::findAllTempoEvents (MidiMessageSequence& tempoChangeEvents) const | |||
| void MidiFile::findAllTempoEvents (MidiMessageSequence& results) const | |||
| { | |||
| for (int i = tracks.size(); --i >= 0;) | |||
| { | |||
| const int numEvents = tracks.getUnchecked(i)->getNumEvents(); | |||
| for (int j = 0; j < numEvents; ++j) | |||
| { | |||
| const MidiMessage& m = tracks.getUnchecked(i)->getEventPointer (j)->message; | |||
| if (m.isTempoMetaEvent()) | |||
| tempoChangeEvents.addEvent (m); | |||
| } | |||
| } | |||
| MidiFileHelpers::findAllMatchingEvents (tracks, results, &MidiMessage::isTempoMetaEvent); | |||
| } | |||
| void MidiFile::findAllTimeSigEvents (MidiMessageSequence& timeSigEvents) const | |||
| void MidiFile::findAllTimeSigEvents (MidiMessageSequence& results) const | |||
| { | |||
| for (int i = tracks.size(); --i >= 0;) | |||
| { | |||
| const int numEvents = tracks.getUnchecked(i)->getNumEvents(); | |||
| for (int j = 0; j < numEvents; ++j) | |||
| { | |||
| const MidiMessage& m = tracks.getUnchecked(i)->getEventPointer (j)->message; | |||
| MidiFileHelpers::findAllMatchingEvents (tracks, results, &MidiMessage::isTimeSignatureMetaEvent); | |||
| } | |||
| if (m.isTimeSignatureMetaEvent()) | |||
| timeSigEvents.addEvent (m); | |||
| } | |||
| } | |||
| void MidiFile::findAllKeySigEvents (MidiMessageSequence& results) const | |||
| { | |||
| MidiFileHelpers::findAllMatchingEvents (tracks, results, &MidiMessage::isKeySignatureMetaEvent); | |||
| } | |||
| double MidiFile::getLastTimestamp() const | |||
| @@ -340,10 +343,7 @@ void MidiFile::convertTimestampTicksToSeconds() | |||
| for (int j = ms.getNumEvents(); --j >= 0;) | |||
| { | |||
| MidiMessage& m = ms.getEventPointer(j)->message; | |||
| m.setTimeStamp (MidiFileHelpers::convertTicksToSeconds (m.getTimeStamp(), | |||
| tempoEvents, | |||
| timeFormat)); | |||
| m.setTimeStamp (MidiFileHelpers::convertTicksToSeconds (m.getTimeStamp(), tempoEvents, timeFormat)); | |||
| } | |||
| } | |||
| } | |||
| @@ -52,28 +52,23 @@ public: | |||
| //============================================================================== | |||
| /** Returns the number of tracks in the file. | |||
| @see getTrack, addTrack | |||
| */ | |||
| int getNumTracks() const noexcept; | |||
| /** Returns a pointer to one of the tracks in the file. | |||
| @returns a pointer to the track, or nullptr if the index is out-of-range | |||
| @see getNumTracks, addTrack | |||
| */ | |||
| const MidiMessageSequence* getTrack (int index) const noexcept; | |||
| /** Adds a midi track to the file. | |||
| This will make its own internal copy of the sequence that is passed-in. | |||
| @see getNumTracks, getTrack | |||
| */ | |||
| void addTrack (const MidiMessageSequence& trackSequence); | |||
| /** Removes all midi tracks from the file. | |||
| @see getNumTracks | |||
| */ | |||
| void clear(); | |||
| @@ -120,23 +115,23 @@ public: | |||
| //============================================================================== | |||
| /** Makes a list of all the tempo-change meta-events from all tracks in the midi file. | |||
| Useful for finding the positions of all the tempo changes in a file. | |||
| @param tempoChangeEvents a list to which all the events will be added | |||
| */ | |||
| void findAllTempoEvents (MidiMessageSequence& tempoChangeEvents) const; | |||
| /** Makes a list of all the time-signature meta-events from all tracks in the midi file. | |||
| Useful for finding the positions of all the tempo changes in a file. | |||
| @param timeSigEvents a list to which all the events will be added | |||
| */ | |||
| void findAllTimeSigEvents (MidiMessageSequence& timeSigEvents) const; | |||
| /** Returns the latest timestamp in any of the tracks. | |||
| /** Makes a list of all the time-signature meta-events from all tracks in the midi file. | |||
| @param keySigEvents a list to which all the events will be added | |||
| */ | |||
| void findAllKeySigEvents (MidiMessageSequence& keySigEvents) const; | |||
| /** Returns the latest timestamp in any of the tracks. | |||
| (Useful for finding the length of the file). | |||
| */ | |||
| double getLastTimestamp() const; | |||
| @@ -156,7 +151,6 @@ public: | |||
| bool readFrom (InputStream& sourceStream); | |||
| /** Writes the midi tracks as a standard midi file. | |||
| @returns true if the operation succeeded. | |||
| */ | |||
| bool writeTo (OutputStream& destStream); | |||
| @@ -171,11 +165,11 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| OwnedArray <MidiMessageSequence> tracks; | |||
| OwnedArray<MidiMessageSequence> tracks; | |||
| short timeFormat; | |||
| void readNextTrack (const uint8* data, int size); | |||
| void writeTrack (OutputStream& mainOut, int trackNum); | |||
| void readNextTrack (const uint8*, int size); | |||
| void writeTrack (OutputStream&, int trackNum); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiFile) | |||
| }; | |||
| @@ -797,7 +797,12 @@ bool MidiMessage::isKeySignatureMetaEvent() const noexcept | |||
| int MidiMessage::getKeySignatureNumberOfSharpsOrFlats() const noexcept | |||
| { | |||
| return (int) *getMetaEventData(); | |||
| return (int) getMetaEventData()[0]; | |||
| } | |||
| bool MidiMessage::isKeySignatureMajorKey() const noexcept | |||
| { | |||
| return getMetaEventData()[1] == 0; | |||
| } | |||
| MidiMessage MidiMessage::endOfTrack() noexcept | |||
| @@ -112,13 +112,11 @@ public: | |||
| //============================================================================== | |||
| /** Returns a pointer to the raw midi data. | |||
| @see getRawDataSize | |||
| */ | |||
| const uint8* getRawData() const noexcept { return data; } | |||
| /** Returns the number of bytes of data in the message. | |||
| @see getRawData | |||
| */ | |||
| int getRawDataSize() const noexcept { return size; } | |||
| @@ -143,15 +141,12 @@ public: | |||
| double getTimeStamp() const noexcept { return timeStamp; } | |||
| /** Changes the message's associated timestamp. | |||
| The units for the timestamp will be application-specific - see the notes for getTimeStamp(). | |||
| @see addToTimeStamp, getTimeStamp | |||
| */ | |||
| void setTimeStamp (double newTimestamp) noexcept { timeStamp = newTimestamp; } | |||
| /** Adds a value to the message's timestamp. | |||
| The units for the timestamp will be application-specific. | |||
| */ | |||
| void addToTimeStamp (double delta) noexcept { timeStamp += delta; } | |||
| @@ -569,7 +564,6 @@ public: | |||
| //============================================================================== | |||
| /** Returns true if this is a 'tempo' meta-event. | |||
| @see getTempoMetaEventTickLength, getTempoSecondsPerQuarterNote | |||
| */ | |||
| bool isTempoMetaEvent() const noexcept; | |||
| @@ -583,49 +577,51 @@ public: | |||
| double getTempoMetaEventTickLength (short timeFormat) const noexcept; | |||
| /** Calculates the seconds-per-quarter-note from a tempo meta-event. | |||
| @see isTempoMetaEvent, getTempoMetaEventTickLength | |||
| */ | |||
| double getTempoSecondsPerQuarterNote() const noexcept; | |||
| /** Creates a tempo meta-event. | |||
| @see isTempoMetaEvent | |||
| */ | |||
| static MidiMessage tempoMetaEvent (int microsecondsPerQuarterNote) noexcept; | |||
| //============================================================================== | |||
| /** Returns true if this is a 'time-signature' meta-event. | |||
| @see getTimeSignatureInfo | |||
| */ | |||
| bool isTimeSignatureMetaEvent() const noexcept; | |||
| /** Returns the time-signature values from a time-signature meta-event. | |||
| @see isTimeSignatureMetaEvent | |||
| */ | |||
| void getTimeSignatureInfo (int& numerator, int& denominator) const noexcept; | |||
| /** Creates a time-signature meta-event. | |||
| @see isTimeSignatureMetaEvent | |||
| */ | |||
| static MidiMessage timeSignatureMetaEvent (int numerator, int denominator); | |||
| //============================================================================== | |||
| /** Returns true if this is a 'key-signature' meta-event. | |||
| @see getKeySignatureNumberOfSharpsOrFlats | |||
| @see getKeySignatureNumberOfSharpsOrFlats, isKeySignatureMajorKey | |||
| */ | |||
| bool isKeySignatureMetaEvent() const noexcept; | |||
| /** Returns the key from a key-signature meta-event. | |||
| @see isKeySignatureMetaEvent | |||
| This method must only be called if isKeySignatureMetaEvent() is true. | |||
| A positive number here indicates the number of sharps in the key signature, | |||
| and a negative number indicates a number of flats. So e.g. 3 = F# + C# + G#, | |||
| -2 = Bb + Eb | |||
| @see isKeySignatureMetaEvent, isKeySignatureMajorKey | |||
| */ | |||
| int getKeySignatureNumberOfSharpsOrFlats() const noexcept; | |||
| /** Returns true if this key-signature event is major, or false if it's minor. | |||
| This method must only be called if isKeySignatureMetaEvent() is true. | |||
| */ | |||
| bool isKeySignatureMajorKey() const noexcept; | |||
| //============================================================================== | |||
| /** Returns true if this is a 'channel' meta-event. | |||
| @@ -807,14 +803,11 @@ public: | |||
| */ | |||
| MidiMachineControlCommand getMidiMachineControlCommand() const noexcept; | |||
| /** Creates an MMC message. | |||
| */ | |||
| /** Creates an MMC message. */ | |||
| static MidiMessage midiMachineControlCommand (MidiMachineControlCommand command); | |||
| /** Checks whether this is an MMC "goto" message. | |||
| If it is, the parameters passed-in are set to the time that the message contains. | |||
| @see midiMachineControlGoto | |||
| */ | |||
| bool isMidiMachineControlGoto (int& hours, | |||
| @@ -823,9 +816,7 @@ public: | |||
| int& frames) const noexcept; | |||
| /** Creates an MMC "goto" message. | |||
| This messages tells the device to go to a specific frame. | |||
| @see isMidiMachineControlGoto | |||
| */ | |||
| static MidiMessage midiMachineControlGoto (int hours, | |||
| @@ -835,14 +826,12 @@ public: | |||
| //============================================================================== | |||
| /** Creates a master-volume change message. | |||
| @param volume the volume, 0 to 1.0 | |||
| */ | |||
| static MidiMessage masterVolume (float volume); | |||
| //============================================================================== | |||
| /** Creates a system-exclusive message. | |||
| The data passed in is wrapped with header and tail bytes of 0xf0 and 0xf7. | |||
| */ | |||
| static MidiMessage createSysExMessage (const void* sysexData, | |||
| @@ -284,7 +284,7 @@ void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumbe | |||
| { | |||
| bool doneProg = false; | |||
| bool donePitchWheel = false; | |||
| Array <int> doneControllers; | |||
| Array<int> doneControllers; | |||
| doneControllers.ensureStorageAllocated (32); | |||
| for (int i = list.size(); --i >= 0;) | |||
| @@ -324,8 +324,7 @@ void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumbe | |||
| //============================================================================== | |||
| MidiMessageSequence::MidiEventHolder::MidiEventHolder (const MidiMessage& mm) | |||
| : message (mm), | |||
| noteOffObject (nullptr) | |||
| : message (mm), noteOffObject (nullptr) | |||
| { | |||
| } | |||
| @@ -22,16 +22,16 @@ | |||
| ============================================================================== | |||
| */ | |||
| BufferingAudioSource::BufferingAudioSource (PositionableAudioSource* source_, | |||
| TimeSliceThread& backgroundThread_, | |||
| BufferingAudioSource::BufferingAudioSource (PositionableAudioSource* s, | |||
| TimeSliceThread& thread, | |||
| const bool deleteSourceWhenDeleted, | |||
| const int numberOfSamplesToBuffer_, | |||
| const int numberOfChannels_) | |||
| : source (source_, deleteSourceWhenDeleted), | |||
| backgroundThread (backgroundThread_), | |||
| numberOfSamplesToBuffer (jmax (1024, numberOfSamplesToBuffer_)), | |||
| numberOfChannels (numberOfChannels_), | |||
| buffer (numberOfChannels_, 0), | |||
| const int bufferSizeSamples, | |||
| const int numChannels) | |||
| : source (s, deleteSourceWhenDeleted), | |||
| backgroundThread (thread), | |||
| numberOfSamplesToBuffer (jmax (1024, bufferSizeSamples)), | |||
| numberOfChannels (numChannels), | |||
| buffer (numChannels, 0), | |||
| bufferValidStart (0), | |||
| bufferValidEnd (0), | |||
| nextPlayPos (0), | |||
| @@ -39,10 +39,10 @@ BufferingAudioSource::BufferingAudioSource (PositionableAudioSource* source_, | |||
| wasSourceLooping (false), | |||
| isPrepared (false) | |||
| { | |||
| jassert (source_ != nullptr); | |||
| jassert (source != nullptr); | |||
| jassert (numberOfSamplesToBuffer_ > 1024); // not much point using this class if you're | |||
| // not using a larger buffer.. | |||
| jassert (numberOfSamplesToBuffer > 1024); // not much point using this class if you're | |||
| // not using a larger buffer.. | |||
| } | |||
| BufferingAudioSource::~BufferingAudioSource() | |||
| @@ -51,20 +51,20 @@ BufferingAudioSource::~BufferingAudioSource() | |||
| } | |||
| //============================================================================== | |||
| void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate_) | |||
| void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double newSampleRate) | |||
| { | |||
| const int bufferSizeNeeded = jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer); | |||
| if (sampleRate_ != sampleRate | |||
| if (newSampleRate != sampleRate | |||
| || bufferSizeNeeded != buffer.getNumSamples() | |||
| || ! isPrepared) | |||
| { | |||
| backgroundThread.removeTimeSliceClient (this); | |||
| isPrepared = true; | |||
| sampleRate = sampleRate_; | |||
| sampleRate = newSampleRate; | |||
| source->prepareToPlay (samplesPerBlockExpected, sampleRate_); | |||
| source->prepareToPlay (samplesPerBlockExpected, newSampleRate); | |||
| buffer.setSize (numberOfChannels, bufferSizeNeeded); | |||
| buffer.clear(); | |||
| @@ -74,7 +74,7 @@ void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sa | |||
| backgroundThread.addTimeSliceClient (this); | |||
| while (bufferValidEnd - bufferValidStart < jmin (((int) sampleRate_) / 4, | |||
| while (bufferValidEnd - bufferValidStart < jmin (((int) newSampleRate) / 4, | |||
| buffer.getNumSamples() / 2)) | |||
| { | |||
| backgroundThread.moveToFrontOfQueue (this); | |||
| @@ -48,12 +48,11 @@ void ToneGeneratorAudioSource::setFrequency (const double newFrequencyHz) | |||
| } | |||
| //============================================================================== | |||
| void ToneGeneratorAudioSource::prepareToPlay (int /*samplesPerBlockExpected*/, | |||
| double sampleRate_) | |||
| void ToneGeneratorAudioSource::prepareToPlay (int /*samplesPerBlockExpected*/, double rate) | |||
| { | |||
| currentPhase = 0.0; | |||
| phasePerSample = 0.0; | |||
| sampleRate = sampleRate_; | |||
| sampleRate = rate; | |||
| } | |||
| void ToneGeneratorAudioSource::releaseResources() | |||
| @@ -22,13 +22,8 @@ | |||
| ============================================================================== | |||
| */ | |||
| SynthesiserSound::SynthesiserSound() | |||
| { | |||
| } | |||
| SynthesiserSound::~SynthesiserSound() | |||
| { | |||
| } | |||
| SynthesiserSound::SynthesiserSound() {} | |||
| SynthesiserSound::~SynthesiserSound() {} | |||
| //============================================================================== | |||
| SynthesiserVoice::SynthesiserVoice() | |||
| @@ -118,9 +113,9 @@ void Synthesiser::removeSound (const int index) | |||
| sounds.remove (index); | |||
| } | |||
| void Synthesiser::setNoteStealingEnabled (const bool shouldStealNotes_) | |||
| void Synthesiser::setNoteStealingEnabled (const bool shouldSteal) | |||
| { | |||
| shouldStealNotes = shouldStealNotes_; | |||
| shouldStealNotes = shouldSteal; | |||
| } | |||
| //============================================================================== | |||
| @@ -139,10 +134,8 @@ void Synthesiser::setCurrentPlaybackSampleRate (const double newRate) | |||
| } | |||
| } | |||
| void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, | |||
| const MidiBuffer& midiData, | |||
| int startSample, | |||
| int numSamples) | |||
| void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBuffer& midiData, | |||
| int startSample, int numSamples) | |||
| { | |||
| // must set the sample rate before using this! | |||
| jassert (sampleRate != 0); | |||
| @@ -180,15 +173,11 @@ void Synthesiser::handleMidiEvent (const MidiMessage& m) | |||
| { | |||
| if (m.isNoteOn()) | |||
| { | |||
| noteOn (m.getChannel(), | |||
| m.getNoteNumber(), | |||
| m.getFloatVelocity()); | |||
| noteOn (m.getChannel(), m.getNoteNumber(), m.getFloatVelocity()); | |||
| } | |||
| else if (m.isNoteOff()) | |||
| { | |||
| noteOff (m.getChannel(), | |||
| m.getNoteNumber(), | |||
| true); | |||
| noteOff (m.getChannel(), m.getNoteNumber(), true); | |||
| } | |||
| else if (m.isAllNotesOff() || m.isAllSoundOff()) | |||
| { | |||
| @@ -204,9 +193,7 @@ void Synthesiser::handleMidiEvent (const MidiMessage& m) | |||
| } | |||
| else if (m.isController()) | |||
| { | |||
| handleController (m.getChannel(), | |||
| m.getControllerNumber(), | |||
| m.getControllerValue()); | |||
| handleController (m.getChannel(), m.getControllerNumber(), m.getControllerValue()); | |||
| } | |||
| } | |||
| @@ -406,9 +393,12 @@ SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay, | |||
| const ScopedLock sl (lock); | |||
| for (int i = voices.size(); --i >= 0;) | |||
| if (voices.getUnchecked (i)->getCurrentlyPlayingNote() < 0 | |||
| && voices.getUnchecked (i)->canPlaySound (soundToPlay)) | |||
| return voices.getUnchecked (i); | |||
| { | |||
| SynthesiserVoice* const voice = voices.getUnchecked (i); | |||
| if (voice->getCurrentlyPlayingNote() < 0 && voice->canPlaySound (soundToPlay)) | |||
| return voice; | |||
| } | |||
| if (stealIfNoneAvailable) | |||
| { | |||
| @@ -64,9 +64,8 @@ public: | |||
| */ | |||
| virtual bool appliesToChannel (const int midiChannel) = 0; | |||
| /** | |||
| */ | |||
| typedef ReferenceCountedObjectPtr <SynthesiserSound> Ptr; | |||
| /** The class is reference-counted, so this is a handy pointer class for it. */ | |||
| typedef ReferenceCountedObjectPtr<SynthesiserSound> Ptr; | |||
| private: | |||
| @@ -96,16 +95,14 @@ public: | |||
| //============================================================================== | |||
| /** Returns the midi note that this voice is currently playing. | |||
| Returns a value less than 0 if no note is playing. | |||
| */ | |||
| int getCurrentlyPlayingNote() const { return currentlyPlayingNote; } | |||
| int getCurrentlyPlayingNote() const noexcept { return currentlyPlayingNote; } | |||
| /** Returns the sound that this voice is currently playing. | |||
| Returns nullptr if it's not playing. | |||
| */ | |||
| SynthesiserSound::Ptr getCurrentlyPlayingSound() const { return currentlyPlayingSound; } | |||
| SynthesiserSound::Ptr getCurrentlyPlayingSound() const noexcept { return currentlyPlayingSound; } | |||
| /** Must return true if this voice object is capable of playing the given sound. | |||
| @@ -116,16 +113,16 @@ public: | |||
| of voice and sound, or it might check the type of the sound object passed-in and | |||
| see if it's one that it understands. | |||
| */ | |||
| virtual bool canPlaySound (SynthesiserSound* sound) = 0; | |||
| virtual bool canPlaySound (SynthesiserSound*) = 0; | |||
| /** Called to start a new note. | |||
| This will be called during the rendering callback, so must be fast and thread-safe. | |||
| */ | |||
| virtual void startNote (const int midiNoteNumber, | |||
| const float velocity, | |||
| virtual void startNote (int midiNoteNumber, | |||
| float velocity, | |||
| SynthesiserSound* sound, | |||
| const int currentPitchWheelPosition) = 0; | |||
| int currentPitchWheelPosition) = 0; | |||
| /** Called to stop a note. | |||
| @@ -140,20 +137,17 @@ public: | |||
| finishes playing (during the rendering callback), it must make sure that it calls | |||
| clearCurrentNote(). | |||
| */ | |||
| virtual void stopNote (const bool allowTailOff) = 0; | |||
| virtual void stopNote (bool allowTailOff) = 0; | |||
| /** Called to let the voice know that the pitch wheel has been moved. | |||
| This will be called during the rendering callback, so must be fast and thread-safe. | |||
| */ | |||
| virtual void pitchWheelMoved (const int newValue) = 0; | |||
| virtual void pitchWheelMoved (int newValue) = 0; | |||
| /** Called to let the voice know that a midi controller has been moved. | |||
| This will be called during the rendering callback, so must be fast and thread-safe. | |||
| */ | |||
| virtual void controllerMoved (const int controllerNumber, | |||
| const int newValue) = 0; | |||
| virtual void controllerMoved (int controllerNumber, int newValue) = 0; | |||
| //============================================================================== | |||
| /** Renders the next block of data for this voice. | |||
| @@ -273,7 +267,7 @@ public: | |||
| void clearVoices(); | |||
| /** Returns the number of voices that have been added. */ | |||
| int getNumVoices() const { return voices.size(); } | |||
| int getNumVoices() const noexcept { return voices.size(); } | |||
| /** Returns one of the voices that have been added. */ | |||
| SynthesiserVoice* getVoice (int index) const; | |||
| @@ -296,10 +290,10 @@ public: | |||
| void clearSounds(); | |||
| /** Returns the number of sounds that have been added to the synth. */ | |||
| int getNumSounds() const { return sounds.size(); } | |||
| int getNumSounds() const noexcept { return sounds.size(); } | |||
| /** Returns one of the sounds. */ | |||
| SynthesiserSound* getSound (int index) const { return sounds [index]; } | |||
| SynthesiserSound* getSound (int index) const noexcept { return sounds [index]; } | |||
| /** Adds a new sound to the synthesiser. | |||
| @@ -323,7 +317,7 @@ public: | |||
| /** Returns true if note-stealing is enabled. | |||
| @see setNoteStealingEnabled | |||
| */ | |||
| bool isNoteStealingEnabled() const { return shouldStealNotes; } | |||
| bool isNoteStealingEnabled() const noexcept { return shouldStealNotes; } | |||
| //============================================================================== | |||
| /** Triggers a note-on event. | |||
| @@ -376,7 +370,7 @@ public: | |||
| virtual void allNotesOff (int midiChannel, | |||
| bool allowTailOff); | |||
| /** Sends a pitch-wheel message. | |||
| /** Sends a pitch-wheel message to any active voices. | |||
| This will send a pitch-wheel message to any voices that are playing sounds on | |||
| the given midi channel. | |||
| @@ -390,7 +384,7 @@ public: | |||
| virtual void handlePitchWheel (int midiChannel, | |||
| int wheelValue); | |||
| /** Sends a midi controller message. | |||
| /** Sends a midi controller message to any active voices. | |||
| This will send a midi controller message to any voices that are playing sounds on | |||
| the given midi channel. | |||
| @@ -406,13 +400,17 @@ public: | |||
| int controllerNumber, | |||
| int controllerValue); | |||
| /** Handles a sustain pedal event. */ | |||
| virtual void handleSustainPedal (int midiChannel, bool isDown); | |||
| /** Handles a sostenuto pedal event. */ | |||
| virtual void handleSostenutoPedal (int midiChannel, bool isDown); | |||
| /** Can be overridden to handle soft pedal events. */ | |||
| virtual void handleSoftPedal (int midiChannel, bool isDown); | |||
| //============================================================================== | |||
| /** Tells the synthesiser what the sample rate is for the audio it's being used to | |||
| render. | |||
| /** Tells the synthesiser what the sample rate is for the audio it's being used to render. | |||
| This value is propagated to the voices so that they can use it to render the correct | |||
| pitches. | |||
| @@ -441,8 +439,8 @@ protected: | |||
| /** This is used to control access to the rendering callback and the note trigger methods. */ | |||
| CriticalSection lock; | |||
| OwnedArray <SynthesiserVoice> voices; | |||
| ReferenceCountedArray <SynthesiserSound> sounds; | |||
| OwnedArray<SynthesiserVoice> voices; | |||
| ReferenceCountedArray<SynthesiserSound> sounds; | |||
| /** The last pitch-wheel values for each midi channel. */ | |||
| int lastPitchWheelValues [16]; | |||
| @@ -33,11 +33,7 @@ | |||
| @see jassert, jassertfalse, Logger | |||
| */ | |||
| #if DEBUG | |||
| #define JUCE_LOG_ASSERTIONS 1 | |||
| #else | |||
| #define JUCE_LOG_ASSERTIONS 0 | |||
| #endif | |||
| #define JUCE_LOG_ASSERTIONS 1 | |||
| //============================================================================= | |||
| /** Config: JUCE_CHECK_MEMORY_LEAKS | |||
| @@ -45,11 +41,7 @@ | |||
| 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 DEBUG | |||
| #define JUCE_CHECK_MEMORY_LEAKS 1 | |||
| //#else | |||
| // #define JUCE_CHECK_MEMORY_LEAKS 0 | |||
| //#endif | |||
| //============================================================================= | |||
| /** Config: JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES | |||
| @@ -59,7 +51,7 @@ | |||
| */ | |||
| #define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES 0 | |||
| /* Config: JUCE_INCLUDE_ZLIB_CODE | |||
| /** 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. | |||
| @@ -68,17 +60,12 @@ | |||
| specify the path where your zlib headers live. | |||
| */ | |||
| #define JUCE_INCLUDE_ZLIB_CODE 1 | |||
| //#define JUCE_ZLIB_INCLUDE_PATH <zlib.h> | |||
| /* Config: JUCE_CATCH_UNHANDLED_EXCEPTIONS | |||
| If enabled, this will add some exception-catching code to forward unhandled exceptions | |||
| to your JUCEApplication::unhandledException() callback. | |||
| to your JUCEApplicationBase::unhandledException() callback. | |||
| */ | |||
| #if DEBUG | |||
| #define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1 | |||
| #else | |||
| #define JUCE_CATCH_UNHANDLED_EXCEPTIONS 0 | |||
| #endif | |||
| #define JUCE_CATCH_UNHANDLED_EXCEPTIONS 0 | |||
| #define JUCE_MODULE_AVAILABLE_juce_audio_basics 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_audio_devices 1 | |||
| @@ -141,8 +141,8 @@ public: | |||
| class WriteThread : public Thread | |||
| { | |||
| public: | |||
| WriteThread (AbstractFifo& fifo_, int* buffer_) | |||
| : Thread ("fifo writer"), fifo (fifo_), buffer (buffer_) | |||
| WriteThread (AbstractFifo& f, int* b, Random rng) | |||
| : Thread ("fifo writer"), fifo (f), buffer (b), random (rng) | |||
| { | |||
| startThread(); | |||
| } | |||
| @@ -155,11 +155,10 @@ public: | |||
| void run() | |||
| { | |||
| int n = 0; | |||
| Random r; | |||
| while (! threadShouldExit()) | |||
| { | |||
| int num = r.nextInt (2000) + 1; | |||
| int num = random.nextInt (2000) + 1; | |||
| int start1, size1, start2, size2; | |||
| fifo.prepareToWrite (num, start1, size1, start2, size2); | |||
| @@ -181,6 +180,7 @@ public: | |||
| private: | |||
| AbstractFifo& fifo; | |||
| int* buffer; | |||
| Random random; | |||
| }; | |||
| void runTest() | |||
| @@ -190,10 +190,11 @@ public: | |||
| int buffer [5000]; | |||
| AbstractFifo fifo (numElementsInArray (buffer)); | |||
| WriteThread writer (fifo, buffer); | |||
| WriteThread writer (fifo, buffer, getRandom()); | |||
| int n = 0; | |||
| Random r; | |||
| Random r = getRandom(); | |||
| r.combineSeed (12345); | |||
| for (int count = 100000; --count >= 0;) | |||
| { | |||
| @@ -546,11 +546,13 @@ public: | |||
| /** Adds elements from an array to the end of this array. | |||
| @param elementsToAdd the array of elements to add | |||
| @param elementsToAdd an array of some kind of object from which elements | |||
| can be constructed. | |||
| @param numElementsToAdd how many elements are in this other array | |||
| @see add | |||
| */ | |||
| void addArray (const ElementType* elementsToAdd, int numElementsToAdd) | |||
| template <typename Type> | |||
| void addArray (const Type* elementsToAdd, int numElementsToAdd) | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| @@ -566,6 +568,22 @@ public: | |||
| } | |||
| } | |||
| /** Adds elements from a null-terminated array of pointers to the end of this array. | |||
| @param elementsToAdd an array of pointers to some kind of object from which elements | |||
| can be constructed. This array must be terminated by a nullptr | |||
| @see addArray | |||
| */ | |||
| template <typename Type> | |||
| void addNullTerminatedArray (const Type* const* elementsToAdd) | |||
| { | |||
| int num = 0; | |||
| for (const Type* const* e = elementsToAdd; *e != nullptr; ++e) | |||
| ++num; | |||
| addArray (elementsToAdd, num); | |||
| } | |||
| /** 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 | |||
| @@ -715,7 +733,7 @@ public: | |||
| @param indexToRemove the index of the element to remove | |||
| @returns the element that has been removed | |||
| @see removeValue, removeRange | |||
| @see removeFirstMatchingValue, removeAllInstancesOf, removeRange | |||
| */ | |||
| ElementType remove (const int indexToRemove) | |||
| { | |||
| @@ -782,7 +800,7 @@ public: | |||
| @param startIndex the index of the first element to remove | |||
| @param numberToRemove how many elements should be removed | |||
| @see remove, removeValue | |||
| @see remove, removeFirstMatchingValue, removeAllInstancesOf | |||
| */ | |||
| void removeRange (int startIndex, int numberToRemove) | |||
| { | |||
| @@ -810,7 +828,7 @@ public: | |||
| /** Removes the last n elements from the array. | |||
| @param howManyToRemove how many elements to remove from the end of the array | |||
| @see remove, removeValue, removeRange | |||
| @see remove, removeFirstMatchingValue, removeAllInstancesOf, removeRange | |||
| */ | |||
| void removeLast (int howManyToRemove = 1) | |||
| { | |||
| @@ -829,7 +847,7 @@ public: | |||
| /** Removes any elements which are also in another array. | |||
| @param otherArray the other array in which to look for elements to remove | |||
| @see removeValuesNotIn, remove, removeValue, removeRange | |||
| @see removeValuesNotIn, remove, removeFirstMatchingValue, removeAllInstancesOf, removeRange | |||
| */ | |||
| template <class OtherArrayType> | |||
| void removeValuesIn (const OtherArrayType& otherArray) | |||
| @@ -857,7 +875,7 @@ public: | |||
| Only elements which occur in this other array will be retained. | |||
| @param otherArray the array in which to look for elements NOT to remove | |||
| @see removeValuesIn, remove, removeValue, removeRange | |||
| @see removeValuesIn, remove, removeFirstMatchingValue, removeAllInstancesOf, removeRange | |||
| */ | |||
| template <class OtherArrayType> | |||
| void removeValuesNotIn (const OtherArrayType& otherArray) | |||
| @@ -65,8 +65,7 @@ void PropertySet::clear() | |||
| } | |||
| } | |||
| String PropertySet::getValue (const String& keyName, | |||
| const String& defaultValue) const noexcept | |||
| String PropertySet::getValue (StringRef keyName, const String& defaultValue) const noexcept | |||
| { | |||
| const ScopedLock sl (lock); | |||
| @@ -79,8 +78,7 @@ String PropertySet::getValue (const String& keyName, | |||
| : defaultValue; | |||
| } | |||
| int PropertySet::getIntValue (const String& keyName, | |||
| const int defaultValue) const noexcept | |||
| int PropertySet::getIntValue (StringRef keyName, const int defaultValue) const noexcept | |||
| { | |||
| const ScopedLock sl (lock); | |||
| const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); | |||
| @@ -92,8 +90,7 @@ int PropertySet::getIntValue (const String& keyName, | |||
| : defaultValue; | |||
| } | |||
| double PropertySet::getDoubleValue (const String& keyName, | |||
| const double defaultValue) const noexcept | |||
| double PropertySet::getDoubleValue (StringRef keyName, const double defaultValue) const noexcept | |||
| { | |||
| const ScopedLock sl (lock); | |||
| const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); | |||
| @@ -105,8 +102,7 @@ double PropertySet::getDoubleValue (const String& keyName, | |||
| : defaultValue; | |||
| } | |||
| bool PropertySet::getBoolValue (const String& keyName, | |||
| const bool defaultValue) const noexcept | |||
| bool PropertySet::getBoolValue (StringRef keyName, const bool defaultValue) const noexcept | |||
| { | |||
| const ScopedLock sl (lock); | |||
| const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys); | |||
| @@ -118,7 +114,7 @@ bool PropertySet::getBoolValue (const String& keyName, | |||
| : defaultValue; | |||
| } | |||
| XmlElement* PropertySet::getXmlValue (const String& keyName) const | |||
| XmlElement* PropertySet::getXmlValue (StringRef keyName) const | |||
| { | |||
| return XmlDocument::parse (getValue (keyName)); | |||
| } | |||
| @@ -142,7 +138,7 @@ void PropertySet::setValue (const String& keyName, const var& v) | |||
| } | |||
| } | |||
| void PropertySet::removeValue (const String& keyName) | |||
| void PropertySet::removeValue (StringRef keyName) | |||
| { | |||
| if (keyName.isNotEmpty()) | |||
| { | |||
| @@ -163,7 +159,7 @@ void PropertySet::setValue (const String& keyName, const XmlElement* const xml) | |||
| : var (xml->createDocument (String::empty, true))); | |||
| } | |||
| bool PropertySet::containsKey (const String& keyName) const noexcept | |||
| bool PropertySet::containsKey (StringRef keyName) const noexcept | |||
| { | |||
| const ScopedLock sl (lock); | |||
| return properties.getAllKeys().contains (keyName, ignoreCaseOfKeys); | |||
| @@ -69,8 +69,7 @@ public: | |||
| @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 (const String& keyName, | |||
| const String& defaultReturnValue = String::empty) const noexcept; | |||
| String getValue (StringRef keyName, const String& defaultReturnValue = String::empty) const noexcept; | |||
| /** Returns one of the properties as an integer. | |||
| @@ -81,8 +80,7 @@ public: | |||
| @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 (const String& keyName, | |||
| const int defaultReturnValue = 0) const noexcept; | |||
| int getIntValue (StringRef keyName, int defaultReturnValue = 0) const noexcept; | |||
| /** Returns one of the properties as an double. | |||
| @@ -93,8 +91,7 @@ public: | |||
| @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 (const String& keyName, | |||
| const double defaultReturnValue = 0.0) const noexcept; | |||
| double getDoubleValue (StringRef keyName, double defaultReturnValue = 0.0) const noexcept; | |||
| /** Returns one of the properties as an boolean. | |||
| @@ -108,8 +105,7 @@ public: | |||
| @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 (const String& keyName, | |||
| const bool defaultReturnValue = false) const noexcept; | |||
| bool getBoolValue (StringRef keyName, bool defaultReturnValue = false) const noexcept; | |||
| /** Returns one of the properties as an XML element. | |||
| @@ -122,7 +118,7 @@ public: | |||
| @param keyName the name of the property to retrieve | |||
| */ | |||
| XmlElement* getXmlValue (const String& keyName) const; | |||
| XmlElement* getXmlValue (StringRef keyName) const; | |||
| //============================================================================== | |||
| /** Sets a named property. | |||
| @@ -150,10 +146,10 @@ public: | |||
| /** Deletes a property. | |||
| @param keyName the name of the property to delete. (This mustn't be an empty string) | |||
| */ | |||
| void removeValue (const String& keyName); | |||
| void removeValue (StringRef keyName); | |||
| /** Returns true if the properies include the given key. */ | |||
| bool containsKey (const String& keyName) const noexcept; | |||
| bool containsKey (StringRef keyName) const noexcept; | |||
| /** Removes all values. */ | |||
| void clear(); | |||
| @@ -340,66 +340,67 @@ int File::hashCode() const { return fullPath.hashCode(); } | |||
| int64 File::hashCode64() const { return fullPath.hashCode64(); } | |||
| //============================================================================== | |||
| bool File::isAbsolutePath (const String& path) | |||
| bool File::isAbsolutePath (StringRef path) | |||
| { | |||
| return path.startsWithChar (separator) | |||
| return path.text[0] == separator | |||
| #if JUCE_WINDOWS | |||
| || (path.isNotEmpty() && path[1] == ':'); | |||
| || (path.isNotEmpty() && path.text[1] == ':'); | |||
| #else | |||
| || path.startsWithChar ('~'); | |||
| || path.text[0] == '~'; | |||
| #endif | |||
| } | |||
| File File::getChildFile (String relativePath) const | |||
| File File::getChildFile (StringRef relativePath) const | |||
| { | |||
| if (isAbsolutePath (relativePath)) | |||
| return File (relativePath); | |||
| return File (String (relativePath.text)); | |||
| if (relativePath.text[0] != '.') | |||
| return File (addTrailingSeparator (fullPath) + relativePath); | |||
| String path (fullPath); | |||
| // It's relative, so remove any ../ or ./ bits at the start.. | |||
| if (relativePath[0] == '.') | |||
| #if JUCE_WINDOWS | |||
| if (relativePath.text.indexOf ((juce_wchar) '/') >= 0) | |||
| return getChildFile (String (relativePath.text).replaceCharacter ('/', '\\')); | |||
| #endif | |||
| while (relativePath[0] == '.') | |||
| { | |||
| #if JUCE_WINDOWS | |||
| relativePath = relativePath.replaceCharacter ('/', '\\'); | |||
| #endif | |||
| const juce_wchar secondChar = relativePath.text[1]; | |||
| while (relativePath[0] == '.') | |||
| if (secondChar == '.') | |||
| { | |||
| const juce_wchar secondChar = relativePath[1]; | |||
| const juce_wchar thirdChar = relativePath.text[2]; | |||
| if (secondChar == '.') | |||
| { | |||
| const juce_wchar thirdChar = relativePath[2]; | |||
| if (thirdChar == 0 || thirdChar == separator) | |||
| { | |||
| const int lastSlash = path.lastIndexOfChar (separator); | |||
| if (lastSlash >= 0) | |||
| path = path.substring (0, lastSlash); | |||
| relativePath = relativePath.substring (3); | |||
| } | |||
| else | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| else if (secondChar == separator) | |||
| if (thirdChar == 0 || thirdChar == separator) | |||
| { | |||
| relativePath = relativePath.substring (2); | |||
| const int lastSlash = path.lastIndexOfChar (separator); | |||
| if (lastSlash >= 0) | |||
| path = path.substring (0, lastSlash); | |||
| relativePath = relativePath.text + (thirdChar == 0 ? 2 : 3); | |||
| } | |||
| else | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| else if (secondChar == separator) | |||
| { | |||
| relativePath = relativePath.text + 2; | |||
| } | |||
| else | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| return File (addTrailingSeparator (path) + relativePath); | |||
| } | |||
| File File::getSiblingFile (const String& fileName) const | |||
| File File::getSiblingFile (StringRef fileName) const | |||
| { | |||
| return getParentDirectory().getChildFile (fileName); | |||
| } | |||
| @@ -602,23 +603,23 @@ String File::getFileExtension() const | |||
| return String::empty; | |||
| } | |||
| bool File::hasFileExtension (const String& possibleSuffix) const | |||
| bool File::hasFileExtension (StringRef possibleSuffix) const | |||
| { | |||
| if (possibleSuffix.isEmpty()) | |||
| return fullPath.lastIndexOfChar ('.') <= fullPath.lastIndexOfChar (separator); | |||
| const int semicolon = possibleSuffix.indexOfChar (0, ';'); | |||
| const int semicolon = possibleSuffix.text.indexOf ((juce_wchar) ';'); | |||
| if (semicolon >= 0) | |||
| { | |||
| return hasFileExtension (possibleSuffix.substring (0, semicolon).trimEnd()) | |||
| || hasFileExtension (possibleSuffix.substring (semicolon + 1).trimStart()); | |||
| return hasFileExtension (String (possibleSuffix.text).substring (0, semicolon).trimEnd()) | |||
| || hasFileExtension ((possibleSuffix.text + (semicolon + 1)).findEndOfWhitespace()); | |||
| } | |||
| else | |||
| { | |||
| if (fullPath.endsWithIgnoreCase (possibleSuffix)) | |||
| { | |||
| if (possibleSuffix.startsWithChar ('.')) | |||
| if (possibleSuffix.text[0] == '.') | |||
| return true; | |||
| const int dotPos = fullPath.length() - possibleSuffix.length() - 1; | |||
| @@ -631,7 +632,7 @@ bool File::hasFileExtension (const String& possibleSuffix) const | |||
| return false; | |||
| } | |||
| File File::withFileExtension (const String& newExtension) const | |||
| File File::withFileExtension (StringRef newExtension) const | |||
| { | |||
| if (fullPath.isEmpty()) | |||
| return File::nonexistent; | |||
| @@ -642,7 +643,7 @@ File File::withFileExtension (const String& newExtension) const | |||
| if (i >= 0) | |||
| filePart = filePart.substring (0, i); | |||
| if (newExtension.isNotEmpty() && ! newExtension.startsWithChar ('.')) | |||
| if (newExtension.isNotEmpty() && newExtension.text[0] != '.') | |||
| filePart << '.'; | |||
| return getSiblingFile (filePart + newExtension); | |||
| @@ -731,7 +732,7 @@ bool File::hasIdenticalContentTo (const File& other) const | |||
| if (in1.openedOk() && in2.openedOk()) | |||
| { | |||
| const int bufferSize = 4096; | |||
| HeapBlock <char> buffer1 (bufferSize), buffer2 (bufferSize); | |||
| HeapBlock<char> buffer1 (bufferSize), buffer2 (bufferSize); | |||
| for (;;) | |||
| { | |||
| @@ -874,7 +875,7 @@ String File::getRelativePathFrom (const File& dir) const | |||
| } | |||
| //============================================================================== | |||
| File File::createTempFile (const String& fileNameEnding) | |||
| File File::createTempFile (StringRef fileNameEnding) | |||
| { | |||
| const File tempFile (getSpecialLocation (tempDirectory) | |||
| .getChildFile ("temp_" + String::toHexString (Random::getSystemRandom().nextInt())) | |||
| @@ -203,7 +203,7 @@ public: | |||
| @see getFileExtension, withFileExtension, getFileNameWithoutExtension | |||
| */ | |||
| bool hasFileExtension (const String& extensionToTest) const; | |||
| bool hasFileExtension (StringRef extensionToTest) const; | |||
| /** Returns a version of this file with a different file extension. | |||
| @@ -215,7 +215,7 @@ public: | |||
| @see getFileName, getFileExtension, hasFileExtension, getFileNameWithoutExtension | |||
| */ | |||
| File withFileExtension (const String& newExtension) const; | |||
| File withFileExtension (StringRef newExtension) const; | |||
| /** Returns the last part of the filename, without its file extension. | |||
| @@ -255,7 +255,7 @@ public: | |||
| @see getSiblingFile, getParentDirectory, getRelativePathFrom, isAChildOf | |||
| */ | |||
| File getChildFile (String relativeOrAbsolutePath) const; | |||
| File getChildFile (StringRef relativeOrAbsolutePath) const; | |||
| /** Returns a file which is in the same directory as this one. | |||
| @@ -263,7 +263,7 @@ public: | |||
| @see getChildFile, getParentDirectory | |||
| */ | |||
| File getSiblingFile (const String& siblingFileName) const; | |||
| File getSiblingFile (StringRef siblingFileName) const; | |||
| //============================================================================== | |||
| /** Returns the directory that contains this file or directory. | |||
| @@ -852,7 +852,7 @@ public: | |||
| This will try to return the name of a non-existent temp file. | |||
| To get the temp folder, you can use getSpecialLocation (File::tempDirectory). | |||
| */ | |||
| static File createTempFile (const String& fileNameEnding); | |||
| static File createTempFile (StringRef fileNameEnding); | |||
| //============================================================================== | |||
| @@ -908,7 +908,7 @@ public: | |||
| static bool areFileNamesCaseSensitive(); | |||
| /** Returns true if the string seems to be a fully-specified absolute path. */ | |||
| static bool isAbsolutePath (const String& path); | |||
| static bool isAbsolutePath (StringRef path); | |||
| /** Creates a file that simply contains this string, without doing the sanity-checking | |||
| that the normal constructors do. | |||
| @@ -330,7 +330,9 @@ public: | |||
| { | |||
| if (v.isString()) | |||
| { | |||
| out << '"'; | |||
| writeString (out, v.toString().getCharPointer()); | |||
| out << '"'; | |||
| } | |||
| else if (v.isVoid()) | |||
| { | |||
| @@ -360,9 +362,6 @@ public: | |||
| } | |||
| } | |||
| private: | |||
| enum { indentSize = 2 }; | |||
| static void writeEscapedChar (OutputStream& out, const unsigned short value) | |||
| { | |||
| out << "\\u" << String::toHexString ((int) value).paddedLeft ('0', 4); | |||
| @@ -370,15 +369,13 @@ private: | |||
| static void writeString (OutputStream& out, String::CharPointerType t) | |||
| { | |||
| out << '"'; | |||
| for (;;) | |||
| { | |||
| const juce_wchar c (t.getAndAdvance()); | |||
| switch (c) | |||
| { | |||
| case 0: out << '"'; return; | |||
| case 0: return; | |||
| case '\"': out << "\\\""; break; | |||
| case '\\': out << "\\\\"; break; | |||
| @@ -472,8 +469,9 @@ private: | |||
| if (! allOnOneLine) | |||
| writeSpaces (out, indentLevel + indentSize); | |||
| out << '"'; | |||
| writeString (out, v->name); | |||
| out << ": "; | |||
| out << "\": "; | |||
| write (out, v->value, indentLevel + indentSize, allOnOneLine); | |||
| if (v->nextListItem.get() != nullptr) | |||
| @@ -494,6 +492,8 @@ private: | |||
| out << '}'; | |||
| } | |||
| enum { indentSize = 2 }; | |||
| }; | |||
| //============================================================================== | |||
| @@ -534,6 +534,14 @@ void JSON::writeToStream (OutputStream& output, const var& data, const bool allO | |||
| JSONFormatter::write (output, data, 0, allOnOneLine); | |||
| } | |||
| String JSON::escapeString (StringRef s) | |||
| { | |||
| MemoryOutputStream mo; | |||
| JSONFormatter::writeString (mo, s.text); | |||
| return mo.toString(); | |||
| } | |||
| //============================================================================== | |||
| //============================================================================== | |||
| #if JUCE_UNIT_TESTS | |||
| @@ -616,8 +624,7 @@ public: | |||
| void runTest() | |||
| { | |||
| beginTest ("JSON"); | |||
| Random r; | |||
| r.setSeedRandomly(); | |||
| Random r = getRandom(); | |||
| expect (JSON::parse (String::empty) == var::null); | |||
| expect (JSON::parse ("{}").isObject()); | |||
| @@ -103,6 +103,9 @@ public: | |||
| const var& objectToFormat, | |||
| bool allOnOneLine = false); | |||
| /** Returns a version of a string with any extended characters escaped. */ | |||
| static String escapeString (StringRef); | |||
| private: | |||
| //============================================================================== | |||
| JSON(); // This class can't be instantiated - just use its static methods. | |||
| @@ -119,7 +119,7 @@ | |||
| /* Config: JUCE_CATCH_UNHANDLED_EXCEPTIONS | |||
| If enabled, this will add some exception-catching code to forward unhandled exceptions | |||
| to your JUCEApplication::unhandledException() callback. | |||
| to your JUCEApplicationBase::unhandledException() callback. | |||
| */ | |||
| #ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS | |||
| //#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1 | |||
| @@ -145,6 +145,7 @@ | |||
| namespace juce | |||
| { | |||
| class StringRef; | |||
| class MemoryBlock; | |||
| class File; | |||
| class InputStream; | |||
| @@ -179,6 +180,7 @@ extern JUCE_API void JUCE_CALLTYPE logAssertion (const char* file, int line) noe | |||
| #endif | |||
| #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" | |||
| @@ -1,7 +1,7 @@ | |||
| { | |||
| "id": "juce_core", | |||
| "name": "JUCE core classes", | |||
| "version": "2.1.2", | |||
| "version": "2.1.3", | |||
| "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 Permissive", | |||
| @@ -953,10 +953,10 @@ String BigInteger::toString (const int base, const int minimumNumCharacters) con | |||
| return isNegative() ? "-" + s : s; | |||
| } | |||
| void BigInteger::parseString (const String& text, const int base) | |||
| void BigInteger::parseString (StringRef text, const int base) | |||
| { | |||
| clear(); | |||
| String::CharPointerType t (text.getCharPointer().findEndOfWhitespace()); | |||
| String::CharPointerType t (text.text.findEndOfWhitespace()); | |||
| setNegative (*t == (juce_wchar) '-'); | |||
| @@ -282,7 +282,7 @@ public: | |||
| Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex). | |||
| Any invalid characters will be ignored. | |||
| */ | |||
| void parseString (const String& text, int base); | |||
| void parseString (StringRef text, int base); | |||
| //============================================================================== | |||
| /** Turns the number into a block of binary data. | |||
| @@ -26,13 +26,11 @@ | |||
| ============================================================================== | |||
| */ | |||
| Random::Random (const int64 seedValue) noexcept | |||
| : seed (seedValue) | |||
| Random::Random (const int64 seedValue) noexcept : seed (seedValue) | |||
| { | |||
| } | |||
| Random::Random() | |||
| : seed (1) | |||
| Random::Random() : seed (1) | |||
| { | |||
| setSeedRandomly(); | |||
| } | |||
| @@ -163,24 +161,20 @@ public: | |||
| { | |||
| beginTest ("Random"); | |||
| for (int j = 10; --j >= 0;) | |||
| Random r = getRandom(); | |||
| for (int i = 2000; --i >= 0;) | |||
| { | |||
| Random r; | |||
| r.setSeedRandomly(); | |||
| for (int i = 20; --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); | |||
| } | |||
| 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); | |||
| } | |||
| } | |||
| }; | |||
| @@ -59,7 +59,6 @@ public: | |||
| ~Random() noexcept; | |||
| /** Returns the next random 32 bit integer. | |||
| @returns a random integer from the full range 0x80000000 to 0x7fffffff | |||
| */ | |||
| int nextInt() noexcept; | |||
| @@ -71,29 +70,24 @@ public: | |||
| int nextInt (int maxValue) 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 to 1.0 | |||
| */ | |||
| float nextFloat() noexcept; | |||
| /** Returns the next random floating-point number. | |||
| @returns a random value in the range 0 to 1.0 | |||
| */ | |||
| double nextDouble() noexcept; | |||
| /** Returns the next random boolean value. | |||
| */ | |||
| /** 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); | |||
| @@ -108,6 +102,9 @@ public: | |||
| /** 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. | |||
| @@ -317,11 +317,11 @@ void MemoryBlock::setBitRange (const size_t bitRangeStart, size_t numBits, int b | |||
| } | |||
| //============================================================================== | |||
| void MemoryBlock::loadFromHexString (const String& hex) | |||
| void MemoryBlock::loadFromHexString (StringRef hex) | |||
| { | |||
| ensureSize ((size_t) hex.length() >> 1); | |||
| char* dest = data; | |||
| String::CharPointerType t (hex.getCharPointer()); | |||
| String::CharPointerType t (hex.text); | |||
| for (;;) | |||
| { | |||
| @@ -373,27 +373,27 @@ String MemoryBlock::toBase64Encoding() const | |||
| return destString; | |||
| } | |||
| bool MemoryBlock::fromBase64Encoding (const String& s) | |||
| bool MemoryBlock::fromBase64Encoding (StringRef s) | |||
| { | |||
| const int startPos = s.indexOfChar ('.') + 1; | |||
| String::CharPointerType dot (CharacterFunctions::find (s.text, CharPointer_ASCII ("."))); | |||
| if (startPos <= 0) | |||
| if (dot.isEmpty()) | |||
| return false; | |||
| const int numBytesNeeded = s.substring (0, startPos - 1).getIntValue(); | |||
| const int numBytesNeeded = String (s.text, dot).getIntValue(); | |||
| setSize ((size_t) numBytesNeeded, true); | |||
| const int numChars = s.length() - startPos; | |||
| String::CharPointerType srcChars (s.getCharPointer()); | |||
| srcChars += startPos; | |||
| String::CharPointerType srcChars (dot + 1); | |||
| int pos = 0; | |||
| for (int i = 0; i < numChars; ++i) | |||
| for (;;) | |||
| { | |||
| const char c = (char) srcChars.getAndAdvance(); | |||
| if (c == 0) | |||
| return true; | |||
| for (int j = 0; j < 64; ++j) | |||
| { | |||
| if (base64EncodingTable[j] == c) | |||
| @@ -404,6 +404,4 @@ bool MemoryBlock::fromBase64Encoding (const String& s) | |||
| } | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| @@ -206,7 +206,7 @@ public: | |||
| @see String::toHexString() | |||
| */ | |||
| void loadFromHexString (const String& sourceHexString); | |||
| void loadFromHexString (StringRef sourceHexString); | |||
| //============================================================================== | |||
| /** Sets a number of bits in the memory block, treating it as a long binary sequence. */ | |||
| @@ -235,7 +235,7 @@ public: | |||
| @see toBase64Encoding | |||
| */ | |||
| bool fromBase64Encoding (const String& encodedString); | |||
| bool fromBase64Encoding (StringRef encodedString); | |||
| private: | |||
| @@ -26,32 +26,13 @@ | |||
| ============================================================================== | |||
| */ | |||
| namespace | |||
| { | |||
| int64 getRandomSeedFromMACAddresses() | |||
| { | |||
| Array<MACAddress> result; | |||
| MACAddress::findAllAddresses (result); | |||
| Random r; | |||
| for (int i = 0; i < result.size(); ++i) | |||
| r.combineSeed (result[i].toInt64()); | |||
| return r.nextInt64(); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| Uuid::Uuid() | |||
| { | |||
| // The normal random seeding is pretty good, but we'll throw some MAC addresses | |||
| // into the mix too, to make it very very unlikely that two UUIDs will ever be the same.. | |||
| static Random r1 (getRandomSeedFromMACAddresses()); | |||
| Random r2; | |||
| Random r; | |||
| for (size_t i = 0; i < sizeof (uuid); ++i) | |||
| uuid[i] = (uint8) (r1.nextInt() ^ r2.nextInt()); | |||
| uuid[i] = (uint8) (r.nextInt (256)); | |||
| } | |||
| Uuid::~Uuid() noexcept {} | |||
| @@ -70,6 +51,11 @@ Uuid& Uuid::operator= (const Uuid& other) noexcept | |||
| 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); } | |||
| Uuid Uuid::null() noexcept | |||
| { | |||
| return Uuid ((const uint8*) nullptr); | |||
| } | |||
| bool Uuid::isNull() const noexcept | |||
| { | |||
| for (size_t i = 0; i < sizeof (uuid); ++i) | |||
| @@ -98,7 +84,7 @@ Uuid& Uuid::operator= (const String& uuidString) | |||
| return *this; | |||
| } | |||
| Uuid::Uuid (const uint8* const rawData) | |||
| Uuid::Uuid (const uint8* const rawData) noexcept | |||
| { | |||
| operator= (rawData); | |||
| } | |||
| @@ -51,17 +51,20 @@ public: | |||
| ~Uuid() noexcept; | |||
| /** Creates a copy of another UUID. */ | |||
| Uuid (const Uuid& other) noexcept; | |||
| Uuid (const Uuid&) noexcept; | |||
| /** Copies another UUID. */ | |||
| Uuid& operator= (const Uuid& other) noexcept; | |||
| Uuid& operator= (const Uuid&) noexcept; | |||
| //============================================================================== | |||
| /** Returns true if the ID is zero. */ | |||
| bool isNull() const noexcept; | |||
| bool operator== (const Uuid& other) const noexcept; | |||
| bool operator!= (const Uuid& other) const noexcept; | |||
| /** Returns a null Uuid object. */ | |||
| static Uuid null() noexcept; | |||
| bool operator== (const Uuid&) const noexcept; | |||
| bool operator!= (const Uuid&) const noexcept; | |||
| //============================================================================== | |||
| /** Returns a stringified version of this UUID. | |||
| @@ -95,7 +98,7 @@ public: | |||
| /** Creates a UUID from a 16-byte array. | |||
| @see getRawData | |||
| */ | |||
| Uuid (const uint8* rawData); | |||
| Uuid (const uint8* rawData) noexcept; | |||
| /** Sets this UUID from 16-bytes of raw data. */ | |||
| Uuid& operator= (const uint8* rawData) noexcept; | |||
| @@ -26,8 +26,7 @@ | |||
| ============================================================================== | |||
| */ | |||
| JNIClassBase::JNIClassBase (const char* classPath_) | |||
| : classPath (classPath_), classRef (0) | |||
| JNIClassBase::JNIClassBase (const char* cp) : classPath (cp), classRef (0) | |||
| { | |||
| getClasses().add (this); | |||
| } | |||
| @@ -129,8 +128,7 @@ AndroidSystem::AndroidSystem() : screenWidth (0), screenHeight (0), dpi (160) | |||
| { | |||
| } | |||
| void AndroidSystem::initialise (JNIEnv* env, jobject activity_, | |||
| jstring appFile_, jstring appDataDir_) | |||
| void AndroidSystem::initialise (JNIEnv* env, jobject act, jstring file, jstring dataDir) | |||
| { | |||
| screenWidth = screenHeight = 0; | |||
| dpi = 160; | |||
| @@ -141,9 +139,9 @@ void AndroidSystem::initialise (JNIEnv* env, jobject activity_, | |||
| systemInitialised = true; | |||
| #endif | |||
| activity = GlobalRef (activity_); | |||
| appFile = juceString (env, appFile_); | |||
| appDataDir = juceString (env, appDataDir_); | |||
| activity = GlobalRef (act); | |||
| appFile = juceString (env, file); | |||
| appDataDir = juceString (env, dataDir); | |||
| } | |||
| void AndroidSystem::shutdown (JNIEnv* env) | |||
| @@ -162,14 +160,12 @@ AndroidSystem android; | |||
| //============================================================================== | |||
| namespace AndroidStatsHelpers | |||
| { | |||
| //============================================================================== | |||
| #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ | |||
| STATICMETHOD (getProperty, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;") | |||
| DECLARE_JNI_CLASS (SystemClass, "java/lang/System"); | |||
| #undef JNI_CLASS_MEMBERS | |||
| //============================================================================== | |||
| String getSystemProperty (const String& name) | |||
| { | |||
| return juceString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (SystemClass, | |||
| @@ -177,7 +173,6 @@ namespace AndroidStatsHelpers | |||
| javaString (name).get()))); | |||
| } | |||
| //============================================================================== | |||
| String getLocaleValue (bool isRegion) | |||
| { | |||
| return juceString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (JuceAppActivity, | |||
| @@ -236,16 +231,13 @@ int SystemStats::getPageSize() | |||
| //============================================================================== | |||
| String SystemStats::getLogonName() | |||
| { | |||
| const char* user = getenv ("USER"); | |||
| if (const char* user = getenv ("USER")) | |||
| return CharPointer_UTF8 (user); | |||
| if (user == 0) | |||
| { | |||
| struct passwd* const pw = getpwuid (getuid()); | |||
| if (pw != 0) | |||
| user = pw->pw_name; | |||
| } | |||
| if (struct passwd* const pw = getpwuid (getuid())) | |||
| return CharPointer_UTF8 (pw->pw_name); | |||
| return CharPointer_UTF8 (user); | |||
| return String::empty; | |||
| } | |||
| String SystemStats::getFullUserName() | |||
| @@ -165,13 +165,13 @@ File File::getSpecialLocation (const SpecialLocationType type) | |||
| { | |||
| case userHomeDirectory: | |||
| { | |||
| const char* homeDir = getenv ("HOME"); | |||
| if (const char* homeDir = getenv ("HOME")) | |||
| return File (CharPointer_UTF8 (homeDir)); | |||
| if (homeDir == nullptr) | |||
| if (struct passwd* const pw = getpwuid (getuid())) | |||
| homeDir = pw->pw_dir; | |||
| if (struct passwd* const pw = getpwuid (getuid())) | |||
| return File (CharPointer_UTF8 (pw->pw_dir)); | |||
| return File (CharPointer_UTF8 (homeDir)); | |||
| return File::nonexistent; | |||
| } | |||
| case userDocumentsDirectory: return resolveXDGFolder ("XDG_DOCUMENTS_DIR", "~"); | |||
| @@ -179,7 +179,7 @@ File File::getSpecialLocation (const SpecialLocationType type) | |||
| case userMoviesDirectory: return resolveXDGFolder ("XDG_VIDEOS_DIR", "~"); | |||
| case userPicturesDirectory: return resolveXDGFolder ("XDG_PICTURES_DIR", "~"); | |||
| case userDesktopDirectory: return resolveXDGFolder ("XDG_DESKTOP_DIR", "~/Desktop"); | |||
| case userApplicationDataDirectory: return File ("~"); | |||
| case userApplicationDataDirectory: return resolveXDGFolder ("XDG_CONFIG_HOME", "~"); | |||
| case commonDocumentsDirectory: | |||
| case commonApplicationDataDirectory: return File ("/var"); | |||
| case globalApplicationsDirectory: return File ("/usr"); | |||
| @@ -247,10 +247,9 @@ bool File::moveToTrash() const | |||
| class DirectoryIterator::NativeIterator::Pimpl | |||
| { | |||
| public: | |||
| Pimpl (const File& directory, const String& wildCard_) | |||
| Pimpl (const File& directory, const String& wc) | |||
| : parentDir (File::addTrailingSeparator (directory.getFullPathName())), | |||
| wildCard (wildCard_), | |||
| dir (opendir (directory.getFullPathName().toUTF8())) | |||
| wildCard (wc), dir (opendir (directory.getFullPathName().toUTF8())) | |||
| { | |||
| } | |||
| @@ -96,13 +96,13 @@ int SystemStats::getPageSize() | |||
| //============================================================================== | |||
| String SystemStats::getLogonName() | |||
| { | |||
| const char* user = getenv ("USER"); | |||
| if (const char* user = getenv ("USER")) | |||
| return CharPointer_UTF8 (user); | |||
| if (user == nullptr) | |||
| if (passwd* const pw = getpwuid (getuid())) | |||
| user = pw->pw_name; | |||
| if (struct passwd* const pw = getpwuid (getuid())) | |||
| return CharPointer_UTF8 (pw->pw_name); | |||
| return CharPointer_UTF8 (user); | |||
| return String::empty; | |||
| } | |||
| String SystemStats::getFullUserName() | |||
| @@ -205,7 +205,7 @@ File File::getSpecialLocation (const SpecialLocationType type) | |||
| { | |||
| File tmp ("~/Library/Caches/" + juce_getExecutableFile().getFileNameWithoutExtension()); | |||
| tmp.createDirectory(); | |||
| return tmp.getFullPathName(); | |||
| return File (tmp.getFullPathName()); | |||
| } | |||
| #endif | |||
| case userMusicDirectory: resultPath = "~/Music"; break; | |||
| @@ -245,7 +245,7 @@ File File::getSpecialLocation (const SpecialLocationType type) | |||
| buffer.calloc (size + 8); | |||
| _NSGetExecutablePath (buffer.getData(), &size); | |||
| return String::fromUTF8 (buffer, (int) size); | |||
| return File (String::fromUTF8 (buffer, (int) size)); | |||
| } | |||
| default: | |||
| @@ -250,18 +250,19 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| struct DelegateClass : public ObjCClass <NSObject> | |||
| struct DelegateClass : public ObjCClass<NSObject> | |||
| { | |||
| DelegateClass() : ObjCClass <NSObject> ("JUCEAppDelegate_") | |||
| DelegateClass() : ObjCClass<NSObject> ("JUCEAppDelegate_") | |||
| { | |||
| addIvar <URLConnectionState*> ("state"); | |||
| addIvar<URLConnectionState*> ("state"); | |||
| addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse, "v@:@@"); | |||
| addMethod (@selector (connection:didFailWithError:), didFailWithError, "v@:@@"); | |||
| addMethod (@selector (connection:didReceiveData:), didReceiveData, "v@:@@"); | |||
| addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse, "v@:@@"); | |||
| addMethod (@selector (connection:didFailWithError:), didFailWithError, "v@:@@"); | |||
| addMethod (@selector (connection:didReceiveData:), didReceiveData, "v@:@@"); | |||
| addMethod (@selector (connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:totalBytesExpectedToWrite:), | |||
| connectionDidSendBodyData, "v@:@iii"); | |||
| addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@"); | |||
| connectionDidSendBodyData, "v@:@iii"); | |||
| addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@"); | |||
| addMethod (@selector (connection:willSendRequest:redirectResponse:), willSendRequest, "@@:@@"); | |||
| registerClass(); | |||
| } | |||
| @@ -285,6 +286,11 @@ private: | |||
| getState (self)->didReceiveData (newData); | |||
| } | |||
| static NSURLRequest* willSendRequest (id, SEL, NSURLConnection*, NSURLRequest* request, NSURLResponse*) | |||
| { | |||
| return request; | |||
| } | |||
| static void connectionDidSendBodyData (id self, SEL, NSURLConnection*, NSInteger, NSInteger totalBytesWritten, NSInteger totalBytesExpected) | |||
| { | |||
| getState (self)->didSendBodyData (totalBytesWritten, totalBytesExpected); | |||
| @@ -317,9 +323,8 @@ public: | |||
| if (responseHeaders != nullptr && connection != nullptr && connection->headers != nil) | |||
| { | |||
| NSEnumerator* enumerator = [connection->headers keyEnumerator]; | |||
| NSString* key; | |||
| while ((key = [enumerator nextObject]) != nil) | |||
| while (NSString* key = [enumerator nextObject]) | |||
| responseHeaders->set (nsStringToJuce (key), | |||
| nsStringToJuce ((NSString*) [connection->headers objectForKey: key])); | |||
| } | |||
| @@ -341,7 +346,7 @@ public: | |||
| JUCE_AUTORELEASEPOOL | |||
| { | |||
| const int bytesRead = connection->read (static_cast <char*> (buffer), bytesToRead); | |||
| const int bytesRead = connection->read (static_cast<char*> (buffer), bytesToRead); | |||
| position += bytesRead; | |||
| if (bytesRead == 0) | |||
| @@ -379,8 +384,7 @@ private: | |||
| const bool isPost; | |||
| const int timeOutMs; | |||
| void createConnection (URL::OpenStreamProgressCallback* progressCallback, | |||
| void* progressCallbackContext) | |||
| void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext) | |||
| { | |||
| jassert (connection == nullptr); | |||
| @@ -424,9 +428,9 @@ InputStream* URL::createNativeStream (const String& address, bool isPost, const | |||
| OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, | |||
| const String& headers, const int timeOutMs, StringPairArray* responseHeaders) | |||
| { | |||
| ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData, | |||
| progressCallback, progressCallbackContext, | |||
| headers, timeOutMs, responseHeaders)); | |||
| ScopedPointer<WebInputStream> wi (new WebInputStream (address, isPost, postData, | |||
| progressCallback, progressCallbackContext, | |||
| headers, timeOutMs, responseHeaders)); | |||
| return wi->isError() ? nullptr : wi.release(); | |||
| } | |||
| @@ -34,29 +34,14 @@ CriticalSection::CriticalSection() noexcept | |||
| #if ! JUCE_ANDROID | |||
| pthread_mutexattr_setprotocol (&atts, PTHREAD_PRIO_INHERIT); | |||
| #endif | |||
| pthread_mutex_init (&internal, &atts); | |||
| } | |||
| CriticalSection::~CriticalSection() noexcept | |||
| { | |||
| pthread_mutex_destroy (&internal); | |||
| } | |||
| void CriticalSection::enter() const noexcept | |||
| { | |||
| pthread_mutex_lock (&internal); | |||
| } | |||
| bool CriticalSection::tryEnter() const noexcept | |||
| { | |||
| return pthread_mutex_trylock (&internal) == 0; | |||
| } | |||
| void CriticalSection::exit() const noexcept | |||
| { | |||
| pthread_mutex_unlock (&internal); | |||
| pthread_mutex_init (&lock, &atts); | |||
| pthread_mutexattr_destroy (&atts); | |||
| } | |||
| CriticalSection::~CriticalSection() noexcept { pthread_mutex_destroy (&lock); } | |||
| void CriticalSection::enter() const noexcept { pthread_mutex_lock (&lock); } | |||
| bool CriticalSection::tryEnter() const noexcept { return pthread_mutex_trylock (&lock) == 0; } | |||
| void CriticalSection::exit() const noexcept { pthread_mutex_unlock (&lock); } | |||
| //============================================================================== | |||
| WaitableEvent::WaitableEvent (const bool useManualReset) noexcept | |||
| @@ -58,7 +58,7 @@ public: | |||
| if (HttpQueryInfo (request, HTTP_QUERY_RAW_HEADERS_CRLF, buffer.getData(), &bufferSizeBytes, 0)) | |||
| { | |||
| StringArray headersArray; | |||
| headersArray.addLines (reinterpret_cast <const WCHAR*> (buffer.getData())); | |||
| headersArray.addLines (String (reinterpret_cast<const WCHAR*> (buffer.getData()))); | |||
| for (int i = 0; i < headersArray.size(); ++i) | |||
| { | |||
| @@ -218,7 +218,7 @@ bool WindowsRegistry::registerFileAssociation (const String& fileExtension, | |||
| && setValue (key + "\\shell\\open\\command\\", targetExecutable.getFullPathName() + " \"%1\"", mode) | |||
| && (iconResourceNumber == 0 | |||
| || setValue (key + "\\DefaultIcon\\", | |||
| targetExecutable.getFullPathName() + "," + String (-iconResourceNumber))); | |||
| targetExecutable.getFullPathName() + "," + String (iconResourceNumber))); | |||
| } | |||
| // These methods are deprecated: | |||
| @@ -28,6 +28,13 @@ | |||
| HWND juce_messageWindowHandle = 0; // (this is used by other parts of the codebase) | |||
| void* getUser32Function (const char* functionName) | |||
| { | |||
| HMODULE module = GetModuleHandleA ("user32.dll"); | |||
| jassert (module != 0); | |||
| return (void*) GetProcAddress (module, functionName); | |||
| } | |||
| //============================================================================== | |||
| #if ! JUCE_USE_INTRINSICS | |||
| // In newer compilers, the inline versions of these are used (in juce_Atomic.h), but in | |||
| @@ -55,59 +62,33 @@ __int64 juce_InterlockedCompareExchange64 (volatile __int64* value, __int64 newV | |||
| CriticalSection::CriticalSection() noexcept | |||
| { | |||
| // (just to check the MS haven't changed this structure and broken things...) | |||
| #if JUCE_VC7_OR_EARLIER | |||
| #if JUCE_VC7_OR_EARLIER | |||
| static_jassert (sizeof (CRITICAL_SECTION) <= 24); | |||
| #else | |||
| static_jassert (sizeof (CRITICAL_SECTION) <= sizeof (internal)); | |||
| #endif | |||
| InitializeCriticalSection ((CRITICAL_SECTION*) internal); | |||
| } | |||
| CriticalSection::~CriticalSection() noexcept | |||
| { | |||
| DeleteCriticalSection ((CRITICAL_SECTION*) internal); | |||
| } | |||
| #else | |||
| static_jassert (sizeof (CRITICAL_SECTION) <= sizeof (lock)); | |||
| #endif | |||
| void CriticalSection::enter() const noexcept | |||
| { | |||
| EnterCriticalSection ((CRITICAL_SECTION*) internal); | |||
| InitializeCriticalSection ((CRITICAL_SECTION*) lock); | |||
| } | |||
| bool CriticalSection::tryEnter() const noexcept | |||
| { | |||
| return TryEnterCriticalSection ((CRITICAL_SECTION*) internal) != FALSE; | |||
| } | |||
| CriticalSection::~CriticalSection() noexcept { DeleteCriticalSection ((CRITICAL_SECTION*) lock); } | |||
| void CriticalSection::enter() const noexcept { EnterCriticalSection ((CRITICAL_SECTION*) lock); } | |||
| bool CriticalSection::tryEnter() const noexcept { return TryEnterCriticalSection ((CRITICAL_SECTION*) lock) != FALSE; } | |||
| void CriticalSection::exit() const noexcept { LeaveCriticalSection ((CRITICAL_SECTION*) lock); } | |||
| void CriticalSection::exit() const noexcept | |||
| { | |||
| LeaveCriticalSection ((CRITICAL_SECTION*) internal); | |||
| } | |||
| //============================================================================== | |||
| WaitableEvent::WaitableEvent (const bool manualReset) noexcept | |||
| : internal (CreateEvent (0, manualReset ? TRUE : FALSE, FALSE, 0)) | |||
| { | |||
| } | |||
| : handle (CreateEvent (0, manualReset ? TRUE : FALSE, FALSE, 0)) {} | |||
| WaitableEvent::~WaitableEvent() noexcept | |||
| { | |||
| CloseHandle (internal); | |||
| } | |||
| bool WaitableEvent::wait (const int timeOutMillisecs) const noexcept | |||
| { | |||
| return WaitForSingleObject (internal, (DWORD) timeOutMillisecs) == WAIT_OBJECT_0; | |||
| } | |||
| WaitableEvent::~WaitableEvent() noexcept { CloseHandle (handle); } | |||
| void WaitableEvent::signal() const noexcept | |||
| { | |||
| SetEvent (internal); | |||
| } | |||
| void WaitableEvent::signal() const noexcept { SetEvent (handle); } | |||
| void WaitableEvent::reset() const noexcept { ResetEvent (handle); } | |||
| void WaitableEvent::reset() const noexcept | |||
| bool WaitableEvent::wait (const int timeOutMs) const noexcept | |||
| { | |||
| ResetEvent (internal); | |||
| return WaitForSingleObject (handle, (DWORD) timeOutMs) == WAIT_OBJECT_0; | |||
| } | |||
| //============================================================================== | |||
| @@ -229,17 +210,15 @@ static SleepEvent sleepEvent; | |||
| void JUCE_CALLTYPE Thread::sleep (const int millisecs) | |||
| { | |||
| jassert (millisecs >= 0); | |||
| if (millisecs >= 10 || sleepEvent.handle == 0) | |||
| { | |||
| Sleep ((DWORD) millisecs); | |||
| } | |||
| else | |||
| { | |||
| // unlike Sleep() this is guaranteed to return to the current thread after | |||
| // the time expires, so we'll use this for short waits, which are more likely | |||
| // to need to be accurate | |||
| WaitForSingleObject (sleepEvent.handle, (DWORD) millisecs); | |||
| } | |||
| } | |||
| void Thread::yield() | |||
| @@ -250,7 +229,7 @@ void Thread::yield() | |||
| //============================================================================== | |||
| static int lastProcessPriority = -1; | |||
| // called by WindowDriver because Windows does weird things to process priority | |||
| // called when the app gains focus because Windows does weird things to process priority | |||
| // when you swap apps, and this forces an update when the app is brought to the front. | |||
| void juce_repeatLastProcessPriority() | |||
| { | |||
| @@ -30,8 +30,7 @@ URL::URL() | |||
| { | |||
| } | |||
| URL::URL (const String& url_) | |||
| : url (url_) | |||
| URL::URL (const String& u) : url (u) | |||
| { | |||
| int i = url.indexOfChar ('?'); | |||
| @@ -198,9 +197,11 @@ namespace URLHelpers | |||
| data << getMangledParameters (url) | |||
| << url.getPostData(); | |||
| // just a short text attachment, so use simple url encoding.. | |||
| headers << "Content-Type: application/x-www-form-urlencoded\r\nContent-length: " | |||
| << (int) data.getDataSize() << "\r\n"; | |||
| // if the user-supplied headers didn't contain a content-type, add one now.. | |||
| if (! headers.containsIgnoreCase ("Content-Type")) | |||
| headers << "Content-Type: application/x-www-form-urlencoded\r\n"; | |||
| headers << "Content-length: " << (int) data.getDataSize() << "\r\n"; | |||
| } | |||
| } | |||
| @@ -313,25 +314,25 @@ bool URL::isProbablyAnEmailAddress (const String& possibleEmailAddress) | |||
| return atSign > 0 | |||
| && possibleEmailAddress.lastIndexOfChar ('.') > (atSign + 1) | |||
| && (! possibleEmailAddress.endsWithChar ('.')); | |||
| && ! possibleEmailAddress.endsWithChar ('.'); | |||
| } | |||
| //============================================================================== | |||
| InputStream* URL::createInputStream (const bool usePostCommand, | |||
| OpenStreamProgressCallback* const progressCallback, | |||
| void* const progressCallbackContext, | |||
| const String& extraHeaders, | |||
| String headers, | |||
| const int timeOutMs, | |||
| StringPairArray* const responseHeaders) const | |||
| { | |||
| String headers; | |||
| MemoryBlock headersAndPostData; | |||
| if (! headers.endsWithChar ('\n')) | |||
| headers << "\r\n"; | |||
| if (usePostCommand) | |||
| URLHelpers::createHeadersAndPostData (*this, headers, headersAndPostData); | |||
| headers += extraHeaders; | |||
| if (! headers.endsWithChar ('\n')) | |||
| headers << "\r\n"; | |||
| @@ -344,7 +345,7 @@ InputStream* URL::createInputStream (const bool usePostCommand, | |||
| bool URL::readEntireBinaryStream (MemoryBlock& destData, | |||
| const bool usePostCommand) const | |||
| { | |||
| const ScopedPointer <InputStream> in (createInputStream (usePostCommand)); | |||
| const ScopedPointer<InputStream> in (createInputStream (usePostCommand)); | |||
| if (in != nullptr) | |||
| { | |||
| @@ -357,7 +358,7 @@ bool URL::readEntireBinaryStream (MemoryBlock& destData, | |||
| String URL::readEntireTextStream (const bool usePostCommand) const | |||
| { | |||
| const ScopedPointer <InputStream> in (createInputStream (usePostCommand)); | |||
| const ScopedPointer<InputStream> in (createInputStream (usePostCommand)); | |||
| if (in != nullptr) | |||
| return in->readEntireStreamAsString(); | |||
| @@ -391,10 +392,10 @@ URL URL::withFileToUpload (const String& parameterName, | |||
| return u; | |||
| } | |||
| URL URL::withPOSTData (const String& postData_) const | |||
| URL URL::withPOSTData (const String& newPostData) const | |||
| { | |||
| URL u (*this); | |||
| u.postData = postData_; | |||
| u.postData = newPostData; | |||
| return u; | |||
| } | |||
| @@ -251,7 +251,7 @@ public: | |||
| InputStream* createInputStream (bool usePostCommand, | |||
| OpenStreamProgressCallback* progressCallback = nullptr, | |||
| void* progressCallbackContext = nullptr, | |||
| const String& extraHeaders = String::empty, | |||
| String extraHeaders = String::empty, | |||
| int connectionTimeOutMs = 0, | |||
| StringPairArray* responseHeaders = nullptr) const; | |||
| @@ -104,12 +104,12 @@ public: | |||
| void runTest() | |||
| { | |||
| beginTest ("Basics"); | |||
| Random r; | |||
| Random r = getRandom(); | |||
| int randomInt = r.nextInt(); | |||
| int64 randomInt64 = r.nextInt64(); | |||
| double randomDouble = r.nextDouble(); | |||
| String randomString (createRandomWideCharString()); | |||
| String randomString (createRandomWideCharString (r)); | |||
| MemoryOutputStream mo; | |||
| mo.writeInt (randomInt); | |||
| @@ -132,10 +132,9 @@ public: | |||
| expect (mi.readDoubleBigEndian() == randomDouble); | |||
| } | |||
| static String createRandomWideCharString() | |||
| static String createRandomWideCharString (Random& r) | |||
| { | |||
| juce_wchar buffer [50] = { 0 }; | |||
| Random r; | |||
| for (int i = 0; i < numElementsInArray (buffer) - 1; ++i) | |||
| { | |||
| @@ -222,17 +222,17 @@ namespace juce | |||
| #if ! JUCE_MODULE_AVAILABLE_juce_gui_basics | |||
| #define JUCE_CATCH_EXCEPTION JUCE_CATCH_ALL | |||
| #else | |||
| /** Used in try-catch blocks, this macro will send exceptions to the JUCEApplication | |||
| /** Used in try-catch blocks, this macro will send exceptions to the JUCEApplicationBase | |||
| object so they can be logged by the application if it wants to. | |||
| */ | |||
| #define JUCE_CATCH_EXCEPTION \ | |||
| catch (const std::exception& e) \ | |||
| { \ | |||
| juce::JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__); \ | |||
| juce::JUCEApplicationBase::sendUnhandledException (&e, __FILE__, __LINE__); \ | |||
| } \ | |||
| catch (...) \ | |||
| { \ | |||
| juce::JUCEApplication::sendUnhandledException (nullptr, __FILE__, __LINE__); \ | |||
| juce::JUCEApplicationBase::sendUnhandledException (nullptr, __FILE__, __LINE__); \ | |||
| } | |||
| #endif | |||
| @@ -36,7 +36,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 2 | |||
| #define JUCE_MINOR_VERSION 1 | |||
| #define JUCE_BUILDNUMBER 2 | |||
| #define JUCE_BUILDNUMBER 3 | |||
| /** Current Juce version number. | |||
| @@ -280,6 +280,26 @@ public: | |||
| return isNeg ? -v : v; | |||
| } | |||
| template <typename ResultType> | |||
| struct HexParser | |||
| { | |||
| template <typename CharPointerType> | |||
| static ResultType parse (CharPointerType t) noexcept | |||
| { | |||
| ResultType result = 0; | |||
| while (! t.isEmpty()) | |||
| { | |||
| const int hexValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance()); | |||
| if (hexValue >= 0) | |||
| result = (result << 4) | hexValue; | |||
| } | |||
| return result; | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| /** Counts the number of characters in a given string, stopping if the count exceeds | |||
| a specified limit. */ | |||
| @@ -38,7 +38,7 @@ | |||
| from a string, so it's much faster to keep a static identifier object to refer | |||
| to frequently-used names, rather than constructing them each time you need it. | |||
| @see NamedPropertySet, ValueTree | |||
| @see NamedValueSet, ValueTree | |||
| */ | |||
| class JUCE_API Identifier | |||
| { | |||
| @@ -82,6 +82,9 @@ public: | |||
| /** Returns this identifier's raw string pointer. */ | |||
| const String::CharPointerType getCharPointer() const noexcept { return name; } | |||
| /** Returns this identifier as a StringRef. */ | |||
| operator StringRef() const noexcept { return name; } | |||
| /** Returns true if this Identifier is not null */ | |||
| bool isValid() const noexcept { return name.getAddress() != nullptr; } | |||
| @@ -53,6 +53,11 @@ public: | |||
| @see getDefault() | |||
| */ | |||
| operator String() const { return getDefault(); } | |||
| /** Returns the default new-line sequence that the library uses. | |||
| @see OutputStream::setNewLineString() | |||
| */ | |||
| operator StringRef() const noexcept { return getDefault(); } | |||
| }; | |||
| //============================================================================== | |||
| @@ -74,5 +79,8 @@ extern NewLine newLine; | |||
| */ | |||
| JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const NewLine&); | |||
| #if JUCE_STRING_UTF_TYPE != 8 && ! defined (DOXYGEN) | |||
| inline String operator+ (String s1, const NewLine&) { return s1 += NewLine::getDefault(); } | |||
| #endif | |||
| #endif // JUCE_NEWLINE_H_INCLUDED | |||
| @@ -296,6 +296,9 @@ public: | |||
| /** Case-insensitive comparison with another string. */ | |||
| bool equalsIgnoreCase (const String& other) const noexcept; | |||
| /** Case-insensitive comparison with another string. */ | |||
| bool equalsIgnoreCase (StringRef other) const noexcept; | |||
| /** Case-insensitive comparison with another string. */ | |||
| bool equalsIgnoreCase (const wchar_t* other) const noexcept; | |||
| @@ -340,7 +343,7 @@ public: | |||
| If the parameter is an empty string, this will always return true. | |||
| Uses a case-sensitive comparison. | |||
| */ | |||
| bool startsWith (const String& text) const noexcept; | |||
| bool startsWith (StringRef text) const noexcept; | |||
| /** Tests whether the string begins with a particular character. | |||
| If the character is 0, this will always return false. | |||
| @@ -352,13 +355,13 @@ public: | |||
| If the parameter is an empty string, this will always return true. | |||
| Uses a case-insensitive comparison. | |||
| */ | |||
| bool startsWithIgnoreCase (const String& text) const noexcept; | |||
| bool startsWithIgnoreCase (StringRef text) const noexcept; | |||
| /** Tests whether the string ends with another string. | |||
| If the parameter is an empty string, this will always return true. | |||
| Uses a case-sensitive comparison. | |||
| */ | |||
| bool endsWith (const String& text) const noexcept; | |||
| bool endsWith (StringRef text) const noexcept; | |||
| /** Tests whether the string ends with a particular character. | |||
| If the character is 0, this will always return false. | |||
| @@ -370,13 +373,13 @@ public: | |||
| If the parameter is an empty string, this will always return true. | |||
| Uses a case-insensitive comparison. | |||
| */ | |||
| bool endsWithIgnoreCase (const String& text) const noexcept; | |||
| bool endsWithIgnoreCase (StringRef text) const noexcept; | |||
| /** Tests whether the string contains another substring. | |||
| If the parameter is an empty string, this will always return true. | |||
| Uses a case-sensitive comparison. | |||
| */ | |||
| bool contains (const String& text) const noexcept; | |||
| bool contains (StringRef text) const noexcept; | |||
| /** Tests whether the string contains a particular character. | |||
| Uses a case-sensitive comparison. | |||
| @@ -386,7 +389,7 @@ public: | |||
| /** Tests whether the string contains another substring. | |||
| Uses a case-insensitive comparison. | |||
| */ | |||
| bool containsIgnoreCase (const String& text) const noexcept; | |||
| bool containsIgnoreCase (StringRef text) const noexcept; | |||
| /** Tests whether the string contains another substring as a distinct word. | |||
| @@ -394,7 +397,7 @@ public: | |||
| non-alphanumeric characters | |||
| @see indexOfWholeWord, containsWholeWordIgnoreCase | |||
| */ | |||
| bool containsWholeWord (const String& wordToLookFor) const noexcept; | |||
| bool containsWholeWord (StringRef wordToLookFor) const noexcept; | |||
| /** Tests whether the string contains another substring as a distinct word. | |||
| @@ -402,7 +405,7 @@ public: | |||
| non-alphanumeric characters | |||
| @see indexOfWholeWordIgnoreCase, containsWholeWord | |||
| */ | |||
| bool containsWholeWordIgnoreCase (const String& wordToLookFor) const noexcept; | |||
| bool containsWholeWordIgnoreCase (StringRef wordToLookFor) const noexcept; | |||
| /** Finds an instance of another substring if it exists as a distinct word. | |||
| @@ -411,7 +414,7 @@ public: | |||
| found, then it will return -1 | |||
| @see indexOfWholeWordIgnoreCase, containsWholeWord | |||
| */ | |||
| int indexOfWholeWord (const String& wordToLookFor) const noexcept; | |||
| int indexOfWholeWord (StringRef wordToLookFor) const noexcept; | |||
| /** Finds an instance of another substring if it exists as a distinct word. | |||
| @@ -420,7 +423,7 @@ public: | |||
| found, then it will return -1 | |||
| @see indexOfWholeWord, containsWholeWordIgnoreCase | |||
| */ | |||
| int indexOfWholeWordIgnoreCase (const String& wordToLookFor) const noexcept; | |||
| int indexOfWholeWordIgnoreCase (StringRef wordToLookFor) const noexcept; | |||
| /** Looks for any of a set of characters in the string. | |||
| Uses a case-sensitive comparison. | |||
| @@ -428,7 +431,7 @@ public: | |||
| @returns true if the string contains any of the characters from | |||
| the string that is passed in. | |||
| */ | |||
| bool containsAnyOf (const String& charactersItMightContain) const noexcept; | |||
| bool containsAnyOf (StringRef charactersItMightContain) const noexcept; | |||
| /** Looks for a set of characters in the string. | |||
| Uses a case-sensitive comparison. | |||
| @@ -437,7 +440,7 @@ public: | |||
| the parameter string. If this string is empty, the return value will | |||
| always be true. | |||
| */ | |||
| bool containsOnly (const String& charactersItMightContain) const noexcept; | |||
| bool containsOnly (StringRef charactersItMightContain) const noexcept; | |||
| /** Returns true if this string contains any non-whitespace characters. | |||
| @@ -455,7 +458,7 @@ public: | |||
| This isn't a full-blown regex though! The only wildcard characters supported | |||
| are "*" and "?". It's mainly intended for filename pattern matching. | |||
| */ | |||
| bool matchesWildcard (const String& wildcard, bool ignoreCase) const noexcept; | |||
| bool matchesWildcard (StringRef wildcard, bool ignoreCase) const noexcept; | |||
| //============================================================================== | |||
| // Substring location methods.. | |||
| @@ -488,7 +491,7 @@ public: | |||
| @see indexOfChar, lastIndexOfAnyOf | |||
| */ | |||
| int indexOfAnyOf (const String& charactersToLookFor, | |||
| int indexOfAnyOf (StringRef charactersToLookFor, | |||
| int startIndex = 0, | |||
| bool ignoreCase = false) const noexcept; | |||
| @@ -497,7 +500,7 @@ public: | |||
| @returns the index of the first occurrence of this substring, or -1 if it's not found. | |||
| If textToLookFor is an empty string, this will always return 0. | |||
| */ | |||
| int indexOf (const String& textToLookFor) const noexcept; | |||
| int indexOf (StringRef textToLookFor) const noexcept; | |||
| /** Searches for a substring within this string. | |||
| Uses a case-sensitive comparison. | |||
| @@ -506,14 +509,14 @@ public: | |||
| @returns the index of the first occurrence of this substring, or -1 if it's not found. | |||
| If textToLookFor is an empty string, this will always return -1. | |||
| */ | |||
| int indexOf (int startIndex, const String& textToLookFor) const noexcept; | |||
| int indexOf (int startIndex, StringRef textToLookFor) const noexcept; | |||
| /** Searches for a substring within this string. | |||
| Uses a case-insensitive comparison. | |||
| @returns the index of the first occurrence of this substring, or -1 if it's not found. | |||
| If textToLookFor is an empty string, this will always return 0. | |||
| */ | |||
| int indexOfIgnoreCase (const String& textToLookFor) const noexcept; | |||
| int indexOfIgnoreCase (StringRef textToLookFor) const noexcept; | |||
| /** Searches for a substring within this string. | |||
| Uses a case-insensitive comparison. | |||
| @@ -522,7 +525,7 @@ public: | |||
| @returns the index of the first occurrence of this substring, or -1 if it's not found. | |||
| If textToLookFor is an empty string, this will always return -1. | |||
| */ | |||
| int indexOfIgnoreCase (int startIndex, const String& textToLookFor) const noexcept; | |||
| int indexOfIgnoreCase (int startIndex, StringRef textToLookFor) const noexcept; | |||
| /** Searches for a character inside this string (working backwards from the end of the string). | |||
| Uses a case-sensitive comparison. | |||
| @@ -535,14 +538,14 @@ public: | |||
| @returns the index of the start of the last occurrence of the substring within this string, | |||
| or -1 if it's not found. If textToLookFor is an empty string, this will always return -1. | |||
| */ | |||
| int lastIndexOf (const String& textToLookFor) const noexcept; | |||
| int lastIndexOf (StringRef textToLookFor) const noexcept; | |||
| /** Searches for a substring inside this string (working backwards from the end of the string). | |||
| Uses a case-insensitive comparison. | |||
| @returns the index of the start of the last occurrence of the substring within this string, or -1 | |||
| if it's not found. If textToLookFor is an empty string, this will always return -1. | |||
| */ | |||
| int lastIndexOfIgnoreCase (const String& textToLookFor) const noexcept; | |||
| int lastIndexOfIgnoreCase (StringRef textToLookFor) const noexcept; | |||
| /** Returns the index of the last character in this string that matches one of the | |||
| characters passed-in to this method. | |||
| @@ -556,7 +559,7 @@ public: | |||
| @see lastIndexOf, indexOfAnyOf | |||
| */ | |||
| int lastIndexOfAnyOf (const String& charactersToLookFor, | |||
| int lastIndexOfAnyOf (StringRef charactersToLookFor, | |||
| bool ignoreCase = false) const noexcept; | |||
| @@ -640,7 +643,7 @@ public: | |||
| @see upToFirstOccurrenceOf, fromLastOccurrenceOf | |||
| */ | |||
| String fromFirstOccurrenceOf (const String& substringToStartFrom, | |||
| String fromFirstOccurrenceOf (StringRef substringToStartFrom, | |||
| bool includeSubStringInResult, | |||
| bool ignoreCase) const; | |||
| @@ -652,7 +655,7 @@ public: | |||
| @see fromFirstOccurrenceOf, upToLastOccurrenceOf | |||
| */ | |||
| String fromLastOccurrenceOf (const String& substringToFind, | |||
| String fromLastOccurrenceOf (StringRef substringToFind, | |||
| bool includeSubStringInResult, | |||
| bool ignoreCase) const; | |||
| @@ -669,7 +672,7 @@ public: | |||
| @see upToLastOccurrenceOf, fromFirstOccurrenceOf | |||
| */ | |||
| String upToFirstOccurrenceOf (const String& substringToEndWith, | |||
| String upToFirstOccurrenceOf (StringRef substringToEndWith, | |||
| bool includeSubStringInResult, | |||
| bool ignoreCase) const; | |||
| @@ -680,7 +683,7 @@ public: | |||
| @see upToFirstOccurrenceOf, fromFirstOccurrenceOf | |||
| */ | |||
| String upToLastOccurrenceOf (const String& substringToFind, | |||
| String upToLastOccurrenceOf (StringRef substringToFind, | |||
| bool includeSubStringInResult, | |||
| bool ignoreCase) const; | |||
| @@ -700,7 +703,7 @@ public: | |||
| @param charactersToTrim the set of characters to remove. | |||
| @see trim, trimStart, trimCharactersAtEnd | |||
| */ | |||
| String trimCharactersAtStart (const String& charactersToTrim) const; | |||
| String trimCharactersAtStart (StringRef charactersToTrim) const; | |||
| /** Returns a copy of this string, having removed a specified set of characters from its end. | |||
| Characters are removed from the end of the string until it finds one that is not in the | |||
| @@ -708,7 +711,7 @@ public: | |||
| @param charactersToTrim the set of characters to remove. | |||
| @see trim, trimEnd, trimCharactersAtStart | |||
| */ | |||
| String trimCharactersAtEnd (const String& charactersToTrim) const; | |||
| String trimCharactersAtEnd (StringRef charactersToTrim) const; | |||
| //============================================================================== | |||
| /** Returns an upper-case version of this string. */ | |||
| @@ -735,7 +738,7 @@ public: | |||
| */ | |||
| String replaceSection (int startIndex, | |||
| int numCharactersToReplace, | |||
| const String& stringToInsert) const; | |||
| StringRef stringToInsert) const; | |||
| /** Replaces all occurrences of a substring with another string. | |||
| @@ -744,8 +747,8 @@ public: | |||
| Note that this is a const method, and won't alter the string itself. | |||
| */ | |||
| String replace (const String& stringToReplace, | |||
| const String& stringToInsertInstead, | |||
| String replace (StringRef stringToReplace, | |||
| StringRef stringToInsertInstead, | |||
| bool ignoreCase = false) const; | |||
| /** Returns a string with all occurrences of a character replaced with a different one. */ | |||
| @@ -762,8 +765,8 @@ public: | |||
| Note that this is a const method, and won't affect the string itself. | |||
| */ | |||
| String replaceCharacters (const String& charactersToReplace, | |||
| const String& charactersToInsertInstead) const; | |||
| String replaceCharacters (StringRef charactersToReplace, | |||
| StringRef charactersToInsertInstead) const; | |||
| /** Returns a version of this string that only retains a fixed set of characters. | |||
| @@ -774,7 +777,7 @@ public: | |||
| Note that this is a const method, and won't alter the string itself. | |||
| */ | |||
| String retainCharacters (const String& charactersToRetain) const; | |||
| String retainCharacters (StringRef charactersToRetain) const; | |||
| /** Returns a version of this string with a set of characters removed. | |||
| @@ -785,14 +788,14 @@ public: | |||
| Note that this is a const method, and won't alter the string itself. | |||
| */ | |||
| String removeCharacters (const String& charactersToRemove) const; | |||
| String removeCharacters (StringRef charactersToRemove) const; | |||
| /** Returns a section from the start of the string that only contains a certain set of characters. | |||
| This returns the leftmost section of the string, up to (and not including) the | |||
| first character that doesn't appear in the string passed in. | |||
| */ | |||
| String initialSectionContainingOnly (const String& permittedCharacters) const; | |||
| String initialSectionContainingOnly (StringRef permittedCharacters) const; | |||
| /** Returns a section from the start of the string that only contains a certain set of characters. | |||
| @@ -800,7 +803,7 @@ public: | |||
| first character that occurs in the string passed in. (If none of the specified | |||
| characters are found in the string, the return value will just be the original string). | |||
| */ | |||
| String initialSectionNotContaining (const String& charactersToStopAt) const; | |||
| String initialSectionNotContaining (StringRef charactersToStopAt) const; | |||
| //============================================================================== | |||
| /** Checks whether the string might be in quotation marks. | |||
| @@ -843,7 +846,7 @@ public: | |||
| @param stringToRepeat the string to repeat | |||
| @param numberOfTimesToRepeat how many times to repeat it | |||
| */ | |||
| static String repeatedString (const String& stringToRepeat, | |||
| static String repeatedString (StringRef stringToRepeat, | |||
| int numberOfTimesToRepeat); | |||
| /** Returns a copy of this string with the specified character repeatedly added to its | |||
| @@ -950,7 +953,6 @@ public: | |||
| int getIntValue() const noexcept; | |||
| /** Reads the value of the string as a decimal number (up to 64 bits in size). | |||
| @returns the value of the string as a 64 bit signed base-10 integer. | |||
| */ | |||
| int64 getLargeIntValue() const noexcept; | |||
| @@ -1293,6 +1295,7 @@ JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer | |||
| JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF16 string2) noexcept; | |||
| /** Case-sensitive comparison of two strings. */ | |||
| JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF32 string2) noexcept; | |||
| /** Case-sensitive comparison of two strings. */ | |||
| JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const String& string2) noexcept; | |||
| /** Case-sensitive comparison of two strings. */ | |||
| @@ -1305,6 +1308,7 @@ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer | |||
| JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF16 string2) noexcept; | |||
| /** Case-sensitive comparison of two strings. */ | |||
| JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF32 string2) noexcept; | |||
| /** Case-sensitive comparison of two strings. */ | |||
| JUCE_API bool JUCE_CALLTYPE operator> (const String& string1, const String& string2) noexcept; | |||
| /** Case-sensitive comparison of two strings. */ | |||
| @@ -1336,5 +1340,8 @@ std::basic_ostream <wchar_t, traits>& JUCE_CALLTYPE operator<< (std::basic_ostre | |||
| /** Writes a string to an OutputStream as UTF8. */ | |||
| JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const String& stringToWrite); | |||
| /** Writes a string to an OutputStream as UTF8. */ | |||
| JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, StringRef stringToWrite); | |||
| #endif // JUCE_STRING_H_INCLUDED | |||
| @@ -47,47 +47,29 @@ StringArray::StringArray (const String& firstValue) | |||
| strings.add (firstValue); | |||
| } | |||
| namespace StringArrayHelpers | |||
| { | |||
| template <typename CharType> | |||
| void addArray (Array<String>& dest, const CharType* const* strings) | |||
| { | |||
| if (strings != nullptr) | |||
| while (*strings != nullptr) | |||
| dest.add (*strings++); | |||
| } | |||
| template <typename Type> | |||
| void addArray (Array<String>& dest, const Type* const strings, const int numberOfStrings) | |||
| { | |||
| for (int i = 0; i < numberOfStrings; ++i) | |||
| dest.add (strings [i]); | |||
| } | |||
| } | |||
| StringArray::StringArray (const String* initialStrings, int numberOfStrings) | |||
| { | |||
| StringArrayHelpers::addArray (strings, initialStrings, numberOfStrings); | |||
| strings.addArray (initialStrings, numberOfStrings); | |||
| } | |||
| StringArray::StringArray (const char* const* const initialStrings) | |||
| StringArray::StringArray (const char* const* initialStrings) | |||
| { | |||
| StringArrayHelpers::addArray (strings, initialStrings); | |||
| strings.addNullTerminatedArray (initialStrings); | |||
| } | |||
| StringArray::StringArray (const char* const* const initialStrings, const int numberOfStrings) | |||
| StringArray::StringArray (const char* const* initialStrings, int numberOfStrings) | |||
| { | |||
| StringArrayHelpers::addArray (strings, initialStrings, numberOfStrings); | |||
| strings.addArray (initialStrings, numberOfStrings); | |||
| } | |||
| StringArray::StringArray (const wchar_t* const* const initialStrings) | |||
| StringArray::StringArray (const wchar_t* const* initialStrings) | |||
| { | |||
| StringArrayHelpers::addArray (strings, initialStrings); | |||
| strings.addNullTerminatedArray (initialStrings); | |||
| } | |||
| StringArray::StringArray (const wchar_t* const* const initialStrings, const int numberOfStrings) | |||
| StringArray::StringArray (const wchar_t* const* initialStrings, int numberOfStrings) | |||
| { | |||
| StringArrayHelpers::addArray (strings, initialStrings, numberOfStrings); | |||
| strings.addArray (initialStrings, numberOfStrings); | |||
| } | |||
| StringArray& StringArray::operator= (const StringArray& other) | |||
| @@ -110,14 +92,7 @@ StringArray::~StringArray() | |||
| bool StringArray::operator== (const StringArray& other) const noexcept | |||
| { | |||
| if (other.size() != size()) | |||
| return false; | |||
| for (int i = size(); --i >= 0;) | |||
| if (other.strings.getReference(i) != strings.getReference(i)) | |||
| return false; | |||
| return true; | |||
| return strings == other.strings; | |||
| } | |||
| bool StringArray::operator!= (const StringArray& other) const noexcept | |||
| @@ -150,7 +125,6 @@ const String& StringArray::operator[] (const int index) const noexcept | |||
| String& StringArray::getReference (const int index) noexcept | |||
| { | |||
| jassert (isPositiveAndBelow (index, strings.size())); | |||
| return strings.getReference (index); | |||
| } | |||
| @@ -190,25 +164,12 @@ void StringArray::set (const int index, const String& newString) | |||
| strings.set (index, newString); | |||
| } | |||
| bool StringArray::contains (const String& stringToLookFor, const bool ignoreCase) const | |||
| bool StringArray::contains (StringRef stringToLookFor, const bool ignoreCase) const | |||
| { | |||
| if (ignoreCase) | |||
| { | |||
| for (int i = size(); --i >= 0;) | |||
| if (strings.getReference(i).equalsIgnoreCase (stringToLookFor)) | |||
| return true; | |||
| } | |||
| else | |||
| { | |||
| for (int i = size(); --i >= 0;) | |||
| if (stringToLookFor == strings.getReference(i)) | |||
| return true; | |||
| } | |||
| return false; | |||
| return indexOf (stringToLookFor, ignoreCase) >= 0; | |||
| } | |||
| int StringArray::indexOf (const String& stringToLookFor, const bool ignoreCase, int i) const | |||
| int StringArray::indexOf (StringRef stringToLookFor, const bool ignoreCase, int i) const | |||
| { | |||
| if (i < 0) | |||
| i = 0; | |||
| @@ -217,23 +178,15 @@ int StringArray::indexOf (const String& stringToLookFor, const bool ignoreCase, | |||
| if (ignoreCase) | |||
| { | |||
| while (i < numElements) | |||
| { | |||
| for (; i < numElements; ++i) | |||
| if (strings.getReference(i).equalsIgnoreCase (stringToLookFor)) | |||
| return i; | |||
| ++i; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| while (i < numElements) | |||
| { | |||
| for (; i < numElements; ++i) | |||
| if (stringToLookFor == strings.getReference (i)) | |||
| return i; | |||
| ++i; | |||
| } | |||
| } | |||
| return -1; | |||
| @@ -245,8 +198,7 @@ void StringArray::remove (const int index) | |||
| strings.remove (index); | |||
| } | |||
| void StringArray::removeString (const String& stringToRemove, | |||
| const bool ignoreCase) | |||
| void StringArray::removeString (StringRef stringToRemove, const bool ignoreCase) | |||
| { | |||
| if (ignoreCase) | |||
| { | |||
| @@ -325,7 +277,7 @@ void StringArray::move (const int currentIndex, int newIndex) noexcept | |||
| //============================================================================== | |||
| String StringArray::joinIntoString (const String& separator, int start, int numberToJoin) const | |||
| String StringArray::joinIntoString (StringRef separator, int start, int numberToJoin) const | |||
| { | |||
| const int last = (numberToJoin < 0) ? size() | |||
| : jmin (size(), start + numberToJoin); | |||
| @@ -339,7 +291,7 @@ String StringArray::joinIntoString (const String& separator, int start, int numb | |||
| if (start == last - 1) | |||
| return strings.getReference (start); | |||
| const size_t separatorBytes = separator.getCharPointer().sizeInBytes() - sizeof (String::CharPointerType::CharType); | |||
| const size_t separatorBytes = separator.text.sizeInBytes() - sizeof (String::CharPointerType::CharType); | |||
| size_t bytesNeeded = separatorBytes * (size_t) (last - start - 1); | |||
| for (int i = start; i < last; ++i) | |||
| @@ -358,7 +310,7 @@ String StringArray::joinIntoString (const String& separator, int start, int numb | |||
| dest.writeAll (s.getCharPointer()); | |||
| if (++start < last && separatorBytes > 0) | |||
| dest.writeAll (separator.getCharPointer()); | |||
| dest.writeAll (separator.text); | |||
| } | |||
| dest.writeNull(); | |||
| @@ -366,23 +318,22 @@ String StringArray::joinIntoString (const String& separator, int start, int numb | |||
| return result; | |||
| } | |||
| int StringArray::addTokens (const String& text, const bool preserveQuotedStrings) | |||
| int StringArray::addTokens (StringRef text, const bool preserveQuotedStrings) | |||
| { | |||
| return addTokens (text, " \n\r\t", preserveQuotedStrings ? "\"" : ""); | |||
| } | |||
| int StringArray::addTokens (const String& text, const String& breakCharacters, const String& quoteCharacters) | |||
| int StringArray::addTokens (StringRef text, StringRef breakCharacters, StringRef quoteCharacters) | |||
| { | |||
| int num = 0; | |||
| String::CharPointerType t (text.getCharPointer()); | |||
| if (! t.isEmpty()) | |||
| if (text.isNotEmpty()) | |||
| { | |||
| for (;;) | |||
| for (String::CharPointerType t (text.text);;) | |||
| { | |||
| String::CharPointerType tokenEnd (CharacterFunctions::findEndOfToken (t, | |||
| breakCharacters.getCharPointer(), | |||
| quoteCharacters.getCharPointer())); | |||
| breakCharacters.text, | |||
| quoteCharacters.text)); | |||
| strings.add (String (t, tokenEnd)); | |||
| ++num; | |||
| @@ -396,10 +347,10 @@ int StringArray::addTokens (const String& text, const String& breakCharacters, c | |||
| return num; | |||
| } | |||
| int StringArray::addLines (const String& sourceText) | |||
| int StringArray::addLines (StringRef sourceText) | |||
| { | |||
| int numLines = 0; | |||
| String::CharPointerType text (sourceText.getCharPointer()); | |||
| String::CharPointerType text (sourceText.text); | |||
| bool finished = text.isEmpty(); | |||
| while (! finished) | |||
| @@ -425,24 +376,23 @@ int StringArray::addLines (const String& sourceText) | |||
| return numLines; | |||
| } | |||
| StringArray StringArray::fromTokens (const String& stringToTokenise, | |||
| bool preserveQuotedStrings) | |||
| StringArray StringArray::fromTokens (StringRef stringToTokenise, bool preserveQuotedStrings) | |||
| { | |||
| StringArray s; | |||
| s.addTokens (stringToTokenise, preserveQuotedStrings); | |||
| return s; | |||
| } | |||
| StringArray StringArray::fromTokens (const String& stringToTokenise, | |||
| const String& breakCharacters, | |||
| const String& quoteCharacters) | |||
| StringArray StringArray::fromTokens (StringRef stringToTokenise, | |||
| StringRef breakCharacters, | |||
| StringRef quoteCharacters) | |||
| { | |||
| StringArray s; | |||
| s.addTokens (stringToTokenise, breakCharacters, quoteCharacters); | |||
| return s; | |||
| } | |||
| StringArray StringArray::fromLines (const String& stringToBreakUp) | |||
| StringArray StringArray::fromLines (StringRef stringToBreakUp) | |||
| { | |||
| StringArray s; | |||
| s.addLines (stringToBreakUp); | |||
| @@ -456,9 +406,7 @@ void StringArray::removeDuplicates (const bool ignoreCase) | |||
| { | |||
| const String s (strings.getReference(i)); | |||
| int nextIndex = i + 1; | |||
| for (;;) | |||
| for (int nextIndex = i + 1;;) | |||
| { | |||
| nextIndex = indexOf (s, ignoreCase, nextIndex); | |||
| @@ -44,10 +44,10 @@ public: | |||
| StringArray() noexcept; | |||
| /** Creates a copy of another string array */ | |||
| StringArray (const StringArray& other); | |||
| StringArray (const StringArray&); | |||
| #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||
| StringArray (StringArray&& other) noexcept; | |||
| StringArray (StringArray&&) noexcept; | |||
| #endif | |||
| /** Creates an array containing a single string. */ | |||
| @@ -90,27 +90,27 @@ public: | |||
| ~StringArray(); | |||
| /** Copies the contents of another string array into this one */ | |||
| StringArray& operator= (const StringArray& other); | |||
| StringArray& operator= (const StringArray&); | |||
| #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||
| StringArray& operator= (StringArray&& other) noexcept; | |||
| StringArray& operator= (StringArray&&) noexcept; | |||
| #endif | |||
| /** Swaps the contents of this and another StringArray. */ | |||
| void swapWith (StringArray& other) noexcept; | |||
| void swapWith (StringArray&) noexcept; | |||
| //============================================================================== | |||
| /** Compares two arrays. | |||
| Comparisons are case-sensitive. | |||
| @returns true only if the other array contains exactly the same strings in the same order | |||
| */ | |||
| bool operator== (const StringArray& other) const noexcept; | |||
| bool operator== (const StringArray&) const noexcept; | |||
| /** Compares two arrays. | |||
| Comparisons are case-sensitive. | |||
| @returns false if the other array contains exactly the same strings in the same order | |||
| */ | |||
| bool operator!= (const StringArray& other) const noexcept; | |||
| bool operator!= (const StringArray&) const noexcept; | |||
| //============================================================================== | |||
| /** Returns the number of strings in the array */ | |||
| @@ -153,7 +153,7 @@ public: | |||
| @returns true if the string is found inside the array | |||
| */ | |||
| bool contains (const String& stringToLookFor, | |||
| bool contains (StringRef stringToLookFor, | |||
| bool ignoreCase = false) const; | |||
| /** Searches for a string in the array. | |||
| @@ -166,7 +166,7 @@ public: | |||
| @returns the index of the first occurrence of the string in this array, | |||
| or -1 if it isn't found. | |||
| */ | |||
| int indexOf (const String& stringToLookFor, | |||
| int indexOf (StringRef stringToLookFor, | |||
| bool ignoreCase = false, | |||
| int startIndex = 0) const; | |||
| @@ -214,8 +214,7 @@ public: | |||
| @returns the number of tokens added | |||
| @see fromTokens | |||
| */ | |||
| int addTokens (const String& stringToTokenise, | |||
| bool preserveQuotedStrings); | |||
| int addTokens (StringRef stringToTokenise, bool preserveQuotedStrings); | |||
| /** Breaks up a string into tokens and adds them to this array. | |||
| @@ -231,9 +230,9 @@ public: | |||
| @returns the number of tokens added | |||
| @see fromTokens | |||
| */ | |||
| int addTokens (const String& stringToTokenise, | |||
| const String& breakCharacters, | |||
| const String& quoteCharacters); | |||
| int addTokens (StringRef stringToTokenise, | |||
| StringRef breakCharacters, | |||
| StringRef quoteCharacters); | |||
| /** Breaks up a string into lines and adds them to this array. | |||
| @@ -241,7 +240,7 @@ public: | |||
| to the array. Line-break characters are omitted from the strings that are added to | |||
| the array. | |||
| */ | |||
| int addLines (const String& stringToBreakUp); | |||
| int addLines (StringRef stringToBreakUp); | |||
| /** Returns an array containing the tokens in a given string. | |||
| @@ -249,7 +248,7 @@ public: | |||
| token delimiters, and return these tokens as an array. | |||
| @see addTokens | |||
| */ | |||
| static StringArray fromTokens (const String& stringToTokenise, | |||
| static StringArray fromTokens (StringRef stringToTokenise, | |||
| bool preserveQuotedStrings); | |||
| /** Returns an array containing the tokens in a given string. | |||
| @@ -265,9 +264,9 @@ public: | |||
| between quotes is not broken up into tokens. | |||
| @see addTokens | |||
| */ | |||
| static StringArray fromTokens (const String& stringToTokenise, | |||
| const String& breakCharacters, | |||
| const String& quoteCharacters); | |||
| static StringArray fromTokens (StringRef stringToTokenise, | |||
| StringRef breakCharacters, | |||
| StringRef quoteCharacters); | |||
| /** Returns an array containing the lines in a given string. | |||
| @@ -275,7 +274,7 @@ public: | |||
| array containing these lines. Line-break characters are omitted from the strings that | |||
| are added to the array. | |||
| */ | |||
| static StringArray fromLines (const String& stringToBreakUp); | |||
| static StringArray fromLines (StringRef stringToBreakUp); | |||
| //============================================================================== | |||
| /** Removes all elements from the array. */ | |||
| @@ -295,7 +294,7 @@ public: | |||
| This will remove the first occurrence of the given string from the array. The | |||
| comparison may be case-insensitive depending on the ignoreCase parameter. | |||
| */ | |||
| void removeString (const String& stringToRemove, | |||
| void removeString (StringRef stringToRemove, | |||
| bool ignoreCase = false); | |||
| /** Removes a range of elements from the array. | |||
| @@ -379,7 +378,7 @@ public: | |||
| @param numberOfElements how many elements to join together. If this is less | |||
| than zero, all available elements will be used. | |||
| */ | |||
| String joinIntoString (const String& separatorString, | |||
| String joinIntoString (StringRef separatorString, | |||
| int startIndex = 0, | |||
| int numberOfElements = -1) const; | |||
| @@ -410,7 +409,7 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| Array <String> strings; | |||
| Array<String> strings; | |||
| JUCE_LEAK_DETECTOR (StringArray) | |||
| }; | |||
| @@ -63,12 +63,12 @@ bool StringPairArray::operator!= (const StringPairArray& other) const | |||
| return ! operator== (other); | |||
| } | |||
| const String& StringPairArray::operator[] (const String& key) const | |||
| const String& StringPairArray::operator[] (StringRef key) const | |||
| { | |||
| return values [keys.indexOf (key, ignoreCase)]; | |||
| } | |||
| String StringPairArray::getValue (const String& key, const String& defaultReturnValue) const | |||
| String StringPairArray::getValue (StringRef key, const String& defaultReturnValue) const | |||
| { | |||
| const int i = keys.indexOf (key, ignoreCase); | |||
| @@ -105,7 +105,7 @@ void StringPairArray::clear() | |||
| values.clear(); | |||
| } | |||
| void StringPairArray::remove (const String& key) | |||
| void StringPairArray::remove (StringRef key) | |||
| { | |||
| remove (keys.indexOf (key, ignoreCase)); | |||
| } | |||
| @@ -77,15 +77,13 @@ public: | |||
| @see getValue | |||
| */ | |||
| const String& operator[] (const String& key) const; | |||
| const String& operator[] (StringRef key) const; | |||
| /** Finds the value corresponding to a key string. | |||
| If no such key is found, this will just return the value provided as a default. | |||
| @see operator[] | |||
| */ | |||
| String getValue (const String& key, const String& defaultReturnValue) const; | |||
| String getValue (StringRef, const String& defaultReturnValue) const; | |||
| /** Returns a list of all keys in the array. */ | |||
| @@ -100,14 +98,12 @@ public: | |||
| //============================================================================== | |||
| /** Adds or amends a key/value pair. | |||
| If a value already exists with this key, its value will be overwritten, | |||
| otherwise the key/value pair will be added to the array. | |||
| */ | |||
| void set (const String& key, const String& value); | |||
| /** Adds the items from another array to this one. | |||
| This is equivalent to using set() to add each of the pairs from the other array. | |||
| */ | |||
| void addArray (const StringPairArray& other); | |||
| @@ -117,13 +113,11 @@ public: | |||
| void clear(); | |||
| /** Removes a string from the array based on its key. | |||
| If the key isn't found, nothing will happen. | |||
| */ | |||
| void remove (const String& key); | |||
| void remove (StringRef key); | |||
| /** Removes a string from the array based on its index. | |||
| If the index is out-of-range, no action will be taken. | |||
| */ | |||
| void remove (int index); | |||
| @@ -48,33 +48,32 @@ namespace StringPoolHelpers | |||
| strings.insert (start, newString); | |||
| return strings.getReference (start).getCharPointer(); | |||
| } | |||
| else | |||
| { | |||
| const String& startString = strings.getReference (start); | |||
| if (startString == newString) | |||
| return startString.getCharPointer(); | |||
| const int halfway = (start + end) >> 1; | |||
| const String& startString = strings.getReference (start); | |||
| if (halfway == start) | |||
| { | |||
| if (startString.compare (newString) < 0) | |||
| ++start; | |||
| if (startString == newString) | |||
| return startString.getCharPointer(); | |||
| strings.insert (start, newString); | |||
| return strings.getReference (start).getCharPointer(); | |||
| } | |||
| const int halfway = (start + end) >> 1; | |||
| const int comp = strings.getReference (halfway).compare (newString); | |||
| if (halfway == start) | |||
| { | |||
| if (startString.compare (newString) < 0) | |||
| ++start; | |||
| if (comp == 0) | |||
| return strings.getReference (halfway).getCharPointer(); | |||
| else if (comp < 0) | |||
| start = halfway; | |||
| else | |||
| end = halfway; | |||
| strings.insert (start, newString); | |||
| return strings.getReference (start).getCharPointer(); | |||
| } | |||
| const int comp = strings.getReference (halfway).compare (newString); | |||
| if (comp == 0) | |||
| return strings.getReference (halfway).getCharPointer(); | |||
| if (comp < 0) | |||
| start = halfway; | |||
| else | |||
| end = halfway; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,135 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the juce_core module of the JUCE library. | |||
| Copyright (c) 2013 - Raw Material Software Ltd. | |||
| Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| or without fee is hereby granted, provided that the above copyright notice and this | |||
| permission notice appear in all copies. | |||
| THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
| TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
| NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
| DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
| IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
| CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| ------------------------------------------------------------------------------ | |||
| NOTE! This permissive ISC license applies ONLY to files within the juce_core module! | |||
| All other JUCE modules are covered by a dual GPL/commercial license, so if you are | |||
| using any other modules, be sure to check that you also comply with their license. | |||
| For more details, visit www.juce.com | |||
| ============================================================================== | |||
| */ | |||
| #ifndef JUCE_STRINGREF_H_INCLUDED | |||
| #define JUCE_STRINGREF_H_INCLUDED | |||
| //============================================================================== | |||
| /** | |||
| A simple class for holding temporary references to a string literal or String. | |||
| Unlike a real String object, the StringRef does not allocate any memory or | |||
| take ownership of the strings you give to it - it simply holds a reference to | |||
| a string that has been allocated elsewhere. | |||
| The main purpose of the class is to be used instead of a const String& as the type | |||
| of function arguments where the caller may pass either a string literal or a String | |||
| object. This means that when the called uses a string literal, there's no need | |||
| for an temporary String object to be allocated, and this cuts down overheads | |||
| substantially. | |||
| Because the class is simply a wrapper around a pointer, you should always pass | |||
| it by value, not by reference. | |||
| @code | |||
| void myStringFunction1 (const String&); | |||
| void myStringFunction2 (StringRef); | |||
| myStringFunction1 ("abc"); // Implicitly allocates a temporary String object. | |||
| myStringFunction2 ("abc"); // Much faster, as no local allocations are needed. | |||
| @endcode | |||
| For examples of it in use, see the XmlElement or StringArray classes. | |||
| Bear in mind that there are still many cases where it's better to use an argument | |||
| which is a const String&. For example if the function stores the string or needs | |||
| to internally create a String from the argument, then it's better for the original | |||
| argument to already be a String. | |||
| @see String | |||
| */ | |||
| class JUCE_API StringRef | |||
| { | |||
| public: | |||
| /** Creates a StringRef from a raw string literal. | |||
| The StringRef object does NOT take ownership or copy this data, so you must | |||
| ensure that the data does not change during the lifetime of the StringRef. | |||
| Note that this pointer not be null! | |||
| */ | |||
| StringRef (const char* stringLiteral) noexcept; | |||
| /** Creates a StringRef from a raw char pointer. | |||
| The StringRef object does NOT take ownership or copy this data, so you must | |||
| ensure that the data does not change during the lifetime of the StringRef. | |||
| */ | |||
| StringRef (String::CharPointerType stringLiteral) noexcept; | |||
| /** Creates a StringRef from a String. | |||
| The StringRef object does NOT take ownership or copy the data from the String, | |||
| so you must ensure that the String is not modified or deleted during the lifetime | |||
| of the StringRef. | |||
| */ | |||
| StringRef (const String& string) noexcept; | |||
| /** Creates a StringRef pointer to an empty string. */ | |||
| StringRef() noexcept; | |||
| //============================================================================== | |||
| /** Returns a raw pointer to the underlying string data. */ | |||
| operator const String::CharPointerType::CharType*() const noexcept { return text.getAddress(); } | |||
| /** Returns a pointer to the underlying string data as a char pointer object. */ | |||
| operator String::CharPointerType() const noexcept { return text; } | |||
| /** Returns true if the string is empty. */ | |||
| bool isEmpty() const noexcept { return text.isEmpty(); } | |||
| /** Returns true if the string is not empty. */ | |||
| bool isNotEmpty() const noexcept { return ! text.isEmpty(); } | |||
| /** Returns the number of characters in the string. */ | |||
| int length() const noexcept { return (int) text.length(); } | |||
| /** Compares this StringRef with a String. */ | |||
| bool operator== (const String& s) const noexcept { return text.compare (s.getCharPointer()) == 0; } | |||
| /** Compares this StringRef with a String. */ | |||
| bool operator!= (const String& s) const noexcept { return text.compare (s.getCharPointer()) != 0; } | |||
| /** Case-sensitive comparison of two StringRefs. */ | |||
| bool operator== (StringRef s) const noexcept { return text.compare (s.text) == 0; } | |||
| /** Case-sensitive comparison of two StringRefs. */ | |||
| bool operator!= (StringRef s) const noexcept { return text.compare (s.text) != 0; } | |||
| //============================================================================== | |||
| /** The text that is referenced. */ | |||
| String::CharPointerType text; | |||
| #if JUCE_STRING_UTF_TYPE != 8 && ! defined (DOXYGEN) | |||
| // Sorry, non-UTF8 people, you're unable to take advantage of StringRef, because | |||
| // you've chosen a character encoding that doesn't match C++ string literals. | |||
| String stringCopy; | |||
| #endif | |||
| }; | |||
| //============================================================================== | |||
| /** Case-sensitive comparison of two strings. */ | |||
| JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, StringRef string2) noexcept; | |||
| /** Case-sensitive comparison of two strings. */ | |||
| JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, StringRef string2) noexcept; | |||
| #if JUCE_STRING_UTF_TYPE != 8 && ! defined (DOXYGEN) | |||
| inline String operator+ (String s1, StringRef s2) { return s1 += String (s2.text); } | |||
| #endif | |||
| #endif // JUCE_STRINGREF_H_INCLUDED | |||
| @@ -191,10 +191,9 @@ class DiffTests : public UnitTest | |||
| public: | |||
| DiffTests() : UnitTest ("TextDiff class") {} | |||
| static String createString() | |||
| static String createString (Random& r) | |||
| { | |||
| juce_wchar buffer[50] = { 0 }; | |||
| Random r; | |||
| for (int i = r.nextInt (49); --i >= 0;) | |||
| { | |||
| @@ -224,6 +223,8 @@ public: | |||
| { | |||
| beginTest ("TextDiff"); | |||
| Random r = getRandom(); | |||
| testDiff (String::empty, String::empty); | |||
| testDiff ("x", String::empty); | |||
| testDiff (String::empty, "x"); | |||
| @@ -234,9 +235,9 @@ public: | |||
| for (int i = 5000; --i >= 0;) | |||
| { | |||
| String s (createString()); | |||
| testDiff (s, createString()); | |||
| testDiff (s + createString(), s + createString()); | |||
| String s (createString (r)); | |||
| testDiff (s, createString (r)); | |||
| testDiff (s + createString (r), s + createString (r)); | |||
| } | |||
| } | |||
| }; | |||
| @@ -103,16 +103,16 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| #if JUCE_WINDOWS | |||
| // To avoid including windows.h in the public JUCE headers, we'll just allocate a | |||
| // block of memory here that's big enough to be used internally as a windows critical | |||
| // section structure. | |||
| // To avoid including windows.h in the public JUCE headers, we'll just allocate | |||
| // a block of memory here that's big enough to be used internally as a windows | |||
| // CRITICAL_SECTION structure. | |||
| #if JUCE_64BIT | |||
| uint8 internal [44]; | |||
| uint8 lock[44]; | |||
| #else | |||
| uint8 internal [24]; | |||
| uint8 lock[24]; | |||
| #endif | |||
| #else | |||
| mutable pthread_mutex_t internal; | |||
| mutable pthread_mutex_t lock; | |||
| #endif | |||
| JUCE_DECLARE_NON_COPYABLE (CriticalSection) | |||
| @@ -36,7 +36,7 @@ | |||
| This contains methods for controlling the current application at the | |||
| process-level. | |||
| @see Thread, JUCEApplication | |||
| @see Thread, JUCEApplicationBase | |||
| */ | |||
| class JUCE_API Process | |||
| { | |||
| @@ -63,7 +63,7 @@ public: | |||
| immediately - it's intended only for use only when something goes | |||
| horribly wrong. | |||
| @see JUCEApplication::quit | |||
| @see JUCEApplicationBase::quit | |||
| */ | |||
| static void JUCE_CALLTYPE terminate(); | |||
| @@ -59,18 +59,15 @@ public: | |||
| ReadWriteLock() noexcept; | |||
| /** Destructor. | |||
| If the object is deleted whilst locked, any subsequent behaviour | |||
| is unpredictable. | |||
| If the object is deleted whilst locked, any subsequent behaviour is undefined. | |||
| */ | |||
| ~ReadWriteLock() noexcept; | |||
| //============================================================================== | |||
| /** Locks this object for reading. | |||
| Multiple threads can simulaneously lock the object for reading, but if another | |||
| thread has it locked for writing, then this will block until it releases the | |||
| lock. | |||
| Multiple threads can simultaneously lock the object for reading, but if another | |||
| thread has it locked for writing, then this will block until it releases the lock. | |||
| @see exitRead, ScopedReadLock | |||
| */ | |||
| @@ -78,7 +75,7 @@ public: | |||
| /** Tries to lock this object for reading. | |||
| Multiple threads can simulaneously lock the object for reading, but if another | |||
| Multiple threads can simultaneously lock the object for reading, but if another | |||
| thread has it locked for writing, then this will fail and return false. | |||
| @returns true if the lock is successfully gained. | |||
| @@ -96,7 +96,6 @@ public: | |||
| //============================================================================== | |||
| /** Resets the event to an unsignalled state. | |||
| If it's not already signalled, this does nothing. | |||
| */ | |||
| void reset() const noexcept; | |||
| @@ -105,7 +104,7 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| #if JUCE_WINDOWS | |||
| void* internal; | |||
| void* handle; | |||
| #else | |||
| mutable pthread_cond_t condition; | |||
| mutable pthread_mutex_t mutex; | |||
| @@ -26,8 +26,8 @@ | |||
| ============================================================================== | |||
| */ | |||
| UnitTest::UnitTest (const String& name_) | |||
| : name (name_), runner (nullptr) | |||
| UnitTest::UnitTest (const String& nm) | |||
| : name (nm), runner (nullptr) | |||
| { | |||
| getAllTests().add (this); | |||
| } | |||
| @@ -46,10 +46,10 @@ Array<UnitTest*>& UnitTest::getAllTests() | |||
| void UnitTest::initialise() {} | |||
| void UnitTest::shutdown() {} | |||
| void UnitTest::performTest (UnitTestRunner* const runner_) | |||
| void UnitTest::performTest (UnitTestRunner* const newRunner) | |||
| { | |||
| jassert (runner_ != nullptr); | |||
| runner = runner_; | |||
| jassert (newRunner != nullptr); | |||
| runner = newRunner; | |||
| initialise(); | |||
| runTest(); | |||
| @@ -58,22 +58,39 @@ void UnitTest::performTest (UnitTestRunner* const runner_) | |||
| void UnitTest::logMessage (const String& message) | |||
| { | |||
| // This method's only valid while the test is being run! | |||
| jassert (runner != nullptr); | |||
| runner->logMessage (message); | |||
| } | |||
| void UnitTest::beginTest (const String& testName) | |||
| { | |||
| // This method's only valid while the test is being run! | |||
| jassert (runner != nullptr); | |||
| runner->beginNewTest (this, testName); | |||
| } | |||
| void UnitTest::expect (const bool result, const String& failureMessage) | |||
| { | |||
| // This method's only valid while the test is being run! | |||
| jassert (runner != nullptr); | |||
| if (result) | |||
| runner->addPass(); | |||
| else | |||
| runner->addFail (failureMessage); | |||
| } | |||
| Random UnitTest::getRandom() const | |||
| { | |||
| // This method's only valid while the test is being run! | |||
| jassert (runner != nullptr); | |||
| return runner->randomForTest; | |||
| } | |||
| //============================================================================== | |||
| UnitTestRunner::UnitTestRunner() | |||
| : currentTest (nullptr), | |||
| @@ -110,11 +127,17 @@ void UnitTestRunner::resultsUpdated() | |||
| { | |||
| } | |||
| void UnitTestRunner::runTests (const Array<UnitTest*>& tests) | |||
| void UnitTestRunner::runTests (const Array<UnitTest*>& tests, int64 randomSeed) | |||
| { | |||
| results.clear(); | |||
| resultsUpdated(); | |||
| if (randomSeed == 0) | |||
| randomSeed = Random().nextInt (0x7ffffff); | |||
| randomForTest = Random (randomSeed); | |||
| logMessage ("Random seed: 0x" + String::toHexString (randomSeed)); | |||
| for (int i = 0; i < tests.size(); ++i) | |||
| { | |||
| if (shouldAbortTests()) | |||
| @@ -133,9 +156,9 @@ void UnitTestRunner::runTests (const Array<UnitTest*>& tests) | |||
| endTest(); | |||
| } | |||
| void UnitTestRunner::runAllTests() | |||
| void UnitTestRunner::runAllTests (int64 randomSeed) | |||
| { | |||
| runTests (UnitTest::getAllTests()); | |||
| runTests (UnitTest::getAllTests(), randomSeed); | |||
| } | |||
| void UnitTestRunner::logMessage (const String& message) | |||
| @@ -163,6 +163,22 @@ public: | |||
| */ | |||
| void logMessage (const String& message); | |||
| /** Returns a shared RNG that all unit tests should use. | |||
| If a test needs random numbers, it's important that when an error is found, the | |||
| exact circumstances can be re-created in order to re-test the problem, by | |||
| repeating the test with the same random seed value. | |||
| To make this possible, the UnitTestRunner class creates a master seed value | |||
| for the run, writes this number to the log, and then this method returns a | |||
| Random object based on that seed. All tests should only use this method to | |||
| create any Random objects that they need. | |||
| Note that this method will return an identical object each time it's called | |||
| for a given run, so if you need several different Random objects, the best | |||
| way to do that is to call Random::combineSeed() on the result to permute it | |||
| with a constant value. | |||
| */ | |||
| Random getRandom() const; | |||
| private: | |||
| //============================================================================== | |||
| const String name; | |||
| @@ -198,13 +214,19 @@ public: | |||
| The tests are performed in order, and the results are logged. To run all the | |||
| registered UnitTest objects that exist, use runAllTests(). | |||
| If you want to run the tests with a predetermined seed, you can pass that into | |||
| the randomSeed argument, or pass 0 to have a randomly-generated seed chosen. | |||
| */ | |||
| void runTests (const Array<UnitTest*>& tests); | |||
| void runTests (const Array<UnitTest*>& tests, int64 randomSeed = 0); | |||
| /** Runs all the UnitTest objects that currently exist. | |||
| This calls runTests() for all the objects listed in UnitTest::getAllTests(). | |||
| If you want to run the tests with a predetermined seed, you can pass that into | |||
| the randomSeed argument, or pass 0 to have a randomly-generated seed chosen. | |||
| */ | |||
| void runAllTests(); | |||
| void runAllTests (int64 randomSeed = 0); | |||
| /** Sets a flag to indicate whether an assertion should be triggered if a test fails. | |||
| This is true by default. | |||
| @@ -274,6 +296,7 @@ private: | |||
| String currentSubCategory; | |||
| OwnedArray <TestResult, CriticalSection> results; | |||
| bool assertOnFailure, logPasses; | |||
| Random randomForTest; | |||
| void beginNewTest (UnitTest* test, const String& subCategory); | |||
| void endTest(); | |||
| @@ -312,7 +312,8 @@ void XmlDocument::skipNextWhiteSpace() | |||
| input += closeComment + 3; | |||
| continue; | |||
| } | |||
| else if (input[1] == '?') | |||
| if (input[1] == '?') | |||
| { | |||
| input += 2; | |||
| const int closeBracket = input.indexOf (CharPointer_ASCII ("?>")); | |||
| @@ -515,7 +516,8 @@ void XmlDocument::readChildElements (XmlElement* parent) | |||
| break; | |||
| } | |||
| else if (c1 == '!' && CharacterFunctions::compareUpTo (input + 2, CharPointer_ASCII ("[CDATA["), 7) == 0) | |||
| if (c1 == '!' && CharacterFunctions::compareUpTo (input + 2, CharPointer_ASCII ("[CDATA["), 7) == 0) | |||
| { | |||
| input += 9; | |||
| const String::CharPointerType inputStart (input); | |||
| @@ -42,7 +42,7 @@ XmlElement::XmlAttributeNode::XmlAttributeNode (const String& n, const String& v | |||
| #endif | |||
| } | |||
| inline bool XmlElement::XmlAttributeNode::hasName (const String& nameToMatch) const noexcept | |||
| bool XmlElement::XmlAttributeNode::hasName (StringRef nameToMatch) const noexcept | |||
| { | |||
| return name.equalsIgnoreCase (nameToMatch); | |||
| } | |||
| @@ -74,9 +74,7 @@ XmlElement& XmlElement::operator= (const XmlElement& other) | |||
| { | |||
| removeAllAttributes(); | |||
| deleteAllChildElements(); | |||
| tagName = other.tagName; | |||
| copyChildrenAndAttributesFrom (other); | |||
| } | |||
| @@ -85,10 +83,10 @@ XmlElement& XmlElement::operator= (const XmlElement& other) | |||
| #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||
| XmlElement::XmlElement (XmlElement&& other) noexcept | |||
| : nextListItem (static_cast <LinkedListPointer <XmlElement>&&> (other.nextListItem)), | |||
| firstChildElement (static_cast <LinkedListPointer <XmlElement>&&> (other.firstChildElement)), | |||
| attributes (static_cast <LinkedListPointer <XmlAttributeNode>&&> (other.attributes)), | |||
| tagName (static_cast <String&&> (other.tagName)) | |||
| : nextListItem (static_cast<LinkedListPointer<XmlElement>&&> (other.nextListItem)), | |||
| firstChildElement (static_cast<LinkedListPointer<XmlElement>&&> (other.firstChildElement)), | |||
| attributes (static_cast<LinkedListPointer<XmlAttributeNode>&&> (other.attributes)), | |||
| tagName (static_cast<String&&> (other.tagName)) | |||
| { | |||
| } | |||
| @@ -99,10 +97,10 @@ XmlElement& XmlElement::operator= (XmlElement&& other) noexcept | |||
| removeAllAttributes(); | |||
| deleteAllChildElements(); | |||
| nextListItem = static_cast <LinkedListPointer <XmlElement>&&> (other.nextListItem); | |||
| firstChildElement = static_cast <LinkedListPointer <XmlElement>&&> (other.firstChildElement); | |||
| attributes = static_cast <LinkedListPointer <XmlAttributeNode>&&> (other.attributes); | |||
| tagName = static_cast <String&&> (other.tagName); | |||
| nextListItem = static_cast<LinkedListPointer<XmlElement>&&> (other.nextListItem); | |||
| firstChildElement = static_cast<LinkedListPointer<XmlElement>&&> (other.firstChildElement); | |||
| attributes = static_cast<LinkedListPointer<XmlAttributeNode>&&> (other.attributes); | |||
| tagName = static_cast<String&&> (other.tagName); | |||
| return *this; | |||
| } | |||
| @@ -163,8 +161,8 @@ namespace XmlOutputFunctions | |||
| static bool isLegalXmlChar (const uint32 c) noexcept | |||
| { | |||
| static const unsigned char legalChars[] = { 0, 0, 0, 0, 187, 255, 255, 175, 255, 255, 255, 191, 254, 255, 255, 127 }; | |||
| static const unsigned char legalChars[] = { 0, 0, 0, 0, 187, 255, 255, 175, 255, | |||
| 255, 255, 191, 254, 255, 255, 127 }; | |||
| return c < sizeof (legalChars) * 8 | |||
| && (legalChars [c >> 3] & (1 << (c & 7))) != 0; | |||
| } | |||
| @@ -297,10 +295,10 @@ void XmlElement::writeElementAsText (OutputStream& outputStream, | |||
| } | |||
| } | |||
| String XmlElement::createDocument (const String& dtdToUse, | |||
| String XmlElement::createDocument (StringRef dtdToUse, | |||
| const bool allOnOneLine, | |||
| const bool includeXmlHeader, | |||
| const String& encodingType, | |||
| StringRef encodingType, | |||
| const int lineWrapLength) const | |||
| { | |||
| MemoryOutputStream mem (2048); | |||
| @@ -310,10 +308,10 @@ String XmlElement::createDocument (const String& dtdToUse, | |||
| } | |||
| void XmlElement::writeToStream (OutputStream& output, | |||
| const String& dtdToUse, | |||
| StringRef dtdToUse, | |||
| const bool allOnOneLine, | |||
| const bool includeXmlHeader, | |||
| const String& encodingType, | |||
| StringRef encodingType, | |||
| const int lineWrapLength) const | |||
| { | |||
| using namespace XmlOutputFunctions; | |||
| @@ -345,8 +343,8 @@ void XmlElement::writeToStream (OutputStream& output, | |||
| } | |||
| bool XmlElement::writeToFile (const File& file, | |||
| const String& dtdToUse, | |||
| const String& encodingType, | |||
| StringRef dtdToUse, | |||
| StringRef encodingType, | |||
| const int lineWrapLength) const | |||
| { | |||
| TemporaryFile tempFile (file); | |||
| @@ -364,7 +362,7 @@ bool XmlElement::writeToFile (const File& file, | |||
| } | |||
| //============================================================================== | |||
| bool XmlElement::hasTagName (const String& possibleTagName) const noexcept | |||
| bool XmlElement::hasTagName (StringRef possibleTagName) const noexcept | |||
| { | |||
| const bool matches = tagName.equalsIgnoreCase (possibleTagName); | |||
| @@ -385,12 +383,12 @@ String XmlElement::getTagNameWithoutNamespace() const | |||
| return tagName.fromLastOccurrenceOf (":", false, false); | |||
| } | |||
| bool XmlElement::hasTagNameIgnoringNamespace (const String& possibleTagName) const | |||
| bool XmlElement::hasTagNameIgnoringNamespace (StringRef possibleTagName) const | |||
| { | |||
| return hasTagName (possibleTagName) || getTagNameWithoutNamespace() == possibleTagName; | |||
| } | |||
| XmlElement* XmlElement::getNextElementWithTagName (const String& requiredTagName) const | |||
| XmlElement* XmlElement::getNextElementWithTagName (StringRef requiredTagName) const | |||
| { | |||
| XmlElement* e = nextListItem; | |||
| @@ -408,89 +406,90 @@ int XmlElement::getNumAttributes() const noexcept | |||
| const String& XmlElement::getAttributeName (const int index) const noexcept | |||
| { | |||
| const XmlAttributeNode* const att = attributes [index]; | |||
| return att != nullptr ? att->name : String::empty; | |||
| if (const XmlAttributeNode* const att = attributes [index]) | |||
| return att->name; | |||
| return String::empty; | |||
| } | |||
| const String& XmlElement::getAttributeValue (const int index) const noexcept | |||
| { | |||
| const XmlAttributeNode* const att = attributes [index]; | |||
| return att != nullptr ? att->value : String::empty; | |||
| if (const XmlAttributeNode* const att = attributes [index]) | |||
| return att->value; | |||
| return String::empty; | |||
| } | |||
| bool XmlElement::hasAttribute (const String& attributeName) const noexcept | |||
| XmlElement::XmlAttributeNode* XmlElement::getAttribute (StringRef attributeName) const noexcept | |||
| { | |||
| for (const XmlAttributeNode* att = attributes; att != nullptr; att = att->nextListItem) | |||
| for (XmlAttributeNode* att = attributes; att != nullptr; att = att->nextListItem) | |||
| if (att->hasName (attributeName)) | |||
| return true; | |||
| return att; | |||
| return false; | |||
| return nullptr; | |||
| } | |||
| bool XmlElement::hasAttribute (StringRef attributeName) const noexcept | |||
| { | |||
| return getAttribute (attributeName) != nullptr; | |||
| } | |||
| //============================================================================== | |||
| const String& XmlElement::getStringAttribute (const String& attributeName) const noexcept | |||
| const String& XmlElement::getStringAttribute (StringRef attributeName) const noexcept | |||
| { | |||
| for (const XmlAttributeNode* att = attributes; att != nullptr; att = att->nextListItem) | |||
| if (att->hasName (attributeName)) | |||
| return att->value; | |||
| if (const XmlAttributeNode* att = getAttribute (attributeName)) | |||
| return att->value; | |||
| return String::empty; | |||
| } | |||
| String XmlElement::getStringAttribute (const String& attributeName, const String& defaultReturnValue) const | |||
| String XmlElement::getStringAttribute (StringRef attributeName, const String& defaultReturnValue) const | |||
| { | |||
| for (const XmlAttributeNode* att = attributes; att != nullptr; att = att->nextListItem) | |||
| if (att->hasName (attributeName)) | |||
| return att->value; | |||
| if (const XmlAttributeNode* att = getAttribute (attributeName)) | |||
| return att->value; | |||
| return defaultReturnValue; | |||
| } | |||
| int XmlElement::getIntAttribute (const String& attributeName, const int defaultReturnValue) const | |||
| int XmlElement::getIntAttribute (StringRef attributeName, const int defaultReturnValue) const | |||
| { | |||
| for (const XmlAttributeNode* att = attributes; att != nullptr; att = att->nextListItem) | |||
| if (att->hasName (attributeName)) | |||
| return att->value.getIntValue(); | |||
| if (const XmlAttributeNode* att = getAttribute (attributeName)) | |||
| return att->value.getIntValue(); | |||
| return defaultReturnValue; | |||
| } | |||
| double XmlElement::getDoubleAttribute (const String& attributeName, const double defaultReturnValue) const | |||
| double XmlElement::getDoubleAttribute (StringRef attributeName, const double defaultReturnValue) const | |||
| { | |||
| for (const XmlAttributeNode* att = attributes; att != nullptr; att = att->nextListItem) | |||
| if (att->hasName (attributeName)) | |||
| return att->value.getDoubleValue(); | |||
| if (const XmlAttributeNode* att = getAttribute (attributeName)) | |||
| return att->value.getDoubleValue(); | |||
| return defaultReturnValue; | |||
| } | |||
| bool XmlElement::getBoolAttribute (const String& attributeName, const bool defaultReturnValue) const | |||
| bool XmlElement::getBoolAttribute (StringRef attributeName, const bool defaultReturnValue) const | |||
| { | |||
| for (const XmlAttributeNode* att = attributes; att != nullptr; att = att->nextListItem) | |||
| if (const XmlAttributeNode* att = getAttribute (attributeName)) | |||
| { | |||
| if (att->hasName (attributeName)) | |||
| { | |||
| const juce_wchar firstChar = *(att->value.getCharPointer().findEndOfWhitespace()); | |||
| const juce_wchar firstChar = *(att->value.getCharPointer().findEndOfWhitespace()); | |||
| return firstChar == '1' | |||
| || firstChar == 't' | |||
| || firstChar == 'y' | |||
| || firstChar == 'T' | |||
| || firstChar == 'Y'; | |||
| } | |||
| return firstChar == '1' | |||
| || firstChar == 't' | |||
| || firstChar == 'y' | |||
| || firstChar == 'T' | |||
| || firstChar == 'Y'; | |||
| } | |||
| return defaultReturnValue; | |||
| } | |||
| bool XmlElement::compareAttribute (const String& attributeName, | |||
| const String& stringToCompareAgainst, | |||
| bool XmlElement::compareAttribute (StringRef attributeName, | |||
| StringRef stringToCompareAgainst, | |||
| const bool ignoreCase) const noexcept | |||
| { | |||
| for (const XmlAttributeNode* att = attributes; att != nullptr; att = att->nextListItem) | |||
| if (att->hasName (attributeName)) | |||
| return ignoreCase ? att->value.equalsIgnoreCase (stringToCompareAgainst) | |||
| : att->value == stringToCompareAgainst; | |||
| if (const XmlAttributeNode* att = getAttribute (attributeName)) | |||
| return ignoreCase ? att->value.equalsIgnoreCase (stringToCompareAgainst) | |||
| : att->value == stringToCompareAgainst; | |||
| return false; | |||
| } | |||
| @@ -561,7 +560,7 @@ XmlElement* XmlElement::getChildElement (const int index) const noexcept | |||
| return firstChildElement [index].get(); | |||
| } | |||
| XmlElement* XmlElement::getChildByName (const String& childName) const noexcept | |||
| XmlElement* XmlElement::getChildByName (StringRef childName) const noexcept | |||
| { | |||
| for (XmlElement* child = firstChildElement; child != nullptr; child = child->nextListItem) | |||
| if (child->hasTagName (childName)) | |||
| @@ -576,8 +575,7 @@ void XmlElement::addChildElement (XmlElement* const newNode) noexcept | |||
| firstChildElement.append (newNode); | |||
| } | |||
| void XmlElement::insertChildElement (XmlElement* const newNode, | |||
| int indexToInsertAt) noexcept | |||
| void XmlElement::insertChildElement (XmlElement* const newNode, int indexToInsertAt) noexcept | |||
| { | |||
| if (newNode != nullptr) | |||
| { | |||
| @@ -700,7 +698,7 @@ void XmlElement::deleteAllChildElements() noexcept | |||
| firstChildElement.deleteAll(); | |||
| } | |||
| void XmlElement::deleteAllChildElementsWithTagName (const String& name) noexcept | |||
| void XmlElement::deleteAllChildElementsWithTagName (StringRef name) noexcept | |||
| { | |||
| for (XmlElement* child = firstChildElement; child != nullptr;) | |||
| { | |||
| @@ -791,8 +789,7 @@ String XmlElement::getAllSubText() const | |||
| return mem.toUTF8(); | |||
| } | |||
| String XmlElement::getChildElementAllSubText (const String& childTagName, | |||
| const String& defaultReturnValue) const | |||
| String XmlElement::getChildElementAllSubText (StringRef childTagName, const String& defaultReturnValue) const | |||
| { | |||
| if (const XmlElement* const child = getChildByName (childTagName)) | |||
| return child->getAllSubText(); | |||
| @@ -193,10 +193,10 @@ public: | |||
| determines how lists of attributes get broken up | |||
| @see writeToStream, writeToFile | |||
| */ | |||
| String createDocument (const String& dtdToUse, | |||
| String createDocument (StringRef dtdToUse, | |||
| bool allOnOneLine = false, | |||
| bool includeXmlHeader = true, | |||
| const String& encodingType = "UTF-8", | |||
| StringRef encodingType = "UTF-8", | |||
| int lineWrapLength = 60) const; | |||
| /** Writes the document to a stream as UTF-8. | |||
| @@ -215,10 +215,10 @@ public: | |||
| @see writeToFile, createDocument | |||
| */ | |||
| void writeToStream (OutputStream& output, | |||
| const String& dtdToUse, | |||
| StringRef dtdToUse, | |||
| bool allOnOneLine = false, | |||
| bool includeXmlHeader = true, | |||
| const String& encodingType = "UTF-8", | |||
| StringRef encodingType = "UTF-8", | |||
| int lineWrapLength = 60) const; | |||
| /** Writes the element to a file as an XML document. | |||
| @@ -241,8 +241,8 @@ public: | |||
| @see createDocument | |||
| */ | |||
| bool writeToFile (const File& destinationFile, | |||
| const String& dtdToUse, | |||
| const String& encodingType = "UTF-8", | |||
| StringRef dtdToUse, | |||
| StringRef encodingType = "UTF-8", | |||
| int lineWrapLength = 60) const; | |||
| //============================================================================== | |||
| @@ -250,7 +250,7 @@ public: | |||
| E.g. for an element such as \<MOOSE legs="4" antlers="2">, this would return "MOOSE". | |||
| @see hasTagName | |||
| */ | |||
| inline const String& getTagName() const noexcept { return tagName; } | |||
| const String& getTagName() const noexcept { return tagName; } | |||
| /** Returns the namespace portion of the tag-name, or an empty string if none is specified. */ | |||
| String getNamespace() const; | |||
| @@ -262,13 +262,13 @@ public: | |||
| @param possibleTagName the tag name you're comparing it with | |||
| @see getTagName | |||
| */ | |||
| bool hasTagName (const String& possibleTagName) const noexcept; | |||
| bool hasTagName (StringRef possibleTagName) const noexcept; | |||
| /** Tests whether this element has a particular tag name, ignoring any XML namespace prefix. | |||
| So a test for e.g. "xyz" will return true for "xyz" and also "foo:xyz", "bar::xyz", etc. | |||
| @see getTagName | |||
| */ | |||
| bool hasTagNameIgnoringNamespace (const String& possibleTagName) const; | |||
| bool hasTagNameIgnoringNamespace (StringRef possibleTagName) const; | |||
| //============================================================================== | |||
| /** Returns the number of XML attributes this element contains. | |||
| @@ -300,13 +300,13 @@ public: | |||
| // Attribute-handling methods.. | |||
| /** Checks whether the element contains an attribute with a certain name. */ | |||
| bool hasAttribute (const String& attributeName) const noexcept; | |||
| bool hasAttribute (StringRef attributeName) const noexcept; | |||
| /** Returns the value of a named attribute. | |||
| @param attributeName the name of the attribute to look up | |||
| */ | |||
| const String& getStringAttribute (const String& attributeName) const noexcept; | |||
| const String& getStringAttribute (StringRef attributeName) const noexcept; | |||
| /** Returns the value of a named attribute. | |||
| @@ -314,8 +314,7 @@ public: | |||
| @param defaultReturnValue a value to return if the element doesn't have an attribute | |||
| with this name | |||
| */ | |||
| String getStringAttribute (const String& attributeName, | |||
| const String& defaultReturnValue) const; | |||
| String getStringAttribute (StringRef attributeName, const String& defaultReturnValue) const; | |||
| /** Compares the value of a named attribute with a value passed-in. | |||
| @@ -325,8 +324,8 @@ public: | |||
| @returns true if the value of the attribute is the same as the string passed-in; | |||
| false if it's different (or if no such attribute exists) | |||
| */ | |||
| bool compareAttribute (const String& attributeName, | |||
| const String& stringToCompareAgainst, | |||
| bool compareAttribute (StringRef attributeName, | |||
| StringRef stringToCompareAgainst, | |||
| bool ignoreCase = false) const noexcept; | |||
| /** Returns the value of a named attribute as an integer. | |||
| @@ -339,8 +338,7 @@ public: | |||
| with this name | |||
| @see setAttribute | |||
| */ | |||
| int getIntAttribute (const String& attributeName, | |||
| int defaultReturnValue = 0) const; | |||
| int getIntAttribute (StringRef attributeName, int defaultReturnValue = 0) const; | |||
| /** Returns the value of a named attribute as floating-point. | |||
| @@ -352,8 +350,7 @@ public: | |||
| with this name | |||
| @see setAttribute | |||
| */ | |||
| double getDoubleAttribute (const String& attributeName, | |||
| double defaultReturnValue = 0.0) const; | |||
| double getDoubleAttribute (StringRef attributeName, double defaultReturnValue = 0.0) const; | |||
| /** Returns the value of a named attribute as a boolean. | |||
| @@ -365,8 +362,7 @@ public: | |||
| @param defaultReturnValue a value to return if the element doesn't have an attribute | |||
| with this name | |||
| */ | |||
| bool getBoolAttribute (const String& attributeName, | |||
| bool defaultReturnValue = false) const; | |||
| bool getBoolAttribute (StringRef attributeName, bool defaultReturnValue = false) const; | |||
| /** Adds a named attribute to the element. | |||
| @@ -381,8 +377,7 @@ public: | |||
| @param newValue the value to set it to | |||
| @see removeAttribute | |||
| */ | |||
| void setAttribute (const String& attributeName, | |||
| const String& newValue); | |||
| void setAttribute (const String& attributeName, const String& newValue); | |||
| /** Adds a named attribute to the element, setting it to an integer value. | |||
| @@ -396,8 +391,7 @@ public: | |||
| @param attributeName the name of the attribute to set | |||
| @param newValue the value to set it to | |||
| */ | |||
| void setAttribute (const String& attributeName, | |||
| int newValue); | |||
| void setAttribute (const String& attributeName, int newValue); | |||
| /** Adds a named attribute to the element, setting it to a floating-point value. | |||
| @@ -411,8 +405,7 @@ public: | |||
| @param attributeName the name of the attribute to set | |||
| @param newValue the value to set it to | |||
| */ | |||
| void setAttribute (const String& attributeName, | |||
| double newValue); | |||
| void setAttribute (const String& attributeName, double newValue); | |||
| /** Removes a named attribute from the element. | |||
| @@ -421,17 +414,14 @@ public: | |||
| */ | |||
| void removeAttribute (const String& attributeName) noexcept; | |||
| /** Removes all attributes from this element. | |||
| */ | |||
| /** Removes all attributes from this element. */ | |||
| void removeAllAttributes() noexcept; | |||
| //============================================================================== | |||
| // Child element methods.. | |||
| /** Returns the first of this element's sub-elements. | |||
| see getNextElement() for an example of how to iterate the sub-elements. | |||
| @see forEachXmlChildElement | |||
| */ | |||
| XmlElement* getFirstChildElement() const noexcept { return firstChildElement; } | |||
| @@ -472,10 +462,9 @@ public: | |||
| @see getNextElement, forEachXmlChildElementWithTagName | |||
| */ | |||
| XmlElement* getNextElementWithTagName (const String& requiredTagName) const; | |||
| XmlElement* getNextElementWithTagName (StringRef requiredTagName) const; | |||
| /** Returns the number of sub-elements in this element. | |||
| @see getChildElement | |||
| */ | |||
| int getNumChildElements() const noexcept; | |||
| @@ -496,7 +485,7 @@ public: | |||
| @returns the first element with this tag name, or nullptr if none is found | |||
| @see getNextElement, isTextElement, getChildElement | |||
| */ | |||
| XmlElement* getChildByName (const String& tagNameToLookFor) const noexcept; | |||
| XmlElement* getChildByName (StringRef tagNameToLookFor) const noexcept; | |||
| //============================================================================== | |||
| /** Appends an element to this element's list of children. | |||
| @@ -560,16 +549,14 @@ public: | |||
| bool shouldDeleteTheChild) noexcept; | |||
| /** Deletes all the child elements in the element. | |||
| @see removeChildElement, deleteAllChildElementsWithTagName | |||
| */ | |||
| void deleteAllChildElements() noexcept; | |||
| /** Deletes all the child elements with a given tag name. | |||
| @see removeChildElement | |||
| */ | |||
| void deleteAllChildElementsWithTagName (const String& tagName) noexcept; | |||
| void deleteAllChildElementsWithTagName (StringRef tagName) noexcept; | |||
| /** Returns true if the given element is a child of this one. */ | |||
| bool containsChildElement (const XmlElement* possibleChild) const noexcept; | |||
| @@ -676,23 +663,20 @@ public: | |||
| @see getAllSubText | |||
| */ | |||
| String getChildElementAllSubText (const String& childTagName, | |||
| String getChildElementAllSubText (StringRef childTagName, | |||
| const String& defaultReturnValue) const; | |||
| /** Appends a section of text to this element. | |||
| @see isTextElement, getText, getAllSubText | |||
| */ | |||
| void addTextElement (const String& text); | |||
| /** Removes all the text elements from this element. | |||
| @see isTextElement, getText, getAllSubText, addTextElement | |||
| */ | |||
| void deleteAllTextElements() noexcept; | |||
| /** Creates a text element that can be added to a parent element. | |||
| */ | |||
| /** Creates a text element that can be added to a parent element. */ | |||
| static XmlElement* createTextElement (const String& text); | |||
| //============================================================================== | |||
| @@ -705,7 +689,7 @@ private: | |||
| LinkedListPointer<XmlAttributeNode> nextListItem; | |||
| String name, value; | |||
| bool hasName (const String&) const noexcept; | |||
| bool hasName (StringRef) const noexcept; | |||
| private: | |||
| XmlAttributeNode& operator= (const XmlAttributeNode&); | |||
| @@ -726,6 +710,7 @@ private: | |||
| void writeElementAsText (OutputStream&, int indentationLevel, int lineWrapLength) const; | |||
| void getChildElementsAsArray (XmlElement**) const noexcept; | |||
| void reorderChildElements (XmlElement**, int) noexcept; | |||
| XmlAttributeNode* getAttribute (StringRef) const noexcept; | |||
| JUCE_LEAK_DETECTOR (XmlElement) | |||
| }; | |||
| @@ -169,7 +169,7 @@ public: | |||
| void runTest() | |||
| { | |||
| beginTest ("GZIP"); | |||
| Random rng; | |||
| Random rng = getRandom(); | |||
| for (int i = 100; --i >= 0;) | |||
| { | |||
| @@ -66,6 +66,10 @@ namespace zlibNamespace | |||
| #undef Byte | |||
| #undef fdopen | |||
| #undef local | |||
| #undef Freq | |||
| #undef Code | |||
| #undef Dad | |||
| #undef Len | |||
| #if JUCE_CLANG | |||
| #pragma clang diagnostic pop | |||