Skip to content

Commit

Permalink
Update range formatter support
Browse files Browse the repository at this point in the history
  • Loading branch information
HenryAWE committed Oct 16, 2024
1 parent 2c804cb commit 7280859
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 0 deletions.
70 changes: 70 additions & 0 deletions include/papilio/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5055,6 +5055,11 @@ class codepoint_formatter : public std_formatter_base
data().fill = dt.fill_or(U' ');
}

void set_debug_format() noexcept
{
data().type = U'?';
}

template <typename FormatContext>
auto format(utf::codepoint cp, FormatContext& ctx)
{
Expand Down Expand Up @@ -5291,6 +5296,11 @@ class range_formatter
m_closing = closing;
}

void set_debug_format() noexcept
{
m_debug = true;
}

template <typename ParseContext>
auto parse(ParseContext& ctx)
-> typename ParseContext::iterator
Expand All @@ -5311,6 +5321,20 @@ class range_formatter
use_set_brackets();
++it;
}
else if(ch == U'?')
{
set_debug_format();
++it;
if(it == ctx.end() || *it != U's')
throw format_error("invalid range format");
m_type = U's';
++it;
}
else if(ch == U's')
{
m_type = U's';
++it;
}
else if(ch != U':')
{
// error
Expand All @@ -5334,6 +5358,8 @@ class range_formatter
{
fmt_t::try_set_debug_format(m_underlying);
}
else if(m_type == U's' && m_debug)
fmt_t::try_set_debug_format(m_underlying);

end_parse:
return it;
Expand All @@ -5345,6 +5371,28 @@ class range_formatter
{
using context_t = format_context_traits<Context>;

if(m_type == U's')
{
constexpr bool is_string_like_range =
std::convertible_to<std::ranges::range_reference_t<R>, CharT> ||
std::convertible_to<std::ranges::range_reference_t<R>, utf::codepoint>;

if constexpr(!is_string_like_range)
throw format_error("invalid range format");
else
{
utf::basic_string_container<CharT> str;
str.assign_range(rng);

if(m_debug)
context_t::append_escaped(ctx, str);
else
context_t::append(ctx, str);
}

return context_t::out(ctx);
}

context_t::append(ctx, m_opening);

bool first = true;
Expand All @@ -5370,6 +5418,7 @@ class range_formatter
string_view_type m_sep = PAPILIO_TSTRING_VIEW(CharT, ", ");
string_view_type m_opening;
string_view_type m_closing;
bool m_debug = false;

static constexpr range_format get_kind()
{
Expand Down Expand Up @@ -5507,6 +5556,11 @@ PAPILIO_EXPORT template <typename CharT>
class formatter<utf::codepoint, CharT>
{
public:
void set_debug_format() noexcept
{
m_data.type = U'?';
}

template <typename ParseContext>
auto parse(ParseContext& ctx) -> typename ParseContext::iterator
{
Expand Down Expand Up @@ -5544,6 +5598,22 @@ class formatter<utf::codepoint, CharT>
std_formatter_data m_data;
};

/**
* @brief Formatter for character type.
* It simply redirect all calls to the Unicode code point formatter.
*
* @sa utf::codepoint
*
* @tparam CharT Character type
*
* Accepted format types are: none, `c`, `?`, `b`,`B`,`x`,`X`,`o`,`d`.
* - none, `c`, `?`: Format as a Unicode code point. @sa codepoint_formatter
* - `b`,`B`,`x`,`X`,`o`,`d`: Format as integer. @sa int_formatter
*/
PAPILIO_EXPORT template <typename CharT>
class formatter<CharT, CharT> : public formatter<utf::codepoint, CharT>
{};

/**
* @brief Formatter for the Boolean type.
*
Expand Down
29 changes: 29 additions & 0 deletions include/papilio/utf/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,35 @@ class basic_string_container<CharT> : public detail::str_impl<CharT, basic_strin
return *this;
}

template <std::ranges::input_range R>
basic_string_container& assign_range(R&& r) noexcept
{
if constexpr(std::convertible_to<std::ranges::range_reference_t<R>, CharT>)
{
string_type buf;
if constexpr(std::ranges::sized_range<R>)
buf.reserve(std::ranges::size(r));
for(CharT ch : r)
buf.push_back(ch);

assign(std::move(buf));
}
else if constexpr(std::convertible_to<std::ranges::range_reference_t<R>, utf::codepoint>)
{
string_type buf;
for(utf::codepoint cp : r)
cp.append_to(buf);

assign(std::move(buf));
}
else
{
static_assert(!sizeof(R), "Invalid range");
}

return *this;
}

constexpr basic_string_container& operator=(const basic_string_container&) = default;
constexpr basic_string_container& operator=(basic_string_container&&) noexcept = default;

Expand Down
39 changes: 39 additions & 0 deletions test/test_format/ranges.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <gtest/gtest.h>
#include <vector>
#include <list>
#include <set>
#include <ranges>
#include <papilio/format.hpp>
Expand Down Expand Up @@ -62,3 +63,41 @@ TEST(ranges, map)
EXPECT_EQ(PAPILIO_NS format(L"{:n}", m), L"(1, 1), (2, 2), (3, 3)");
EXPECT_EQ(PAPILIO_NS format(L"{:m}", m), L"{1: 1, 2: 2, 3: 3}");
}

TEST(ranges, string_like)
{
using namespace papilio;

{
static_assert(formattable<std::list<char>>);

std::list<char> vec{'a', '"', 'b'};
EXPECT_EQ(PAPILIO_NS format("{}", vec), "[a, \", b]");
EXPECT_EQ(PAPILIO_NS format("{:s}", vec), "a\"b");
EXPECT_EQ(PAPILIO_NS format("{:?s}", vec), "a\\\"b");
}

{
static_assert(formattable<std::list<wchar_t>, wchar_t>);

std::list<wchar_t> vec{L'a', L'"', L'b'};
EXPECT_EQ(PAPILIO_NS format(L"{}", vec), L"[a, \", b]");
EXPECT_EQ(PAPILIO_NS format(L"{:s}", vec), L"a\"b");
EXPECT_EQ(PAPILIO_NS format(L"{:?s}", vec), L"a\\\"b");
}

{
static_assert(formattable<std::list<utf::codepoint>>);
static_assert(formattable<std::list<utf::codepoint>, wchar_t>);

std::list<utf::codepoint> vec{U'a'_cp, U'"'_cp, U'b'_cp};

EXPECT_EQ(PAPILIO_NS format("{}", vec), "[a, \", b]");
EXPECT_EQ(PAPILIO_NS format("{:s}", vec), "a\"b");
EXPECT_EQ(PAPILIO_NS format("{:?s}", vec), "a\\\"b");

EXPECT_EQ(PAPILIO_NS format(L"{}", vec), L"[a, \", b]");
EXPECT_EQ(PAPILIO_NS format(L"{:s}", vec), L"a\"b");
EXPECT_EQ(PAPILIO_NS format(L"{:?s}", vec), L"a\\\"b");
}
}

0 comments on commit 7280859

Please sign in to comment.