diff --git a/.clang-tidy b/.clang-tidy index 183995b..3db09f5 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,4 +1,14 @@ -Checks: 'cert-*,cppcoreguidelines-*,performance-*,clang-diagnostic-*,clang-analyzer-*,-clang-diagnostic-unqualified-std-cast-call,-clang-diagnostic-unknown-warning-option,-clang-analyzer-unix.BlockInCriticalSection' +Checks: " + cert-*, + cppcoreguidelines-*, + performance-*, + clang-diagnostic-*, + clang-analyzer-*, + -clang-diagnostic-unqualified-std-cast-call, + -clang-diagnostic-unknown-warning-option, + -clang-analyzer-unix.BlockInCriticalSection, + -cppcoreguidelines-pro-bounds-avoid-unchecked-container-access, +" WarningsAsErrors: '*' HeaderFileExtensions: - '' @@ -17,11 +27,13 @@ FormatStyle: none CheckOptions: cert-dcl16-c.NewSuffixes: 'L;LL;LU;LLU' cert-err33-c.AllowCastToVoid: 'true' - cert-err33-c.CheckedFunctions: '::aligned_alloc;::asctime_s;::at_quick_exit;::atexit;::bsearch;::bsearch_s;::btowc;::c16rtomb;::c32rtomb;::calloc;::clock;::cnd_broadcast;::cnd_init;::cnd_signal;::cnd_timedwait;::cnd_wait;::ctime_s;::fclose;::fflush;::fgetc;::fgetpos;::fgets;::fgetwc;::fopen;::fopen_s;::fprintf;::fprintf_s;::fputc;::fputs;::fputwc;::fputws;::fread;::freopen;::freopen_s;::fscanf;::fscanf_s;::fseek;::fsetpos;::ftell;::fwprintf;::fwprintf_s;::fwrite;::fwscanf;::fwscanf_s;::getc;::getchar;::getenv;::getenv_s;::gets_s;::getwc;::getwchar;::gmtime;::gmtime_s;::localtime;::localtime_s;::malloc;::mbrtoc16;::mbrtoc32;::mbsrtowcs;::mbsrtowcs_s;::mbstowcs;::mbstowcs_s;::memchr;::mktime;::mtx_init;::mtx_lock;::mtx_timedlock;::mtx_trylock;::mtx_unlock;::printf_s;::putc;::putwc;::raise;::realloc;::remove;::rename;::scanf;::scanf_s;::setlocale;::setvbuf;::signal;::snprintf;::snprintf_s;::sprintf;::sprintf_s;::sscanf;::sscanf_s;::strchr;::strerror_s;::strftime;::strpbrk;::strrchr;::strstr;::strtod;::strtof;::strtoimax;::strtok;::strtok_s;::strtol;::strtold;::strtoll;::strtoul;::strtoull;::strtoumax;::strxfrm;::swprintf;::swprintf_s;::swscanf;::swscanf_s;::thrd_create;::thrd_detach;::thrd_join;::thrd_sleep;::time;::timespec_get;::tmpfile;::tmpfile_s;::tmpnam;::tmpnam_s;::tss_create;::tss_get;::tss_set;::ungetc;::ungetwc;::vfprintf;::vfprintf_s;::vfscanf;::vfscanf_s;::vfwprintf;::vfwprintf_s;::vfwscanf;::vfwscanf_s;::vprintf_s;::vscanf;::vscanf_s;::vsnprintf;::vsnprintf_s;::vsprintf;::vsprintf_s;::vsscanf;::vsscanf_s;::vswprintf;::vswprintf_s;::vswscanf;::vswscanf_s;::vwprintf_s;::vwscanf;::vwscanf_s;::wcrtomb;::wcschr;::wcsftime;::wcspbrk;::wcsrchr;::wcsrtombs;::wcsrtombs_s;::wcsstr;::wcstod;::wcstof;::wcstoimax;::wcstok;::wcstok_s;::wcstol;::wcstold;::wcstoll;::wcstombs;::wcstombs_s;::wcstoul;::wcstoull;::wcstoumax;::wcsxfrm;::wctob;::wctrans;::wctype;::wmemchr;::wprintf_s;::wscanf;::wscanf_s;' + cert-err33-c.CheckedFunctions: '*' cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField: 'false' cert-str34-c.DiagnoseSignedUnsignedCharComparisons: 'false' cppcoreguidelines-non-private-member-variables-in-classes.IgnorePublicMemberVariables: 'true' cppcoreguidelines-rvalue-reference-param-not-moved.AllowPartialMove: 'true' + cppcoreguidelines-avoid-magic-numbers.IgnoredIntegerValues: '1;2;3;4;10' + cppcoreguidelines-avoid-magic-numbers.IgnoredFloatingPointValues: '1.0;2.0;10.0;100.0' google-readability-braces-around-statements.ShortStatementLines: '1' google-readability-function-size.StatementThreshold: '800' google-readability-namespace-comments.ShortNamespaceLines: '10' diff --git a/src/duplication_results.cpp b/src/duplication_results.cpp index f2842d7..85d8efb 100644 --- a/src/duplication_results.cpp +++ b/src/duplication_results.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,7 @@ static constexpr auto n_bins = 16; -static constexpr auto bin_breaks = std::array{ +static constexpr auto bin_breaks_impl = std::array{ 1, 2, 3, @@ -54,11 +55,12 @@ static constexpr auto bin_breaks = std::array{ 10'000, std::numeric_limits::max(), }; +static constexpr std::span bin_breaks = bin_breaks_impl; // clang-format off // ADS: previously for plots: std::array{"1", "2", ..., "5k+", "10k+"} -static constexpr auto bin_labels = std::array{ +static constexpr auto bin_labels_impl = std::array{ "0", "1", "2", @@ -77,6 +79,7 @@ static constexpr auto bin_labels = std::array{ ">5k", ">10k", }; +static constexpr std::span bin_labels = bin_labels_impl; // clang-format on @@ -181,9 +184,7 @@ make_bins(const auto &breaks, const auto &hist) { std::vector binned(std::size(breaks), 0); auto b_itr = std::cbegin(breaks); for (const auto [i, h] : falco::views::enumerate(hist)) { - // ADS: clang-tidy false positive? - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - b_itr += (b_itr < std::cend(breaks) && i >= *b_itr); + b_itr += (b_itr != std::cend(breaks) && i >= *b_itr); binned[std::distance(std::cbegin(breaks), b_itr)] += h; } return binned; diff --git a/src/falco.cpp b/src/falco.cpp index 7150b38..6a26b3f 100644 --- a/src/falco.cpp +++ b/src/falco.cpp @@ -277,7 +277,7 @@ main(int argc, char *argv[]) { if (argc >= 2) app.footer(std::format(description, falco::get_share_dir())); - // NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers) + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) app.get_formatter()->long_option_alignment_ratio(0.2); app.set_help_flag("-h,--help", "Print more detailed help"); app.set_version_flag("--version", VERSION, "Print program version"); diff --git a/src/falco_config.cpp b/src/falco_config.cpp index f5a3a38..5989748 100644 --- a/src/falco_config.cpp +++ b/src/falco_config.cpp @@ -95,11 +95,10 @@ load_config_and_set_graders(const std::string &filename, continue; const auto get_cutoff = [&](const std::string &label0) { const auto x = json_in[label][label0].get(); - const auto beg = std::data(x); - const auto end = beg + std::size(x); // NOLINT(*-pointer-arithmetic) double val{}; - const auto res = std::from_chars(beg, end, val); - if (res.ec != std::errc{}) + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + if (std::from_chars(std::data(x), std::data(x) + std::size(x), val) + .ec != std::errc{}) throw std::runtime_error("error parsing cutoff: " + x); return val; }; diff --git a/src/falco_utils.cpp b/src/falco_utils.cpp index 926dc39..2feba81 100644 --- a/src/falco_utils.cpp +++ b/src/falco_utils.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include // for std::localtime #include @@ -17,7 +18,6 @@ [[nodiscard]] auto size_to_units(const std::int64_t s, const std::string &suffix) -> std::string { const auto as_frac_2 = [](const auto a, const auto b) { - // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) return std::floor(10 * as_frac(a, b)) / 10; }; if (s >= gigabytes) @@ -63,10 +63,9 @@ get_theoretical_distribution(const std::vector &gc, const auto sd = std::sqrt(as_frac( std::reduce(std::cbegin(id_gc), std::cend(id_gc)), total_count - 1)); const auto to_normal = [&](const auto val) { - // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) return std::exp(-cntr_sq(val) / (2.0 * sd * sd)); }; - auto normed = std::views::iota(0u, n_bins) | + auto normed = std::views::iota(0U, n_bins) | std::views::transform(to_normal) | std::ranges::to(); const auto denom = std::reduce(std::cbegin(normed), std::cend(normed)); @@ -103,52 +102,51 @@ smooth_gc_content(const std::vector &data, std::ranges::subrange(std::cbegin(data), std::cbegin(data) + w))); #if __cpp_lib_ranges_slide for (const auto &window : data | std::views::slide(window_size)) - // cppcheck-suppress useStlAlgorithm smoothed.push_back(get_mean(window)); #else - for (auto i = 0LU; i < std::size(data); ++i) - // cppcheck-suppress useStlAlgorithm - smoothed.push_back(get_mean(std::ranges::subrange( - std::cbegin(data) + i, std::cbegin(data) + i + window_size))); + const auto lim = std::cend(data) - window_size; + for (auto itr = std::cbegin(data); itr != lim; ++itr) + smoothed.push_back(get_mean(std::ranges::subrange(itr, itr + window_size))); #endif + const auto d_end = std::cend(data); for (auto w = (window_size + 1) / 2; w > 1; --w) - smoothed.push_back(get_mean( - std::ranges::subrange(std::cend(data) - w + 1, std::cend(data)))); + smoothed.push_back(get_mean(std::ranges::subrange(d_end - w + 1, d_end))); return smoothed; } [[nodiscard]] auto -combine_gc_content_for_lengths(const std::vector &gcs) +combine_gc_content_for_lengths(const std::vector &gcs) -> std::vector { static constexpr auto histogram_size = 101; std::vector hist(histogram_size); - for (auto i = 0U; i < std::size(gcs); ++i) { - if (std::reduce(std::cbegin(gcs[i]), std::cend(gcs[i])) == 0) + for (const auto &gc : gcs) { + if (std::ranges::none_of(gc, [](const auto x) { return x > 0.0; })) continue; - const auto increm = as_frac(histogram_size, std::size(gcs[i])); - for (auto gc_idx = 0U; gc_idx < std::size(gcs[i]); ++gc_idx) { - const auto curr_percent = gc_idx * increm; - const auto next_percent = (gc_idx + 1) * increm; + const auto increment = as_frac(histogram_size, std::size(gc)); + for (auto gc_idx = 0U; gc_idx < std::size(gc); ++gc_idx) { + const auto curr_percent = gc_idx * increment; + const auto next_percent = (gc_idx + 1) * increment; const auto start_in_hist = - static_cast(std::floor(curr_percent)); + static_cast(std::floor(curr_percent)); // ADS: below, not sure best way to do this for all edge cases const auto stop_in_hist = - static_cast(std::min(static_cast(histogram_size), - std::ceil(next_percent))) - + static_cast(std::min(static_cast(histogram_size), + std::ceil(next_percent))) - 1; assert(stop_in_hist < histogram_size); const auto splits = start_in_hist != stop_in_hist; const auto frac_left = splits ? static_cast(start_in_hist) + 1.0 - curr_percent - : increm; + : increment; const auto frac_right = - splits ? next_percent - static_cast(stop_in_hist) : increm; - for (auto h_idx = start_in_hist; h_idx <= stop_in_hist; ++h_idx) { - const auto contrib = (h_idx == start_in_hist) ? frac_left - : (h_idx == stop_in_hist) ? frac_right - : 1.0; - hist[h_idx] += contrib * as_frac(gcs[i][gc_idx], increm); - } + splits ? next_percent - static_cast(stop_in_hist) : increment; + const auto hist_begin = std::begin(hist) + start_in_hist; + const auto hist_end = std::cbegin(hist) + stop_in_hist; + const auto gc_val = as_frac(gc[gc_idx], increment); + for (auto hist_itr = hist_begin; hist_itr <= hist_end; ++hist_itr) + *hist_itr += gc_val * ((hist_itr == hist_begin) ? frac_left + : (hist_itr == hist_end) ? frac_right + : 1.0); } } return hist; diff --git a/src/falco_utils.hpp b/src/falco_utils.hpp index 7888847..bd79a80 100644 --- a/src/falco_utils.hpp +++ b/src/falco_utils.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -29,36 +30,44 @@ static constexpr auto adenine_index = 0; static constexpr auto cytosine_index = 1; static constexpr auto thymine_index = 2; static constexpr auto guanine_index = 3; +static constexpr std::span bases = "ACTG"; // ADS: index this with vars above + +static constexpr auto alphabet_size = 4; static constexpr auto unknown_base_index = 3; -static constexpr auto bases = "ACTG"; // ADS: index this with vars above +static constexpr auto nibble_size = 4; -static constexpr auto base_permutation_for_report = { +namespace falco { +static constexpr auto base_permutation_for_report_impl = { guanine_index, adenine_index, thymine_index, cytosine_index, }; - -static constexpr auto base_colors_for_html = std::array{ +static constexpr auto base_colors_for_html_impl = std::array{ "green", // adenine "blue", // cytosine "red", // thymine "black", // guanine }; +} // namespace falco + +static constexpr std::span base_permutation_for_report = + falco::base_permutation_for_report_impl; +static constexpr std::span base_colors_for_html = + falco::base_colors_for_html_impl; namespace falco { -static constexpr auto alphabet_size = 4; -// ADS: gc_content_array_max_lim: the max read length for which there will be a -// vector of the exact size to count the number of GC in reads of that length -// without any kind of rounding. I think this was originally 500 in Falco v1, -// but I'm not sure it makes any difference. The algorithm for combining the -// different lengths is different, and in theory more accurate (principled), but -// the implementation led me to much confusion. -static constexpr auto gc_content_array_max_lim = 250; -static constexpr auto gc_content_array_max_size = gc_content_array_max_lim + 1; +// ADS: gc_content_max_lim: the max read length for which there will be a vector +// of the exact size to count the number of GC in reads of that length without +// any kind of rounding. I think this was originally 500 in Falco v1, but I'm +// not sure it makes any difference. The algorithm for combining the different +// lengths is different, and in theory more accurate (principled), but the +// implementation led me to much confusion. +static constexpr auto gc_content_max_lim = 250; +static constexpr auto gc_content_max_size = gc_content_max_lim + 1; using nuc_array = std::array; -using gc_content_array = std::vector; +using gc_content_t = std::vector; // ADS: this is because I wrote falco v2 using std::views::enumerate in many // places, but macOS apple-clang still doesn't have this c++20 feature. Not @@ -74,7 +83,7 @@ struct enumerate_t : std::ranges::range_adaptor_closure { [[nodiscard]] constexpr auto operator()(R &&r) const { const auto d = std::ranges::distance(r); - return std::views::zip(std::views::iota(0, d), static_cast(r)); + return std::views::zip(std::views::iota(0, d), std::forward(r)); } }; inline constexpr enumerate_t enumerate; @@ -88,16 +97,17 @@ static constexpr std::int64_t kilobytes = 1024; [[nodiscard]] inline auto resize_gc_content(const std::uint32_t updated_length, - std::vector &gc_content) { + std::vector &gc_content) { const auto prev_size = std::size(gc_content); gc_content.resize(std::min(static_cast(updated_length + 1), - falco::gc_content_array_max_size)); - for (auto i = prev_size; i < std::size(gc_content); ++i) - gc_content[i].resize(i + 1); + falco::gc_content_max_size)); + auto sp = std::span(std::begin(gc_content) + prev_size, std::end(gc_content)); + for (auto [idx, gc] : falco::views::enumerate(sp)) + gc.resize(prev_size + idx + 1); } [[nodiscard]] auto -combine_gc_content_for_lengths(const std::vector &gcs) +combine_gc_content_for_lengths(const std::vector &gcs) -> std::vector; [[nodiscard]] auto @@ -145,7 +155,8 @@ inline constexpr auto end_module_tag = ">>END_MODULE\n"; [[nodiscard]] inline constexpr auto encode(const char c) { - return (c >> 1) & 3; // Ns are counted as G so must be subtracted + static constexpr auto two_bit_mask = 3; + return (c >> 1) & two_bit_mask; // Ns are counted as G so must be subtracted } [[nodiscard]] inline constexpr auto @@ -153,13 +164,10 @@ is_gc(const char c) { return (c >> 1) & 1; } -inline constexpr auto nibble_size = 4; - [[nodiscard]] inline constexpr auto encode_nibble(const char c) { - // ADS: 15 is to keep 4 bits - // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) - return (c >> 1) & 15; // N gets separate encoding + static constexpr auto four_bit_mask = 15; // ADS: 15 is to keep 4 bits + return (c >> 1) & four_bit_mask; // N gets separate encoding } [[nodiscard]] inline constexpr auto @@ -282,7 +290,7 @@ count_gc(auto seq_itr, const auto seq_end) { [[nodiscard]] inline auto tabular_dot(const auto &a) { - auto total = static_cast::value_type>(0); + typename std::remove_cvref_t::value_type total{}; for (const auto [i, x] : falco::views::enumerate(a)) total += i * x; return total; @@ -290,9 +298,7 @@ tabular_dot(const auto &a) { [[nodiscard]] inline auto mean_tabular(const auto &a) { - const auto num = tabular_dot(a); - const auto denom = std::reduce(std::cbegin(a), std::cend(a)); - return static_cast(num) / static_cast(denom); + return as_frac(tabular_dot(a), std::reduce(std::cbegin(a), std::cend(a))); } [[nodiscard]] inline auto @@ -300,18 +306,16 @@ median_tabular(const auto &a) { using value_type = std::decay_t::value_type; std::vector cumul(std::size(a), 0); std::inclusive_scan(std::cbegin(a), std::cend(a), std::begin(cumul)); - const auto ub = std::ranges::upper_bound(cumul, cumul.back() / 2); - return static_cast(std::distance(std::begin(cumul), ub)); + const auto upper = std::ranges::upper_bound(cumul, cumul.back() / 2); + return static_cast(std::distance(std::begin(cumul), upper)); } // clang-format off -// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers) [[nodiscard]] inline constexpr auto median_val(const auto &q) { return q[0]; } [[nodiscard]] inline constexpr auto lquart_val(const auto &q) { return q[1]; } [[nodiscard]] inline constexpr auto uquart_val(const auto &q) { return q[2]; } [[nodiscard]] inline constexpr auto ldec_val(const auto &q) { return q[3]; } [[nodiscard]] inline constexpr auto udec_val(const auto &q) { return q[4]; } -// NOLINTEND(cppcoreguidelines-avoid-magic-numbers) // clang-format on // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers) @@ -336,8 +340,8 @@ five_quants(const auto &a) -> std::array { // NOLINTEND(cppcoreguidelines-avoid-magic-numbers) [[nodiscard]] auto -size_to_units(const std::int64_t s, const std::string &suffix = "iB") - -> std::string; +size_to_units(const std::int64_t s, + const std::string &suffix = "iB") -> std::string; [[nodiscard]] inline auto get_max_size(const auto &x) { @@ -347,28 +351,31 @@ get_max_size(const auto &x) { } [[nodiscard]] inline auto -estimate_read_length_fastq_chunk(const auto &data, const auto n) { +estimate_read_length_fastq_chunk(const auto &data, + const auto n) -> std::uint64_t { static constexpr auto fastq_lines_per_read = 4; assert(n >= 1); const auto valid = [](const auto c) { return c == 'A' || c == 'C' || c == 'G' || c == 'T' || c == 'N'; }; std::vector lines; - for (auto i = 0u; i + 1 < n; ++i) + for (auto i = 0U; i + 1 < n; ++i) if (data[i] == '\n') lines.push_back(i + 1); if (std::size(lines) < fastq_lines_per_read) - return 1ul; - auto total = 0ul; + return 1LU; + const auto is_record = [&](const auto l) { + return data[std::get<0>(l)] == '@' && data[std::get<2>(l)] == '+' && + valid(data[std::get<1>(l)]); + }; + auto total = 0LU; #if __cpp_lib_ranges_zip for (const auto l : lines | std::views::adjacent) { #else - for (auto i = 0U; i + fastq_lines_per_read < std::size(lines) + 1; ++i) { - std::tuple l{i, i + 1, i + 2}; + for (auto i = 0L; i + fastq_lines_per_read < std::ssize(lines) + 1; ++i) { + auto l = std::tuple{i, i + 1, i + 2}; #endif - if (data[std::get<0>(l)] == '@' && data[std::get<2>(l)] == '+' && - valid(data[std::get<1>(l)])) - // cppcheck-suppress useStlAlgorithm + if (is_record(l)) total += (std::get<2>(l) - std::get<1>(l)) - 1; } return total / (std::size(lines) / fastq_lines_per_read); diff --git a/src/falco_word.hpp b/src/falco_word.hpp index 52e4e22..3a5380b 100644 --- a/src/falco_word.hpp +++ b/src/falco_word.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include // conversion for kmers to include 'N' @@ -18,6 +19,8 @@ // T (84)10 = (1010100)2 => 001 struct falco_word { + static constexpr std::span extended_bases = "GTCAN"; + static constexpr auto extended_alpha_size = 5; static constexpr auto shift_for_width_bits = 56u; static constexpr auto width_bits_removal_mask = 0xffffffffffffff; static constexpr auto max_lo_lim = 27u; @@ -30,12 +33,10 @@ struct falco_word { falco_word(auto b, std::uint64_t w) { static constexpr auto fw_encode = [](const auto c) { - // NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers) - return ((c >> 1) & 7) ^ 3; + return ((c >> 1) & 7) ^ 3; // NOLINT(*-avoid-magic-numbers) }; static const auto enc_shift = [&](auto &x, auto &c) { - // NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers) - x = (x * 5) + fw_encode(*c++); + x = (x * extended_alpha_size) + fw_encode(*c++); }; w = w < max_hi_lim ? w : max_hi_lim; const auto lo_lim = b + (w > max_lo_lim ? max_lo_lim : w); @@ -49,11 +50,8 @@ struct falco_word { [[nodiscard]] static auto string_impl(auto word, auto n_bases) { - static constexpr auto extended_bases = "GTCAN"; - static constexpr auto extended_alpha_size = 5; std::string r; for (auto i = 0u; i < n_bases; ++i) { - // NOLINTNEXTLINE (cppcoreguidelines-pro-bounds-pointer-arithmetic) r += extended_bases[word % extended_alpha_size]; word /= extended_alpha_size; } @@ -74,11 +72,12 @@ struct falco_word { [[nodiscard]] auto hash() const noexcept { // ADS: from boost multiprecision hash, but for 64 bits + // ADS: this might already be in the boost unordered_map header + static constexpr auto left_shift = 6; static constexpr auto magic = 0x517cc1b727220a95; static constexpr auto hashfun = std::hash{}; const auto h = hashfun(lo); - // NOLINTNEXTLINE (cppcoreguidelines-pro-bounds-pointer-arithmetic) - return h ^ ((hashfun(hi) + magic) + (h << 6) + (h >> 2)); + return h ^ ((hashfun(hi) + magic) + (h << left_shift) + (h >> 2)); } }; diff --git a/src/html.cpp b/src/html.cpp index fb88c8e..6c69921 100644 --- a/src/html.cpp +++ b/src/html.cpp @@ -26,9 +26,10 @@ #include #include #include +#include #include #include -#include // IWYU pragma: keep +#include [[nodiscard]] auto get_summary(const file_grades &grades) -> std::string { @@ -187,10 +188,9 @@ line: {{color: "{}"}} }); const auto total_by_pos = nucs | std::views::transform(sum); std::vector r; - // NOLINTBEGIN(*-constant-array-index,*-pointer-arithmetic) - for (const auto idx : std::views::iota(0, falco::alphabet_size)) { + for (const auto idx : std::views::iota(0, alphabet_size)) { const auto pct_for_pos = [idx](const auto &nucs_for_pos, const auto tot) { - return pct(as_frac(nucs_for_pos[idx], tot)); + return pct(as_frac(std::span{nucs_for_pos}[idx], tot)); }; #if __cpp_lib_ranges_zip const auto y = std::views::zip_transform(pct_for_pos, nucs, total_by_pos); @@ -203,7 +203,6 @@ line: {{color: "{}"}} fmt::join(y, ","), bases[idx], base_colors_for_html[idx])); } - // NOLINTEND(*-constant-array-index,*-pointer-arithmetic) const auto grade = grades.grade(label); const auto title = grades.get_title(label); return fmt::format(html_module_fmt, grade, label, title, grade, @@ -281,19 +280,16 @@ yaxis: {{title: "Density", rangemode: "tozero"}}, const auto title = grades.get_title(label); // output quality values between first non-zero and last zero const auto gt0 = [&](const auto x) { return x > 0; }; - const auto begin_obs_itr = std::ranges::find_if(qual_by_read, gt0); - if (begin_obs_itr == std::cend(qual_by_read)) + const auto qbr = std::span{qual_by_read}; + const auto beg_itr = std::ranges::find_if(qbr, gt0); + if (beg_itr == std::cend(qbr)) throw std::runtime_error("error finding quality scores generating html"); - const std::int64_t begin_obs = - std::distance(std::cbegin(qual_by_read), begin_obs_itr); - const auto end_obs_subrange = std::ranges::find_last_if(qual_by_read, gt0); - const std::int64_t end_obs = - std::ssize(qual_by_read) - std::ssize(end_obs_subrange) + 1; - assert(begin_obs >= 0 && end_obs <= falco::max_qual_val); - const auto x = std::views::iota(begin_obs, end_obs); - const auto q_beg = std::cbegin(qual_by_read); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - const auto y = std::ranges::subrange{q_beg + begin_obs, q_beg + end_obs}; + const auto beg_pos = std::distance(std::cbegin(qbr), beg_itr); + const auto end_range = std::ranges::find_last_if(qbr, gt0); + const auto end_pos = std::ssize(qbr) - std::ssize(end_range) + 1; + assert(beg_pos >= 0 && end_pos <= falco::max_qual_val); + const auto x = std::views::iota(beg_pos, end_pos); + const auto y = qbr.subspan(beg_pos, std::size(x)); return fmt::format( html_module_fmt, grade, label, title, grade, fmt::format(plot_fmt, fmt::join(x, ","), fmt::join(y, ","))); @@ -382,8 +378,8 @@ basic_stats_html(const file_info &info, const std::uint64_t n_reads, [[nodiscard]] auto tile_html(const tile_processor::tiles_centered_t ¢ered, - const std::vector &groups, const file_grades &grades) - -> std::string { + const std::vector &groups, + const file_grades &grades) -> std::string { static constexpr auto label = "tile"; static constexpr auto n_quants = 20.0; // ADS: ??? (-10: red, 0: light blue, +10: dark blue) @@ -442,8 +438,8 @@ yaxis: {{title: "tile", type: "category"}}, } [[nodiscard]] auto -kmer_html(const std::vector &results, const file_grades &grades) - -> std::string { +kmer_html(const std::vector &results, + const file_grades &grades) -> std::string { static constexpr auto label = "kmer"; static constexpr auto plot_format = R"(