diff --git a/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp b/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp index 9505682ce5..95d228e30c 100644 --- a/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp +++ b/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp @@ -482,17 +482,16 @@ public: template 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 d (original); @@ -549,49 +548,50 @@ public: template struct Test3 { - static void test (UnitTest& unitTest) + static void test (UnitTest& unitTest, Random& r) { - Test5 ::test (unitTest); - Test5 ::test (unitTest); + Test5 ::test (unitTest, r); + Test5 ::test (unitTest, r); } }; template struct Test2 { - static void test (UnitTest& unitTest) + static void test (UnitTest& unitTest, Random& r) { - Test3 ::test (unitTest); - Test3 ::test (unitTest); - Test3 ::test (unitTest); - Test3 ::test (unitTest); - Test3 ::test (unitTest); - Test3 ::test (unitTest); + Test3 ::test (unitTest, r); + Test3 ::test (unitTest, r); + Test3 ::test (unitTest, r); + Test3 ::test (unitTest, r); + Test3 ::test (unitTest, r); + Test3 ::test (unitTest, r); } }; template struct Test1 { - static void test (UnitTest& unitTest) + static void test (UnitTest& unitTest, Random& r) { - Test2 ::test (unitTest); - Test2 ::test (unitTest); + Test2 ::test (unitTest, r); + Test2 ::test (unitTest, r); } }; void runTest() { + Random r = getRandom(); beginTest ("Round-trip conversion: Int8"); - Test1 ::test (*this); + Test1 ::test (*this, r); beginTest ("Round-trip conversion: Int16"); - Test1 ::test (*this); + Test1 ::test (*this, r); beginTest ("Round-trip conversion: Int24"); - Test1 ::test (*this); + Test1 ::test (*this, r); beginTest ("Round-trip conversion: Int32"); - Test1 ::test (*this); + Test1 ::test (*this, r); beginTest ("Round-trip conversion: Float32"); - Test1 ::test (*this); + Test1 ::test (*this, r); } }; diff --git a/modules/juce_core/containers/juce_AbstractFifo.cpp b/modules/juce_core/containers/juce_AbstractFifo.cpp index 666cc50d04..c14625a2e8 100644 --- a/modules/juce_core/containers/juce_AbstractFifo.cpp +++ b/modules/juce_core/containers/juce_AbstractFifo.cpp @@ -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;) { diff --git a/modules/juce_core/json/juce_JSON.cpp b/modules/juce_core/json/juce_JSON.cpp index 319dba47af..9407d4cfa9 100644 --- a/modules/juce_core/json/juce_JSON.cpp +++ b/modules/juce_core/json/juce_JSON.cpp @@ -616,8 +616,7 @@ public: void runTest() { beginTest ("JSON"); - Random r; - r.setSeedRandomly(); + Random r = getRandom(); expect (JSON::parse (String::empty) == var::null); expect (JSON::parse ("{}").isObject()); diff --git a/modules/juce_core/maths/juce_BigInteger.cpp b/modules/juce_core/maths/juce_BigInteger.cpp index 0cfc5646b7..784bc5ff05 100644 --- a/modules/juce_core/maths/juce_BigInteger.cpp +++ b/modules/juce_core/maths/juce_BigInteger.cpp @@ -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) '-'); diff --git a/modules/juce_core/maths/juce_BigInteger.h b/modules/juce_core/maths/juce_BigInteger.h index e79182034b..cca7b9b078 100644 --- a/modules/juce_core/maths/juce_BigInteger.h +++ b/modules/juce_core/maths/juce_BigInteger.h @@ -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. diff --git a/modules/juce_core/maths/juce_Random.cpp b/modules/juce_core/maths/juce_Random.cpp index 2f7874bed9..3b796730ad 100644 --- a/modules/juce_core/maths/juce_Random.cpp +++ b/modules/juce_core/maths/juce_Random.cpp @@ -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); } } }; diff --git a/modules/juce_core/maths/juce_Random.h b/modules/juce_core/maths/juce_Random.h index 060b084721..a5a0be153a 100644 --- a/modules/juce_core/maths/juce_Random.h +++ b/modules/juce_core/maths/juce_Random.h @@ -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. diff --git a/modules/juce_core/memory/juce_MemoryBlock.cpp b/modules/juce_core/memory/juce_MemoryBlock.cpp index 16438f6def..f6562c2c8e 100644 --- a/modules/juce_core/memory/juce_MemoryBlock.cpp +++ b/modules/juce_core/memory/juce_MemoryBlock.cpp @@ -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; } diff --git a/modules/juce_core/memory/juce_MemoryBlock.h b/modules/juce_core/memory/juce_MemoryBlock.h index 62eeec9fdd..801a9e1f5b 100644 --- a/modules/juce_core/memory/juce_MemoryBlock.h +++ b/modules/juce_core/memory/juce_MemoryBlock.h @@ -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: diff --git a/modules/juce_core/streams/juce_MemoryInputStream.cpp b/modules/juce_core/streams/juce_MemoryInputStream.cpp index de64475c08..19b10524a0 100644 --- a/modules/juce_core/streams/juce_MemoryInputStream.cpp +++ b/modules/juce_core/streams/juce_MemoryInputStream.cpp @@ -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) { diff --git a/modules/juce_core/text/juce_String.cpp b/modules/juce_core/text/juce_String.cpp index 26febf7652..d08ca8f883 100644 --- a/modules/juce_core/text/juce_String.cpp +++ b/modules/juce_core/text/juce_String.cpp @@ -2075,6 +2075,10 @@ String String::fromUTF8 (const char* const buffer, int bufferSizeBytes) #endif //============================================================================== +StringRef::StringRef() noexcept : text ("\0\0\0") +{ +} + StringRef::StringRef (const String::CharPointerType::CharType* stringLiteral) noexcept : text (stringLiteral) { jassert (stringLiteral != nullptr); // This must be a valid string literal, not a null pointer!! @@ -2086,8 +2090,8 @@ StringRef::StringRef (const String::CharPointerType::CharType* stringLiteral) no create them. The source data could be UTF-8, ASCII or one of many local code-pages. To get around this problem, you must be more explicit when you pass an ambiguous 8-bit - string to the String class - so for example if your source data is actually UTF-8, - you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to + string to the StringRef class - so for example if your source data is actually UTF-8, + you'd call StringRef (CharPointer_UTF8 ("my utf8 string..")), and it would be able to correctly convert the multi-byte characters to unicode. It's *highly* recommended that you use UTF-8 with escape characters in your source code to represent extended characters, because there's no other way to represent these strings in a way that isn't dependent on @@ -2116,9 +2120,9 @@ public: template struct TestUTFConversion { - static void test (UnitTest& test) + static void test (UnitTest& test, Random& r) { - String s (createRandomWideCharString()); + String s (createRandomWideCharString (r)); typename CharPointerType::CharType buffer [300]; @@ -2138,10 +2142,9 @@ public: } }; - static String createRandomWideCharString() + static String createRandomWideCharString (Random& r) { juce_wchar buffer[50] = { 0 }; - Random r; for (int i = 0; i < numElementsInArray (buffer) - 1; ++i) { @@ -2162,6 +2165,8 @@ public: void runTest() { + Random r = getRandom(); + { beginTest ("Basics"); @@ -2402,9 +2407,9 @@ public: { beginTest ("UTF conversions"); - TestUTFConversion ::test (*this); - TestUTFConversion ::test (*this); - TestUTFConversion ::test (*this); + TestUTFConversion ::test (*this, r); + TestUTFConversion ::test (*this, r); + TestUTFConversion ::test (*this, r); } { diff --git a/modules/juce_core/text/juce_StringRef.h b/modules/juce_core/text/juce_StringRef.h index 6b7623d3c0..c7579608f2 100644 --- a/modules/juce_core/text/juce_StringRef.h +++ b/modules/juce_core/text/juce_StringRef.h @@ -86,6 +86,9 @@ public: */ 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(); } diff --git a/modules/juce_core/text/juce_TextDiff.cpp b/modules/juce_core/text/juce_TextDiff.cpp index da1a47fd4d..6b4c80794e 100644 --- a/modules/juce_core/text/juce_TextDiff.cpp +++ b/modules/juce_core/text/juce_TextDiff.cpp @@ -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)); } } }; diff --git a/modules/juce_core/unit_tests/juce_UnitTest.cpp b/modules/juce_core/unit_tests/juce_UnitTest.cpp index 9fd6a8e38d..f5a60c1a54 100644 --- a/modules/juce_core/unit_tests/juce_UnitTest.cpp +++ b/modules/juce_core/unit_tests/juce_UnitTest.cpp @@ -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::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& tests) +void UnitTestRunner::runTests (const Array& 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& tests) endTest(); } -void UnitTestRunner::runAllTests() +void UnitTestRunner::runAllTests (int64 randomSeed) { - runTests (UnitTest::getAllTests()); + runTests (UnitTest::getAllTests(), randomSeed); } void UnitTestRunner::logMessage (const String& message) diff --git a/modules/juce_core/unit_tests/juce_UnitTest.h b/modules/juce_core/unit_tests/juce_UnitTest.h index cfbb77b8e3..f5908c17cb 100644 --- a/modules/juce_core/unit_tests/juce_UnitTest.h +++ b/modules/juce_core/unit_tests/juce_UnitTest.h @@ -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& tests); + void runTests (const Array& 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 results; bool assertOnFailure, logPasses; + Random randomForTest; void beginNewTest (UnitTest* test, const String& subCategory); void endTest(); diff --git a/modules/juce_core/zip/juce_GZIPCompressorOutputStream.cpp b/modules/juce_core/zip/juce_GZIPCompressorOutputStream.cpp index 7f99ef5aa5..cb9a577eb5 100644 --- a/modules/juce_core/zip/juce_GZIPCompressorOutputStream.cpp +++ b/modules/juce_core/zip/juce_GZIPCompressorOutputStream.cpp @@ -169,7 +169,7 @@ public: void runTest() { beginTest ("GZIP"); - Random rng; + Random rng = getRandom(); for (int i = 100; --i >= 0;) { diff --git a/modules/juce_cryptography/hashing/juce_MD5.cpp b/modules/juce_cryptography/hashing/juce_MD5.cpp index 3902829e38..889f6d3706 100644 --- a/modules/juce_cryptography/hashing/juce_MD5.cpp +++ b/modules/juce_cryptography/hashing/juce_MD5.cpp @@ -221,10 +221,10 @@ MD5::MD5 (CharPointer_UTF8 utf8) noexcept processData (utf8.getAddress(), utf8.sizeInBytes() - 1); } -MD5 MD5::fromUTF32 (const String& text) +MD5 MD5::fromUTF32 (StringRef text) { MD5Generator generator; - String::CharPointerType t (text.getCharPointer()); + String::CharPointerType t (text.text); while (! t.isEmpty()) { diff --git a/modules/juce_cryptography/hashing/juce_MD5.h b/modules/juce_cryptography/hashing/juce_MD5.h index 2eb7ae9e68..2878d96cda 100644 --- a/modules/juce_cryptography/hashing/juce_MD5.h +++ b/modules/juce_cryptography/hashing/juce_MD5.h @@ -94,7 +94,7 @@ public: this operation on it. In new code, you shouldn't use this, and are recommended to use the constructor that takes a CharPointer_UTF8 instead. */ - static MD5 fromUTF32 (const String&); + static MD5 fromUTF32 (StringRef); //============================================================================== bool operator== (const MD5&) const noexcept; diff --git a/modules/juce_data_structures/values/juce_ValueTree.cpp b/modules/juce_data_structures/values/juce_ValueTree.cpp index 716986d87d..26cd5bb2d4 100644 --- a/modules/juce_data_structures/values/juce_ValueTree.cpp +++ b/modules/juce_data_structures/values/juce_ValueTree.cpp @@ -1019,11 +1019,10 @@ class ValueTreeTests : public UnitTest public: ValueTreeTests() : UnitTest ("ValueTrees") {} - static String createRandomIdentifier() + static String createRandomIdentifier (Random& r) { char buffer[50] = { 0 }; const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-:"; - Random r; for (int i = 1 + r.nextInt (numElementsInArray (buffer) - 2); --i >= 0;) buffer[i] = chars [r.nextInt (sizeof (chars) - 1)]; @@ -1031,10 +1030,9 @@ public: return CharPointer_ASCII (buffer); } - static String createRandomWideCharString() + static String createRandomWideCharString (Random& r) { juce_wchar buffer[50] = { 0 }; - Random r; for (int i = r.nextInt (numElementsInArray (buffer) - 1); --i >= 0;) { @@ -1053,20 +1051,19 @@ public: return CharPointer_UTF32 (buffer); } - static ValueTree createRandomTree (UndoManager* undoManager, int depth) + static ValueTree createRandomTree (UndoManager* undoManager, int depth, Random& r) { - Random r; - ValueTree v (createRandomIdentifier()); + ValueTree v (createRandomIdentifier (r)); for (int i = r.nextInt (10); --i >= 0;) { switch (r.nextInt (5)) { - case 0: v.setProperty (createRandomIdentifier(), createRandomWideCharString(), undoManager); break; - case 1: v.setProperty (createRandomIdentifier(), r.nextInt(), undoManager); break; - case 2: if (depth < 5) v.addChild (createRandomTree (undoManager, depth + 1), r.nextInt (v.getNumChildren() + 1), undoManager); break; - case 3: v.setProperty (createRandomIdentifier(), r.nextBool(), undoManager); break; - case 4: v.setProperty (createRandomIdentifier(), r.nextDouble(), undoManager); break; + case 0: v.setProperty (createRandomIdentifier (r), createRandomWideCharString (r), undoManager); break; + case 1: v.setProperty (createRandomIdentifier (r), r.nextInt(), undoManager); break; + case 2: if (depth < 5) v.addChild (createRandomTree (undoManager, depth + 1, r), r.nextInt (v.getNumChildren() + 1), undoManager); break; + case 3: v.setProperty (createRandomIdentifier (r), r.nextBool(), undoManager); break; + case 4: v.setProperty (createRandomIdentifier (r), r.nextDouble(), undoManager); break; default: break; } } @@ -1077,11 +1074,12 @@ public: void runTest() { beginTest ("ValueTree"); + Random r = getRandom(); for (int i = 10; --i >= 0;) { MemoryOutputStream mo; - ValueTree v1 (createRandomTree (nullptr, 0)); + ValueTree v1 (createRandomTree (nullptr, 0, r)); v1.writeToStream (mo); MemoryInputStream mi (mo.getData(), mo.getDataSize(), false); diff --git a/modules/juce_graphics/geometry/juce_Path.cpp b/modules/juce_graphics/geometry/juce_Path.cpp index ac2ea98dff..9997b50945 100644 --- a/modules/juce_graphics/geometry/juce_Path.cpp +++ b/modules/juce_graphics/geometry/juce_Path.cpp @@ -1475,12 +1475,12 @@ String Path::toString() const return s.toUTF8(); } -void Path::restoreFromString (const String& stringVersion) +void Path::restoreFromString (StringRef stringVersion) { clear(); setUsingNonZeroWinding (true); - String::CharPointerType t (stringVersion.getCharPointer()); + String::CharPointerType t (stringVersion.text); juce_wchar marker = 'm'; int numValues = 2; float values [6]; diff --git a/modules/juce_graphics/geometry/juce_Path.h b/modules/juce_graphics/geometry/juce_Path.h index 42637db015..b17e704bad 100644 --- a/modules/juce_graphics/geometry/juce_Path.h +++ b/modules/juce_graphics/geometry/juce_Path.h @@ -740,7 +740,7 @@ public: /** Restores this path from a string that was created with the toString() method. @see toString() */ - void restoreFromString (const String& stringVersion); + void restoreFromString (StringRef stringVersion); private: diff --git a/modules/juce_gui_extra/code_editor/juce_CodeDocument.cpp b/modules/juce_gui_extra/code_editor/juce_CodeDocument.cpp index 7f6d6c6421..beb5d87cf0 100644 --- a/modules/juce_gui_extra/code_editor/juce_CodeDocument.cpp +++ b/modules/juce_gui_extra/code_editor/juce_CodeDocument.cpp @@ -25,20 +25,21 @@ class CodeDocumentLine { public: - CodeDocumentLine (const String::CharPointerType l, + CodeDocumentLine (const String::CharPointerType startOfLine, + const String::CharPointerType endOfLine, const int lineLen, const int numNewLineChars, const int startInFile) - : line (l, (size_t) lineLen), + : line (startOfLine, endOfLine), lineStartInFile (startInFile), lineLength (lineLen), lineLengthWithoutNewLines (lineLen - numNewLineChars) { } - static void createLines (Array & newLines, const String& text) + static void createLines (Array& newLines, StringRef text) { - String::CharPointerType t (text.getCharPointer()); + String::CharPointerType t (text.text); int charNumInFile = 0; bool finished = false; @@ -84,7 +85,7 @@ public: } } - newLines.add (new CodeDocumentLine (startOfLine, lineLength, + newLines.add (new CodeDocumentLine (startOfLine, t, lineLength, numNewLineChars, startOfLineInFile)); } @@ -791,7 +792,8 @@ void CodeDocument::checkLastLineStatus() if (lastLine != nullptr && lastLine->endsWithLineBreak()) { // check that there's an empty line at the end if the preceding one ends in a newline.. - lines.add (new CodeDocumentLine (String::empty.getCharPointer(), 0, 0, lastLine->lineStartInFile + lastLine->lineLength)); + lines.add (new CodeDocumentLine (StringRef(), StringRef(), 0, 0, + lastLine->lineStartInFile + lastLine->lineLength)); } } diff --git a/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp b/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp index 331bff0e90..95d3296314 100644 --- a/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp +++ b/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp @@ -227,9 +227,9 @@ private: namespace CodeEditorHelpers { - static int findFirstNonWhitespaceChar (const String& line) noexcept + static int findFirstNonWhitespaceChar (StringRef line) noexcept { - String::CharPointerType t (line.getCharPointer()); + String::CharPointerType t (line.text); int i = 0; while (! t.isEmpty()) @@ -1418,7 +1418,8 @@ String CodeEditorComponent::getTabString (const int numSpaces) const int CodeEditorComponent::indexToColumn (int lineNum, int index) const noexcept { - String::CharPointerType t (document.getLine (lineNum).getCharPointer()); + const String line (document.getLine (lineNum)); + String::CharPointerType t (line.getCharPointer()); int col = 0; for (int i = 0; i < index; ++i) @@ -1440,7 +1441,8 @@ int CodeEditorComponent::indexToColumn (int lineNum, int index) const noexcept int CodeEditorComponent::columnToIndex (int lineNum, int column) const noexcept { - String::CharPointerType t (document.getLine (lineNum).getCharPointer()); + const String line (document.getLine (lineNum)); + String::CharPointerType t (line.getCharPointer()); int i = 0, col = 0;