diff options
Diffstat (limited to 'src/lib/util/strformat.h')
-rw-r--r-- | src/lib/util/strformat.h | 988 |
1 files changed, 534 insertions, 454 deletions
diff --git a/src/lib/util/strformat.h b/src/lib/util/strformat.h index db3666e448b..f09965bc002 100644 --- a/src/lib/util/strformat.h +++ b/src/lib/util/strformat.h @@ -106,11 +106,12 @@ The format string type can be a pointer to a NUL-terminated string, an array containing a NUL-terminated or non-terminated string, or a STL contiguous container holding a string (e.g. std::string, - std::vector or std::array). Note that NUL characters characters are - only treated as terminators for pointers and arrays, they are - treated as normal characters for other containers. A non-contiguous - container (e.g. std::list or std::deque) will result in undesirable - behaviour likely culminating in a crash. + std::string_view, std::vector or std::array). Note that NUL + characters characters are only treated as terminators for pointers + and arrays, they are treated as normal characters for other + containers. Using a non-contiguous container (e.g. std::list or + std::deque) will result in undesirable behaviour likely culminating + in a crash. The value type of the format string and the character type of the output stream/string need to match. You can't use a wchar_t format @@ -131,6 +132,7 @@ - Inappropriate type for parameterised width/precision - Positional width/precision specifier not terminated with $ - Inappropriate type for n conversion + - Default conversion for type that lacks stream out operator Some limitations have been described in passing. Major limitations and bugs include: @@ -171,8 +173,6 @@ #pragma once -#include "vecstream.h" - #include <algorithm> #include <array> #include <cassert> @@ -184,26 +184,14 @@ #include <locale> #include <sstream> #include <string> +#include <string_view> #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 //************************************************************************** @@ -370,52 +358,54 @@ public: { } - template <typename Stream> void apply(Stream &stream) const + template <typename Character, typename Traits = std::char_traits<Character> > + void apply(std::basic_ostream<Character, Traits> &stream) const { - typedef format_chars<typename Stream::char_type> chars; + using stream_type = std::basic_ostream<Character, Traits>; + using chars = format_chars<Character>; stream.unsetf( - Stream::basefield | - Stream::adjustfield | - Stream::floatfield | - Stream::boolalpha | - Stream::showbase | - Stream::showpoint | - Stream::showpos | - Stream::uppercase); - - if (get_alternate_format()) stream.setf(Stream::showbase | Stream::showpoint); + stream_type::basefield | + stream_type::adjustfield | + stream_type::floatfield | + stream_type::boolalpha | + stream_type::showbase | + stream_type::showpoint | + stream_type::showpos | + stream_type::uppercase); + + if (get_alternate_format()) stream.setf(stream_type::showbase | stream_type::showpoint); stream.fill(get_zero_pad() ? chars::zero : chars::space); - stream.setf(get_left_align() ? Stream::left : get_zero_pad() ? Stream::internal : Stream::right); - if (positive_sign::plus == get_positive_sign()) stream.setf(Stream::showpos); + stream.setf(get_left_align() ? stream_type::left : get_zero_pad() ? stream_type::internal : stream_type::right); + if (positive_sign::plus == get_positive_sign()) stream.setf(stream_type::showpos); stream.precision((get_precision() < 0) ? 6 : get_precision()); stream.width(get_field_width()); - if (get_uppercase()) stream.setf(Stream::uppercase); + if (get_uppercase()) stream.setf(stream_type::uppercase); switch (get_conversion()) { case conversion::unspecified: break; case conversion::signed_decimal: case conversion::unsigned_decimal: - stream.setf(Stream::dec); + stream.setf(stream_type::dec); break; case conversion::octal: - stream.setf(Stream::oct); + stream.setf(stream_type::oct); break; case conversion::hexadecimal: - stream.setf(Stream::hex | Stream::scientific | Stream::fixed); + stream.setf(stream_type::hex | stream_type::scientific | stream_type::fixed); break; case conversion::scientific_decimal: - stream.setf(Stream::dec | Stream::scientific); + stream.setf(stream_type::dec | stream_type::scientific); break; case conversion::fixed_decimal: - stream.setf(Stream::dec | Stream::fixed); + stream.setf(stream_type::dec | stream_type::fixed); break; case conversion::floating_decimal: - stream.setf(Stream::dec); + stream.setf(stream_type::dec); break; case conversion::scientific_hexadecimal: - stream.setf(Stream::hex | Stream::scientific | Stream::fixed); + stream.setf(stream_type::hex | stream_type::scientific | stream_type::fixed); break; case conversion::character: case conversion::string: @@ -556,6 +546,7 @@ public: case conversion::octal: case conversion::hexadecimal: m_positive_sign = positive_sign::none; + [[fallthrough]]; case conversion::signed_decimal: if (0 <= m_precision) m_zero_pad = false; @@ -588,207 +579,268 @@ template <typename Stream, typename T> class format_output { private: - template <typename U> struct signed_integer_semantics - { static constexpr bool value = std::is_integral<U>::value && std::is_signed<U>::value; }; - template <typename U> struct unsigned_integer_semantics - { static constexpr bool value = std::is_integral<U>::value && !std::is_signed<U>::value; }; - template <typename U> struct default_semantics - { static constexpr bool value = !signed_integer_semantics<U>::value && !unsigned_integer_semantics<U>::value; }; + template <typename U> + struct string_semantics : public std::false_type { }; + template <typename CharT, typename Traits, typename Allocator> + struct string_semantics<std::basic_string<CharT, Traits, Allocator> > : public std::true_type { }; + template <typename CharT, typename Traits> + struct string_semantics<std::basic_string_view<CharT, Traits> > : public std::true_type { }; + template <typename U> + using signed_integer_semantics = std::bool_constant<std::is_integral_v<U> && std::is_signed_v<U> >; + template <typename U> + using unsigned_integer_semantics = std::bool_constant<std::is_integral_v<U> && !std::is_signed_v<U> >; + + template <typename U> + static std::enable_if_t<std::is_same_v<std::make_signed_t<U>, std::make_signed_t<char> > || std::is_integral_v<U> > apply_signed(Stream &str, U const &value) + { + if constexpr (std::is_same_v<std::make_signed_t<U>, std::make_signed_t<char> >) + str << int(std::make_signed_t<U>(value)); + else if constexpr (!std::is_signed_v<U> || std::is_same_v<typename Stream::char_type, U>) + str << std::make_signed_t<U>(value); +#if __cplusplus > 201703L + else if constexpr (!std::is_invocable_v<decltype([] (auto &x, auto &y) -> decltype(x << y) { return x << y; }), Stream &, U const &>) + str << std::make_signed_t<U>(value); +#endif + else + str << value; + } + + template <typename U> + static std::enable_if_t<std::is_same_v<std::make_unsigned_t<U>, std::make_unsigned_t<char> > || std::is_integral_v<U> > apply_unsigned(Stream &str, U const &value) + { + if constexpr (std::is_same_v<std::make_unsigned_t<U>, std::make_unsigned_t<char> >) + str << unsigned(std::make_unsigned_t<U>(value)); + else if constexpr (!std::is_unsigned_v<U> || std::is_same_v<typename Stream::char_type, U>) + str << std::make_unsigned_t<U>(value); +#if __cplusplus > 201703L + else if constexpr (!std::is_invocable_v<decltype([] (auto &x, auto &y) -> decltype(x << y) { return x << y; }), Stream &, U const &>) + str << std::make_unsigned_t<U>(value); +#endif + else + 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) + static void apply(Stream &str, format_flags const &flags, U const &value) { - switch (flags.get_conversion()) + if constexpr (string_semantics<U>::value) { - case format_flags::conversion::signed_decimal: - switch (flags.get_length()) + int const precision(flags.get_precision()); + if ((0 <= precision) && (value.size() > unsigned(precision))) { - case format_flags::length::character: - str << int(static_cast<signed char>(value)); - break; - case format_flags::length::short_integer: - str << short(value); - break; - case format_flags::length::long_integer: - str << long(value); - break; - case format_flags::length::long_long_integer: - str << static_cast<long long>(value); - break; - case format_flags::length::integer_maximum: - str << std::intmax_t(value); - break; - case format_flags::length::size_type: - str << std::make_signed_t<std::size_t>(value); - break; - case format_flags::length::pointer_difference: - str << std::make_signed_t<std::ptrdiff_t>(value); - break; - case format_flags::length::integer_32: - str << std::uint32_t(std::int32_t(value)); - break; - case format_flags::length::integer_64: - 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); + if constexpr (std::is_same_v<typename U::value_type, typename Stream::char_type>) + { + unsigned width(flags.get_field_width()); + bool const pad(unsigned(precision) < width); + typename Stream::fmtflags const adjust(str.flags() & Stream::adjustfield); + if (!pad || (Stream::left == adjust)) str.write(&*value.begin(), unsigned(precision)); + if (pad) + { + for (width -= precision; 0U < width; --width) str.put(str.fill()); + if (Stream::left != adjust) str.write(&*value.begin(), unsigned(precision)); + } + str.width(0); + } else - str << value; + { + str << value.substr(0, unsigned(precision)); + } } - break; - case format_flags::conversion::unsigned_decimal: - case format_flags::conversion::octal: - case format_flags::conversion::hexadecimal: - switch (flags.get_length()) + else { - case format_flags::length::character: - str << unsigned(static_cast<unsigned char>(static_cast<signed char>(value))); - break; - case format_flags::length::short_integer: - str << static_cast<unsigned short>(short(value)); - break; - case format_flags::length::long_integer: - str << static_cast<unsigned long>(long(value)); - break; - case format_flags::length::long_long_integer: - str << static_cast<unsigned long long>(static_cast<long long>(value)); - break; - case format_flags::length::integer_maximum: - str << std::uintmax_t(std::intmax_t(value)); - break; - case format_flags::length::size_type: - str << std::make_unsigned_t<std::size_t>(std::make_signed_t<std::size_t>(value)); - break; - case format_flags::length::pointer_difference: - str << std::make_unsigned_t<std::ptrdiff_t>(std::make_signed_t<std::ptrdiff_t>(value)); - break; - case format_flags::length::integer_32: - str << std::uint32_t(std::int32_t(value)); - break; - case format_flags::length::integer_64: - 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); + str << value; } - break; - case format_flags::conversion::character: - if (std::is_signed<typename Stream::char_type>::value) - str << typename Stream::char_type(value); - else - str << typename Stream::char_type(std::make_signed_t<typename Stream::char_type>(value)); - break; - case format_flags::conversion::pointer: - str << reinterpret_cast<void const *>(std::uintptr_t(std::intptr_t(value))); - break; - default: - str << value; } - } - template <typename U> - static void apply(std::enable_if_t<unsigned_integer_semantics<U>::value, Stream> &str, format_flags const &flags, U const &value) - { - switch (flags.get_conversion()) + else if constexpr (signed_integer_semantics<U>::value) { - case format_flags::conversion::signed_decimal: - switch (flags.get_length()) + switch (flags.get_conversion()) { - case format_flags::length::character: - str << int(static_cast<signed char>(static_cast<unsigned char>(value))); - break; - case format_flags::length::short_integer: - str << short(static_cast<unsigned short>(value)); - break; - case format_flags::length::long_integer: - str << long(static_cast<unsigned long>(value)); - break; - case format_flags::length::long_long_integer: - str << static_cast<long long>(static_cast<unsigned long long>(value)); - break; - case format_flags::length::integer_maximum: - str << std::intmax_t(std::uintmax_t(value)); - break; - case format_flags::length::size_type: - str << std::make_signed_t<std::size_t>(std::make_unsigned_t<std::size_t>(value)); + case format_flags::conversion::signed_decimal: + switch (flags.get_length()) + { + case format_flags::length::character: + str << int(static_cast<signed char>(value)); + break; + case format_flags::length::short_integer: + str << short(value); + break; + case format_flags::length::long_integer: + str << long(value); + break; + case format_flags::length::long_long_integer: + str << static_cast<long long>(value); + break; + case format_flags::length::integer_maximum: + str << std::intmax_t(value); + break; + case format_flags::length::size_type: + str << std::make_signed_t<std::size_t>(value); + break; + case format_flags::length::pointer_difference: + str << std::make_signed_t<std::ptrdiff_t>(value); + break; + case format_flags::length::integer_32: + str << std::uint32_t(std::int32_t(value)); + break; + case format_flags::length::integer_64: + str << std::int64_t(value); + break; + default: + apply_signed(str, value); + } break; - case format_flags::length::pointer_difference: - str << std::make_signed_t<std::ptrdiff_t>(std::make_unsigned_t<std::ptrdiff_t>(value)); + case format_flags::conversion::unsigned_decimal: + case format_flags::conversion::octal: + case format_flags::conversion::hexadecimal: + switch (flags.get_length()) + { + case format_flags::length::character: + str << unsigned(static_cast<unsigned char>(static_cast<signed char>(value))); + break; + case format_flags::length::short_integer: + str << static_cast<unsigned short>(short(value)); + break; + case format_flags::length::long_integer: + str << static_cast<unsigned long>(long(value)); + break; + case format_flags::length::long_long_integer: + str << static_cast<unsigned long long>(static_cast<long long>(value)); + break; + case format_flags::length::integer_maximum: + str << std::uintmax_t(std::intmax_t(value)); + break; + case format_flags::length::size_type: + str << std::make_unsigned_t<std::size_t>(std::make_signed_t<std::size_t>(value)); + break; + case format_flags::length::pointer_difference: + str << std::make_unsigned_t<std::ptrdiff_t>(std::make_signed_t<std::ptrdiff_t>(value)); + break; + case format_flags::length::integer_32: + str << std::uint32_t(std::int32_t(value)); + break; + case format_flags::length::integer_64: + str << std::uint64_t(std::int64_t(value)); + break; + default: + apply_unsigned(str, value); + } break; - case format_flags::length::integer_32: - str << std::int32_t(std::uint32_t(value)); + case format_flags::conversion::character: + if (std::is_signed<typename Stream::char_type>::value) + str << typename Stream::char_type(value); + else + str << typename Stream::char_type(std::make_signed_t<typename Stream::char_type>(value)); break; - case format_flags::length::integer_64: - str << std::int64_t(std::uint64_t(value)); + case format_flags::conversion::pointer: + str << reinterpret_cast<void const *>(std::uintptr_t(std::intptr_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); + str << value; } - break; - case format_flags::conversion::unsigned_decimal: - case format_flags::conversion::octal: - case format_flags::conversion::hexadecimal: - switch (flags.get_length()) + } + else if constexpr (unsigned_integer_semantics<U>::value) + { + switch (flags.get_conversion()) { - case format_flags::length::character: - str << unsigned(static_cast<unsigned char>(value)); - break; - case format_flags::length::short_integer: - str << static_cast<unsigned short>(value); - break; - case format_flags::length::long_integer: - str << static_cast<unsigned long>(value); - break; - case format_flags::length::long_long_integer: - str << static_cast<unsigned long long>(value); - break; - case format_flags::length::integer_maximum: - str << std::uintmax_t(value); - break; - case format_flags::length::size_type: - str << std::make_unsigned_t<std::size_t>(value); + case format_flags::conversion::signed_decimal: + switch (flags.get_length()) + { + case format_flags::length::character: + str << int(static_cast<signed char>(static_cast<unsigned char>(value))); + break; + case format_flags::length::short_integer: + str << short(static_cast<unsigned short>(value)); + break; + case format_flags::length::long_integer: + str << long(static_cast<unsigned long>(value)); + break; + case format_flags::length::long_long_integer: + str << static_cast<long long>(static_cast<unsigned long long>(value)); + break; + case format_flags::length::integer_maximum: + str << std::intmax_t(std::uintmax_t(value)); + break; + case format_flags::length::size_type: + str << std::make_signed_t<std::size_t>(std::make_unsigned_t<std::size_t>(value)); + break; + case format_flags::length::pointer_difference: + str << std::make_signed_t<std::ptrdiff_t>(std::make_unsigned_t<std::ptrdiff_t>(value)); + break; + case format_flags::length::integer_32: + str << std::int32_t(std::uint32_t(value)); + break; + case format_flags::length::integer_64: + str << std::int64_t(std::uint64_t(value)); + break; + default: + apply_signed(str, value); + } break; - case format_flags::length::pointer_difference: - str << std::make_unsigned_t<std::ptrdiff_t>(value); + case format_flags::conversion::unsigned_decimal: + case format_flags::conversion::octal: + case format_flags::conversion::hexadecimal: + switch (flags.get_length()) + { + case format_flags::length::character: + str << unsigned(static_cast<unsigned char>(value)); + break; + case format_flags::length::short_integer: + str << static_cast<unsigned short>(value); + break; + case format_flags::length::long_integer: + str << static_cast<unsigned long>(value); + break; + case format_flags::length::long_long_integer: + str << static_cast<unsigned long long>(value); + break; + case format_flags::length::integer_maximum: + str << std::uintmax_t(value); + break; + case format_flags::length::size_type: + str << std::make_unsigned_t<std::size_t>(value); + break; + case format_flags::length::pointer_difference: + str << std::make_unsigned_t<std::ptrdiff_t>(value); + break; + case format_flags::length::integer_32: + str << std::uint32_t(std::int32_t(value)); + break; + case format_flags::length::integer_64: + str << std::int64_t(value); + break; + default: + apply_unsigned(str, value); + } break; - case format_flags::length::integer_32: - str << std::uint32_t(std::int32_t(value)); + case format_flags::conversion::character: + if (std::is_signed<typename Stream::char_type>::value) + str << typename Stream::char_type(value); + else + str << typename Stream::char_type(std::make_signed_t<typename Stream::char_type>(value)); break; - case format_flags::length::integer_64: - str << std::int64_t(value); + case format_flags::conversion::pointer: + str << reinterpret_cast<void const *>(std::uintptr_t(value)); break; default: - if (std::is_same<std::make_unsigned_t<U>, std::make_unsigned_t<char> >::value) - str << unsigned(value); +#if __cplusplus > 201703L + if constexpr (!std::is_invocable_v<decltype([] (auto &x, auto &y) -> decltype(x << y) { return x << y; }), Stream &, U const &>) + { + assert(false); // stream out operator not declared or declared deleted + str << '?'; + } else +#endif + { str << value; + } } - break; - case format_flags::conversion::character: - if (std::is_signed<typename Stream::char_type>::value) - str << typename Stream::char_type(value); - else - str << typename Stream::char_type(std::make_signed_t<typename Stream::char_type>(value)); - break; - case format_flags::conversion::pointer: - str << reinterpret_cast<void const *>(std::uintptr_t(value)); - break; - default: + } + else + { str << value; } } - template <typename U> - static void apply(std::enable_if_t<default_semantics<U>::value, Stream> &str, format_flags const &flags, U const &value) - { - str << value; - } static void apply(Stream &str, format_flags const &flags, bool value) { switch (flags.get_conversion()) @@ -810,88 +862,59 @@ public: str << value; } } - template <typename CharT, typename Traits, typename Allocator> - static void apply(std::enable_if_t<std::is_same<CharT, typename Stream::char_type>::value, Stream> &str, format_flags const &flags, std::basic_string<CharT, Traits, Allocator> const &value) - { - int const precision(flags.get_precision()); - if ((0 <= precision) && (value.size() > unsigned(precision))) - { - unsigned width(flags.get_field_width()); - bool const pad(unsigned(precision) < width); - typename Stream::fmtflags const adjust(str.flags() & Stream::adjustfield); - if (!pad || (Stream::left == adjust)) str.write(&*value.begin(), unsigned(precision)); - if (pad) - { - for (width -= precision; 0U < width; --width) str.put(str.fill()); - if (Stream::left != adjust) str.write(&*value.begin(), unsigned(precision)); - } - str.width(0); - } - else - { - str << value; - } - } - template <typename CharT, typename Traits, typename Allocator> - static void apply(std::enable_if_t<!std::is_same<CharT, typename Stream::char_type>::value, Stream> &str, format_flags const &flags, std::basic_string<CharT, Traits, Allocator> const &value) - { - int const precision(flags.get_precision()); - if ((0 <= precision) && (value.size() > unsigned(precision))) - str << value.substr(0, unsigned(precision)); - else - str << value; - } }; template <typename Stream, typename T> class format_output<Stream, T *> { protected: - template <typename U> struct string_semantics - { static constexpr bool value = std::is_same<std::remove_const_t<U>, typename Stream::char_type>::value; }; + template <typename U> + using string_semantics = std::bool_constant<std::is_same_v<std::remove_const_t<U>, typename Stream::char_type> >; public: template <typename U> - static void apply(std::enable_if_t<string_semantics<U>::value, Stream> &str, format_flags const &flags, U const *value) + static void apply(Stream &str, format_flags const &flags, U const *value) { - switch (flags.get_conversion()) + if constexpr (string_semantics<U>::value) { - case format_flags::conversion::string: + switch (flags.get_conversion()) { - int precision(flags.get_precision()); - if (0 <= flags.get_precision()) + case format_flags::conversion::string: { - std::streamsize cnt(0); - for ( ; (0 < precision) && (U(format_chars<U>::nul) != value[cnt]); --precision, ++cnt) { } - unsigned width(flags.get_field_width()); - bool const pad(std::make_unsigned_t<std::streamsize>(cnt) < width); - typename Stream::fmtflags const adjust(str.flags() & Stream::adjustfield); - if (!pad || (Stream::left == adjust)) str.write(value, cnt); - if (pad) + int precision(flags.get_precision()); + if (0 <= flags.get_precision()) { - for (width -= cnt; 0U < width; --width) str.put(str.fill()); - if (Stream::left != adjust) str.write(value, cnt); + std::streamsize cnt(0); + for ( ; (0 < precision) && (U(format_chars<U>::nul) != value[cnt]); --precision, ++cnt) { } + unsigned width(flags.get_field_width()); + bool const pad(std::make_unsigned_t<std::streamsize>(cnt) < width); + typename Stream::fmtflags const adjust(str.flags() & Stream::adjustfield); + if (!pad || (Stream::left == adjust)) str.write(value, cnt); + if (pad) + { + for (width -= cnt; 0U < width; --width) str.put(str.fill()); + if (Stream::left != adjust) str.write(value, cnt); + } + str.width(0); + } + else + { + str << value; } - str.width(0); - } - else - { - str << value; } + break; + case format_flags::conversion::pointer: + str << reinterpret_cast<void const *>(const_cast<std::remove_volatile_t<U> *>(value)); + break; + default: + str << value; } - break; - case format_flags::conversion::pointer: + } + else + { str << reinterpret_cast<void const *>(const_cast<std::remove_volatile_t<U> *>(value)); - break; - default: - str << value; } } - template <typename U> - static void apply(std::enable_if_t<!string_semantics<U>::value, Stream> &str, format_flags const &flags, U const *value) - { - str << reinterpret_cast<void const *>(const_cast<std::remove_volatile_t<U> *>(value)); - } }; template <typename Stream, typename T, std::size_t N> @@ -920,27 +943,28 @@ template <typename T> class format_make_integer { private: - template <typename U> struct use_unsigned_cast - { static constexpr bool value = std::is_convertible<U const, unsigned>::value && std::is_unsigned<U>::value; }; - template <typename U> struct use_signed_cast - { static constexpr bool value = !use_unsigned_cast<U>::value && std::is_convertible<U const, int>::value; }; - template <typename U> struct disable - { static constexpr bool value = !use_unsigned_cast<U>::value && !use_signed_cast<U>::value; }; + template <typename U> + using use_unsigned_cast = std::bool_constant<std::is_convertible_v<U const, unsigned> && std::is_unsigned_v<U> >; + template <typename U> + using use_signed_cast = std::bool_constant<!use_unsigned_cast<U>::value && std::is_convertible_v<U const, int> >; public: - template <typename U> static std::enable_if_t<use_unsigned_cast<U>::value, bool> apply(U const &value, int &result) - { - result = int(unsigned(value)); - return true; - } - template <typename U> static std::enable_if_t<use_signed_cast<U>::value, bool> apply(U const &value, int &result) + template <typename U> static bool apply(U const &value, int &result) { - result = int(value); - return true; - } - template <typename U> static std::enable_if_t<disable<U>::value, bool> apply(U const &value, int &result) - { - return false; + if constexpr (use_unsigned_cast<U>::value) + { + result = int(unsigned(value)); + return true; + } + else if constexpr (use_signed_cast<U>::value) + { + result = int(value); + return true; + } + else + { + return false; + } } }; @@ -953,32 +977,33 @@ template <typename T> class format_store_integer { private: - template <typename U> struct is_non_const_ptr - { static constexpr bool value = std::is_pointer<U>::value && !std::is_const<std::remove_pointer_t<U> >::value; }; - template <typename U> struct is_unsigned_ptr - { static constexpr bool value = std::is_pointer<U>::value && std::is_unsigned<std::remove_pointer_t<U> >::value; }; - template <typename U> struct use_unsigned_cast - { static constexpr bool value = is_non_const_ptr<U>::value && is_unsigned_ptr<U>::value && std::is_convertible<std::make_unsigned_t<std::streamoff>, std::remove_pointer_t<U> >::value; }; - template <typename U> struct use_signed_cast - { static constexpr bool value = is_non_const_ptr<U>::value && !use_unsigned_cast<U>::value && std::is_convertible<std::streamoff, std::remove_pointer_t<U> >::value; }; - template <typename U> struct disable - { static constexpr bool value = !use_unsigned_cast<U>::value && !use_signed_cast<U>::value; }; + template <typename U> + using is_non_const_ptr = std::bool_constant<std::is_pointer_v<U> && !std::is_const_v<std::remove_pointer_t<U> > >; + template <typename U> + using is_unsigned_ptr = std::bool_constant<std::is_pointer_v<U> && std::is_unsigned_v<std::remove_pointer_t<U> > >; + template <typename U> + using use_unsigned_cast = std::bool_constant<is_non_const_ptr<U>::value && is_unsigned_ptr<U>::value && std::is_convertible_v<std::make_unsigned_t<std::streamoff>, std::remove_pointer_t<U> > >; + template <typename U> + using use_signed_cast = std::bool_constant<is_non_const_ptr<U>::value && !use_unsigned_cast<U>::value && std::is_convertible_v<std::streamoff, std::remove_pointer_t<U> > >; public: - template <typename U> static std::enable_if_t<use_unsigned_cast<U>::value, bool> apply(U const &value, std::streamoff data) - { - *value = std::remove_pointer_t<U>(std::make_unsigned_t<std::streamoff>(data)); - return true; - } - template <typename U> static std::enable_if_t<use_signed_cast<U>::value, bool> apply(U const &value, std::streamoff data) - { - *value = std::remove_pointer_t<U>(std::make_signed_t<std::streamoff>(data)); - return true; - } - template <typename U> static std::enable_if_t<disable<U>::value, bool> apply(U const &value, std::streamoff data) + template <typename U> static bool apply(U const &value, std::streamoff data) { - assert(false); // inappropriate type for storing characters written so far - return false; + if constexpr (use_unsigned_cast<U>::value) + { + *value = std::remove_pointer_t<U>(std::make_unsigned_t<std::streamoff>(data)); + return true; + } + else if constexpr (use_signed_cast<U>::value) + { + *value = std::remove_pointer_t<U>(std::make_signed_t<std::streamoff>(data)); + return true; + } + else + { + assert(false); // inappropriate type for storing characters written so far + return false; + } } }; @@ -987,10 +1012,12 @@ public: // NON-POLYMORPHIC ARGUMENT WRAPPER //************************************************************************** -template <typename Stream> +template <typename Character, typename Traits = std::char_traits<Character> > class format_argument { public: + using stream_type = std::basic_ostream<Character, Traits>; + format_argument() : m_value(nullptr) , m_output_function(nullptr) @@ -1008,18 +1035,18 @@ public: { } - void output(Stream &str, format_flags const &flags) const { m_output_function(str, flags, m_value); } + void output(stream_type &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 void (*output_function)(stream_type &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 <typename T> static void static_output(Stream &str, format_flags const &flags, void const *value) + template <typename T> static void static_output(stream_type &str, format_flags const &flags, void const *value) { - format_output<Stream, T>::apply(str, flags, *reinterpret_cast<T const *>(value)); + format_output<stream_type, T>::apply(str, flags, *reinterpret_cast<T const *>(value)); } template <typename T> static bool static_make_integer(void const *value, int &result) @@ -1043,11 +1070,12 @@ private: // NON-POLYMORPHIC ARGUMENT PACK WRAPPER BASE //************************************************************************** -template <typename Stream = std::ostream> +template <typename Character = char, typename Traits = std::char_traits<Character> > class format_argument_pack { public: - typedef typename Stream::char_type char_type; + using stream_type = std::basic_ostream<Character, Traits>; + using char_type = Character; typedef char_type const *iterator; iterator format_begin() const { @@ -1061,7 +1089,7 @@ public: { return m_argument_count; } - format_argument<Stream> const &operator[](std::size_t index) const + format_argument<char_type, Traits> const &operator[](std::size_t index) const { assert(m_argument_count > index); return m_arguments[index]; @@ -1069,16 +1097,16 @@ public: protected: template <typename T> - struct handle_char_ptr { static constexpr bool value = std::is_pointer<T>::value && std::is_same<std::remove_cv_t<std::remove_pointer_t<T> >, char_type>::value; }; + using handle_char_ptr = std::bool_constant<std::is_pointer_v<T> && std::is_same_v<std::remove_cv_t<std::remove_pointer_t<T> >, char_type> >; template <typename T> - struct handle_char_array { static constexpr bool value = std::is_array<T>::value && std::is_same<std::remove_cv_t<std::remove_extent_t<T> >, char_type>::value; }; + using handle_char_array = std::bool_constant<std::is_array_v<T> && std::is_same_v<std::remove_cv_t<std::remove_extent_t<T> >, char_type> >; template <typename T> - struct handle_container { static constexpr bool value = !handle_char_ptr<T>::value && !handle_char_array<T>::value; }; + using handle_container = std::bool_constant<!handle_char_ptr<T>::value && !handle_char_array<T>::value>; template <typename Format> format_argument_pack( Format &&fmt, - format_argument<Stream> const *arguments, + format_argument<char_type, Traits> const *arguments, std::enable_if_t<handle_char_ptr<std::remove_reference_t<Format> >::value, std::size_t> argument_count) : m_begin(fmt) , m_end(nullptr) @@ -1094,7 +1122,7 @@ protected: template <typename Format> format_argument_pack( Format &&fmt, - format_argument<Stream> const *arguments, + format_argument<char_type, Traits> const *arguments, std::enable_if_t<handle_char_array<std::remove_reference_t<Format> >::value, std::size_t> argument_count) : m_begin(std::cbegin(fmt)) , m_end(std::cend(fmt)) @@ -1110,7 +1138,7 @@ protected: template <typename Format> format_argument_pack( Format &&fmt, - format_argument<Stream> const *arguments, + format_argument<char_type, Traits> const *arguments, std::enable_if_t<handle_container<std::remove_reference_t<Format> >::value, std::size_t> argument_count) : m_begin(fmt.empty() ? nullptr : &*std::cbegin(fmt)) , m_end(fmt.empty() ? nullptr : (m_begin + std::distance(std::cbegin(fmt), std::cend(fmt)))) @@ -1124,17 +1152,17 @@ protected: assert(m_arguments || !m_argument_count); } - format_argument_pack(format_argument_pack<Stream> const &) = default; - format_argument_pack(format_argument_pack<Stream> &&) = default; - format_argument_pack &operator=(format_argument_pack<Stream> const &) = default; - format_argument_pack &operator=(format_argument_pack<Stream> &&) = default; + format_argument_pack(format_argument_pack<char_type, Traits> const &) = default; + format_argument_pack(format_argument_pack<char_type, Traits> &&) = default; + format_argument_pack &operator=(format_argument_pack<char_type, Traits> const &) = default; + format_argument_pack &operator=(format_argument_pack<char_type, Traits> &&) = default; private: - iterator m_begin; - iterator m_end; - bool m_check_nul; - format_argument<Stream> const *m_arguments; - std::size_t m_argument_count; + iterator m_begin; + iterator m_end; + bool m_check_nul; + format_argument<char_type, Traits> const *m_arguments; + std::size_t m_argument_count; }; @@ -1142,27 +1170,27 @@ private: // ARGUMENT PACK WRAPPER IMPLEMENTATION //************************************************************************** -template <typename Stream, std::size_t Count> +template <typename Character, typename Traits, std::size_t Count> class format_argument_pack_impl - : private std::array<format_argument<Stream>, Count> - , public format_argument_pack<Stream> + : private std::array<format_argument<Character, Traits>, Count> + , public format_argument_pack<Character, Traits> { public: - using typename format_argument_pack<Stream>::iterator; - using format_argument_pack<Stream>::operator[]; + using typename format_argument_pack<Character, Traits>::iterator; + using format_argument_pack<Character, Traits>::operator[]; template <typename Format, typename... Params> format_argument_pack_impl(Format &&fmt, Params &&... args) - : std::array<format_argument<Stream>, Count>({ { format_argument<Stream>(std::forward<Params>(args))... } }) - , format_argument_pack<Stream>(std::forward<Format>(fmt), Count ? &*this->cbegin() : nullptr, Count) + : std::array<format_argument<Character, Traits>, Count>({ { format_argument<Character, Traits>(std::forward<Params>(args))... } }) + , format_argument_pack<Character, Traits>(std::forward<Format>(fmt), Count ? &*this->cbegin() : nullptr, Count) { static_assert(sizeof...(Params) == Count, "Wrong number of constructor arguments"); } - format_argument_pack_impl(format_argument_pack_impl<Stream, Count> const &) = default; - format_argument_pack_impl(format_argument_pack_impl<Stream, Count> &&) = default; - format_argument_pack_impl &operator=(format_argument_pack_impl<Stream, Count> const &) = default; - format_argument_pack_impl &operator=(format_argument_pack_impl<Stream, Count> &&) = default; + format_argument_pack_impl(format_argument_pack_impl<Character, Traits, Count> const &) = default; + format_argument_pack_impl(format_argument_pack_impl<Character, Traits, Count> &&) = default; + format_argument_pack_impl &operator=(format_argument_pack_impl<Character, Traits, Count> const &) = default; + format_argument_pack_impl &operator=(format_argument_pack_impl<Character, Traits, Count> &&) = default; }; @@ -1171,9 +1199,9 @@ public: //************************************************************************** template <typename Stream = std::ostream, typename Format, typename... Params> -inline format_argument_pack_impl<Stream, sizeof...(Params)> make_format_argument_pack(Format &&fmt, Params &&... args) +inline auto make_format_argument_pack(Format &&fmt, Params &&... args) { - return format_argument_pack_impl<Stream, sizeof...(Params)>(std::forward<Format>(fmt), std::forward<Params>(args)...); + return format_argument_pack_impl<typename Stream::char_type, typename Stream::traits_type, sizeof...(Params)>(std::forward<Format>(fmt), std::forward<Params>(args)...); } @@ -1406,38 +1434,45 @@ public: break; case format_helper::X: flags.set_uppercase(); + [[fallthrough]]; case format_helper::x: flags.set_conversion(format_flags::conversion::hexadecimal); break; case format_helper::E: flags.set_uppercase(); + [[fallthrough]]; case format_helper::e: flags.set_conversion(format_flags::conversion::scientific_decimal); break; case format_helper::F: flags.set_uppercase(); + [[fallthrough]]; case format_helper::f: flags.set_conversion(format_flags::conversion::fixed_decimal); break; case format_helper::G: flags.set_uppercase(); + [[fallthrough]]; case format_helper::g: flags.set_conversion(format_flags::conversion::floating_decimal); break; case format_helper::A: flags.set_uppercase(); + [[fallthrough]]; case format_helper::a: flags.set_conversion(format_flags::conversion::scientific_hexadecimal); break; case format_helper::C: if (format_flags::length::unspecified == flags.get_length()) flags.set_length(format_flags::length::long_integer); + [[fallthrough]]; case format_helper::c: flags.set_conversion(format_flags::conversion::character); break; case format_helper::S: if (format_flags::length::unspecified == flags.get_length()) flags.set_length(format_flags::length::long_integer); + [[fallthrough]]; case format_helper::s: flags.set_conversion(format_flags::conversion::string); break; @@ -1514,15 +1549,16 @@ private: // CORE FORMATTING FUNCTION //************************************************************************** -template <typename Stream, typename Base> -typename Stream::off_type stream_format(Stream &str, format_argument_pack<Base> const &args) +template <typename Character, typename Traits = std::char_traits<Character> > +typename std::basic_ostream<Character, Traits>::off_type stream_format(std::basic_ostream<Character, Traits> &str, format_argument_pack<Character, Traits> const &args) { - typedef format_helper<format_argument_pack<Base> > format_helper; - typedef typename format_argument_pack<Base>::iterator iterator; + using stream_type = std::basic_ostream<Character, Traits>; + using format_helper = format_helper<format_argument_pack<Character, Traits> >; + using iterator = typename format_argument_pack<Character, Traits>::iterator; class stream_preserver { public: - stream_preserver(Stream &stream) + stream_preserver(stream_type &stream) : m_stream(stream) , m_fill(stream.fill()) , m_flags(stream.flags()) @@ -1538,14 +1574,14 @@ typename Stream::off_type stream_format(Stream &str, format_argument_pack<Base> m_stream.fill(m_fill); } private: - Stream &m_stream; - typename Stream::char_type m_fill; - typename Stream::fmtflags m_flags; - std::streamsize m_precision; - std::streamsize m_width; + stream_type &m_stream; + typename stream_type::char_type m_fill; + typename stream_type::fmtflags m_flags; + std::streamsize m_precision; + std::streamsize m_width; }; - typename Stream::pos_type const begin(str.tellp()); + typename stream_type::pos_type const begin(str.tellp()); stream_preserver const preserver(str); int next_pos(1); iterator start = args.format_begin(); @@ -1618,7 +1654,7 @@ typename Stream::off_type stream_format(Stream &str, format_argument_pack<Base> } else if (format_flags::conversion::percent == flags.get_conversion()) { - str << typename Stream::char_type(format_chars<typename Stream::char_type>::percent); + str << Character(format_chars<Character>::percent); start = it; } else @@ -1629,10 +1665,10 @@ typename Stream::off_type stream_format(Stream &str, format_argument_pack<Base> continue; if (format_flags::conversion::tell == flags.get_conversion()) { - typename Stream::pos_type const current(str.tellp()); + typename stream_type::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) + ((typename stream_type::pos_type(-1) == begin) || (typename stream_type::pos_type(-1) == current)) + ? typename stream_type::off_type(-1) : (current - begin)); } else @@ -1643,9 +1679,9 @@ typename Stream::off_type stream_format(Stream &str, format_argument_pack<Base> } } } - 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) + typename stream_type::pos_type const end(str.tellp()); + return ((typename stream_type::pos_type(-1) == begin) || (typename stream_type::pos_type(-1) == end)) + ? typename stream_type::off_type(-1) : (end - begin); } @@ -1662,14 +1698,14 @@ inline typename Stream::off_type stream_format(Stream &str, Format const &fmt, P return detail::stream_format(str, detail::make_format_argument_pack<Stream>(fmt, std::forward<Params>(args)...)); } -template <typename Stream, typename Base> -inline typename Stream::off_type stream_format(Stream &str, detail::format_argument_pack<Base> const &args) +template <typename Stream, typename Character, typename Traits> +inline typename Stream::off_type stream_format(Stream &str, detail::format_argument_pack<Character, Traits> const &args) { return detail::stream_format(str, args); } -template <typename Stream, typename Base> -inline typename Stream::off_type stream_format(Stream &str, detail::format_argument_pack<Base> &&args) +template <typename Stream, typename Character, typename Traits> +inline typename Stream::off_type stream_format(Stream &str, detail::format_argument_pack<Character, Traits> &&args) { return detail::stream_format(str, args); } @@ -1682,7 +1718,7 @@ inline typename Stream::off_type stream_format(Stream &str, detail::format_argum template <typename String = std::string, typename Format, typename... Params> inline String string_format(Format &&fmt, Params &&... args) { - typedef std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type> ostream; + using ostream = std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type>; ostream str; stream_format(str, fmt, std::forward<Params>(args)...); return str.str(); @@ -1691,45 +1727,45 @@ inline String string_format(Format &&fmt, Params &&... args) template <typename String = std::string, typename Format, typename... Params> inline String string_format(std::locale const &locale, Format &&fmt, Params &&... args) { - typedef std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type> ostream; + using ostream = std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type>; ostream str; str.imbue(locale); stream_format(str, fmt, std::forward<Params>(args)...); return str.str(); }; -template <typename String = std::string, typename Stream> -inline String string_format(detail::format_argument_pack<Stream> const &args) +template <typename String = std::string> +inline String string_format(detail::format_argument_pack<typename String::value_type, typename String::traits_type> const &args) { - typedef std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type> ostream; + using ostream = std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type>; ostream str; detail::stream_format(str, args); return str.str(); }; -template <typename String = std::string, typename Stream> -inline String string_format(detail::format_argument_pack<Stream> &&args) +template <typename String = std::string> +inline String string_format(detail::format_argument_pack<typename String::value_type, typename String::traits_type> &&args) { - typedef std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type> ostream; + using ostream = std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type>; ostream str; detail::stream_format(str, std::move(args)); return str.str(); }; -template <typename String = std::string, typename Stream> -inline String string_format(std::locale const &locale, detail::format_argument_pack<Stream> const &args) +template <typename String = std::string> +inline String string_format(std::locale const &locale, detail::format_argument_pack<typename String::value_type, typename String::traits_type> const &args) { - typedef std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type> ostream; + using ostream = std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type>; ostream str; str.imbue(locale); detail::stream_format(str, args); return str.str(); }; -template <typename String = std::string, typename Stream> -inline String string_format(std::locale const &locale, detail::format_argument_pack<Stream> &&args) +template <typename String = std::string> +inline String string_format(std::locale const &locale, detail::format_argument_pack<typename String::value_type, typename String::traits_type> &&args) { - typedef std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type> ostream; + using ostream = std::basic_ostringstream<typename String::value_type, typename String::traits_type, typename String::allocator_type>; ostream str; str.imbue(locale); detail::stream_format(str, std::move(args)); @@ -1746,8 +1782,6 @@ using detail::make_format_argument_pack; } // namespace util -using util::string_format; - //************************************************************************** // EXTERNAL TEMPLATE INSTANTIATIONS @@ -1762,69 +1796,115 @@ extern template class format_chars<wchar_t>; extern template void format_flags::apply(std::ostream &) const; extern template void format_flags::apply(std::wostream &) const; -extern template void format_flags::apply(std::iostream &) const; -extern template void format_flags::apply(std::wiostream &) const; -extern template void format_flags::apply(std::ostringstream &) const; -extern template void format_flags::apply(std::wostringstream &) const; -extern template void format_flags::apply(std::stringstream &) const; -extern template void format_flags::apply(std::wstringstream &) const; -extern template void format_flags::apply(ovectorstream &) const; -extern template void format_flags::apply(wovectorstream &) const; -extern template void format_flags::apply(vectorstream &) const; -extern template void format_flags::apply(wvectorstream &) const; - -extern template class format_argument<std::ostream>; -extern template class format_argument<std::wostream>; -extern template class format_argument<std::iostream>; -extern template class format_argument<std::wiostream>; -extern template class format_argument<std::ostringstream>; -extern template class format_argument<std::wostringstream>; -extern template class format_argument<std::stringstream>; -extern template class format_argument<std::wstringstream>; -extern template class format_argument<ovectorstream>; -extern template class format_argument<wovectorstream>; -extern template class format_argument<vectorstream>; -extern template class format_argument<wvectorstream>; - -extern template class format_argument_pack<std::ostream>; -extern template class format_argument_pack<std::wostream>; -extern template class format_argument_pack<std::iostream>; -extern template class format_argument_pack<std::wiostream>; -extern template class format_argument_pack<std::ostringstream>; -extern template class format_argument_pack<std::wostringstream>; -extern template class format_argument_pack<std::stringstream>; -extern template class format_argument_pack<std::wstringstream>; -extern template class format_argument_pack<ovectorstream>; -extern template class format_argument_pack<wovectorstream>; -extern template class format_argument_pack<vectorstream>; -extern template class format_argument_pack<wvectorstream>; - -extern template std::ostream::off_type stream_format(std::ostream &, format_argument_pack<std::ostream> const &); -extern template std::wostream::off_type stream_format(std::wostream &, format_argument_pack<std::wostream> const &); -extern template std::iostream::off_type stream_format(std::iostream &, format_argument_pack<std::ostream> const &); -extern template std::iostream::off_type stream_format(std::iostream &, format_argument_pack<std::iostream> const &); -extern template std::wiostream::off_type stream_format(std::wiostream &, format_argument_pack<std::wostream> const &); -extern template std::wiostream::off_type stream_format(std::wiostream &, format_argument_pack<std::wiostream> const &); -extern template std::ostringstream::off_type stream_format(std::ostringstream &, format_argument_pack<std::ostream> const &); -extern template std::ostringstream::off_type stream_format(std::ostringstream &, format_argument_pack<std::ostringstream> const &); -extern template std::wostringstream::off_type stream_format(std::wostringstream &, format_argument_pack<std::wostream> const &); -extern template std::wostringstream::off_type stream_format(std::wostringstream &, format_argument_pack<std::wostringstream> const &); -extern template std::stringstream::off_type stream_format(std::stringstream &, format_argument_pack<std::ostream> const &); -extern template std::stringstream::off_type stream_format(std::stringstream &, format_argument_pack<std::iostream> const &); -extern template std::stringstream::off_type stream_format(std::stringstream &, format_argument_pack<std::stringstream> const &); -extern template std::wstringstream::off_type stream_format(std::wstringstream &, format_argument_pack<std::wostream> const &); -extern template std::wstringstream::off_type stream_format(std::wstringstream &, format_argument_pack<std::wiostream> const &); -extern template std::wstringstream::off_type stream_format(std::wstringstream &, format_argument_pack<std::wstringstream> const &); -extern template ovectorstream::off_type stream_format(ovectorstream &, format_argument_pack<std::ostream> const &); -extern template ovectorstream::off_type stream_format(ovectorstream &, format_argument_pack<ovectorstream> const &); -extern template wovectorstream::off_type stream_format(wovectorstream &, format_argument_pack<std::wostream> const &); -extern template wovectorstream::off_type stream_format(wovectorstream &, format_argument_pack<wovectorstream> const &); -extern template vectorstream::off_type stream_format(vectorstream &, format_argument_pack<std::ostream> const &); -extern template vectorstream::off_type stream_format(vectorstream &, format_argument_pack<std::iostream> const &); -extern template vectorstream::off_type stream_format(vectorstream &, format_argument_pack<vectorstream> const &); -extern template wvectorstream::off_type stream_format(wvectorstream &, format_argument_pack<std::wostream> const &); -extern template wvectorstream::off_type stream_format(wvectorstream &, format_argument_pack<std::wiostream> const &); -extern template wvectorstream::off_type stream_format(wvectorstream &, format_argument_pack<wvectorstream> const &); + +extern template class format_argument<char>; +extern template void format_argument<char>::static_output<bool>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<char>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<signed char>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<unsigned char>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<short>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<unsigned short>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<int>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<unsigned int>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<long>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<unsigned long>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<long long>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<unsigned long long>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<char *>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<char const *>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<std::string>(std::ostream &, format_flags const &, void const *); +extern template void format_argument<char>::static_output<std::string_view>(std::ostream &, format_flags const &, void const *); +extern template bool format_argument<char>::static_make_integer<bool>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<char>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<signed char>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<unsigned char>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<short>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<unsigned short>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<int>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<unsigned int>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<long>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<unsigned long>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<long long>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<unsigned long long>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<char *>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<char const *>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<std::string>(void const *, int &); +extern template bool format_argument<char>::static_make_integer<std::string_view>(void const *, int &); +extern template void format_argument<char>::static_store_integer<bool>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<char>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<signed char>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<unsigned char>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<short>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<unsigned short>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<int>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<unsigned int>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<long>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<unsigned long>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<long long>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<unsigned long long>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<char *>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<char const *>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<std::string>(void const *, std::streamoff); +extern template void format_argument<char>::static_store_integer<std::string_view>(void const *, std::streamoff); + +extern template class format_argument<wchar_t>; +extern template void format_argument<wchar_t>::static_output<bool>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<char>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<signed char>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<unsigned char>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<wchar_t>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<short>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<unsigned short>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<int>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<unsigned int>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<long>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<unsigned long>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<long long>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<unsigned long long>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<wchar_t *>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<wchar_t const *>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<std::wstring>(std::wostream &, format_flags const &, void const *); +extern template void format_argument<wchar_t>::static_output<std::wstring_view>(std::wostream &, format_flags const &, void const *); +extern template bool format_argument<wchar_t>::static_make_integer<bool>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<char>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<signed char>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<unsigned char>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<wchar_t>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<short>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<unsigned short>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<int>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<unsigned int>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<long>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<unsigned long>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<long long>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<unsigned long long>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<wchar_t *>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<wchar_t const *>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<std::wstring>(void const *, int &); +extern template bool format_argument<wchar_t>::static_make_integer<std::wstring_view>(void const *, int &); +extern template void format_argument<wchar_t>::static_store_integer<bool>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<char>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<signed char>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<unsigned char>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<wchar_t>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<short>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<unsigned short>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<int>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<unsigned int>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<long>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<unsigned long>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<long long>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<unsigned long long>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<wchar_t *>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<wchar_t const *>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<std::wstring>(void const *, std::streamoff); +extern template void format_argument<wchar_t>::static_store_integer<std::wstring_view>(void const *, std::streamoff); + +extern template class format_argument_pack<char>; +extern template class format_argument_pack<wchar_t>; + +extern template std::ostream::off_type stream_format(std::ostream &, format_argument_pack<char> const &); +extern template std::wostream::off_type stream_format(std::wostream &, format_argument_pack<wchar_t> const &); } // namespace detail |