Skip to content

Commit f3fb705

Browse files
authored
perf(ini): Improve INI parsing performance by using std::from_chars (TheSuperHackers#2532)
1 parent 69b7882 commit f3fb705

File tree

1 file changed

+61
-4
lines changed
  • Core/GameEngine/Source/Common/INI

1 file changed

+61
-4
lines changed

Core/GameEngine/Source/Common/INI/INI.cpp

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@
5959
#include "GameLogic/ScriptEngine.h"
6060
#include "GameLogic/Weapon.h"
6161

62+
#if __cplusplus >= 201611L
63+
#define USE_STD_FROM_CHARS_PARSING 1
64+
#else
65+
#define USE_STD_FROM_CHARS_PARSING 0
66+
#endif
67+
68+
#if USE_STD_FROM_CHARS_PARSING
69+
#include <charconv>
70+
#include <string_view>
71+
#include <type_traits>
72+
#endif
6273

6374
///////////////////////////////////////////////////////////////////////////////////////////////////
6475
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
@@ -1624,40 +1635,86 @@ void INI::initFromINIMulti( void *what, const MultiIniFieldParse& parseTableList
16241635
return TheScienceStore->friend_lookupScience( token );
16251636
}
16261637

1638+
#if USE_STD_FROM_CHARS_PARSING
1639+
1640+
template <typename Type>
1641+
Type scanType(std::string_view token)
1642+
{
1643+
// TheSuperHackers @info std::from_chars cannot parse "-1" as uint32 so the result needs to be int64 for integers.
1644+
std::conditional_t<std::is_integral_v<Type>, Int64, Real> result{};
1645+
const auto [ptr, ec] = std::from_chars(token.data(), token.data() + token.size(), result);
1646+
1647+
if (ec != std::errc{})
1648+
{
1649+
throw INI_INVALID_DATA;
1650+
}
1651+
1652+
return static_cast<Type>(result);
1653+
}
1654+
1655+
#endif
1656+
16271657
//-------------------------------------------------------------------------------------------------
16281658
/*static*/ Int INI::scanInt(const char* token)
16291659
{
1660+
#if USE_STD_FROM_CHARS_PARSING == 1
1661+
return scanType<Int>(token);
1662+
#else
16301663
Int value;
16311664
if (sscanf( token, "%d", &value ) != 1)
16321665
throw INI_INVALID_DATA;
1666+
1667+
#if USE_STD_FROM_CHARS_PARSING == -1
1668+
if (value != scanType<Int>(token))
1669+
throw INI_INVALID_DATA;
1670+
#endif
1671+
16331672
return value;
1673+
#endif
16341674
}
16351675

16361676
//-------------------------------------------------------------------------------------------------
16371677
/*static*/ UnsignedInt INI::scanUnsignedInt(const char* token)
16381678
{
1679+
#if USE_STD_FROM_CHARS_PARSING == 1
1680+
return scanType<UnsignedInt>(token);
1681+
#else
16391682
UnsignedInt value;
16401683
if (sscanf( token, "%u", &value ) != 1) // unsigned int is %u, not %d
16411684
throw INI_INVALID_DATA;
1685+
1686+
#if USE_STD_FROM_CHARS_PARSING == -1
1687+
if (value != scanType<UnsignedInt>(token))
1688+
throw INI_INVALID_DATA;
1689+
#endif
1690+
16421691
return value;
1692+
#endif
16431693
}
16441694

16451695
//-------------------------------------------------------------------------------------------------
16461696
/*static*/ Real INI::scanReal(const char* token)
16471697
{
1698+
#if USE_STD_FROM_CHARS_PARSING == 1
1699+
return scanType<Real>(token);
1700+
#else
16481701
Real value;
16491702
if (sscanf( token, "%f", &value ) != 1)
16501703
throw INI_INVALID_DATA;
1704+
1705+
#if USE_STD_FROM_CHARS_PARSING == -1
1706+
if (value != scanType<Real>(token))
1707+
throw INI_INVALID_DATA;
1708+
#endif
1709+
16511710
return value;
1711+
#endif
16521712
}
16531713

16541714
//-------------------------------------------------------------------------------------------------
16551715
/*static*/ Real INI::scanPercentToReal(const char* token)
16561716
{
1657-
Real value;
1658-
if (sscanf( token, "%f", &value ) != 1)
1659-
throw INI_INVALID_DATA;
1660-
return value / 100.0f;
1717+
return scanReal(token) / 100.0f;
16611718
}
16621719

16631720
//-------------------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)