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>
development
lumberyard-employee-dm 4 years ago committed by GitHub
parent b69ae11ec6
commit 60adc098da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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;

Loading…
Cancel
Save