blob: 04ef159db3920d760d0069e4e7c151afe73757be [file]
// { dg-additional-options "-lstdc++exp" { target { *-*-mingw* } } }
// { dg-do run { target c++23 } }
#include <sstream>
#include <algorithm>
#include <testsuite_hooks.h>
struct ThrowingFormat
{
std::string val;
bool throw_from_format = false;
};
template<>
struct std::formatter<ThrowingFormat, char>
{
constexpr
std::format_parse_context::iterator
parse(std::format_parse_context& ctx) const
{ return ctx.begin(); }
template<typename Out>
Out
format(const ThrowingFormat& t, std::basic_format_context<Out, char>& fc) const
{
if (t.throw_from_format)
throw std::logic_error("Formatting stopped");
return std::ranges::copy(t.val, fc.out()).out;
}
};
void
test_throwing()
{
std::string s;
s.reserve(100);
std::ostringstream out(std::move(s));
ThrowingFormat tf1{std::string(500, 'a'), false}, tf2{std::string(500, 'b'), true};
try
{
std::print(out, "{} {}", tf1, tf2);
VERIFY(false);
} catch (...) {
VERIFY(true);
}
VERIFY( out.view().empty() );
}
struct MixedFormat
{
std::ostream* out;
std::string val;
};
template<>
struct std::formatter<MixedFormat, char>
{
constexpr
std::format_parse_context::iterator
parse(std::format_parse_context& ctx) const
{ return ctx.begin(); }
template<typename Out>
Out
format(const MixedFormat& t, std::basic_format_context<Out, char>& fc) const
{
if (t.out)
*t.out << "<<[" << t.val << "]";
return std::ranges::copy(t.val, fc.out()).out;
}
};
void
test_interleaved()
{
std::string s;
s.reserve(100);
std::ostringstream out(std::move(s));
MixedFormat mf1{&out, "abc"}, mf2{&out, "DEF"};
std::print(out, "f[{}]f[{}]", mf1, mf2);
VERIFY( out.view() == "<<[abc]<<[DEF]f[abc]f[DEF]" );
}
int main()
{
test_throwing();
test_interleaved();
}