Skip to content

Commit

Permalink
Update formatters
Browse files Browse the repository at this point in the history
1. Add formatters for two vocabulary types (`std::optional` and `std::variant`)
2. `formatter/misc.hpp` now needs to include manually for reducing dependencies
  • Loading branch information
HenryAWE committed Aug 3, 2024
1 parent c492f0a commit f84c455
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 1 deletion.
2 changes: 1 addition & 1 deletion include/papilio/format.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,6 @@ class formatter<joiner<R, CharT>, CharT>
#include "detail/suffix.hpp"

#include "formatter/tuple.hpp"
#include "formatter/misc.hpp"
#include "formatter/vocabulary.hpp"

#endif
86 changes: 86 additions & 0 deletions include/papilio/formatter/vocabulary.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* @file formatter/vocabulary.hpp
* @author HenryAWE
* @brief Formatters for vocabulary types, like std::optional, std::variant, etc.
*/

#ifndef PAPILIO_FORMATTER_VOCABULARY_HPP
#define PAPILIO_FORMATTER_VOCABULARY_HPP

#include <optional>
#include <variant>
#include "../format.hpp"
#include "../detail/prefix.hpp"

namespace papilio
{
template <typename T, typename CharT>
class formatter<std::optional<T>, CharT>
{
public:
template <typename ParseContext, typename FormatContext>
requires formattable_with<T, FormatContext>
auto format(const std::optional<T>& val, ParseContext& parse_ctx, FormatContext& fmt_ctx) const
-> typename FormatContext::iterator
{
(void)parse_ctx;

using context_t = format_context_traits<FormatContext>;

if(val.has_value())
{
context_t::format_to(fmt_ctx, PAPILIO_TSTRING_VIEW(CharT, "{}"), *val);
}
else
{
context_t::append(fmt_ctx, PAPILIO_TSTRING_VIEW(CharT, "nullopt"));
}

return fmt_ctx.out();
}
};

namespace detail
{
template <typename T, typename Context>
concept variant_formattable_helper =
std::same_as<std::decay_t<T>, std::monostate> ||
formattable_with<T, Context>;

template <typename Context, typename... Ts>
concept variant_formattable = (variant_formattable_helper<Ts, Context> && ...);
} // namespace detail

template <typename... Ts, typename CharT>
class formatter<std::variant<Ts...>, CharT>
{
public:
template <typename ParseContext, typename FormatContext>
requires detail::variant_formattable<FormatContext, Ts...>
auto format(const std::variant<Ts...>& val, ParseContext& parse_ctx, FormatContext& fmt_ctx) const
-> typename FormatContext::iterator
{
(void)parse_ctx;

using context_t = format_context_traits<FormatContext>;

std::visit(
[&](auto&& v)
{
using type = std::decay_t<decltype(v)>;
if constexpr(std::same_as<type, std::monostate>)
context_t::append(fmt_ctx, PAPILIO_TSTRING_VIEW(CharT, "monostate"));
else
context_t::format_to(fmt_ctx, PAPILIO_TSTRING_VIEW(CharT, "{}"), v);
},
val
);

return fmt_ctx.out();
}
};
} // namespace papilio

#include "../detail/suffix.hpp"

#endif
1 change: 1 addition & 0 deletions test/test_format/misc.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <gtest/gtest.h>
#include <papilio/format.hpp>
#include <papilio/formatter/misc.hpp>
#include "test_format.hpp"
#include <papilio_test/setup.hpp>

Expand Down
52 changes: 52 additions & 0 deletions test/test_format/vocabulary_formatter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include <gtest/gtest.h>
#include <papilio/format.hpp>
#include <papilio_test/setup.hpp>

TEST(vocabulary_formatter, optional)
{
using namespace papilio;

{
std::optional<std::string> opt = "hello";

EXPECT_EQ(PAPILIO_NS format("{}", opt), "hello");

opt.reset();
EXPECT_EQ(PAPILIO_NS format("{}", opt), "nullopt");
}

{
std::optional<std::wstring> opt = L"hello";

EXPECT_EQ(PAPILIO_NS format(L"{}", opt), L"hello");

opt.reset();
EXPECT_EQ(PAPILIO_NS format(L"{}", opt), L"nullopt");
}
}

TEST(vocabulary_formatter, variant)
{
using namespace papilio;
{
std::variant<std::monostate, int, std::string> var;
EXPECT_EQ(PAPILIO_NS format("{}", var), "monostate");

var.emplace<int>(42);
EXPECT_EQ(PAPILIO_NS format("{}", var), "42");

var.emplace<std::string>("hello");
EXPECT_EQ(PAPILIO_NS format("{}", var), "hello");
}

{
std::variant<std::monostate, int, std::wstring> var;
EXPECT_EQ(PAPILIO_NS format(L"{}", var), L"monostate");

var.emplace<int>(42);
EXPECT_EQ(PAPILIO_NS format(L"{}", var), L"42");

var.emplace<std::wstring>(L"hello");
EXPECT_EQ(PAPILIO_NS format(L"{}", var), L"hello");
}
}

0 comments on commit f84c455

Please sign in to comment.