Skip to content

Commit

Permalink
Simplify fmt format function
Browse files Browse the repository at this point in the history
  • Loading branch information
jsallay committed Mar 20, 2024
1 parent e12a123 commit 80039c0
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 60 deletions.
5 changes: 0 additions & 5 deletions include/pmtv/meson.build
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
files = [
'pmt.hpp',
'rva_variant.hpp',
<<<<<<< HEAD
'version.hpp',
'type_helpers.hpp'
=======
'type_helpers.hpp',
'version.hpp'
>>>>>>> base/main
]

install_headers(files, subdir : 'pmtv')
Expand Down
67 changes: 12 additions & 55 deletions include/pmtv/pmt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ T cast(const P& value)
return std::visit(
[](const auto& arg) -> T {
using U = std::decay_t<decltype(arg)>;
if constexpr (std::constructible_from<T, U>) {
if constexpr (std::convertible_to<U, T>) {
if constexpr(Complex<T>) {
if constexpr (std::integral<U> || std::floating_point<U>) {
return std::complex<typename T::value_type>(static_cast<typename T::value_type>(arg));
Expand Down Expand Up @@ -593,67 +593,24 @@ struct formatter<P>

template <typename FormatContext>
auto format(const P& value, FormatContext& ctx) const {
// Due to an issue with the c++ spec that has since been resolved, we have to do something
// funky here. See
// https://stackoverflow.com/questions/37526366/nested-constexpr-function-calls-before-definition-in-a-constant-expression-con
// This problem only appears to occur in gcc 11 in certain optimization modes. The problem
// occurs when we want to format a vector<pmt>. Ideally, we can write something like:
// return fmt::format_to(ctx.out(), "[{}]", fmt::join(arg, ", "));
// It looks like the issue effects clang 14/15 as well.
// However, due to the above issue, it fails to compile. So we have to do the equivalent
// ourselves. We can't recursively call the formatter, but we can recursively call a lambda
// function that does the formatting.
// It gets more complicated, because we need to pass the function into the lambda. We can't
// pass in the lamdba as it is defined, so we create a nested lambda. Which accepts a function
// as a argument.
// Because we are calling std::visit, we can't pass non-variant arguments to the visitor, so we
// have to create a new nested lambda every time we format a vector to ensure that it works.
using namespace pmtv;
using ret_type = decltype(fmt::format_to(ctx.out(), ""));
auto format_func = [&ctx](const auto format_arg) {
auto function_main = [&ctx](const auto arg, auto function) -> ret_type {
return std::visit([&ctx](const auto arg) -> ret_type {
using namespace pmtv;
using T = std::decay_t<decltype(arg)>;
if constexpr (Scalar<T> || Complex<T>)
return fmt::format_to(ctx.out(), "{}", arg);
else if constexpr (std::same_as<T, std::string>)
return fmt::format_to(ctx.out(), "{}", arg);
else if constexpr (UniformVector<T> || UniformStringVector<T>)
return fmt::format_to(ctx.out(), "[{}]", fmt::join(arg, ", "));
else if constexpr (std::same_as<T, std::vector<pmt>>) {
fmt::format_to(ctx.out(), "[");
auto new_func = [&function](const auto new_arg) -> ret_type { return function(new_arg, function); };
for (auto& a: std::span(arg).first(arg.size()-1)) {
std::visit(new_func, a);
fmt::format_to(ctx.out(), ", ");
if constexpr(std::ranges::range<T> && !std::same_as<std::string, T>) {
if constexpr(PmtMap<T>) {
return fmt::format_to(ctx.out(), "{{{}}}", fmt::join(arg, ", "));
}
std::visit(new_func, arg[arg.size()-1]);
return fmt::format_to(ctx.out(), "]");
// When we drop support for gcc11/clang15, get rid of the nested lambda and replace
// the above with this line.
//return fmt::format_to(ctx.out(), "[{}]", fmt::join(arg, ", "));
} else if constexpr (PmtMap<T>) {
fmt::format_to(ctx.out(), "{{");
auto new_func = [&function](const auto new_arg) -> ret_type { return function(new_arg, function); };
size_t i = 0;
for (auto& [k, v]: arg) {
fmt::format_to(ctx.out(), "{}: ", k);
std::visit(new_func, v);
if (i++ < arg.size() - 1)
fmt::format_to(ctx.out(), ", ");
else {
return fmt::format_to(ctx.out(), "[{}]", fmt::join(arg, ", "));
}
return fmt::format_to(ctx.out(), "}}");
// When we drop support for gcc11/clang15, get rid of the nested lambda and replace
// the above with this line.
//return fmt::format_to(ctx.out(), "{{{}}}", fmt::join(arg, ", "));
} else if constexpr (std::same_as<std::monostate, T>)
} else if constexpr(std::same_as<std::monostate, T>) {
return fmt::format_to(ctx.out(), "null");
return fmt::format_to(ctx.out(), "unknown type {}", typeid(T).name());
};
return function_main(format_arg, function_main);
};
return std::visit(format_func, value);

} else {
return fmt::format_to(ctx.out(), "{}", arg);
}
}, value);
}
};

Expand Down

0 comments on commit 80039c0

Please sign in to comment.