+ }
+
+ private:
+ template<ranges::input_range _Rg, typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ _M_format(_Rg& __rg, basic_format_context<_Out, _CharT>& __fc) const
+ {
if constexpr (same_as<_Tp, _CharT>)
if (_M_spec._M_type == __format::_Pres_str
|| _M_spec._M_type == __format::_Pres_esc)
@@ -5379,16 +5657,17 @@ namespace __format
__format::__formatter_str __fstr(_M_spec);
return __fstr._M_format_range(__rg, __fc);
}
- if (_M_spec._M_get_width(__fc) > 0)
- return _M_format_with_padding(__rg, __fc);
- return _M_format_no_padding(__rg, __fc);
+ return __format::__format_padded(
+ __fc, _M_spec,
+ [this, &__rg](basic_format_context<_Out, _CharT>& __nfc)
+ { return _M_format_elems(__rg, __nfc); });
}
- private:
+
template<ranges::input_range _Rg, typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
- _M_format_no_padding(_Rg& __rg,
- basic_format_context<_Out, _CharT>& __fc) const
+ _M_format_elems(_Rg& __rg,
+ basic_format_context<_Out, _CharT>& __fc) const
{
auto __out = __format::__write(__fc.out(), _M_open);
@@ -5409,50 +5688,6 @@ namespace __format
return __format::__write(__out, _M_close);
}
- template<ranges::input_range _Rg, typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- _M_format_with_padding(_Rg& __rg,
- basic_format_context<_Out, _CharT>& __fc) const
- {
- struct _Restore_out
- {
- _Restore_out(basic_format_context<_Out, _CharT>& __fc)
- : _M_ctx(addressof(__fc)), _M_out(__fc.out())
- { }
-
- void trigger()
- {
- if (_M_ctx)
- _M_ctx->advance_to(_M_out);
- _M_ctx = nullptr;
- }
-
- ~_Restore_out()
- { trigger(); }
-
- private:
- basic_format_context<_Out, _CharT>* _M_ctx;
- __format::_Sink_iter<_CharT> _M_out;
- };
-
- _Restore_out __restore{__fc};
- // TODO Consider double sinking, first buffer of width
- // size and then original sink, if first buffer is overrun
- // we do not need to align
- __format::_Str_sink<_CharT> __buf;
- __fc.advance_to(__format::_Sink_iter<_CharT>(__buf));
- _M_format_no_padding(__rg, __fc);
- __restore.trigger();
-
- _String_view __s(__buf.view());
- size_t __width;
- if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
- __width = __unicode::__field_width(__s);
- else
- __width = __s.size();
- return __format::__write_padded_as_spec(__s, __width, __fc, _M_spec);
- }
-
__format::_Spec<_CharT> _M_spec{};
_String_view _M_open = _Seps::_S_squares().substr(0, 1);
_String_view _M_close = _Seps::_S_squares().substr(1, 1);
@@ -5537,7 +5772,7 @@ namespace __format
return _M_under._M_format_range(__rg, __fc);
else
return _M_under.format(__rg, __fc);
- }
+ }
private:
using _Formatter_under
diff --git a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
index 2045b51547a..a4f5d9210dd 100644
--- a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
+++ b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
@@ -97,6 +97,7 @@ void
test_override()
{
MyVector<_CharT, Formatter> vc{'a', 'b', 'c', 'd'};
+ MyVector<std::pair<int, int>, Formatter> vp{{1, 11}, {2, 21}};
std::basic_string<_CharT> res;
res = std::format(WIDEN("{:s}"), vc);
@@ -106,7 +107,10 @@ test_override()
res = std::format(WIDEN("{:+^6s}"), vc);
VERIFY( res == WIDEN("+abcd+") );
- // TODO test map
+ res = std::format(WIDEN("{:m}"), vp);
+ VERIFY( res == WIDEN("{1: 11, 2: 21}") );
+ res = std::format(WIDEN("{:=^20m}"), vp);
+ VERIFY( res == WIDEN("==={1: 11, 2: 21}===") );
}
template<template<typename, typename> class Formatter>
diff --git a/libstdc++-v3/testsuite/std/format/ranges/map.cc
b/libstdc++-v3/testsuite/std/format/ranges/map.cc
new file mode 100644
index 00000000000..34c5ed554b8
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/ranges/map.cc
@@ -0,0 +1,209 @@
+// { dg-do run { target c++23 } }
+
+#include <flat_map>
+#include <format>
+#include <list>
+#include <map>
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <vector>
+
+struct NotFormattable
+{
+ friend auto operator<=>(NotFormattable, NotFormattable) = default;
+};
+
+static_assert( !std::formattable<std::map<int, NotFormattable>, char> );
+static_assert( !std::formattable<std::map<NotFormattable, int>, wchar_t> );
+
+template<typename... Args>
+bool
+is_format_string_for(const char* str, Args&&... args)
+{
+ try {
+ (void) std::vformat(str, std::make_format_args(args...));
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+template<typename... Args>
+bool
+is_format_string_for(const wchar_t* str, Args&&... args)
+{
+ try {
+ (void) std::vformat(str, std::make_wformat_args(args...));
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+template<typename Rg, typename CharT>
+bool is_range_formatter_spec_for(CharT const* spec, Rg&& rg)
+{
+ using V = std::remove_cvref_t<std::ranges::range_reference_t<Rg>>;
+ std::range_formatter<V, CharT> fmt;
+ std::basic_format_parse_context<CharT> pc(spec);
+ try {
+ (void)fmt.parse(pc);
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(_CharT, S)
+
+void
+test_format_string()
+{
+ // only pair<T, U> amd tuple<T, U> value types are supported
+ VERIFY( !is_range_formatter_spec_for("m", std::vector<int>()) );
+ VERIFY( !is_format_string_for("{:m}", std::vector<int>()) );
+ VERIFY( !is_range_formatter_spec_for("m", std::vector<std::tuple<int, int,
int>>()) );
+ VERIFY( !is_format_string_for("{:m}", std::vector<std::tuple<int, int,
int>>()) );
+
+ // invalid format stringss
+ VERIFY( !is_range_formatter_spec_for("?m", std::vector<std::pair<int,
int>>()) );
+ VERIFY( !is_format_string_for("{:?m}", std::vector<std::pair<int, int>>()) );
+ VERIFY( !is_range_formatter_spec_for("m:", std::vector<std::pair<int,
int>>()) );
+ VERIFY( !is_format_string_for("{:m:}", std::vector<std::pair<int, int>>()) );
+
+ // precision is not supported
+ VERIFY( !is_range_formatter_spec_for(".10m", std::vector<std::pair<int,
int>>()) );
+ VERIFY( !is_format_string_for("{:.10m}", std::vector<std::pair<int, int>>())
);
+ VERIFY( !is_format_string_for("{:.{}m}", std::vector<std::pair<int, int>>(),
10) );
+
+ // width needs to be integer type
+ VERIFY( !is_format_string_for("{:{}m}", std::vector<std::pair<int, int>>(),
1.0f) );
+}
+
+template<typename _CharT, typename Range>
+void test_output(bool mapIsDefault)
+{
+ using Sv = std::basic_string_view<_CharT>;
+ using Pt = std::ranges::range_value_t<Range>;
+ using Ft = std::remove_cvref_t<std::tuple_element_t<0, Pt>>;
+ using St = std::remove_cvref_t<std::tuple_element_t<1, Pt>>;
+ auto makeRange = [](std::span<Pt> s) {
+ return Range(s.data(), s.data() + s.size());
+ };
+
+ std::basic_string<_CharT> res;
+ size_t size = 0;
+
+ Ft f1[]{1, 2, 3};
+ St s1[]{11, 22, 33};
+ Pt v1[]{{f1[0], s1[0]}, {f1[1], s1[1]}, {f1[2], s1[2]}};
+
+ res = std::format(WIDEN("{}"), makeRange(v1));
+ if (mapIsDefault)
+ VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}") );
+ else
+ VERIFY( res == WIDEN("[(1, 11), (2, 22), (3, 33)]") );
+
+ res = std::format(WIDEN("{:m}"), makeRange(v1));
+ VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}") );
+ res = std::format(WIDEN("{:nm}"), makeRange(v1));
+ VERIFY( res == WIDEN("1: 11, 2: 22, 3: 33") );
+
+ res = std::format(WIDEN("{:3m}"), makeRange(v1));
+ VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}") );
+
+ res = std::format(WIDEN("{:25m}"), makeRange(v1));
+ VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33} ") );
+
+ res = std::format(WIDEN("{:{}m}"), makeRange(v1), 25);
+ VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33} ") );
+
+ res = std::format(WIDEN("{1:{0}m}"), 25, makeRange(v1));
+ VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33} ") );
+
+ res = std::format(WIDEN("{:25nm}"), makeRange(v1));
+ VERIFY( res == WIDEN("1: 11, 2: 22, 3: 33 ") );
+
+ res = std::format(WIDEN("{:*<23m}"), makeRange(v1));
+ VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}**") );
+
+ res = std::format(WIDEN("{:->24m}"), makeRange(v1));
+ VERIFY( res == WIDEN("---{1: 11, 2: 22, 3: 33}") );
+
+ res = std::format(WIDEN("{:=^25m}"), makeRange(v1));
+ VERIFY( res == WIDEN("=={1: 11, 2: 22, 3: 33}==") );
+
+ res = std::format(WIDEN("{:=^25nm}"), makeRange(v1));
+ VERIFY( res == WIDEN("===1: 11, 2: 22, 3: 33===") );
+
+ size = std::formatted_size(WIDEN("{:m}"), makeRange(v1));
+ VERIFY( size == Sv(WIDEN("{1: 11, 2: 22, 3: 33}")).size() );
+
+ size = std::formatted_size(WIDEN("{:3m}"), makeRange(v1));
+ VERIFY( size == Sv(WIDEN("{1: 11, 2: 22, 3: 33}")).size() );
+
+ size = std::formatted_size(WIDEN("{:25m}"), makeRange(v1));
+ VERIFY( size == 25 );
+}
+
+template<class Range>
+void test_output_c(bool mapIsDefault = false)
+{
+ test_output<char, Range>(mapIsDefault);
+ test_output<wchar_t, Range>(mapIsDefault);
+}
+
+template<template<typename> class RangeT>
+void test_output_pc()
+{
+ test_output_c<RangeT<std::pair<int, int>>>();
+ test_output_c<RangeT<std::pair<const int, int>>>();
+ test_output_c<RangeT<std::tuple<const int&, int&>>>();
+}
+
+void
+test_outputs()
+{
+ using namespace __gnu_test;
+ test_output_c<std::map<int, int>>(true);
+ test_output_c<std::flat_map<int, int>>(true);
+
+ test_output_pc<std::vector>();
+ test_output_pc<std::list>();
+ test_output_pc<std::span>();
+
+ test_output_pc<test_forward_range>();
+ test_output_pc<test_input_range>();
+ test_output_pc<test_input_range_nocopy>();
+}
+
+void
+test_nested()
+{
+ std::vector<std::map<int, std::string>> vm{
+ {{1, "one"}, {2, "two"}},
+ {{1, "jeden"}, {2, "dwa"}},
+ };
+ std::string res;
+
+ res = std::format("{}", vm);
+ VERIFY( res == R"([{1: "one", 2: "two"}, {1: "jeden", 2: "dwa"}])" );
+ res = std::format("{:n:n}", vm);
+ VERIFY( res == R"(1: "one", 2: "two", 1: "jeden", 2: "dwa")" );
+
+ std::map<std::string, std::vector<std::string>> mv{
+ {"english", {"zero", "one", "two"}},
+ {"polish", {"zero", "jeden", "dwa"}},
+ };
+ res = std::format("{}", mv);
+ VERIFY( res == R"({"english": ["zero", "one", "two"], "polish": ["zero", "jeden",
"dwa"]})" );
+}
+
+int main()
+{
+ test_format_string();
+ test_outputs();
+ test_nested();
+}
diff --git a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
index 06574379ed5..61fc68ea252 100644
--- a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
+++ b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
@@ -1,7 +1,9 @@
// { dg-do run { target c++23 } }
+#include <array>
#include <format>
#include <list>
+#include <ranges>
#include <span>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
@@ -73,19 +75,23 @@ test_format_string()
#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
#define WIDEN(S) WIDEN_(_CharT, S)
-template<typename _CharT, typename Range>
+template<typename _CharT, typename Range, typename Storage>
void test_output()
{
using Sv = std::basic_string_view<_CharT>;
using T = std::ranges::range_value_t<Range>;
- auto makeRange = [](std::span<T> s) {
- return Range(s.data(), s.data() + s.size());
+ auto makeRange = [](Storage& s) -> Range {
+ if constexpr (std::is_same_v<std::remove_cvref_t<Range>, Storage>)
+ return s;
+ else
+ return Range(std::ranges::data(s),
+ std::ranges::data(s) + std::ranges::size(s));
};
std::basic_string<_CharT> res;
size_t size = 0;
- T v1[]{1, 2, 3};
+ Storage v1{1, 2, 3};
res = std::format(WIDEN("{}"), makeRange(v1));
VERIFY( res == WIDEN("[1, 2, 3]") );
res = std::format(WIDEN("{:}"), makeRange(v1));
@@ -143,27 +149,37 @@ void test_output()
VERIFY( size == 25 );
}
-template<typename Range>
-void test_output_c()
+template<typename Cont>
+void test_output_cont()
{
- test_output<char, Range>();
- test_output<wchar_t, Range>();
+ test_output<char, Cont&, Cont>();
+ test_output<wchar_t, Cont const&, Cont>();
+}
+
+template<typename View>
+void test_output_view()
+{
+ test_output<char, View, int[3]>();
+ test_output<wchar_t, View, int[3]>();
}
void
test_outputs()
{
using namespace __gnu_test;
- test_output_c<std::vector<int>>();
- test_output_c<std::list<int>>();
- test_output_c<std::span<int>>();
-
- test_output_c<test_forward_range<int>>();
- test_output_c<test_input_range<int>>();
- test_output_c<test_range_nocopy<int, input_iterator_wrapper_nocopy>>();
-
- test_output_c<std::span<const int>>();
- test_output_c<test_forward_range<const int>>();
+ test_output_cont<std::vector<int>>();
+ test_output_cont<std::list<int>>();
+ test_output_cont<std::array<int, 3>>();
+
+ test_output_view<std::span<int>>();
+ test_output_view<std::ranges::subrange<int*>>();
+ test_output_view<test_forward_range<int>>();
+ test_output_view<test_input_range<int>>();
+ test_output_view<test_input_range_nocopy<int>>();
+
+ test_output_view<std::span<const int>>();
+ test_output_view<std::ranges::subrange<const int*>>();
+ test_output_view<test_forward_range<const int>>();
}
void
diff --git a/libstdc++-v3/testsuite/std/format/tuple.cc
b/libstdc++-v3/testsuite/std/format/tuple.cc
new file mode 100644
index 00000000000..62f9d293aab
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/tuple.cc
@@ -0,0 +1,259 @@
+// { dg-do run { target c++23 } }
+
+#include <format>
+#include <string>
+#include <testsuite_hooks.h>
+#include <tuple>
+#include <utility>
+
+struct NotFormattable
+{};
+
+static_assert( !std::formattable<std::pair<int, NotFormattable>, char> );
+static_assert( !std::formattable<std::tuple<int, NotFormattable, int>,
wchar_t> );
+
+template<typename... Args>
+bool
+is_format_string_for(const char* str, Args&&... args)
+{
+ try {
+ (void) std::vformat(str, std::make_format_args(args...));
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+template<typename... Args>
+bool
+is_format_string_for(const wchar_t* str, Args&&... args)
+{
+ try {
+ (void) std::vformat(str, std::make_wformat_args(args...));
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(_CharT, S)
+
+void
+test_format_string()
+{
+ // invalid format stringss
+ VERIFY( !is_format_string_for("{:p}", std::tuple<>()) );
+ VERIFY( !is_format_string_for("{:nm}", std::tuple<>()) );
+
+ // 'm' is only valid for 2 elemenst
+ VERIFY( !is_format_string_for("{:m}", std::tuple<>()) );
+ VERIFY( !is_format_string_for("{:m}", std::tuple<int, int, int>()) );
+
+ // element specifier is not supported
+ VERIFY( !is_format_string_for("{::}", std::tuple<>()) );
+
+ // precision is not supported
+ VERIFY( !is_format_string_for("{:.10}", std::tuple<>()) );
+
+ // width needs to be integer type
+ VERIFY( !is_format_string_for("{:{}}", std::tuple<>(), 1.0f) );
+}
+
+template<typename _CharT>
+void test_multi()
+{
+ using Sv = std::basic_string_view<_CharT>;
+ using Str = std::basic_string<_CharT>;
+
+ std::basic_string<_CharT> res;
+ std::size_t size = 0;
+ std::tuple<int, Str, float> t1(1, WIDEN("test"), 2.1);
+
+ res = std::format(WIDEN("{}"), t1);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1))") );
+ res = std::format(WIDEN("{:}"), t1);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1))") );
+ res = std::format(WIDEN("{:n}"), t1);
+ VERIFY( res == WIDEN(R"(1, "test", 2.1)") );
+
+ res = std::format(WIDEN("{:3}"), t1);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1))") );
+
+ res = std::format(WIDEN("{:20}"), t1);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1) )") );
+
+ res = std::format(WIDEN("{:{}}"), t1, 20);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1) )") );
+
+ res = std::format(WIDEN("{1:{0}}"), 20, t1);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1) )") );
+
+ res = std::format(WIDEN("{:^>17}"), t1);
+ VERIFY( res == WIDEN(R"(^(1, "test", 2.1))") );
+
+ res = std::format(WIDEN("{:$<18}"), t1);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1)$$)") );
+
+ res = std::format(WIDEN("{:+^19}"), t1);
+ VERIFY( res == WIDEN(R"(+(1, "test", 2.1)++)") );
+
+ res = std::format(WIDEN("{:|^19n}"), t1);
+ VERIFY( res == WIDEN(R"(||1, "test", 2.1|||)") );
+
+ size = std::formatted_size(WIDEN("{}"), t1);
+ VERIFY( size == Sv(WIDEN(R"((1, "test", 2.1))")).size() );
+
+ size = std::formatted_size(WIDEN("{:3}"), t1);
+ VERIFY( size == Sv(WIDEN(R"((1, "test", 2.1))")).size() );
+
+ size = std::formatted_size(WIDEN("{:20}"), t1);
+ VERIFY( size == 20 );
+
+ std::tuple<int&, Str&, float&> t2 = t1;
+ res = std::format(WIDEN("{}"), t2);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1))") );
+
+ std::tuple<int, int, int, int> t3(1, 2, 3, 4);
+ res = std::format(WIDEN("{}"), t3);
+ VERIFY( res == WIDEN(R"((1, 2, 3, 4))") );
+
+}
+
+template<typename _CharT, typename Tuple>
+void test_empty()
+{
+ std::basic_string<_CharT> res;
+
+ Tuple e1;
+ res = std::format(WIDEN("{}"), e1);
+ VERIFY( res == WIDEN(R"(())") );
+
+ res = std::format(WIDEN("{:}"), e1);
+ VERIFY( res == WIDEN(R"(())") );
+
+ res = std::format(WIDEN("{:n}"), e1);
+ VERIFY( res == WIDEN(R"()") );
+
+ res = std::format(WIDEN("{:^>6}"), e1);
+ VERIFY( res == WIDEN(R"(^^^^())") );
+}
+
+template<typename _CharT, typename Pair>
+void test_pair()
+{
+ using Ft = std::remove_cvref_t<std::tuple_element_t<0, Pair>>;
+ using St = std::remove_cvref_t<std::tuple_element_t<1, Pair>>;
+
+ std::basic_string<_CharT> res;
+
+ Ft f1 = 1;
+ St s1 = WIDEN("abc");
+ Pair p1(f1, s1);
+
+ res = std::format(WIDEN("{}"), p1);
+ VERIFY( res == WIDEN(R"((1, "abc"))") );
+
+ res = std::format(WIDEN("{:}"), p1);
+ VERIFY( res == WIDEN(R"((1, "abc"))") );
+
+ res = std::format(WIDEN("{:m}"), p1);
+ VERIFY( res == WIDEN(R"(1: "abc")") );
+
+ res = std::format(WIDEN("{:|^12m}"), p1);
+ VERIFY( res == WIDEN(R"(||1: "abc"||)") );
+}
+
+template<typename CharT, template<typename, typename> class PairT>
+void test_pair_e()
+{
+ test_pair<CharT, PairT<int, std::basic_string<CharT>>>();
+ test_pair<CharT, PairT<int, const CharT*>>();
+ test_pair<CharT, PairT<const int, std::basic_string<CharT>>>();
+ test_pair<CharT, PairT<int&, std::basic_string<CharT>&>>();
+ test_pair<CharT, PairT<const int&, const std::basic_string<CharT>&>>();
+}
+
+template<typename Pair>
+struct MyPair : Pair
+{
+ using Pair::Pair;
+};
+
+template<typename Pair, typename CharT>
+struct std::formatter<MyPair<Pair>, CharT>
+{
+ constexpr formatter() noexcept
+ {
+ using _CharT = CharT;
+ _formatter.set_brackets(WIDEN("<"), WIDEN(">"));
+ _formatter.set_separator(WIDEN("; "));
+ }
+
+ constexpr std::basic_format_parse_context<CharT>::iterator
+ parse(std::basic_format_parse_context<CharT>& pc)
+ { return _formatter.parse(pc); }
+
+ template<typename Out>
+ typename std::basic_format_context<Out, CharT>::iterator
+ format(const MyPair<Pair>& mp,
+ std::basic_format_context<Out, CharT>& fc) const
+ { return _formatter.format(mp, fc); }
+
+private:
+ std::formatter<Pair, CharT> _formatter;
+};
+
+template<typename _CharT, template<typename, typename> class PairT>
+void test_custom()
+{
+ std::basic_string<_CharT> res;
+ MyPair<PairT<int, const _CharT*>> c1(1, WIDEN("abc"));
+
+ res = std::format(WIDEN("{}"), c1);
+ VERIFY( res == WIDEN(R"(<1; "abc">)") );
+
+ res = std::format(WIDEN("{:}"), c1);
+ VERIFY( res == WIDEN(R"(<1; "abc">)") );
+
+ res = std::format(WIDEN("{:n}"), c1);
+ VERIFY( res == WIDEN(R"(1; "abc")") );
+
+ res = std::format(WIDEN("{:m}"), c1);
+ VERIFY( res == WIDEN(R"(1: "abc")") );
+
+ res = std::format(WIDEN("{:|^14}"), c1);
+ VERIFY( res == WIDEN(R"(||<1; "abc">||)") );
+}
+
+template<typename CharT>
+void test_outputs()
+{
+ test_multi<CharT>();
+ test_empty<CharT, std::tuple<>>();
+ test_pair_e<CharT, std::pair>();
+ test_pair_e<CharT, std::tuple>();
+ test_custom<CharT, std::pair>();
+ test_custom<CharT, std::tuple>();
+}
+
+void test_nested()
+{
+ std::string res;
+ std::tuple<std::tuple<>, std::pair<int, std::string>> tt{{}, {1, "abc"}};
+
+ res = std::format("{}", tt);
+ VERIFY( res == R"(((), (1, "abc")))" );
+ res = std::format("{:n}", tt);
+ VERIFY( res == R"((), (1, "abc"))" );
+ res = std::format("{:m}", tt);
+ VERIFY( res == R"((): (1, "abc"))" );
+}
+
+int main()
+{
+ test_format_string();
+ test_outputs<char>();
+ test_outputs<wchar_t>();
+ test_nested();
+}
diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h
b/libstdc++-v3/testsuite/util/testsuite_iterators.h
index 20539ecaca6..74a87395cd7 100644
--- a/libstdc++-v3/testsuite/util/testsuite_iterators.h
+++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h
@@ -891,6 +891,9 @@ namespace __gnu_test
template<typename T>
using test_input_range
= test_range<T, input_iterator_wrapper>;
+ template<typename T>
+ using test_input_range_nocopy
+ = test_range_nocopy<T, input_iterator_wrapper_nocopy>;
template<typename T>
using test_output_range
= test_range<T, output_iterator_wrapper>;
--
2.49.0