aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Blake <oak99sky@yahoo.co.uk>2020-07-27 09:51:35 +0100
committerGitHub <noreply@github.com>2020-07-27 09:51:35 +0100
commit45686bddb1f308ec580f97eb4b228b8a6606b320 (patch)
treef5c282a03e871e4aee62f97b2382ed8211e04493
parentacbb8160ed0ed4e39bae58db0329f479ce5c4f64 (diff)
parent1e4e926823a7038d44da7eae3a40faa7f1aba8c8 (diff)
downloadxbmc-18.8-Leia.tar.xz
Merge pull request #18216 from Paxxi/fix_enum_backport18.8-Leia
Fix enum formatting for libfmt 6 [backport]
-rw-r--r--xbmc/utils/StringUtils.h27
-rw-r--r--xbmc/utils/test/TestStringUtils.cpp55
2 files changed, 78 insertions, 4 deletions
diff --git a/xbmc/utils/StringUtils.h b/xbmc/utils/StringUtils.h
index e6dca5a04d..1abc071cc5 100644
--- a/xbmc/utils/StringUtils.h
+++ b/xbmc/utils/StringUtils.h
@@ -51,6 +51,25 @@ DEF_TO_STR_VALUE(foo) // outputs "4"
#define DEF_TO_STR_NAME(x) #x
#define DEF_TO_STR_VALUE(x) DEF_TO_STR_NAME(x)
+template< bool B, class T = void >
+using enable_if_t = typename std::enable_if<B,T>::type;
+
+template< class T > struct remove_rvalue_reference {typedef T type;};
+template< class T > struct remove_rvalue_reference<T&> {typedef T& type;};
+template< class T > struct remove_rvalue_reference<T*> {typedef T* type;};
+template< class T > struct remove_rvalue_reference<T&&> {typedef T type;};
+
+template<typename T, enable_if_t<!std::is_enum<T>::value, int> = 0>
+constexpr auto EnumToInt(T&& arg) noexcept -> typename remove_rvalue_reference<decltype(arg)>::type
+{
+ return arg;
+}
+template<typename T, enable_if_t<std::is_enum<T>::value, int> = 0>
+constexpr auto EnumToInt(T&& arg) noexcept -> int
+{
+ return static_cast<int>(arg);
+}
+
class StringUtils
{
public:
@@ -69,9 +88,9 @@ public:
static std::string Format(const std::string& fmt, Args&&... args)
{
// coverity[fun_call_w_exception : FALSE]
- auto result = ::fmt::format(fmt, std::forward<Args>(args)...);
+ auto result = ::fmt::format(fmt, EnumToInt(std::forward<Args>(args))...);
if (result == fmt)
- result = ::fmt::sprintf(fmt, std::forward<Args>(args)...);
+ result = ::fmt::sprintf(fmt, EnumToInt(std::forward<Args>(args))...);
return result;
}
@@ -79,9 +98,9 @@ public:
static std::wstring Format(const std::wstring& fmt, Args&&... args)
{
// coverity[fun_call_w_exception : FALSE]
- auto result = ::fmt::format(fmt, std::forward<Args>(args)...);
+ auto result = ::fmt::format(fmt, EnumToInt(std::forward<Args>(args))...);
if (result == fmt)
- result = ::fmt::sprintf(fmt, std::forward<Args>(args)...);
+ result = ::fmt::sprintf(fmt, EnumToInt(std::forward<Args>(args))...);
return result;
}
diff --git a/xbmc/utils/test/TestStringUtils.cpp b/xbmc/utils/test/TestStringUtils.cpp
index baf1d42783..a25a45a246 100644
--- a/xbmc/utils/test/TestStringUtils.cpp
+++ b/xbmc/utils/test/TestStringUtils.cpp
@@ -11,6 +11,32 @@
#include "gtest/gtest.h"
+enum class ECG
+{
+ A,
+ B
+};
+
+enum EG
+{
+ C,
+ D
+};
+
+namespace test_enum
+{
+enum class ECN
+{
+ A = 1,
+ B
+};
+enum EN
+{
+ C = 1,
+ D
+};
+}
+
TEST(TestStringUtils, Format)
{
std::string refstr = "test 25 2.7 ff FF";
@@ -22,6 +48,35 @@ TEST(TestStringUtils, Format)
EXPECT_STREQ("", varstr.c_str());
}
+TEST(TestStringUtils, FormatEnum)
+{
+ const char* zero = "0";
+ const char* one = "1";
+
+ std::string varstr = StringUtils::Format("{}", ECG::A);
+ EXPECT_STREQ(zero, varstr.c_str());
+
+ varstr = StringUtils::Format("{}", EG::C);
+ EXPECT_STREQ(zero, varstr.c_str());
+
+ varstr = StringUtils::Format("{}", test_enum::ECN::A);
+ EXPECT_STREQ(one, varstr.c_str());
+
+ varstr = StringUtils::Format("{}", test_enum::EN::C);
+ EXPECT_STREQ(one, varstr.c_str());
+}
+
+TEST(TestStringUtils, FormatEnumWidth)
+{
+ const char* one = "01";
+
+ std::string varstr = StringUtils::Format("{:02d}", ECG::B);
+ EXPECT_STREQ(one, varstr.c_str());
+
+ varstr = StringUtils::Format("%02d", EG::D);
+ EXPECT_STREQ(one, varstr.c_str());
+}
+
TEST(TestStringUtils, ToUpper)
{
std::string refstr = "TEST";