Fixed implicit conversion to bool in AZStd::to_string. (#7755)
This specifically implies to the value returning to_string overloads Added a range based StringFunc::Join overload. Reduced the number of AZStd::to_string calls in the TranslationKey operator<< function. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
b69ae11ec6
commit
60adc098da
@@ -416,27 +416,27 @@ namespace AZ
|
||||
Join(fixedOutput, example.begin(), example.end(), ",");
|
||||
// fixedOutput == "test,string,joining"
|
||||
*/
|
||||
template<typename TStringType, typename TConvertableToStringViewIterator, typename TSeparatorString>
|
||||
template<typename StringType, typename ConvertableToStringViewIterator, typename SeparatorString>
|
||||
inline void Join(
|
||||
TStringType& joinTarget,
|
||||
const TConvertableToStringViewIterator& iteratorBegin,
|
||||
const TConvertableToStringViewIterator& iteratorEnd,
|
||||
const TSeparatorString& separator)
|
||||
StringType& joinTarget,
|
||||
const ConvertableToStringViewIterator& iteratorBegin,
|
||||
const ConvertableToStringViewIterator& iteratorEnd,
|
||||
const SeparatorString& separator)
|
||||
{
|
||||
if (iteratorBegin == iteratorEnd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using CharType = typename TStringType::value_type;
|
||||
using CharTraitsType = typename TStringType::traits_type;
|
||||
using CharType = typename StringType::value_type;
|
||||
using CharTraitsType = typename StringType::traits_type;
|
||||
size_t size = joinTarget.size() + AZStd::basic_string_view<CharType, CharTraitsType>(*iteratorBegin).size();
|
||||
for (auto currentIterator = AZStd::next(iteratorBegin); currentIterator != iteratorEnd; ++currentIterator)
|
||||
{
|
||||
size += AZStd::basic_string_view<CharType, CharTraitsType>(*currentIterator).size();
|
||||
|
||||
// Special case for when the separator is just the character type
|
||||
if constexpr (AZStd::is_same_v<AZStd::remove_cvref_t<TSeparatorString>, CharType>)
|
||||
if constexpr (AZStd::is_same_v<AZStd::remove_cvref_t<SeparatorString>, CharType>)
|
||||
{
|
||||
size += 1;
|
||||
}
|
||||
@@ -455,6 +455,19 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
template<typename StringType, typename Range, typename SeparatorString,
|
||||
class = AZStd::enable_if_t<AZStd::ranges::input_range<Range> &&
|
||||
AZStd::convertible_to<AZStd::ranges::range_value_t<Range>,
|
||||
AZStd::basic_string_view<typename StringType::value_type, typename StringType::traits_type>>
|
||||
>>
|
||||
void Join(StringType& joinTarget, Range&& stringViewConvertibleRange, const SeparatorString& separator)
|
||||
{
|
||||
Join(joinTarget,
|
||||
AZStd::ranges::begin(stringViewConvertibleRange),
|
||||
AZStd::ranges::end(stringViewConvertibleRange),
|
||||
separator);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//! StringFunc::NumberFormatting Namespace
|
||||
/*! For string functions supporting string representations of numbers
|
||||
|
||||
@@ -302,7 +302,13 @@ namespace AZStd
|
||||
inline AZStd::string to_string(long long val) { AZStd::string str; to_string(str, val); return str; }
|
||||
inline AZStd::string to_string(unsigned long long val) { AZStd::string str; to_string(str, val); return str; }
|
||||
inline AZStd::string to_string(long double val) { AZStd::string str; to_string(str, val); return str; }
|
||||
inline AZStd::string to_string(bool val) { AZStd::string str; to_string(str, val); return str; }
|
||||
template<class BoolType>
|
||||
auto to_string(BoolType value) -> enable_if_t<same_as<remove_cvref_t<BoolType>, bool>, AZStd::string>
|
||||
{
|
||||
AZStd::string str;
|
||||
to_string(str, value);
|
||||
return str;
|
||||
}
|
||||
|
||||
// In our engine we assume AZStd::string is Utf8 encoded!
|
||||
template<class Allocator>
|
||||
|
||||
@@ -656,18 +656,6 @@ namespace UnitTest
|
||||
fval = AZStd::stof(wfloatStr);
|
||||
AZ_TEST_ASSERT_FLOAT_CLOSE(fval, 2.32f);
|
||||
|
||||
AZStd::to_string(intStr, 20);
|
||||
AZ_TEST_ASSERT(intStr == "20");
|
||||
|
||||
EXPECT_EQ("20", AZStd::to_string(static_cast<int16_t>(20)));
|
||||
EXPECT_EQ("20", AZStd::to_string(static_cast<uint16_t>(20)));
|
||||
EXPECT_EQ("20", AZStd::to_string(static_cast<int32_t>(20)));
|
||||
EXPECT_EQ("20", AZStd::to_string(static_cast<uint32_t>(20)));
|
||||
EXPECT_EQ("20", AZStd::to_string(static_cast<int64_t>(20)));
|
||||
EXPECT_EQ("20", AZStd::to_string(static_cast<uint64_t>(20)));
|
||||
EXPECT_EQ("false", AZStd::to_string(false));
|
||||
EXPECT_EQ("true", AZStd::to_string(true));
|
||||
|
||||
// wstring to string
|
||||
AZStd::string str1;
|
||||
AZStd::to_string(str1, wstr);
|
||||
@@ -978,6 +966,47 @@ namespace UnitTest
|
||||
AZ_TEST_ASSERT(*vecIt++ == "Xiph Xlater 10000");
|
||||
}
|
||||
|
||||
// Concept to model if AZStd::to_string(<type>) is a valid expression
|
||||
template<class T, class = void>
|
||||
constexpr bool IsToStringInvocable = false;
|
||||
|
||||
template<class T>
|
||||
constexpr bool IsToStringInvocable<T, AZStd::void_t<decltype(AZStd::to_string(AZStd::declval<T>()))>> = true;
|
||||
|
||||
TEST_F(String, String_to_stringOverload_DoesNotImplicitlyConvertToBool)
|
||||
{
|
||||
AZStd::string intStr;
|
||||
AZStd::to_string(intStr, 20);
|
||||
EXPECT_EQ("20", intStr);
|
||||
|
||||
EXPECT_EQ("20", AZStd::to_string(static_cast<int16_t>(20)));
|
||||
EXPECT_EQ("20", AZStd::to_string(static_cast<uint16_t>(20)));
|
||||
EXPECT_EQ("20", AZStd::to_string(static_cast<int32_t>(20)));
|
||||
EXPECT_EQ("20", AZStd::to_string(static_cast<uint32_t>(20)));
|
||||
EXPECT_EQ("20", AZStd::to_string(static_cast<int64_t>(20)));
|
||||
EXPECT_EQ("20", AZStd::to_string(static_cast<uint64_t>(20)));
|
||||
EXPECT_EQ("false", AZStd::to_string(false));
|
||||
EXPECT_EQ("true", AZStd::to_string(true));
|
||||
|
||||
// AZStd::to_string should not be invocable with a char or wchar_t literal
|
||||
static_assert(!IsToStringInvocable<decltype("NarrowStrLiteral")>);
|
||||
static_assert(!IsToStringInvocable<decltype(L"WideStrLiteral")>);
|
||||
|
||||
// AZStd::to_string should
|
||||
static_assert(IsToStringInvocable<bool>);
|
||||
static_assert(IsToStringInvocable<AZ::s8>);
|
||||
static_assert(IsToStringInvocable<AZ::u8>);
|
||||
static_assert(IsToStringInvocable<AZ::s16>);
|
||||
static_assert(IsToStringInvocable<AZ::u16>);
|
||||
static_assert(IsToStringInvocable<AZ::s32>);
|
||||
static_assert(IsToStringInvocable<AZ::u32>);
|
||||
static_assert(IsToStringInvocable<AZ::s64>);
|
||||
static_assert(IsToStringInvocable<AZ::u64>);
|
||||
static_assert(IsToStringInvocable<float>);
|
||||
static_assert(IsToStringInvocable<double>);
|
||||
static_assert(IsToStringInvocable<long double>);
|
||||
}
|
||||
|
||||
class Regex
|
||||
: public AllocatorsFixture
|
||||
{
|
||||
|
||||
@@ -196,6 +196,19 @@ namespace AZ
|
||||
ASSERT_EQ(joinResult, expectedResult);
|
||||
}
|
||||
|
||||
TEST_F(StringFuncTest, Join_NonPathJoin_CanJoinRange)
|
||||
{
|
||||
AZStd::string result;
|
||||
AZ::StringFunc::Join(result, AZStd::initializer_list<const char*>{ "1", "2", "3", "4", "3" }, '/');
|
||||
EXPECT_EQ("1/2/3/4/3", result);
|
||||
|
||||
result.clear();
|
||||
|
||||
// Try joining with a string literal instead of a char literal
|
||||
AZ::StringFunc::Join(result, AZStd::initializer_list<const char*>{ "1", "2", "3", "4", "3" }, "/");
|
||||
EXPECT_EQ("1/2/3/4/3", result);
|
||||
}
|
||||
|
||||
TEST_F(StringFuncTest, Tokenize_SingleDelimeter_Empty)
|
||||
{
|
||||
AZStd::string input = "";
|
||||
|
||||
@@ -47,22 +47,24 @@ namespace GraphCanvas
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto operator << (T value) -> AZStd::enable_if_t<AZStd::is_same_v<std::void_t<decltype(AZStd::to_string(value))>, void>, TranslationKey&>
|
||||
auto operator<< (T&& value) ->
|
||||
AZStd::enable_if_t<AZStd::is_void_v<AZStd::void_t<decltype(AZStd::to_string(value))>>, TranslationKey&>
|
||||
{
|
||||
if (!m_key.empty() && !AZStd::to_string(value).empty())
|
||||
AZStd::string valueString = AZStd::to_string(AZStd::forward<T>(value));
|
||||
if (!m_key.empty() && !valueString.empty())
|
||||
{
|
||||
m_key.append(".");
|
||||
}
|
||||
|
||||
if (!AZStd::to_string(value).empty())
|
||||
if (!valueString.empty())
|
||||
{
|
||||
m_key.append(AZStd::to_string(value));
|
||||
m_key.append(valueString);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TranslationKey& operator << (const AZStd::string& value)
|
||||
TranslationKey& operator<< (const AZStd::string& value)
|
||||
{
|
||||
if (!m_key.empty() && !value.empty())
|
||||
{
|
||||
@@ -70,7 +72,7 @@ namespace GraphCanvas
|
||||
}
|
||||
if (!value.empty())
|
||||
{
|
||||
m_key.append(value.c_str());
|
||||
m_key.append(value);
|
||||
}
|
||||
|
||||
return *this;
|
||||
|
||||
Reference in New Issue
Block a user