summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2020-02-09 13:44:35 +1100
committer Vas Crabb <vas@vastheman.com>2020-02-09 13:44:35 +1100
commitfead8792cc7efc5a003220c728b66986822cb1c2 (patch)
tree7e80b65b1429056ee5072b251ac81031465ff7f1 /src/lib
parente2ed5d10085861af5cee459fd85ab49e280fe09b (diff)
util/strformat.h: future-proof for C++20 (GitHub #6275)
(nw) I've triple-checked the code and it looks sane, but I'm still a bit nervous about changing such a fundamental part of MAME. If integer formatting appears to have changed after this, let me know ASAP. Also removed a workaround for older versions of GNU libstdc++ with incomplete C++14 support.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/util/strformat.h85
1 files changed, 54 insertions, 31 deletions
diff --git a/src/lib/util/strformat.h b/src/lib/util/strformat.h
index db3666e448b..cfba977f69c 100644
--- a/src/lib/util/strformat.h
+++ b/src/lib/util/strformat.h
@@ -187,23 +187,10 @@
#include <type_traits>
#include <utility>
-#if defined(__GLIBCXX__)
-namespace std {
-namespace mame_cxx14_compat {
-template <typename T>
-inline constexpr auto cbegin(const T& cont) noexcept(noexcept(std::begin(cont))) -> decltype(std::begin(cont))
-{ return std::begin(cont); }
-
-template <typename T>
-inline constexpr auto cend(const T& cont) noexcept(noexcept(std::end(cont))) -> decltype(std::end(cont))
-{ return std::end(cont); }
-}
-using namespace mame_cxx14_compat;
-}
-#endif
-
namespace util {
+
namespace detail {
+
//**************************************************************************
// FORMAT CHARACTER DEFINITIONS
//**************************************************************************
@@ -595,6 +582,54 @@ private:
template <typename U> struct default_semantics
{ static constexpr bool value = !signed_integer_semantics<U>::value && !unsigned_integer_semantics<U>::value; };
+ static void apply_signed(Stream &str, char16_t const &value)
+ {
+ str << std::make_signed_t<std::uint_least16_t>(std::uint_least16_t(value));
+ }
+ static void apply_signed(Stream &str, char32_t const &value)
+ {
+ str << std::make_signed_t<std::uint_least32_t>(std::uint_least32_t(value));
+ }
+ template <typename U>
+ static std::enable_if_t<std::is_same<std::make_signed_t<U>, std::make_signed_t<char> >::value> apply_signed(Stream &str, U const &value)
+ {
+ str << int(std::make_signed_t<U>(value));
+ }
+ template <typename U>
+ static std::enable_if_t<!std::is_same<std::make_signed_t<U>, std::make_signed_t<char> >::value && signed_integer_semantics<U>::value> apply_signed(Stream &str, U const &value)
+ {
+ str << value;
+ }
+ template <typename U>
+ static std::enable_if_t<!std::is_same<std::make_signed_t<U>, std::make_signed_t<char> >::value && unsigned_integer_semantics<U>::value> apply_signed(Stream &str, U const &value)
+ {
+ str << std::make_signed_t<U>(value);
+ }
+
+ static void apply_unsigned(Stream &str, char16_t const &value)
+ {
+ str << std::uint_least16_t(value);
+ }
+ static void apply_unsigned(Stream &str, char32_t const &value)
+ {
+ str << std::uint_least32_t(value);
+ }
+ template <typename U>
+ static std::enable_if_t<std::is_same<std::make_unsigned_t<U>, std::make_unsigned_t<char> >::value> apply_unsigned(Stream &str, U const &value)
+ {
+ str << unsigned(std::make_unsigned_t<U>(value));
+ }
+ template <typename U>
+ static std::enable_if_t<!std::is_same<std::make_unsigned_t<U>, std::make_unsigned_t<char> >::value && signed_integer_semantics<U>::value> apply_unsigned(Stream &str, U const &value)
+ {
+ str << std::make_unsigned_t<U>(value);
+ }
+ template <typename U>
+ static std::enable_if_t<!std::is_same<std::make_unsigned_t<U>, std::make_unsigned_t<char> >::value && unsigned_integer_semantics<U>::value> apply_unsigned(Stream &str, U const &value)
+ {
+ str << value;
+ }
+
public:
template <typename U>
static void apply(std::enable_if_t<signed_integer_semantics<U>::value, Stream> &str, format_flags const &flags, U const &value)
@@ -632,10 +667,7 @@ public:
str << std::int64_t(value);
break;
default:
- if (std::is_same<std::make_signed_t<U>, std::make_signed_t<char> >::value)
- str << int(value);
- else
- str << value;
+ apply_signed(str, value);
}
break;
case format_flags::conversion::unsigned_decimal:
@@ -671,10 +703,7 @@ public:
str << std::uint64_t(std::int64_t(value));
break;
default:
- if (std::is_same<std::make_unsigned_t<U>, std::make_unsigned_t<char> >::value)
- str << unsigned(std::make_unsigned_t<U>(value));
- else
- str << std::make_unsigned_t<U>(value);
+ apply_unsigned(str, value);
}
break;
case format_flags::conversion::character:
@@ -726,10 +755,7 @@ public:
str << std::int64_t(std::uint64_t(value));
break;
default:
- if (std::is_same<std::make_signed_t<U>, std::make_signed_t<char> >::value)
- str << int(std::make_signed_t<U>(value));
- else
- str << std::make_signed_t<U>(value);
+ apply_signed(str, value);
}
break;
case format_flags::conversion::unsigned_decimal:
@@ -765,10 +791,7 @@ public:
str << std::int64_t(value);
break;
default:
- if (std::is_same<std::make_unsigned_t<U>, std::make_unsigned_t<char> >::value)
- str << unsigned(value);
- else
- str << value;
+ apply_unsigned(str, value);
}
break;
case format_flags::conversion::character: