diff --git a/Foundation/library/JamomaFoundation.xcodeproj/project.pbxproj b/Foundation/library/JamomaFoundation.xcodeproj/project.pbxproj index 9d6bfa02b..f5e887271 100644 --- a/Foundation/library/JamomaFoundation.xcodeproj/project.pbxproj +++ b/Foundation/library/JamomaFoundation.xcodeproj/project.pbxproj @@ -455,16 +455,16 @@ 2209F8FF1AA0E67A00FB8D49 /* TTRegex.h */, 2209F8AF1AA0E66800FB8D49 /* TTRegex.cpp */, 2209F9001AA0E67A00FB8D49 /* TTString.h */, + 2209F8B01AA0E66800FB8D49 /* TTString.cpp */, + 2209F9131AA0E6A600FB8D49 /* TTString.test.cpp */, + 2209F9141AA0E6A600FB8D49 /* TTString.test.h */, 2209F9011AA0E67A00FB8D49 /* TTSymbol.h */, 2209F9021AA0E67A00FB8D49 /* TTSymbolBase.h */, 2209F8B11AA0E66800FB8D49 /* TTSymbolBase.cpp */, 2209F9031AA0E67A00FB8D49 /* TTSymbolCache.h */, 2209F9041AA0E67A00FB8D49 /* TTSymbolTable.h */, - 2209F8B01AA0E66800FB8D49 /* TTString.cpp */, 2209F8B21AA0E66800FB8D49 /* TTSymbolCache.cpp */, 2209F8B31AA0E66800FB8D49 /* TTSymbolTable.cpp */, - 2209F9131AA0E6A600FB8D49 /* TTString.test.cpp */, - 2209F9141AA0E6A600FB8D49 /* TTString.test.h */, 2209F9151AA0E6A600FB8D49 /* TTSymbol.test.cpp */, 2209F9161AA0E6A600FB8D49 /* TTSymbol.test.h */, ); diff --git a/Foundation/library/includes/TTAddress.h b/Foundation/library/includes/TTAddress.h index 4d6453ea9..c966b1e79 100644 --- a/Foundation/library/includes/TTAddress.h +++ b/Foundation/library/includes/TTAddress.h @@ -58,11 +58,14 @@ class TTFOUNDATION_EXPORT TTAddress : public TTSymbol } + TTAddress(const TTString& s) : TTAddress(s.c_str()) {} + TTAddress(const TTSymbol& s) : TTAddress(s.c_str()) {} + + + // TODO: address code duplication between TTAddress and TTSymbol TTAddress(const int int_to_convert_to_string) { - TTString s; - - s.append(int_to_convert_to_string); + TTString s = std::to_string(int_to_convert_to_string); mSymbolPointer = gTTAddressTable.lookup(s); } diff --git a/Foundation/library/includes/TTElement.h b/Foundation/library/includes/TTElement.h index d51923b4a..31aaf8b69 100644 --- a/Foundation/library/includes/TTElement.h +++ b/Foundation/library/includes/TTElement.h @@ -323,7 +323,7 @@ class TTFOUNDATION_EXPORT TT_ALIGN_16 TTElement { //if (mType == kTypeAddress) // return *mValue.mAddress; if (mType == kTypeSymbol) - return TTAddress(*mValue.mSymbol); + return TTAddress(*mValue.mSymbol->c_str()); else return kTTAdrsEmpty; } diff --git a/Foundation/library/includes/TTRegex.h b/Foundation/library/includes/TTRegex.h index f047c6a81..e58e66046 100644 --- a/Foundation/library/includes/TTRegex.h +++ b/Foundation/library/includes/TTRegex.h @@ -39,16 +39,16 @@ class TTFOUNDATION_EXPORT TTRegex { @param begin the beginning of the string to parse @param end the end of the string to parse @return a error code */ - TTErr parse(TTStringIter& begin, TTStringIter& end); + TTErr parse(TTString::iterator& begin, TTString::iterator& end); /** Get where start the result */ //TTRegexStringPosition begin(); - TTStringIter begin(); + TTString::iterator begin(); /** Get where end the result */ //TTRegexStringPosition end(); - TTStringIter end(); + TTString::iterator end(); }; diff --git a/Foundation/library/includes/TTString.h b/Foundation/library/includes/TTString.h index e731efcd1..dbe7be302 100644 --- a/Foundation/library/includes/TTString.h +++ b/Foundation/library/includes/TTString.h @@ -6,10 +6,32 @@ http://creativecommons.org/licenses/BSD/ */ +#pragma once + +//#include +#include "TTBase.h" + +using TTString = std::string; + +// NOTE: we do not export TTString because it is defined in a header as a subclass of a stl template +// but we do want to export this method, which is not defined inline so that we don't pick up a direct +// dependency on Mersenne Twister +/** Replace contents with a pseudo-random string. */ +std::string TTFOUNDATION_EXPORT TTGenerateRandomString(); + +// TODO: These conversions seem a bit misguided, but are being maintained momentarily for backward compatibility. +// Should be replaced with standard calls like std::stoi() and friends. + +TTBoolean TTFOUNDATION_EXPORT TTStringToTTInt32(const std::string s, TTInt32& convertedInt); +TTBoolean TTFOUNDATION_EXPORT TTStringToTTUInt32(const std::string s, TTUInt32& convertedUInt); +TTBoolean TTFOUNDATION_EXPORT TTStringToTTFloat32(const std::string s, TTFloat32& convertedFloat); + + +#define __TT_STRING_H__ + #ifndef __TT_STRING_H__ #define __TT_STRING_H__ -#include "TTBase.h" /****************************************************************************************************/ @@ -369,42 +391,8 @@ class TTString : public std::vector { } - // NOTE: we do not export TTString because it is defined in a header as a subclass of a stl template - // but we do want to export this method, which is not defined inline so that we don't pick up a direct - // dependency on Mersenne Twister - /** Replace contents with a pseudo-random string. */ - void TTFOUNDATION_EXPORT random(); - - TTBoolean toTTInt32(TTInt32& convertedInt) const - { - char * pEnd; - convertedInt = (TTInt32)strtol(c_str(), &pEnd, 10); - return *pEnd == 0; - } - - - TTBoolean toTTUInt32(TTUInt32& convertedUInt) const - { - char * pEnd; - - convertedUInt = (TTUInt32)strtoul(c_str(), &pEnd, 10); - - // is the last letter is a 'u' ? - return *pEnd == 'u' && pEnd == (c_str() + length() - 1); - } - - /* note : isTTFloat32 works only because the TTInt32 case is matched before - see in TTValue::fromString method - */ - TTBoolean toTTFloat32(TTFloat32& convertedFloat) const - { - char * pEnd; - - convertedFloat = strtod(c_str(), &pEnd); - return *pEnd == 0; - } }; diff --git a/Foundation/library/includes/TTSymbol.h b/Foundation/library/includes/TTSymbol.h index 36f919512..cee598b17 100644 --- a/Foundation/library/includes/TTSymbol.h +++ b/Foundation/library/includes/TTSymbol.h @@ -48,12 +48,10 @@ class TTFOUNDATION_EXPORT TTSymbol mSymbolPointer = gTTSymbolTable.lookup(aString); } - + // TODO: make this a template for all numeric values TTSymbol(const int int_to_convert_to_string) { - TTString s; - - s.append(int_to_convert_to_string); + TTString s = std::to_string(int_to_convert_to_string); mSymbolPointer = gTTSymbolTable.lookup(s); } @@ -154,9 +152,7 @@ class TTFOUNDATION_EXPORT TTSymbol /** Generate a pseudo-random symbol */ static TTSymbol random() { - TTString s; - - s.random(); + TTString s = TTGenerateRandomString(); return TTSymbol(s); } diff --git a/Foundation/library/includes/TTValue.h b/Foundation/library/includes/TTValue.h index 518ee968f..b9c5bc18c 100644 --- a/Foundation/library/includes/TTValue.h +++ b/Foundation/library/includes/TTValue.h @@ -390,18 +390,15 @@ class TTValue : public TTElementVector { for (unsigned int i = 0; i < strList.size(); ++i) { TTString currentString = strList.at(i).c_str(); - if (currentString.toTTInt32(convertedInt) && !numberAsSymbol) { - + if (TTStringToTTInt32(currentString, convertedInt) && !numberAsSymbol) { at(n) = int(convertedInt); n++; } - else if (currentString.toTTUInt32(convertedUInt) && !numberAsSymbol) { - + else if (TTStringToTTUInt32(currentString, convertedUInt) && !numberAsSymbol) { at(n) = TTUInt32(convertedUInt); n++; } - else if (currentString.toTTFloat32(convertedFloat) && !numberAsSymbol) { - + else if (TTStringToTTFloat32(currentString, convertedFloat) && !numberAsSymbol) { at(n) = TTFloat64(convertedFloat); // cast float32 into float64 n++; } diff --git a/Foundation/library/source/TTAddress.cpp b/Foundation/library/source/TTAddress.cpp index 4d54feb8e..e78193ccd 100644 --- a/Foundation/library/source/TTAddress.cpp +++ b/Foundation/library/source/TTAddress.cpp @@ -27,13 +27,13 @@ TTErr TTAddress::parseInstanceZero(const char* cstr, TTString& parsed) parsed = toParse; - TTStringIter begin = parsed.begin(); - TTStringIter end = parsed.end(); + TTString::iterator begin = parsed.begin(); + TTString::iterator end = parsed.end(); // parse and remove ".0" while (!ttRegexForInstanceZero->parse(begin, end)) { - TTStringIter z_begin = ttRegexForInstanceZero->begin() - 2; - TTStringIter z_end = ttRegexForInstanceZero->end(); + TTString::iterator z_begin = ttRegexForInstanceZero->begin() - 2; + TTString::iterator z_end = ttRegexForInstanceZero->end(); TTString a(begin, z_begin); TTString b(z_end, end); diff --git a/Foundation/library/source/TTAddressBase.cpp b/Foundation/library/source/TTAddressBase.cpp index 8fec3bcff..abfc7c80b 100644 --- a/Foundation/library/source/TTAddressBase.cpp +++ b/Foundation/library/source/TTAddressBase.cpp @@ -235,8 +235,8 @@ TTErr TTAddressBase::parse() TTString s_instance; TTString s_attribute; - TTStringIter begin = s_toParse.begin(); - TTStringIter end = s_toParse.end(); + TTString::iterator begin = s_toParse.begin(); + TTString::iterator end = s_toParse.end(); // warning : addresses with special regex characters (like [, {) that could be problematic // TODO : rewrite the parsing without regex because we want to use those special characters ! @@ -252,8 +252,8 @@ TTErr TTAddressBase::parse() // parse directory if (!ttRegexForDirectory->parse(begin, end)) { - TTStringIter temp_begin = ttRegexForDirectory->begin(); - TTStringIter temp_end = ttRegexForDirectory->end(); + TTString::iterator temp_begin = ttRegexForDirectory->begin(); + TTString::iterator temp_end = ttRegexForDirectory->end(); s_directory = TTString(temp_begin, temp_end); @@ -285,8 +285,8 @@ TTErr TTAddressBase::parse() // parse attribute if (!ttRegexForAttribute->parse(begin, end)) { - TTStringIter temp_begin = ttRegexForAttribute->begin(); - TTStringIter temp_end = ttRegexForAttribute->end(); + TTString::iterator temp_begin = ttRegexForAttribute->begin(); + TTString::iterator temp_end = ttRegexForAttribute->end(); s_attribute = TTString(temp_begin, end); s_toParse = TTString(begin, temp_end-1); // -1 to remove ":" @@ -316,7 +316,7 @@ TTErr TTAddressBase::parse() else s_parent += TTString(ttRegexForParent->begin(), ttRegexForParent->end()); - s_toParse = TTString(ttRegexForParent->end()+1, end-1); // +1 to remove "/", -1 to remove a useless \0 + s_toParse = TTString(ttRegexForParent->end()+1, end); // +1 to remove "/" begin = s_toParse.begin(); end = s_toParse.end(); @@ -329,7 +329,10 @@ TTErr TTAddressBase::parse() // parse instance if (!ttRegexForInstance->parse(begin, end)) { - s_instance = TTString(ttRegexForInstance->end(), end-1); // -1 to remove a '\0' at the end + // s_instance = TTString(ttRegexForInstance->end(), end-1); // -1 to remove a '\0' at the end + // The above changed to the below when going from std::vector-based TTString to std::string-based TTString because of crashes in the unit test + // The std::vector version used a NULL termination char whereas the std::string version does not. + s_instance = TTString(ttRegexForInstance->end(), end); s_toParse = TTString(begin, ttRegexForInstance->begin()-1); // -1 to remove "." begin = s_toParse.begin(); diff --git a/Foundation/library/source/TTNodeDirectory.cpp b/Foundation/library/source/TTNodeDirectory.cpp index 98a9041a7..6145713be 100644 --- a/Foundation/library/source/TTNodeDirectory.cpp +++ b/Foundation/library/source/TTNodeDirectory.cpp @@ -855,7 +855,7 @@ TTBoolean testNodeUsingFilter(TTNodePtr n, TTPtr args) TTRegex* aRegex; TTString s_toParse; - TTStringIter begin, end; + TTString::iterator begin, end; // get filter aFilter = TTDictionaryBasePtr((TTPtr)v[0]); diff --git a/Foundation/library/source/TTRegex.cpp b/Foundation/library/source/TTRegex.cpp index e2394d755..5b55d7787 100644 --- a/Foundation/library/source/TTRegex.cpp +++ b/Foundation/library/source/TTRegex.cpp @@ -13,7 +13,7 @@ using namespace boost; using namespace std; typedef boost::regex TTExpression; -typedef boost::match_results TTRegexStringResult; +typedef boost::match_results TTRegexStringResult; #else #include using namespace std; @@ -52,7 +52,7 @@ TTRegex::~TTRegex() } //TTErr TTRegex::parse(TTRegexStringPosition& begin, TTRegexStringPosition& end) -TTErr TTRegex::parse(TTStringIter& begin, TTStringIter& end) +TTErr TTRegex::parse(TTString::iterator& begin, TTString::iterator& end) { if (regex_search(begin, end, mRESULT, mEXPRESSION)) return kTTErrNone; @@ -62,7 +62,7 @@ TTErr TTRegex::parse(TTStringIter& begin, TTStringIter& end) /** Get where start the result */ //TTRegexStringPosition TTRegex::begin() -TTStringIter TTRegex::begin() +TTString::iterator TTRegex::begin() { #if BOOST_REGEX return mRESULT[1].first; @@ -73,7 +73,7 @@ TTStringIter TTRegex::begin() /** Get where end the result */ //TTRegexStringPosition TTRegex::end() -TTStringIter TTRegex::end() +TTString::iterator TTRegex::end() { #if BOOST_REGEX return mRESULT[1].second; diff --git a/Foundation/library/source/TTString.cpp b/Foundation/library/source/TTString.cpp index c2968c56a..5dcdb814f 100644 --- a/Foundation/library/source/TTString.cpp +++ b/Foundation/library/source/TTString.cpp @@ -10,13 +10,49 @@ #include "MersenneTwister.h" -void TTString::random() +std::string TTGenerateRandomString() { MTRand twister; unsigned int i = (unsigned int)twister.randInt(); char s[16]; + TTString str; snprintf(s, 16, "j%u", i); s[15] = 0; - (*this) = s; + str = s; + return str; +} + + +// TODO: These conversions seem a bit misguided, but are being maintained momentarily for backward compatibility. +// Should be replaced with standard calls like std::stoi() and friends. + +TTBoolean TTStringToTTInt32(const std::string s, TTInt32& convertedInt) +{ + char * pEnd; + + convertedInt = (TTInt32)strtol(s.c_str(), &pEnd, 10); + return *pEnd == 0; +} + + +TTBoolean TTStringToTTUInt32(const std::string s,TTUInt32& convertedUInt) +{ + char * pEnd; + + convertedUInt = (TTUInt32)strtoul(s.c_str(), &pEnd, 10); + + // is the last letter is a 'u' ? + return *pEnd == 'u' && pEnd == (s.c_str() + s.length() - 1); +} + +/* note : isTTFloat32 works only because the TTInt32 case is matched before + see in TTValue::fromString method + */ +TTBoolean TTStringToTTFloat32(const std::string s, TTFloat32& convertedFloat) +{ + char * pEnd; + + convertedFloat = strtod(s.c_str(), &pEnd); + return *pEnd == 0; } diff --git a/Foundation/library/tests/TTString.test.cpp b/Foundation/library/tests/TTString.test.cpp index e1e184740..a1e780de1 100755 --- a/Foundation/library/tests/TTString.test.cpp +++ b/Foundation/library/tests/TTString.test.cpp @@ -38,10 +38,14 @@ void TTStringTestBasic(int& errorCount, int&testAssertionCount) empty.length() == 0, testAssertionCount, errorCount); +#ifdef ILLEGAL_TEST_ASSERTION__WILL_CRASH + // With a std::string of size zero, this element is out of range and accessing it will crash! + // The old std::vector implementation of size zero was actually implemented with a size of 1, which led to this misleading test assertion! TTTestAssertion("created from static const char* arg correctly null terminated", empty.at(0) == 0, testAssertionCount, errorCount); +#endif // ILLEGAL_TEST_ASSERTION__WILL_CRASH // TEST: c-string init @@ -62,10 +66,14 @@ void TTStringTestBasic(int& errorCount, int&testAssertionCount) foo.at(0) == 'f' && foo.at(1) == 'o' && foo.at(2) == 'o', testAssertionCount, errorCount); +#ifdef ILLEGAL_TEST_ASSERTION__WILL_CRASH + // With a std::string of size 3, this element is out of range and accessing it will crash! + // The old std::vector implementation of size 3 was actually implemented with a size of 4, which led to this misleading test assertion! TTTestAssertion("created from static const char* arg correctly null terminated", foo.at(3) == 0, testAssertionCount, errorCount); +#endif // ILLEGAL_TEST_ASSERTION__WILL_CRASH // TEST: = init @@ -87,11 +95,13 @@ void TTStringTestBasic(int& errorCount, int&testAssertionCount) jet.at(0) == 'j' && jet.at(1) == 'e' && jet.at(2) == 't', testAssertionCount, errorCount); +#ifdef ILLEGAL_TEST_ASSERTION__WILL_CRASH TTTestAssertion("created from = correctly null terminated", jet.at(3) == 0, testAssertionCount, errorCount); - +#endif + // TEST: clear TTTestLog("\n"); @@ -108,10 +118,6 @@ void TTStringTestBasic(int& errorCount, int&testAssertionCount) empty.length() == 0, testAssertionCount, errorCount); - TTTestAssertion("cleared string correctly null terminated", - empty.at(0) == 0, - testAssertionCount, - errorCount); // TEST: individual char access @@ -204,10 +210,6 @@ void TTStringTestNumeric(int& errorCount, int&testAssertionCount) sub.at(0) == '3' && sub.at(1) == '4' && sub.at(2) == '5', testAssertionCount, errorCount); - TTTestAssertion("created from substr correctly null terminated", - sub.at(3) == 0, - testAssertionCount, - errorCount); TTTestLog("\n"); TTTestLog("Testing summing operation"); @@ -223,10 +225,6 @@ void TTStringTestNumeric(int& errorCount, int&testAssertionCount) sumA.length() == 1, testAssertionCount, errorCount); - TTTestAssertion("created from += operator correctly null terminated", - sumA.at(1) == 0, - testAssertionCount, - errorCount); TTString sumB; sumB += '/'; @@ -239,10 +237,6 @@ void TTStringTestNumeric(int& errorCount, int&testAssertionCount) sumB.length() == 1, testAssertionCount, errorCount); - TTTestAssertion("created from += operator correctly null terminated", - sumB.at(1) == 0, - testAssertionCount, - errorCount); // TEST: appending numbers @@ -254,9 +248,9 @@ void TTStringTestNumeric(int& errorCount, int&testAssertionCount) TTString b("Pi is roughly 7/22"); a += "Pi is roughly "; - a += 7u; + a += std::to_string(7u); a += "/"; - a += 22; + a += std::to_string(22); TTTestAssertion("string built-up with a couple of ints in it", a == b, testAssertionCount, @@ -264,7 +258,7 @@ void TTStringTestNumeric(int& errorCount, int&testAssertionCount) b = "Pi is roughly 3.140000"; a = "Pi is roughly "; - a += 3.14f; + a += std::to_string(3.14f); TTTestAssertion("string built-up with a float in it", a == b, @@ -272,7 +266,7 @@ void TTStringTestNumeric(int& errorCount, int&testAssertionCount) errorCount); a = "Pi is roughly "; - a += 3.14; + a += std::to_string(3.14); TTTestAssertion("string built-up with a double in it", a == b, testAssertionCount,