Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't use std::visit for formatting. It is too slow and complex #112

Merged
merged 14 commits into from
Oct 2, 2024
Merged
10 changes: 5 additions & 5 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
jobs:
linux-docker:
# All of these shall depend on the formatting check (needs: check-formatting)
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
# The GH default is 360 minutes (it's also the max as of Feb-2021). However,
# we should fail sooner. The only reason to exceed this time is if a test
# hangs.
Expand All @@ -23,11 +23,11 @@ jobs:
# descriptive name, and one key 'containerid' with the name of the
# container (i.e., what you want to docker-pull)
distro:
- name: 'Ubuntu 22.04'
containerid: 'ghcr.io/gnuradio/gnuradio-docker:ubuntu-22.04'
- name: 'Ubuntu 24.04'
containerid: 'ghcr.io/gnuradio/gnuradio-docker:ubuntu-24.04'
cxxflags: -Werror
- name: 'Fedora 36'
containerid: 'ghcr.io/gnuradio/gnuradio-docker:fedora-36'
- name: 'Fedora 40'
containerid: 'ghcr.io/gnuradio/gnuradio-docker:fedora-40'
cxxflags: ''
# - distro: 'CentOS 8.3'
# containerid: 'gnuradio/ci:centos-8.3-3.9'
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/emscripten.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
jobs:
linux-docker:
# All of these shall depend on the formatting check (needs: check-formatting)
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
# The GH default is 360 minutes (it's also the max as of Feb-2021). However,
# we should fail sooner. The only reason to exceed this time is if a test
# hangs.
Expand All @@ -23,8 +23,8 @@ jobs:
# descriptive name, and one key 'containerid' with the name of the
# container (i.e., what you want to docker-pull)
distro:
- name: 'Ubuntu 22.04'
containerid: 'ghcr.io/gnuradio/gnuradio-docker:ubuntu-22.04'
- name: 'Ubuntu 24.04'
containerid: 'ghcr.io/gnuradio/gnuradio-docker:ubuntu-24.04'
cxxflags: -Werror
compiler:
- name: "emscripten"
Expand All @@ -40,7 +40,7 @@ jobs:
name: Checkout Project
- name: Install emscripten
run: |
DEBIAN_FRONTEND=noninteractive apt-get install -qy bzip2
DEBIAN_FRONTEND=noninteractive apt-get install -qy bzip2 clang
cd
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
Expand Down
52 changes: 5 additions & 47 deletions include/pmtv/format.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Gcc12 does not support it.
// Eventually replace with std::format when that is widely available.
#include <fmt/format.h>
#include <fmt/ranges.h>

namespace fmt {
template <>
Expand Down Expand Up @@ -45,25 +46,7 @@ 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) {
using namespace pmtv;
using T = std::decay_t<decltype(arg)>;
if constexpr (Scalar<T> || Complex<T>)
Expand All @@ -73,38 +56,13 @@ struct formatter<P>
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(), ", ");
}
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, ", "));
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(), ", ");
}
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, ", "));
return fmt::format_to(ctx.out(), "{{{}}}", fmt::join(arg, ", "));
} 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);
}, value);

}
};
Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ endif
gtest_dep = dependency('gtest', main : true, version : '>=1.10', required : get_option('enable_testing'))
gtest_main_dep = dependency('gtest_main', version : '>=1.10', required : get_option('enable_testing'))
CLI11_dep = dependency('CLI11', fallback : [ 'cli11' , 'CLI11_dep' ])
fmt_dep = dependency('fmt', version:'>=8.1.1')
fmt_dep = dependency('fmt', version:'>=10.0.0')

cmake = import('cmake')

Expand Down
16 changes: 8 additions & 8 deletions subprojects/fmt.wrap
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[wrap-file]
directory = fmt-8.1.1
source_url = https://github.com/fmtlib/fmt/archive/8.1.1.tar.gz
source_filename = fmt-8.1.1.tar.gz
source_hash = 3d794d3cf67633b34b2771eb9f073bde87e846e0d395d254df7b211ef1ec7346
patch_filename = fmt_8.1.1-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/fmt_8.1.1-2/get_patch
patch_hash = cd001046281330a8862591780a9ea71a1fa594edd0d015deb24e44680c9ea33b
wrapdb_version = 8.1.1-2
directory = fmt-11.0.2
source_url = https://github.com/fmtlib/fmt/archive/11.0.2.tar.gz
source_filename = fmt-11.0.2.tar.gz
source_hash = 6cb1e6d37bdcb756dbbe59be438790db409cdb4868c66e888d5df9f13f7c027f
patch_filename = fmt_11.0.2-1_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/fmt_11.0.2-1/get_patch
patch_hash = 90c9e3b8e8f29713d40ca949f6f93ad115d78d7fb921064112bc6179e6427c5e
wrapdb_version = 11.0.2-1

[provide]
fmt = fmt_dep
Loading