From a830ea76270b7894a03922a172d58bfaefbc827f Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Tue, 1 Mar 2016 06:45:41 +1100 Subject: * Support *n conversion in stream_format/string_format * Make stream_format return characters printed * Add iostreams with std::vector storage * Move to type-safe templates for logerror and popmessage * Remove now-unnecessary I64FMT from calls to logerror/popmessage * Put some lib/util stuff in util:: namespace * Some fixes to Japanese translation --- src/lib/util/strformat.h | 86 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 7 deletions(-) (limited to 'src/lib/util/strformat.h') diff --git a/src/lib/util/strformat.h b/src/lib/util/strformat.h index 3bf95a5df29..96add0dfcca 100644 --- a/src/lib/util/strformat.h +++ b/src/lib/util/strformat.h @@ -91,6 +91,8 @@ widening or narrowing - s/S: default stream output behaviour for argument - p/P: cast any integer/char/bool/pointer/array to void const * + - n: store characters printed so far, produces no output, argument + must be pointer to type that std::streamoff is convertible to - m: output of std::strerror(errno), no automatic widening or narrowing, does not consume an argument - %: literal %, field width applied, does not consume an argument @@ -128,13 +130,13 @@ - Out-of-range argument/width/precision position - Inappropriate type for parameterised width/precision - Positional width/precision specifier not terminated with $ + - Inappropriate type for n conversion Some limitations have been described in passing. Major limitations and bugs include: - No automatic widening/narrowing support, so no simple way to output wide characters/strings to narrow streams/strings and vice versa. - - No support for n conversion (store characters printed so far) - Precision ignored for d/i/u/o/x/X conversions (should set minimum digits to print). - Precisoin for s/S conversion is only honoured for string-like @@ -183,7 +185,7 @@ #include #include - +namespace util { namespace detail { template class format_chars @@ -221,6 +223,7 @@ public: l = Character('l'), L = Character('L'), m = Character('m'), + n = Character('n'), o = Character('o'), p = Character('p'), s = Character('s'), @@ -270,6 +273,7 @@ public: l = L'l', L = L'L', m = L'm', + n = L'n', o = L'o', p = L'p', s = L's', @@ -320,6 +324,7 @@ public: character, // c, C string, // s, S pointer, // p + tell, // n strerror, // m percent // % }; @@ -389,6 +394,7 @@ public: case conversion::character: case conversion::string: case conversion::pointer: + case conversion::tell: case conversion::strerror: case conversion::percent: break; @@ -839,6 +845,9 @@ public: case format_helper::p: flags.set_conversion(format_flags::conversion::pointer); break; + case format_helper::n: + flags.set_conversion(format_flags::conversion::tell); + break; case format_helper::m: flags.set_conversion(format_flags::conversion::strerror); break; @@ -1256,6 +1265,39 @@ public: } }; +template +class format_store_integer +{ +private: + template struct is_non_const_ptr + { static constexpr bool value = std::is_pointer::value && !std::is_const >::value; }; + template struct is_unsigned_ptr + { static constexpr bool value = std::is_pointer::value && std::is_unsigned >::value; }; + template struct use_unsigned_cast + { static constexpr bool value = is_non_const_ptr::value && is_unsigned_ptr::value && std::is_convertible, std::remove_pointer_t >::value; }; + template struct use_signed_cast + { static constexpr bool value = is_non_const_ptr::value && !use_unsigned_cast::value && std::is_convertible >::value; }; + template struct disable + { static constexpr bool value = !use_unsigned_cast::value && !use_signed_cast::value; }; + +public: + template static std::enable_if_t::value, bool> apply(U const &value, std::streamoff data) + { + *value = std::remove_pointer_t(std::make_unsigned_t(data)); + return true; + } + template static std::enable_if_t::value, bool> apply(U const &value, std::streamoff data) + { + *value = std::remove_pointer_t(std::make_signed_t(data)); + return true; + } + template static std::enable_if_t::value, bool> apply(U const &value, std::streamoff data) + { + assert(false); // inappropriate type for storing characters written so far + return false; + } +}; + template class format_argument { @@ -1264,6 +1306,7 @@ public: : m_value(nullptr) , m_output_function(nullptr) , m_make_integer_function(nullptr) + , m_store_integer_function(nullptr) { } @@ -1272,15 +1315,18 @@ public: : m_value(reinterpret_cast(&value)) , m_output_function(&static_output) , m_make_integer_function(&static_make_integer) + , m_store_integer_function(&static_store_integer) { } void output(Stream &str, format_flags const &flags) const { m_output_function(str, flags, m_value); } bool make_integer(int &result) const { return m_make_integer_function(m_value, result); } + void store_integer(std::streamoff data) const { m_store_integer_function(m_value, data); } private: typedef void (*output_function)(Stream &str, format_flags const &flags, void const *value); typedef bool (*make_integer_function)(void const *value, int &result); + typedef void (*store_integer_function)(void const *value, std::streamoff data); template static void static_output(Stream &str, format_flags const &flags, void const *value) { @@ -1292,9 +1338,15 @@ private: return format_make_integer::apply(*reinterpret_cast(value), result); } + template static void static_store_integer(void const *value, std::streamoff data) + { + format_store_integer::apply(*reinterpret_cast(value), data); + } + void const *m_value; output_function m_output_function; make_integer_function m_make_integer_function; + store_integer_function m_store_integer_function; }; template @@ -1304,7 +1356,7 @@ inline std::array, sizeof...(Params)> make_format_argume } template -void stream_format(Stream &str, Format const &fmt, std::array, Count> const &args) +typename Stream::off_type stream_format(Stream &str, Format const &fmt, std::array, Count> const &args) { typedef format_helper > format_helper; typedef typename format_helper::iterator iterator; @@ -1334,7 +1386,8 @@ void stream_format(Stream &str, Format const &fmt, std::array= unsigned(arg_pos)); if ((0 >= arg_pos) || (args.size() < unsigned(arg_pos))) continue; - args[arg_pos - 1].output(str, flags); + if (format_flags::conversion::tell == flags.get_conversion()) + { + typename Stream::pos_type const current(str.tellp()); + args[arg_pos - 1].store_integer( + ((typename Stream::pos_type(-1) == begin) || (typename Stream::pos_type(-1) == current)) + ? typename Stream::off_type(-1) + : (current - begin)); + } + else + { + args[arg_pos - 1].output(str, flags); + } start = it; } } } + typename Stream::pos_type const end(str.tellp()); + return ((typename Stream::pos_type(-1) == begin) || (typename Stream::pos_type(-1) == end)) + ? typename Stream::off_type(-1) + : (end - begin); } } // namespace detail template -inline void stream_format(Stream &str, Format const &fmt, Params &&... args) +inline typename Stream::off_type stream_format(Stream &str, Format const &fmt, Params &&... args) { auto const arg_pack(detail::make_format_arguments(std::forward(args)...)); - detail::stream_format(str, fmt, arg_pack); + return detail::stream_format(str, fmt, arg_pack); } template @@ -1450,4 +1518,8 @@ inline String string_format(std::locale const &locale, Format const &fmt, Params return str.str(); }; +} // namespace util + +using util::string_format; + #endif // __MAME_UTIL_STRFORMAT_H__ -- cgit v1.2.3-70-g09d2