diff --git a/bench/bm_pmt_dict_pack_unpack.cpp b/bench/bm_pmt_dict_pack_unpack.cpp index 670ddb0..6eba198 100644 --- a/bench/bm_pmt_dict_pack_unpack.cpp +++ b/bench/bm_pmt_dict_pack_unpack.cpp @@ -7,6 +7,7 @@ #include "CLI/Formatter.hpp" #include +#include using namespace pmtv; diff --git a/bench/bm_pmt_dict_ref.cpp b/bench/bm_pmt_dict_ref.cpp index f30f534..6f057c8 100644 --- a/bench/bm_pmt_dict_ref.cpp +++ b/bench/bm_pmt_dict_ref.cpp @@ -7,6 +7,7 @@ #include "CLI/Formatter.hpp" #include +#include using namespace pmtv; diff --git a/include/pmtv/format.hpp b/include/pmtv/format.hpp new file mode 100644 index 0000000..feba6f4 --- /dev/null +++ b/include/pmtv/format.hpp @@ -0,0 +1,120 @@ +// Support for std::format is really spotty. +// Gcc12 does not support it. +// Eventually replace with std::format when that is widely available. +#include + +namespace fmt { +template <> +struct formatter { + template + constexpr auto parse(ParseContext& ctx) { + return ctx.begin(); + } + + template + auto format(const pmtv::map_t::value_type& kv, FormatContext& ctx) const { + return fmt::format_to(ctx.out(), "{}: {}", kv.first, kv.second); + } +}; + +template +struct formatter { + template + constexpr auto parse(ParseContext& ctx) { + return ctx.begin(); + } + + template + auto format(const C& arg, FormatContext& ctx) const { + if (arg.imag() >= 0) + return fmt::format_to(ctx.out(), "{0}+j{1}", arg.real(), arg.imag()); + else + return fmt::format_to(ctx.out(), "{0}-j{1}", arg.real(), -arg.imag()); + } +}; + + +template +struct formatter

+{ + + template + constexpr auto parse(ParseContext& ctx) { + return ctx.begin(); + } + + template + 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. 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 { + using namespace pmtv; + using T = std::decay_t; + if constexpr (Scalar || Complex) + return fmt::format_to(ctx.out(), "{}", arg); + else if constexpr (std::same_as) + return fmt::format_to(ctx.out(), "{}", arg); + else if constexpr (UniformVector || UniformStringVector) + return fmt::format_to(ctx.out(), "[{}]", fmt::join(arg, ", ")); + else if constexpr (std::same_as>) { + 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(), ", "); + } + 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) { + 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(), ", "); + } + 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) + 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); + + } +}; + +} // namespace fmt + +namespace pmtv { + template + std::ostream& operator<<(std::ostream& os, const P& value) { + os << fmt::format("{}", value); + return os; + } +} diff --git a/include/pmtv/meson.build b/include/pmtv/meson.build index 9edb38e..f67cc41 100644 --- a/include/pmtv/meson.build +++ b/include/pmtv/meson.build @@ -1,4 +1,5 @@ files = [ + 'format.hpp', 'pmt.hpp', 'rva_variant.hpp', 'type_helpers.hpp', diff --git a/include/pmtv/pmt.hpp b/include/pmtv/pmt.hpp index 73ce0c6..9326a95 100644 --- a/include/pmtv/pmt.hpp +++ b/include/pmtv/pmt.hpp @@ -21,11 +21,6 @@ #pragma GCC diagnostic pop #endif -// Support for std::format is really spotty. -// Gcc12 does not support it. -// Eventually replace with std::format when that is widely available. -#include - namespace pmtv { using pmt = pmt_var_t; @@ -528,7 +523,7 @@ T cast(const P& value) return std::visit( [](const auto& arg) -> T { using U = std::decay_t; - if constexpr (std::constructible_from) { + if constexpr (std::convertible_to || (Complex && Complex)) { if constexpr(Complex) { if constexpr (std::integral || std::floating_point) { return std::complex(static_cast(arg)); @@ -543,127 +538,9 @@ T cast(const P& value) // return std::get>>(arg); // } else - throw std::runtime_error(fmt::format( - "Invalid PMT Cast {} {}", typeid(T).name(), typeid(U).name())); + throw std::runtime_error("Invalid PMT Cast " + std::string(typeid(T).name()) + " " + std::string(typeid(U).name())); }, value); } } // namespace pmtv - -namespace fmt { -template <> -struct formatter { - template - constexpr auto parse(ParseContext& ctx) { - return ctx.begin(); - } - - template - auto format(const pmtv::map_t::value_type& kv, FormatContext& ctx) const { - return fmt::format_to(ctx.out(), "{}: {}", kv.first, kv.second); - } -}; - -template -struct formatter { - template - constexpr auto parse(ParseContext& ctx) { - return ctx.begin(); - } - - template - auto format(const C& arg, FormatContext& ctx) const { - if (arg.imag() >= 0) - return fmt::format_to(ctx.out(), "{0}+j{1}", arg.real(), arg.imag()); - else - return fmt::format_to(ctx.out(), "{0}-j{1}", arg.real(), -arg.imag()); - } -}; - - -template -struct formatter

-{ - - template - constexpr auto parse(ParseContext& ctx) { - return ctx.begin(); - } - - template - 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. 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 { - using namespace pmtv; - using T = std::decay_t; - if constexpr (Scalar || Complex) - return fmt::format_to(ctx.out(), "{}", arg); - else if constexpr (std::same_as) - return fmt::format_to(ctx.out(), "{}", arg); - else if constexpr (UniformVector || UniformStringVector) - return fmt::format_to(ctx.out(), "[{}]", fmt::join(arg, ", ")); - else if constexpr (std::same_as>) { - 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(), ", "); - } - 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) { - 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(), ", "); - } - 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) - 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); - - } -}; - -} // namespace fmt - -namespace pmtv { - template - std::ostream& operator<<(std::ostream& os, const P& value) { - os << fmt::format("{}", value); - return os; - } -} - diff --git a/python/pmtv/bindings/pmt_python.cc b/python/pmtv/bindings/pmt_python.cc index d59b24a..7302f8a 100644 --- a/python/pmtv/bindings/pmt_python.cc +++ b/python/pmtv/bindings/pmt_python.cc @@ -30,6 +30,7 @@ namespace py = pybind11; #include +#include // pydoc.h is automatically generated in the build directory // #include diff --git a/test/qa_map.cpp b/test/qa_map.cpp index 6b5c899..80dae56 100644 --- a/test/qa_map.cpp +++ b/test/qa_map.cpp @@ -11,6 +11,7 @@ #include #include +#include using namespace pmtv; diff --git a/test/qa_scalar.cpp b/test/qa_scalar.cpp index 8ebbe06..c5d0fdc 100644 --- a/test/qa_scalar.cpp +++ b/test/qa_scalar.cpp @@ -10,6 +10,7 @@ #include #include +#include #include using namespace pmtv; diff --git a/test/qa_string.cpp b/test/qa_string.cpp index abd1298..2225eb6 100644 --- a/test/qa_string.cpp +++ b/test/qa_string.cpp @@ -10,6 +10,7 @@ #include #include +#include #include using namespace pmtv; diff --git a/test/qa_uniform_vector.cpp b/test/qa_uniform_vector.cpp index f79dbff..0a73979 100644 --- a/test/qa_uniform_vector.cpp +++ b/test/qa_uniform_vector.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include diff --git a/test/qa_vector_of_pmts.cpp b/test/qa_vector_of_pmts.cpp index 42481de..2efcaf5 100644 --- a/test/qa_vector_of_pmts.cpp +++ b/test/qa_vector_of_pmts.cpp @@ -12,6 +12,7 @@ #include #include +#include #include