mirror of
https://github.com/UberGames/rpgxEF.git
synced 2025-04-22 17:00:53 +00:00
Added ToString, ReplaceAll, and Format function
This commit is contained in:
parent
37f1a0edd9
commit
181f85ad1d
6 changed files with 241 additions and 11 deletions
|
@ -1,5 +1,6 @@
|
|||
#include "String.h"
|
||||
#include "../doctest/parts/doctest_fwd.h"
|
||||
#include "Warnings.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
|
@ -364,5 +365,87 @@ namespace Common
|
|||
REQUIRE(CompareNoCase(Str3, Str5) == 1);
|
||||
REQUIRE(CompareNoCase(Str4, Str5) == 1);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("String ToString Ptr")
|
||||
{
|
||||
int32_t* Test = nullptr;
|
||||
|
||||
WARNINGS_OFF(4127);
|
||||
|
||||
if(sizeof(void*) == 4)
|
||||
REQUIRE(ToString(Test) == _T("00000000"));
|
||||
else
|
||||
// ReSharper disable once CppUnreachableCode
|
||||
REQUIRE(ToString(Test) == _T("0000000000000000"));
|
||||
|
||||
WARNINGS_ON;
|
||||
}
|
||||
|
||||
TEST_CASE("String ToString String")
|
||||
{
|
||||
const String Test = _T("Test");
|
||||
|
||||
REQUIRE(ToString(Test) == Test);
|
||||
}
|
||||
|
||||
TEST_CASE("String ToString Bool")
|
||||
{
|
||||
REQUIRE(ToString(true) == _T("1"));
|
||||
REQUIRE(ToString(false) == _T("0"));
|
||||
REQUIRE(ToString(true, true) == _T("true"));
|
||||
REQUIRE(ToString(false, true) == _T("false"));
|
||||
REQUIRE(ToString(1 == 1) == _T("1"));
|
||||
REQUIRE(ToString(1 == 42) == _T("0"));
|
||||
REQUIRE(ToString(1 == 1, true) == _T("true"));
|
||||
REQUIRE(ToString(1 == 42, true) == _T("false"));
|
||||
}
|
||||
|
||||
TEST_CASE("String ToString Floating Point")
|
||||
{
|
||||
float f = 42.0f;
|
||||
|
||||
ToString(4.02, 5);
|
||||
|
||||
REQUIRE(ToString(f, 5, true) == _T("42.00000"));
|
||||
REQUIRE(ToString(2.04, 5) == _T("2.04"));
|
||||
REQUIRE(ToString(2.04, 1) == _T("2"));
|
||||
|
||||
auto Temp = ToString(f, 10, true, true, 20);
|
||||
REQUIRE(Temp.length() == 20);
|
||||
}
|
||||
|
||||
TEST_CASE("String ToString Integral")
|
||||
{
|
||||
int32_t I1 = 42;
|
||||
uint32_t I2 = 42;
|
||||
int16_t I3 = -42;
|
||||
|
||||
REQUIRE(ToString(I1) == _T("42"));
|
||||
REQUIRE(ToString(I2) == _T("42"));
|
||||
REQUIRE(ToString(I3) == _T("-42"));
|
||||
|
||||
REQUIRE(ToString(I1, EIntegralFormat::Hexadecimal) == _T("2a"));
|
||||
REQUIRE(ToString(I2, EIntegralFormat::Hexadecimal) == _T("2a"));
|
||||
REQUIRE(ToString(I3, EIntegralFormat::Hexadecimal) == _T("ffd6"));
|
||||
|
||||
REQUIRE(ToString(I1, EIntegralFormat::Octal) == _T("52"));
|
||||
REQUIRE(ToString(I2, EIntegralFormat::Octal) == _T("52"));
|
||||
REQUIRE(ToString(I3, EIntegralFormat::Octal) == _T("177726"));
|
||||
|
||||
REQUIRE(ToString(I1, EIntegralFormat::Decimal, 5).length() == 5);
|
||||
REQUIRE(ToString(I2, EIntegralFormat::Decimal, 5).length() == 5);
|
||||
REQUIRE(ToString(I3, EIntegralFormat::Decimal, 5).length() == 5);
|
||||
|
||||
REQUIRE(ToString(I1, EIntegralFormat::Decimal, 5, _T('.')) == _T("...42"));
|
||||
REQUIRE(ToString(I2, EIntegralFormat::Decimal, 5, _T('.')) == _T("...42"));
|
||||
REQUIRE(ToString(I3, EIntegralFormat::Decimal, 5, _T('.')) == _T("..-42"));
|
||||
}
|
||||
|
||||
TEST_CASE("String Format")
|
||||
{
|
||||
REQUIRE(Format(_T("%0 %1 %2"), 42, _T("test"), true) == _T("42 test 1"));
|
||||
REQUIRE(Format(_T("%1%0%1"), 1, 0) == _T("010"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <locale>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <array>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <iomanip>
|
||||
#include <cctype>
|
||||
#include <optional>
|
||||
|
||||
#if defined (UNICODE)
|
||||
#define _T(X) L##X
|
||||
|
@ -47,4 +52,135 @@ namespace Common
|
|||
bool EqualNoCase(const String& A, const String& B);
|
||||
|
||||
int32_t CompareNoCase(const String& A, const String& B);
|
||||
|
||||
template<typename T, typename = std::enable_if_t<std::is_pointer<T>::value && !std::is_convertible<T, const char*>::value && !std::is_convertible<T, const wchar_t*>::value>>
|
||||
String ToString(T Value)
|
||||
{
|
||||
StringStream Stringstream;
|
||||
Stringstream << static_cast<const void*>(Value);
|
||||
return Stringstream.str();
|
||||
}
|
||||
|
||||
inline String ToString(String Value) { return Value; }
|
||||
|
||||
template<typename T, typename = std::enable_if_t<std::is_floating_point<T>::value>>
|
||||
String ToString(T Value, std::optional<int32_t> Precision = std::nullopt, bool Fixed = false, bool Scientific = false, std::optional<int32_t>Width = std::nullopt)
|
||||
{
|
||||
StringStream Stringstream;
|
||||
|
||||
if(Precision)
|
||||
Stringstream << std::setprecision(*Precision);
|
||||
|
||||
if(Fixed)
|
||||
Stringstream << std::fixed;
|
||||
|
||||
if(Scientific)
|
||||
Stringstream << std::scientific;
|
||||
|
||||
if(Width)
|
||||
Stringstream << std::setw(*Width);
|
||||
|
||||
Stringstream << Value;
|
||||
return Stringstream.str();
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_same<T, bool>::value>>
|
||||
String ToString(T Value, bool Alpha = false)
|
||||
{
|
||||
StringStream Stringstream;
|
||||
if(Alpha)
|
||||
Stringstream << std::boolalpha;
|
||||
Stringstream << Value;
|
||||
return Stringstream.str();
|
||||
}
|
||||
|
||||
enum class EIntegralFormat
|
||||
{
|
||||
Decimal,
|
||||
Hexadecimal,
|
||||
Octal
|
||||
};
|
||||
|
||||
template<typename T, typename = std::enable_if_t<std::is_integral<T>::value && !std::is_same<T, bool>::value>>
|
||||
String ToString(T Value, EIntegralFormat Format = EIntegralFormat::Decimal, std::optional<int32_t> Width = std::nullopt, std::optional<String::value_type> Fill = std::nullopt)
|
||||
{
|
||||
StringStream StringStream;
|
||||
|
||||
switch(Format)
|
||||
{
|
||||
case EIntegralFormat::Hexadecimal:
|
||||
{
|
||||
StringStream << std::hex;
|
||||
break;
|
||||
}
|
||||
case EIntegralFormat::Octal:
|
||||
{
|
||||
StringStream << std::oct;
|
||||
break;
|
||||
}
|
||||
case EIntegralFormat::Decimal:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(Width)
|
||||
StringStream << std::setw(*Width);
|
||||
|
||||
if(Fill)
|
||||
StringStream << std::setfill(*Fill);
|
||||
|
||||
StringStream << Value;
|
||||
return StringStream.str();
|
||||
}
|
||||
|
||||
template<typename T, typename = std::enable_if_t<!std::is_integral<T>::value && !std::is_floating_point<T>::value && !std::is_pointer<T>::value>, typename = void>
|
||||
String ToString(T Value)
|
||||
{
|
||||
StringStream StringStream;
|
||||
StringStream << Value;
|
||||
return StringStream.str();
|
||||
}
|
||||
|
||||
template<typename MatchType, typename RepType, typename = std::enable_if_t<std::is_convertible<MatchType, String>::value && std::is_convertible<RepType, String>::value>>
|
||||
String& ReplaceAll(String& Str, MatchType&& Match, RepType&& Rep)
|
||||
{
|
||||
String M{ Match };
|
||||
|
||||
if(M.empty())
|
||||
return Str;
|
||||
|
||||
String R{ Rep };
|
||||
String::size_type Index = 0;
|
||||
while(true)
|
||||
{
|
||||
Index = Str.find(M, Index);
|
||||
if(Index == String::npos)
|
||||
break;
|
||||
Str.replace(Index, M.size(), R);
|
||||
Index += R.size();
|
||||
}
|
||||
|
||||
return Str;
|
||||
}
|
||||
|
||||
template<typename MatchType, typename RepType, typename = std::enable_if_t<std::is_convertible<MatchType, String>::value && std::is_convertible<RepType, String>::value>>
|
||||
String ReplaceAll(const String& Str, MatchType&& Match, RepType&& Rep)
|
||||
{
|
||||
auto Copy(Str);
|
||||
return ReplaceAll(Copy, std::forward<MatchType>(Match), std::forward<RepType>(Rep));
|
||||
}
|
||||
|
||||
template<typename... ArgsT>
|
||||
String Format(const String& Format, ArgsT const & ... Args)
|
||||
{
|
||||
auto Copy(Format);
|
||||
std::array<String, sizeof...(Args)> StringArgs = { {ToString(Args)...} };
|
||||
|
||||
for(auto i = 0; i < sizeof...(Args); i++)
|
||||
{
|
||||
ReplaceAll(Copy, _T("%") + ToString(i), StringArgs[i]);
|
||||
}
|
||||
|
||||
return Copy;
|
||||
}
|
||||
}
|
||||
|
|
10
code/common_game/Warnings.h
Normal file
10
code/common_game/Warnings.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define WARNINGS_OFF(...) __pragma (warning(push))\
|
||||
__pragma (warning(disable: __VA_ARGS__))
|
||||
|
||||
#define WARNINGS_ON __pragma (warning(pop))
|
||||
|
||||
#endif
|
|
@ -129,8 +129,9 @@
|
|||
<WarningLevel>Level4</WarningLevel>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<CompileAs>CompileAsCpp</CompileAs>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>true</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
|
|
|
@ -6,12 +6,9 @@
|
|||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="C:\Users\Walter\Source\Repos\rpgxEF\misc\doctest\..\..\code\doctest\parts\doctest_impl.h">
|
||||
<Filter>parts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="C:\Users\Walter\Source\Repos\rpgxEF\misc\doctest\..\..\code\doctest\parts\doctest_fwd.h">
|
||||
<Filter>parts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\code\doctest\runner.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\code\doctest\doctest.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\code\doctest\parts\doctest_fwd.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\code\doctest\parts\doctest_impl.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -16,8 +16,11 @@
|
|||
<ItemGroup>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\..\code\common_game\Position2D.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\..\code\common_game\String.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\..\code\common_game\Warnings.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\..\code\common_game\String.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\..\code\common_game\String.cpp">
|
||||
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in a new issue