21
21
#pragma GCC diagnostic pop
22
22
#endif
23
23
24
- // Support for std::format is really spotty.
25
- // Gcc12 does not support it.
26
- // Eventually replace with std::format when that is widely available.
27
- #include < fmt/format.h>
28
-
29
24
namespace pmtv {
30
25
31
26
using pmt = pmt_var_t ;
@@ -528,7 +523,7 @@ T cast(const P& value)
528
523
return std::visit (
529
524
[](const auto & arg) -> T {
530
525
using U = std::decay_t <decltype (arg)>;
531
- if constexpr (std::constructible_from<T, U> ) {
526
+ if constexpr (std::convertible_to<U, T> || (Complex<T> && Complex<U>) ) {
532
527
if constexpr (Complex<T>) {
533
528
if constexpr (std::integral<U> || std::floating_point<U>) {
534
529
return std::complex<typename T::value_type>(static_cast <typename T::value_type>(arg));
@@ -543,127 +538,9 @@ T cast(const P& value)
543
538
// return std::get<std::map<std::string, pmt_var_t, std::less<>>>(arg);
544
539
// }
545
540
else
546
- throw std::runtime_error (fmt::format (
547
- " Invalid PMT Cast {} {}" , typeid (T).name (), typeid (U).name ()));
541
+ throw std::runtime_error (" Invalid PMT Cast " + std::string (typeid (T).name ()) + " " + std::string (typeid (U).name ()));
548
542
},
549
543
value);
550
544
}
551
545
552
546
} // namespace pmtv
553
-
554
- namespace fmt {
555
- template <>
556
- struct formatter <pmtv::map_t ::value_type> {
557
- template <typename ParseContext>
558
- constexpr auto parse (ParseContext& ctx) {
559
- return ctx.begin ();
560
- }
561
-
562
- template <typename FormatContext>
563
- auto format (const pmtv::map_t ::value_type& kv, FormatContext& ctx) const {
564
- return fmt::format_to (ctx.out (), " {}: {}" , kv.first , kv.second );
565
- }
566
- };
567
-
568
- template <pmtv::Complex C>
569
- struct formatter <C> {
570
- template <typename ParseContext>
571
- constexpr auto parse (ParseContext& ctx) {
572
- return ctx.begin ();
573
- }
574
-
575
- template <typename FormatContext>
576
- auto format (const C& arg, FormatContext& ctx) const {
577
- if (arg.imag () >= 0 )
578
- return fmt::format_to (ctx.out (), " {0}+j{1}" , arg.real (), arg.imag ());
579
- else
580
- return fmt::format_to (ctx.out (), " {0}-j{1}" , arg.real (), -arg.imag ());
581
- }
582
- };
583
-
584
-
585
- template <pmtv::IsPmt P>
586
- struct formatter <P>
587
- {
588
-
589
- template <typename ParseContext>
590
- constexpr auto parse (ParseContext& ctx) {
591
- return ctx.begin ();
592
- }
593
-
594
- template <typename FormatContext>
595
- auto format (const P& value, FormatContext& ctx) const {
596
- // Due to an issue with the c++ spec that has since been resolved, we have to do something
597
- // funky here. See
598
- // https://stackoverflow.com/questions/37526366/nested-constexpr-function-calls-before-definition-in-a-constant-expression-con
599
- // This problem only appears to occur in gcc 11 in certain optimization modes. The problem
600
- // occurs when we want to format a vector<pmt>. Ideally, we can write something like:
601
- // return fmt::format_to(ctx.out(), "[{}]", fmt::join(arg, ", "));
602
- // It looks like the issue effects clang 14/15 as well.
603
- // However, due to the above issue, it fails to compile. So we have to do the equivalent
604
- // ourselves. We can't recursively call the formatter, but we can recursively call a lambda
605
- // function that does the formatting.
606
- // It gets more complicated, because we need to pass the function into the lambda. We can't
607
- // pass in the lamdba as it is defined, so we create a nested lambda. Which accepts a function
608
- // as a argument.
609
- // Because we are calling std::visit, we can't pass non-variant arguments to the visitor, so we
610
- // have to create a new nested lambda every time we format a vector to ensure that it works.
611
- using namespace pmtv ;
612
- using ret_type = decltype (fmt::format_to (ctx.out (), " " ));
613
- auto format_func = [&ctx](const auto format_arg) {
614
- auto function_main = [&ctx](const auto arg, auto function) -> ret_type {
615
- using namespace pmtv ;
616
- using T = std::decay_t <decltype (arg)>;
617
- if constexpr (Scalar<T> || Complex<T>)
618
- return fmt::format_to (ctx.out (), " {}" , arg);
619
- else if constexpr (std::same_as<T, std::string>)
620
- return fmt::format_to (ctx.out (), " {}" , arg);
621
- else if constexpr (UniformVector<T> || UniformStringVector<T>)
622
- return fmt::format_to (ctx.out (), " [{}]" , fmt::join (arg, " , " ));
623
- else if constexpr (std::same_as<T, std::vector<pmt>>) {
624
- fmt::format_to (ctx.out (), " [" );
625
- auto new_func = [&function](const auto new_arg) -> ret_type { return function (new_arg, function); };
626
- for (auto & a: std::span (arg).first (arg.size ()-1 )) {
627
- std::visit (new_func, a);
628
- fmt::format_to (ctx.out (), " , " );
629
- }
630
- std::visit (new_func, arg[arg.size ()-1 ]);
631
- return fmt::format_to (ctx.out (), " ]" );
632
- // When we drop support for gcc11/clang15, get rid of the nested lambda and replace
633
- // the above with this line.
634
- // return fmt::format_to(ctx.out(), "[{}]", fmt::join(arg, ", "));
635
- } else if constexpr (PmtMap<T>) {
636
- fmt::format_to (ctx.out (), " {{" );
637
- auto new_func = [&function](const auto new_arg) -> ret_type { return function (new_arg, function); };
638
- size_t i = 0 ;
639
- for (auto & [k, v]: arg) {
640
- fmt::format_to (ctx.out (), " {}: " , k);
641
- std::visit (new_func, v);
642
- if (i++ < arg.size () - 1 )
643
- fmt::format_to (ctx.out (), " , " );
644
- }
645
- return fmt::format_to (ctx.out (), " }}" );
646
- // When we drop support for gcc11/clang15, get rid of the nested lambda and replace
647
- // the above with this line.
648
- // return fmt::format_to(ctx.out(), "{{{}}}", fmt::join(arg, ", "));
649
- } else if constexpr (std::same_as<std::monostate, T>)
650
- return fmt::format_to (ctx.out (), " null" );
651
- return fmt::format_to (ctx.out (), " unknown type {}" , typeid (T).name ());
652
- };
653
- return function_main (format_arg, function_main);
654
- };
655
- return std::visit (format_func, value);
656
-
657
- }
658
- };
659
-
660
- } // namespace fmt
661
-
662
- namespace pmtv {
663
- template <IsPmt P>
664
- std::ostream& operator <<(std::ostream& os, const P& value) {
665
- os << fmt::format (" {}" , value);
666
- return os;
667
- }
668
- }
669
-
0 commit comments