Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a48b5d3
src/quality_score.hcpp: renaming the to_string function because the a…
andrewdavidsmith Sep 1, 2026
3697635
.cppcheck_suppress: ignoring fmt and ignoring constStatement which se…
andrewdavidsmith Sep 1, 2026
6633d46
src/samrec.cpp: adding missing include
andrewdavidsmith Sep 1, 2026
c256b39
src/tile_processor.cpp: renaming variables to avoid shadowing
andrewdavidsmith Sep 1, 2026
7e962a2
src/bam_file.hcpp: headers and formatting for new clang-tidy
andrewdavidsmith Sep 1, 2026
d9a4f45
src/base_groups.hpp: removing nodiscard on void functions
andrewdavidsmith Sep 1, 2026
4a8c6f0
src/sam_file.cpp: adding includes and initializing cursor and last in…
andrewdavidsmith Sep 1, 2026
cd9127e
src/kmer_counter.hcpp: removing the apply_groups function which isn't…
andrewdavidsmith Sep 1, 2026
a39a7c8
src/original_duplicates.cpp: changed loop to alg
andrewdavidsmith Sep 1, 2026
5396c2e
src/falco_utils.hcpp: fixing nodiscards and an include
andrewdavidsmith Sep 1, 2026
d39f1df
src/falco_analyzer.cpp: adding an include for iwyu that seems wrong a…
andrewdavidsmith Sep 1, 2026
8cc60aa
src/bgzf_reader.cpp: static analysis
andrewdavidsmith Sep 1, 2026
646cd9c
src/falco_grade.hcpp: making a member function get_tile static and re…
andrewdavidsmith Sep 1, 2026
e79f931
src/adapter_set.cpp: iterating using itr = next(itr) for now when cle…
andrewdavidsmith Sep 1, 2026
0f5e495
src/html.cpp: headers and nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
2163c8f
src/fastq_gz_file.cpp: header and nolint on pointer arithmetic
andrewdavidsmith Sep 1, 2026
e3fb8ce
src/falco_config.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
77235a3
src/fastq_bgzf_file.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
9320554
src/falco_word.hpp: nolint on array bound
andrewdavidsmith Sep 1, 2026
7524af5
src/contaminants.cpp: iterating using itr = next(itr) for now when cl…
andrewdavidsmith Sep 1, 2026
ea20a1b
src/contaminants.hpp: adding a header
andrewdavidsmith Sep 1, 2026
2d181f8
src/fastq_file.cpp: adding headers
andrewdavidsmith Sep 1, 2026
badab36
src/adapter_matcher.cpp: nolint and fixing the number of positions ou…
andrewdavidsmith Sep 1, 2026
37d4a61
src/falco_file_format.hcpp: includes
andrewdavidsmith Sep 1, 2026
4ce3f0e
src/duplication_results.hpp: explicit on single param constructor
andrewdavidsmith Sep 1, 2026
dcd8535
src/duplication_results.cpp: nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
cadffe0
src/results_collector.hpp: casting in an assert to avoid side effect …
andrewdavidsmith Sep 1, 2026
c26cde0
src/results_summary.cpp: fixing var name to avoid shadowing
andrewdavidsmith Sep 1, 2026
089c478
src/report.cpp: removing include and fixing to_string for encoding to…
andrewdavidsmith Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cppcheck_suppress
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,9 +35,12 @@ missingInclude
*:*CLI11.hpp
*:*json.hpp
*:*boost_unordered.hpp
*:fmt/*.h
# Problem caused by external files
toomanyconfigs
# More problems caused by external files -- with too many ifdefs
normalCheckLevelMaxBranches
# This seems not to work with the designs used here
duplInheritedMember
# Seems like iterator variables for std::views disagree with this
constStatement
15 changes: 9 additions & 6 deletions src/adapter_matcher.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -131,6 +131,7 @@ y: {},
type: "line",
name: "{}",
}})";
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
assert(std::size(groups) == std::size(adap_counts));
// calcualte the x axis first
const auto x = groups | std::views::transform([&](const auto &g) {
Expand All@@ -146,9 +147,9 @@ name: "{}",
std::ranges::transform(cumulative[curr], cumulative[prev],
std::begin(cumulative[curr]), std::plus{});
#endif
const auto n_pos = max_read_len + 1 >= adapter_size
? max_read_len - adapter_size + 1
: max_read_len;
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
const auto n_pos =
max_read_len + 1 > adapter_size ? (max_read_len + 1) - adapter_size : 0U;
const auto last_group_to_keep = std::ranges::find_if(
groups, [&](const auto &g) { return n_pos <= g.first; });
cumulative.resize(std::distance(std::cbegin(groups), last_group_to_keep));
Expand All@@ -164,13 +165,15 @@ name: "{}",
return pct_of_reads(cumul[adap_id]);
};
const auto y = cumulative | std::views::transform(make_y);
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
html_by_adapter.emplace_back(fmt::format(adapter_fmt, x, y, adap_name));
}
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter)));
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter));
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}

auto
Expand Down
3 changes: 2 additions & 1 deletion src/adapter_set.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,8 @@ load_adapters(const std::string &filename) {
// ADS: need to make sure this can't fail
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
6 changes: 4 additions & 2 deletions src/bam_file.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,9 @@
#include <stdexcept>
#include <string>
#include <system_error>
#include <tuple>
#include <utility>
#include <vector>

[[nodiscard]] auto
estimate_n_reads_bam(const std::string &filename)
Expand DownExpand Up@@ -63,8 +65,8 @@ estimate_n_reads_bam(const std::string &filename)
}

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t {
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t {
static constexpr auto complem = [](const auto x) {
return "TNGNNNCNNNNNNNNNNNNA"[x - 'A'];
};
Expand Down
9 changes: 6 additions & 3 deletions src/bam_file.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,7 +62,10 @@ class bam_file {
~bam_file() = default;
// clang-format on

[[nodiscard]] operator bool() const { return !had_last_chunks; }
[[nodiscard]]
operator bool() const {
return !had_last_chunks;
}

friend auto
reset(bam_file &reads_file) -> void;
Expand DownExpand Up@@ -121,8 +124,8 @@ estimate_n_reads_bam(const std::string &filename)
-> std::tuple<std::uint64_t, std::uint64_t, std::int64_t>;

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t;
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t;

inline auto
make_tasks(bam_file &reads_file, //
Expand Down
8 changes: 4 additions & 4 deletions src/base_groups.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,16 +23,16 @@ make_base_groups(const std::uint64_t n_bases, const std::uint64_t n_initial,
const std::uint64_t n_groups_target) -> base_group_vec;

[[nodiscard]] auto
get_default_base_groups(const std::uint64_t n_bases,
const bool make_groups) -> base_group_vec;
get_default_base_groups(const std::uint64_t n_bases, const bool make_groups)
-> base_group_vec;

[[nodiscard]] auto
make_group_tag(const base_group_t g) -> std::string;

[[nodiscard]] auto
make_group_tag_quoted(const base_group_t g) -> std::string;

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand All@@ -50,7 +50,7 @@ apply_base_groups(const base_group_vec &groups, auto &rows) {
rows.resize(current_row);
}

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows, const auto &adder) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand Down
5 changes: 4 additions & 1 deletion src/bgzf_reader.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@
#include <cassert>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <memory>
Expand All@@ -28,6 +29,7 @@ get_unaligned_le32(const auto p) -> std::int32_t {
get_isize(const auto data, const auto data_size) {
static constexpr decltype(data_size) isize_size = 4;
assert(data_size > isize_size);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
const auto data_isize = data + data_size - isize_size;
return data_size < isize_size ? 0 : get_unaligned_le32(data_isize);
}
Expand All@@ -50,7 +52,8 @@ bgzf_reader::bgzf_reader(const std::string &filename,
next_in{inbuf.get()}, //
end_in{inbuf.get()}, //
next_out{outbuf.get()}, //
end_out{outbuf.get() + buf_size} //
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
end_out{outbuf.get() + buf_size} //
{}

[[nodiscard]] auto
Expand Down
4 changes: 3 additions & 1 deletion src/contaminants.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include <stdexcept>
#include <string>
#include <string_view>
#include <tuple> // for std::get
#include <utility>
#include <vector>

Expand DownExpand Up@@ -197,7 +198,8 @@ load_contaminants(const std::string &filename) -> void {
continue;
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
1 change: 1 addition & 0 deletions src/contaminants.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@
#define SRC_CONTAMINANTS_HPP_

#include <cstdint>
#include <ranges> // for std::pair
#include <string>
#include <utility> // IWYU pragma: keep
#include <vector>
Expand Down
25 changes: 14 additions & 11 deletions src/duplication_results.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include "run_mode.hpp"

#define FMT_HEADER_ONLY
#include "fmt/base.h"
#include "fmt/format.h"
#include "fmt/ranges.h"

Expand DownExpand Up@@ -124,8 +125,8 @@ duplication_results::get_overrepresented(const std::uint64_t n_reads) const
}

auto
duplication_results::initialize(const run_mode &mode,
const file_info &info) -> void {
duplication_results::initialize(const run_mode &mode, const file_info &info)
-> void {
read_skip =
info.n_reads_est < max_n_reads_total
? 0
Expand DownExpand Up@@ -282,8 +283,8 @@ get_grade_duplication(const dup_summary_t &summary) -> std::string {
}

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto start_tag = ">>Sequence Duplication Levels\t{}\n"
"#Total Deduplicated Percentage\t{:.6f}\n";
Expand All@@ -305,9 +306,10 @@ duplication_report(const dup_summary_t &summary,
std::max(static_cast<std::uint64_t>(1), reduce(summary.hist_mass)));
auto r = std::format(start_tag, grades.grade(label), pct(frac_dedup));
r += header;
for (const auto [label, mass] :
for (const auto [bin_label, mass] :
std::views::zip(bin_labels, binned_mass_pct) | std::views::drop(1))
r += std::format("{}\t{:.3g}\n", label, mass); // Percentage format is .3g
r +=
std::format("{}\t{:.3g}\n", bin_label, mass); // Percentage format is .3g
return r + end_module_tag;
}

Expand DownExpand Up@@ -345,8 +347,8 @@ overrepresented_html(const std::vector<overrep_t> &overrep,
}

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto plot_format = R"(<div id="duplication_plot"></div>
<script>Plotly.newPlot("duplication_plot",
Expand DownExpand Up@@ -389,11 +391,12 @@ yaxis: {{title: "% of sequences"}},
};
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
fmt::format(plot_format, //
x, to_pct(summary.hist_mass) | std::views::drop(1), // y_tot,
x, to_pct(summary.hist_dedup) | std::views::drop(1), // y_dedup
x, x_text | std::views::drop(1) // tickvals
));
);
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}
10 changes: 5 additions & 5 deletions src/duplication_results.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ struct dups_init_t {
std::int64_t count_at_limit{};
dups_map_t dups_zero;
dups_init_t() = default;
dups_init_t(const dups_map_t &dups) {
explicit dups_init_t(const dups_map_t &dups) {
const auto vals = dups | std::views::values;
count_at_limit = static_cast<std::int64_t>(
std::reduce(std::cbegin(vals), std::cend(vals)));
Expand DownExpand Up@@ -113,12 +113,12 @@ struct duplication_results {
get_grade_duplication(const dup_summary_t &summary) -> std::string;

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
get_grade_overrepresented(const std::uint64_t n_reads,
Expand Down
3 changes: 2 additions & 1 deletion src/falco_analyzer.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
#include <mutex>
#include <ranges>
#include <thread>
#include <tuple> // for std::get (iwyu fp)
#include <utility>
#include <variant>
#include <vector>
Expand All@@ -34,7 +35,6 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
const std::int32_t n_files = static_cast<std::int32_t>(std::size(infos));
if (dups_init.empty())
dups_init.resize(n_files);
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::atomic_uint32_t n_active_files{static_cast<std::uint32_t>(n_files)};
auto results =
std::vector(n_threads, std::vector<results_collector>(n_files));
Expand All@@ -45,6 +45,7 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
tq.push(file_id, std::monostate{});

{ // scope to join jthreads
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::vector<std::jthread> workers;
for (const auto th_id : std::views::iota(0u, n_threads))
workers.emplace_back([&, n_threads, th_id] {
Expand Down
18 changes: 10 additions & 8 deletions src/falco_config.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,8 +41,8 @@ split(const std::string &s) {
}

auto
load_config_and_set_graders(const std::string &filename,
run_mode &mode) -> void {
load_config_and_set_graders(const std::string &filename, run_mode &mode)
-> void {
// ADS: (todo) handle carriage returns and other control chars
std::ifstream in(filename);
if (!in)
Expand All@@ -61,9 +61,10 @@ load_config_and_set_graders(const std::string &filename,
}

// modes
for (const auto &label : run_mode::get_labels())
std::ranges::for_each(run_mode::get_labels(), [&](const auto &label) {
if (json_in.contains(label) && !json_in[label].contains("ignore"))
throw std::runtime_error("invalid config: " + to_string(json_in[label]));
});

std::unordered_map<std::string, bool> modes_in;
try {
Expand All@@ -83,11 +84,12 @@ load_config_and_set_graders(const std::string &filename,
mode.assign(modes_in);

// grades
for (const auto &label : grade_labels)
if (json_in.contains(label) &&
!(json_in[label].contains("error") && json_in[label].contains("warn")))
throw std::runtime_error("missing config value for: " +
std::string(label));
std::ranges::for_each(grade_labels, [&](const auto &l) {
if (json_in.contains(l) &&
!(json_in[l].contains("error") && json_in[l].contains("warn")))
throw std::runtime_error("missing config value for: " + std::string(l));
});

std::unordered_map<std::string, grader> graders;
try {
for (const auto &label : grade_labels) {
Expand Down
4 changes: 4 additions & 0 deletions src/falco_file_format.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,7 +7,11 @@
#include <array>
#include <cstdlib>
#include <filesystem>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <string>
#include <tuple>

[[nodiscard]] auto
get_file_format(const std::string &filename)
Expand Down
2 changes: 0 additions & 2 deletions src/falco_file_format.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,8 +7,6 @@

#include <cstdint>
#include <format>
#include <iterator>
#include <memory>
#include <string>
#include <thread>
#include <tuple>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a48b5d3
src/quality_score.hcpp: renaming the to_string function because the a…
andrewdavidsmith Sep 1, 2026
3697635
.cppcheck_suppress: ignoring fmt and ignoring constStatement which se…
andrewdavidsmith Sep 1, 2026
6633d46
src/samrec.cpp: adding missing include
andrewdavidsmith Sep 1, 2026
c256b39
src/tile_processor.cpp: renaming variables to avoid shadowing
andrewdavidsmith Sep 1, 2026
7e962a2
src/bam_file.hcpp: headers and formatting for new clang-tidy
andrewdavidsmith Sep 1, 2026
d9a4f45
src/base_groups.hpp: removing nodiscard on void functions
andrewdavidsmith Sep 1, 2026
4a8c6f0
src/sam_file.cpp: adding includes and initializing cursor and last in…
andrewdavidsmith Sep 1, 2026
cd9127e
src/kmer_counter.hcpp: removing the apply_groups function which isn't…
andrewdavidsmith Sep 1, 2026
a39a7c8
src/original_duplicates.cpp: changed loop to alg
andrewdavidsmith Sep 1, 2026
5396c2e
src/falco_utils.hcpp: fixing nodiscards and an include
andrewdavidsmith Sep 1, 2026
d39f1df
src/falco_analyzer.cpp: adding an include for iwyu that seems wrong a…
andrewdavidsmith Sep 1, 2026
8cc60aa
src/bgzf_reader.cpp: static analysis
andrewdavidsmith Sep 1, 2026
646cd9c
src/falco_grade.hcpp: making a member function get_tile static and re…
andrewdavidsmith Sep 1, 2026
e79f931
src/adapter_set.cpp: iterating using itr = next(itr) for now when cle…
andrewdavidsmith Sep 1, 2026
0f5e495
src/html.cpp: headers and nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
2163c8f
src/fastq_gz_file.cpp: header and nolint on pointer arithmetic
andrewdavidsmith Sep 1, 2026
e3fb8ce
src/falco_config.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
77235a3
src/fastq_bgzf_file.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
9320554
src/falco_word.hpp: nolint on array bound
andrewdavidsmith Sep 1, 2026
7524af5
src/contaminants.cpp: iterating using itr = next(itr) for now when cl…
andrewdavidsmith Sep 1, 2026
ea20a1b
src/contaminants.hpp: adding a header
andrewdavidsmith Sep 1, 2026
2d181f8
src/fastq_file.cpp: adding headers
andrewdavidsmith Sep 1, 2026
badab36
src/adapter_matcher.cpp: nolint and fixing the number of positions ou…
andrewdavidsmith Sep 1, 2026
37d4a61
src/falco_file_format.hcpp: includes
andrewdavidsmith Sep 1, 2026
4ce3f0e
src/duplication_results.hpp: explicit on single param constructor
andrewdavidsmith Sep 1, 2026
dcd8535
src/duplication_results.cpp: nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
cadffe0
src/results_collector.hpp: casting in an assert to avoid side effect …
andrewdavidsmith Sep 1, 2026
c26cde0
src/results_summary.cpp: fixing var name to avoid shadowing
andrewdavidsmith Sep 1, 2026
089c478
src/report.cpp: removing include and fixing to_string for encoding to…
andrewdavidsmith Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cppcheck_suppress
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,9 +35,12 @@ missingInclude
*:*CLI11.hpp
*:*json.hpp
*:*boost_unordered.hpp
*:fmt/*.h
# Problem caused by external files
toomanyconfigs
# More problems caused by external files -- with too many ifdefs
normalCheckLevelMaxBranches
# This seems not to work with the designs used here
duplInheritedMember
# Seems like iterator variables for std::views disagree with this
constStatement
15 changes: 9 additions & 6 deletions src/adapter_matcher.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -131,6 +131,7 @@ y: {},
type: "line",
name: "{}",
}})";
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
assert(std::size(groups) == std::size(adap_counts));
// calcualte the x axis first
const auto x = groups | std::views::transform([&](const auto &g) {
Expand All@@ -146,9 +147,9 @@ name: "{}",
std::ranges::transform(cumulative[curr], cumulative[prev],
std::begin(cumulative[curr]), std::plus{});
#endif
const auto n_pos = max_read_len + 1 >= adapter_size
? max_read_len - adapter_size + 1
: max_read_len;
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
const auto n_pos =
max_read_len + 1 > adapter_size ? (max_read_len + 1) - adapter_size : 0U;
const auto last_group_to_keep = std::ranges::find_if(
groups, [&](const auto &g) { return n_pos <= g.first; });
cumulative.resize(std::distance(std::cbegin(groups), last_group_to_keep));
Expand All@@ -164,13 +165,15 @@ name: "{}",
return pct_of_reads(cumul[adap_id]);
};
const auto y = cumulative | std::views::transform(make_y);
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
html_by_adapter.emplace_back(fmt::format(adapter_fmt, x, y, adap_name));
}
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter)));
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter));
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}

auto
Expand Down
3 changes: 2 additions & 1 deletion src/adapter_set.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,8 @@ load_adapters(const std::string &filename) {
// ADS: need to make sure this can't fail
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
6 changes: 4 additions & 2 deletions src/bam_file.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,9 @@
#include <stdexcept>
#include <string>
#include <system_error>
#include <tuple>
#include <utility>
#include <vector>

[[nodiscard]] auto
estimate_n_reads_bam(const std::string &filename)
Expand DownExpand Up@@ -63,8 +65,8 @@ estimate_n_reads_bam(const std::string &filename)
}

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t {
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t {
static constexpr auto complem = [](const auto x) {
return "TNGNNNCNNNNNNNNNNNNA"[x - 'A'];
};
Expand Down
9 changes: 6 additions & 3 deletions src/bam_file.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,7 +62,10 @@ class bam_file {
~bam_file() = default;
// clang-format on

[[nodiscard]] operator bool() const { return !had_last_chunks; }
[[nodiscard]]
operator bool() const {
return !had_last_chunks;
}

friend auto
reset(bam_file &reads_file) -> void;
Expand DownExpand Up@@ -121,8 +124,8 @@ estimate_n_reads_bam(const std::string &filename)
-> std::tuple<std::uint64_t, std::uint64_t, std::int64_t>;

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t;
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t;

inline auto
make_tasks(bam_file &reads_file, //
Expand Down
8 changes: 4 additions & 4 deletions src/base_groups.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,16 +23,16 @@ make_base_groups(const std::uint64_t n_bases, const std::uint64_t n_initial,
const std::uint64_t n_groups_target) -> base_group_vec;

[[nodiscard]] auto
get_default_base_groups(const std::uint64_t n_bases,
const bool make_groups) -> base_group_vec;
get_default_base_groups(const std::uint64_t n_bases, const bool make_groups)
-> base_group_vec;

[[nodiscard]] auto
make_group_tag(const base_group_t g) -> std::string;

[[nodiscard]] auto
make_group_tag_quoted(const base_group_t g) -> std::string;

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand All@@ -50,7 +50,7 @@ apply_base_groups(const base_group_vec &groups, auto &rows) {
rows.resize(current_row);
}

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows, const auto &adder) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand Down
5 changes: 4 additions & 1 deletion src/bgzf_reader.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@
#include <cassert>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <memory>
Expand All@@ -28,6 +29,7 @@ get_unaligned_le32(const auto p) -> std::int32_t {
get_isize(const auto data, const auto data_size) {
static constexpr decltype(data_size) isize_size = 4;
assert(data_size > isize_size);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
const auto data_isize = data + data_size - isize_size;
return data_size < isize_size ? 0 : get_unaligned_le32(data_isize);
}
Expand All@@ -50,7 +52,8 @@ bgzf_reader::bgzf_reader(const std::string &filename,
next_in{inbuf.get()}, //
end_in{inbuf.get()}, //
next_out{outbuf.get()}, //
end_out{outbuf.get() + buf_size} //
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
end_out{outbuf.get() + buf_size} //
{}

[[nodiscard]] auto
Expand Down
4 changes: 3 additions & 1 deletion src/contaminants.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include <stdexcept>
#include <string>
#include <string_view>
#include <tuple> // for std::get
#include <utility>
#include <vector>

Expand DownExpand Up@@ -197,7 +198,8 @@ load_contaminants(const std::string &filename) -> void {
continue;
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
1 change: 1 addition & 0 deletions src/contaminants.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@
#define SRC_CONTAMINANTS_HPP_

#include <cstdint>
#include <ranges> // for std::pair
#include <string>
#include <utility> // IWYU pragma: keep
#include <vector>
Expand Down
25 changes: 14 additions & 11 deletions src/duplication_results.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include "run_mode.hpp"

#define FMT_HEADER_ONLY
#include "fmt/base.h"
#include "fmt/format.h"
#include "fmt/ranges.h"

Expand DownExpand Up@@ -124,8 +125,8 @@ duplication_results::get_overrepresented(const std::uint64_t n_reads) const
}

auto
duplication_results::initialize(const run_mode &mode,
const file_info &info) -> void {
duplication_results::initialize(const run_mode &mode, const file_info &info)
-> void {
read_skip =
info.n_reads_est < max_n_reads_total
? 0
Expand DownExpand Up@@ -282,8 +283,8 @@ get_grade_duplication(const dup_summary_t &summary) -> std::string {
}

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto start_tag = ">>Sequence Duplication Levels\t{}\n"
"#Total Deduplicated Percentage\t{:.6f}\n";
Expand All@@ -305,9 +306,10 @@ duplication_report(const dup_summary_t &summary,
std::max(static_cast<std::uint64_t>(1), reduce(summary.hist_mass)));
auto r = std::format(start_tag, grades.grade(label), pct(frac_dedup));
r += header;
for (const auto [label, mass] :
for (const auto [bin_label, mass] :
std::views::zip(bin_labels, binned_mass_pct) | std::views::drop(1))
r += std::format("{}\t{:.3g}\n", label, mass); // Percentage format is .3g
r +=
std::format("{}\t{:.3g}\n", bin_label, mass); // Percentage format is .3g
return r + end_module_tag;
}

Expand DownExpand Up@@ -345,8 +347,8 @@ overrepresented_html(const std::vector<overrep_t> &overrep,
}

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto plot_format = R"(<div id="duplication_plot"></div>
<script>Plotly.newPlot("duplication_plot",
Expand DownExpand Up@@ -389,11 +391,12 @@ yaxis: {{title: "% of sequences"}},
};
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
fmt::format(plot_format, //
x, to_pct(summary.hist_mass) | std::views::drop(1), // y_tot,
x, to_pct(summary.hist_dedup) | std::views::drop(1), // y_dedup
x, x_text | std::views::drop(1) // tickvals
));
);
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}
10 changes: 5 additions & 5 deletions src/duplication_results.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ struct dups_init_t {
std::int64_t count_at_limit{};
dups_map_t dups_zero;
dups_init_t() = default;
dups_init_t(const dups_map_t &dups) {
explicit dups_init_t(const dups_map_t &dups) {
const auto vals = dups | std::views::values;
count_at_limit = static_cast<std::int64_t>(
std::reduce(std::cbegin(vals), std::cend(vals)));
Expand DownExpand Up@@ -113,12 +113,12 @@ struct duplication_results {
get_grade_duplication(const dup_summary_t &summary) -> std::string;

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
get_grade_overrepresented(const std::uint64_t n_reads,
Expand Down
3 changes: 2 additions & 1 deletion src/falco_analyzer.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
#include <mutex>
#include <ranges>
#include <thread>
#include <tuple> // for std::get (iwyu fp)
#include <utility>
#include <variant>
#include <vector>
Expand All@@ -34,7 +35,6 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
const std::int32_t n_files = static_cast<std::int32_t>(std::size(infos));
if (dups_init.empty())
dups_init.resize(n_files);
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::atomic_uint32_t n_active_files{static_cast<std::uint32_t>(n_files)};
auto results =
std::vector(n_threads, std::vector<results_collector>(n_files));
Expand All@@ -45,6 +45,7 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
tq.push(file_id, std::monostate{});

{ // scope to join jthreads
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::vector<std::jthread> workers;
for (const auto th_id : std::views::iota(0u, n_threads))
workers.emplace_back([&, n_threads, th_id] {
Expand Down
18 changes: 10 additions & 8 deletions src/falco_config.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,8 +41,8 @@ split(const std::string &s) {
}

auto
load_config_and_set_graders(const std::string &filename,
run_mode &mode) -> void {
load_config_and_set_graders(const std::string &filename, run_mode &mode)
-> void {
// ADS: (todo) handle carriage returns and other control chars
std::ifstream in(filename);
if (!in)
Expand All@@ -61,9 +61,10 @@ load_config_and_set_graders(const std::string &filename,
}

// modes
for (const auto &label : run_mode::get_labels())
std::ranges::for_each(run_mode::get_labels(), [&](const auto &label) {
if (json_in.contains(label) && !json_in[label].contains("ignore"))
throw std::runtime_error("invalid config: " + to_string(json_in[label]));
});

std::unordered_map<std::string, bool> modes_in;
try {
Expand All@@ -83,11 +84,12 @@ load_config_and_set_graders(const std::string &filename,
mode.assign(modes_in);

// grades
for (const auto &label : grade_labels)
if (json_in.contains(label) &&
!(json_in[label].contains("error") && json_in[label].contains("warn")))
throw std::runtime_error("missing config value for: " +
std::string(label));
std::ranges::for_each(grade_labels, [&](const auto &l) {
if (json_in.contains(l) &&
!(json_in[l].contains("error") && json_in[l].contains("warn")))
throw std::runtime_error("missing config value for: " + std::string(l));
});

std::unordered_map<std::string, grader> graders;
try {
for (const auto &label : grade_labels) {
Expand Down
4 changes: 4 additions & 0 deletions src/falco_file_format.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,7 +7,11 @@
#include <array>
#include <cstdlib>
#include <filesystem>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <string>
#include <tuple>

[[nodiscard]] auto
get_file_format(const std::string &filename)
Expand Down
2 changes: 0 additions & 2 deletions src/falco_file_format.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,8 +7,6 @@

#include <cstdint>
#include <format>
#include <iterator>
#include <memory>
#include <string>
#include <thread>
#include <tuple>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a48b5d3
src/quality_score.hcpp: renaming the to_string function because the a…
andrewdavidsmith Sep 1, 2026
3697635
.cppcheck_suppress: ignoring fmt and ignoring constStatement which se…
andrewdavidsmith Sep 1, 2026
6633d46
src/samrec.cpp: adding missing include
andrewdavidsmith Sep 1, 2026
c256b39
src/tile_processor.cpp: renaming variables to avoid shadowing
andrewdavidsmith Sep 1, 2026
7e962a2
src/bam_file.hcpp: headers and formatting for new clang-tidy
andrewdavidsmith Sep 1, 2026
d9a4f45
src/base_groups.hpp: removing nodiscard on void functions
andrewdavidsmith Sep 1, 2026
4a8c6f0
src/sam_file.cpp: adding includes and initializing cursor and last in…
andrewdavidsmith Sep 1, 2026
cd9127e
src/kmer_counter.hcpp: removing the apply_groups function which isn't…
andrewdavidsmith Sep 1, 2026
a39a7c8
src/original_duplicates.cpp: changed loop to alg
andrewdavidsmith Sep 1, 2026
5396c2e
src/falco_utils.hcpp: fixing nodiscards and an include
andrewdavidsmith Sep 1, 2026
d39f1df
src/falco_analyzer.cpp: adding an include for iwyu that seems wrong a…
andrewdavidsmith Sep 1, 2026
8cc60aa
src/bgzf_reader.cpp: static analysis
andrewdavidsmith Sep 1, 2026
646cd9c
src/falco_grade.hcpp: making a member function get_tile static and re…
andrewdavidsmith Sep 1, 2026
e79f931
src/adapter_set.cpp: iterating using itr = next(itr) for now when cle…
andrewdavidsmith Sep 1, 2026
0f5e495
src/html.cpp: headers and nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
2163c8f
src/fastq_gz_file.cpp: header and nolint on pointer arithmetic
andrewdavidsmith Sep 1, 2026
e3fb8ce
src/falco_config.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
77235a3
src/fastq_bgzf_file.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
9320554
src/falco_word.hpp: nolint on array bound
andrewdavidsmith Sep 1, 2026
7524af5
src/contaminants.cpp: iterating using itr = next(itr) for now when cl…
andrewdavidsmith Sep 1, 2026
ea20a1b
src/contaminants.hpp: adding a header
andrewdavidsmith Sep 1, 2026
2d181f8
src/fastq_file.cpp: adding headers
andrewdavidsmith Sep 1, 2026
badab36
src/adapter_matcher.cpp: nolint and fixing the number of positions ou…
andrewdavidsmith Sep 1, 2026
37d4a61
src/falco_file_format.hcpp: includes
andrewdavidsmith Sep 1, 2026
4ce3f0e
src/duplication_results.hpp: explicit on single param constructor
andrewdavidsmith Sep 1, 2026
dcd8535
src/duplication_results.cpp: nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
cadffe0
src/results_collector.hpp: casting in an assert to avoid side effect …
andrewdavidsmith Sep 1, 2026
c26cde0
src/results_summary.cpp: fixing var name to avoid shadowing
andrewdavidsmith Sep 1, 2026
089c478
src/report.cpp: removing include and fixing to_string for encoding to…
andrewdavidsmith Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cppcheck_suppress
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,9 +35,12 @@ missingInclude
*:*CLI11.hpp
*:*json.hpp
*:*boost_unordered.hpp
*:fmt/*.h
# Problem caused by external files
toomanyconfigs
# More problems caused by external files -- with too many ifdefs
normalCheckLevelMaxBranches
# This seems not to work with the designs used here
duplInheritedMember
# Seems like iterator variables for std::views disagree with this
constStatement
15 changes: 9 additions & 6 deletions src/adapter_matcher.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -131,6 +131,7 @@ y: {},
type: "line",
name: "{}",
}})";
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
assert(std::size(groups) == std::size(adap_counts));
// calcualte the x axis first
const auto x = groups | std::views::transform([&](const auto &g) {
Expand All@@ -146,9 +147,9 @@ name: "{}",
std::ranges::transform(cumulative[curr], cumulative[prev],
std::begin(cumulative[curr]), std::plus{});
#endif
const auto n_pos = max_read_len + 1 >= adapter_size
? max_read_len - adapter_size + 1
: max_read_len;
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
const auto n_pos =
max_read_len + 1 > adapter_size ? (max_read_len + 1) - adapter_size : 0U;
const auto last_group_to_keep = std::ranges::find_if(
groups, [&](const auto &g) { return n_pos <= g.first; });
cumulative.resize(std::distance(std::cbegin(groups), last_group_to_keep));
Expand All@@ -164,13 +165,15 @@ name: "{}",
return pct_of_reads(cumul[adap_id]);
};
const auto y = cumulative | std::views::transform(make_y);
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
html_by_adapter.emplace_back(fmt::format(adapter_fmt, x, y, adap_name));
}
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter)));
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter));
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}

auto
Expand Down
3 changes: 2 additions & 1 deletion src/adapter_set.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,8 @@ load_adapters(const std::string &filename) {
// ADS: need to make sure this can't fail
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
6 changes: 4 additions & 2 deletions src/bam_file.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,9 @@
#include <stdexcept>
#include <string>
#include <system_error>
#include <tuple>
#include <utility>
#include <vector>

[[nodiscard]] auto
estimate_n_reads_bam(const std::string &filename)
Expand DownExpand Up@@ -63,8 +65,8 @@ estimate_n_reads_bam(const std::string &filename)
}

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t {
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t {
static constexpr auto complem = [](const auto x) {
return "TNGNNNCNNNNNNNNNNNNA"[x - 'A'];
};
Expand Down
9 changes: 6 additions & 3 deletions src/bam_file.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,7 +62,10 @@ class bam_file {
~bam_file() = default;
// clang-format on

[[nodiscard]] operator bool() const { return !had_last_chunks; }
[[nodiscard]]
operator bool() const {
return !had_last_chunks;
}

friend auto
reset(bam_file &reads_file) -> void;
Expand DownExpand Up@@ -121,8 +124,8 @@ estimate_n_reads_bam(const std::string &filename)
-> std::tuple<std::uint64_t, std::uint64_t, std::int64_t>;

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t;
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t;

inline auto
make_tasks(bam_file &reads_file, //
Expand Down
8 changes: 4 additions & 4 deletions src/base_groups.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,16 +23,16 @@ make_base_groups(const std::uint64_t n_bases, const std::uint64_t n_initial,
const std::uint64_t n_groups_target) -> base_group_vec;

[[nodiscard]] auto
get_default_base_groups(const std::uint64_t n_bases,
const bool make_groups) -> base_group_vec;
get_default_base_groups(const std::uint64_t n_bases, const bool make_groups)
-> base_group_vec;

[[nodiscard]] auto
make_group_tag(const base_group_t g) -> std::string;

[[nodiscard]] auto
make_group_tag_quoted(const base_group_t g) -> std::string;

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand All@@ -50,7 +50,7 @@ apply_base_groups(const base_group_vec &groups, auto &rows) {
rows.resize(current_row);
}

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows, const auto &adder) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand Down
5 changes: 4 additions & 1 deletion src/bgzf_reader.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@
#include <cassert>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <memory>
Expand All@@ -28,6 +29,7 @@ get_unaligned_le32(const auto p) -> std::int32_t {
get_isize(const auto data, const auto data_size) {
static constexpr decltype(data_size) isize_size = 4;
assert(data_size > isize_size);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
const auto data_isize = data + data_size - isize_size;
return data_size < isize_size ? 0 : get_unaligned_le32(data_isize);
}
Expand All@@ -50,7 +52,8 @@ bgzf_reader::bgzf_reader(const std::string &filename,
next_in{inbuf.get()}, //
end_in{inbuf.get()}, //
next_out{outbuf.get()}, //
end_out{outbuf.get() + buf_size} //
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
end_out{outbuf.get() + buf_size} //
{}

[[nodiscard]] auto
Expand Down
4 changes: 3 additions & 1 deletion src/contaminants.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include <stdexcept>
#include <string>
#include <string_view>
#include <tuple> // for std::get
#include <utility>
#include <vector>

Expand DownExpand Up@@ -197,7 +198,8 @@ load_contaminants(const std::string &filename) -> void {
continue;
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
1 change: 1 addition & 0 deletions src/contaminants.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@
#define SRC_CONTAMINANTS_HPP_

#include <cstdint>
#include <ranges> // for std::pair
#include <string>
#include <utility> // IWYU pragma: keep
#include <vector>
Expand Down
25 changes: 14 additions & 11 deletions src/duplication_results.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include "run_mode.hpp"

#define FMT_HEADER_ONLY
#include "fmt/base.h"
#include "fmt/format.h"
#include "fmt/ranges.h"

Expand DownExpand Up@@ -124,8 +125,8 @@ duplication_results::get_overrepresented(const std::uint64_t n_reads) const
}

auto
duplication_results::initialize(const run_mode &mode,
const file_info &info) -> void {
duplication_results::initialize(const run_mode &mode, const file_info &info)
-> void {
read_skip =
info.n_reads_est < max_n_reads_total
? 0
Expand DownExpand Up@@ -282,8 +283,8 @@ get_grade_duplication(const dup_summary_t &summary) -> std::string {
}

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto start_tag = ">>Sequence Duplication Levels\t{}\n"
"#Total Deduplicated Percentage\t{:.6f}\n";
Expand All@@ -305,9 +306,10 @@ duplication_report(const dup_summary_t &summary,
std::max(static_cast<std::uint64_t>(1), reduce(summary.hist_mass)));
auto r = std::format(start_tag, grades.grade(label), pct(frac_dedup));
r += header;
for (const auto [label, mass] :
for (const auto [bin_label, mass] :
std::views::zip(bin_labels, binned_mass_pct) | std::views::drop(1))
r += std::format("{}\t{:.3g}\n", label, mass); // Percentage format is .3g
r +=
std::format("{}\t{:.3g}\n", bin_label, mass); // Percentage format is .3g
return r + end_module_tag;
}

Expand DownExpand Up@@ -345,8 +347,8 @@ overrepresented_html(const std::vector<overrep_t> &overrep,
}

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto plot_format = R"(<div id="duplication_plot"></div>
<script>Plotly.newPlot("duplication_plot",
Expand DownExpand Up@@ -389,11 +391,12 @@ yaxis: {{title: "% of sequences"}},
};
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
fmt::format(plot_format, //
x, to_pct(summary.hist_mass) | std::views::drop(1), // y_tot,
x, to_pct(summary.hist_dedup) | std::views::drop(1), // y_dedup
x, x_text | std::views::drop(1) // tickvals
));
);
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}
10 changes: 5 additions & 5 deletions src/duplication_results.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ struct dups_init_t {
std::int64_t count_at_limit{};
dups_map_t dups_zero;
dups_init_t() = default;
dups_init_t(const dups_map_t &dups) {
explicit dups_init_t(const dups_map_t &dups) {
const auto vals = dups | std::views::values;
count_at_limit = static_cast<std::int64_t>(
std::reduce(std::cbegin(vals), std::cend(vals)));
Expand DownExpand Up@@ -113,12 +113,12 @@ struct duplication_results {
get_grade_duplication(const dup_summary_t &summary) -> std::string;

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
get_grade_overrepresented(const std::uint64_t n_reads,
Expand Down
3 changes: 2 additions & 1 deletion src/falco_analyzer.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
#include <mutex>
#include <ranges>
#include <thread>
#include <tuple> // for std::get (iwyu fp)
#include <utility>
#include <variant>
#include <vector>
Expand All@@ -34,7 +35,6 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
const std::int32_t n_files = static_cast<std::int32_t>(std::size(infos));
if (dups_init.empty())
dups_init.resize(n_files);
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::atomic_uint32_t n_active_files{static_cast<std::uint32_t>(n_files)};
auto results =
std::vector(n_threads, std::vector<results_collector>(n_files));
Expand All@@ -45,6 +45,7 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
tq.push(file_id, std::monostate{});

{ // scope to join jthreads
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::vector<std::jthread> workers;
for (const auto th_id : std::views::iota(0u, n_threads))
workers.emplace_back([&, n_threads, th_id] {
Expand Down
18 changes: 10 additions & 8 deletions src/falco_config.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,8 +41,8 @@ split(const std::string &s) {
}

auto
load_config_and_set_graders(const std::string &filename,
run_mode &mode) -> void {
load_config_and_set_graders(const std::string &filename, run_mode &mode)
-> void {
// ADS: (todo) handle carriage returns and other control chars
std::ifstream in(filename);
if (!in)
Expand All@@ -61,9 +61,10 @@ load_config_and_set_graders(const std::string &filename,
}

// modes
for (const auto &label : run_mode::get_labels())
std::ranges::for_each(run_mode::get_labels(), [&](const auto &label) {
if (json_in.contains(label) && !json_in[label].contains("ignore"))
throw std::runtime_error("invalid config: " + to_string(json_in[label]));
});

std::unordered_map<std::string, bool> modes_in;
try {
Expand All@@ -83,11 +84,12 @@ load_config_and_set_graders(const std::string &filename,
mode.assign(modes_in);

// grades
for (const auto &label : grade_labels)
if (json_in.contains(label) &&
!(json_in[label].contains("error") && json_in[label].contains("warn")))
throw std::runtime_error("missing config value for: " +
std::string(label));
std::ranges::for_each(grade_labels, [&](const auto &l) {
if (json_in.contains(l) &&
!(json_in[l].contains("error") && json_in[l].contains("warn")))
throw std::runtime_error("missing config value for: " + std::string(l));
});

std::unordered_map<std::string, grader> graders;
try {
for (const auto &label : grade_labels) {
Expand Down
4 changes: 4 additions & 0 deletions src/falco_file_format.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,7 +7,11 @@
#include <array>
#include <cstdlib>
#include <filesystem>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <string>
#include <tuple>

[[nodiscard]] auto
get_file_format(const std::string &filename)
Expand Down
2 changes: 0 additions & 2 deletions src/falco_file_format.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,8 +7,6 @@

#include <cstdint>
#include <format>
#include <iterator>
#include <memory>
#include <string>
#include <thread>
#include <tuple>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a48b5d3
src/quality_score.hcpp: renaming the to_string function because the a…
andrewdavidsmith Sep 1, 2026
3697635
.cppcheck_suppress: ignoring fmt and ignoring constStatement which se…
andrewdavidsmith Sep 1, 2026
6633d46
src/samrec.cpp: adding missing include
andrewdavidsmith Sep 1, 2026
c256b39
src/tile_processor.cpp: renaming variables to avoid shadowing
andrewdavidsmith Sep 1, 2026
7e962a2
src/bam_file.hcpp: headers and formatting for new clang-tidy
andrewdavidsmith Sep 1, 2026
d9a4f45
src/base_groups.hpp: removing nodiscard on void functions
andrewdavidsmith Sep 1, 2026
4a8c6f0
src/sam_file.cpp: adding includes and initializing cursor and last in…
andrewdavidsmith Sep 1, 2026
cd9127e
src/kmer_counter.hcpp: removing the apply_groups function which isn't…
andrewdavidsmith Sep 1, 2026
a39a7c8
src/original_duplicates.cpp: changed loop to alg
andrewdavidsmith Sep 1, 2026
5396c2e
src/falco_utils.hcpp: fixing nodiscards and an include
andrewdavidsmith Sep 1, 2026
d39f1df
src/falco_analyzer.cpp: adding an include for iwyu that seems wrong a…
andrewdavidsmith Sep 1, 2026
8cc60aa
src/bgzf_reader.cpp: static analysis
andrewdavidsmith Sep 1, 2026
646cd9c
src/falco_grade.hcpp: making a member function get_tile static and re…
andrewdavidsmith Sep 1, 2026
e79f931
src/adapter_set.cpp: iterating using itr = next(itr) for now when cle…
andrewdavidsmith Sep 1, 2026
0f5e495
src/html.cpp: headers and nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
2163c8f
src/fastq_gz_file.cpp: header and nolint on pointer arithmetic
andrewdavidsmith Sep 1, 2026
e3fb8ce
src/falco_config.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
77235a3
src/fastq_bgzf_file.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
9320554
src/falco_word.hpp: nolint on array bound
andrewdavidsmith Sep 1, 2026
7524af5
src/contaminants.cpp: iterating using itr = next(itr) for now when cl…
andrewdavidsmith Sep 1, 2026
ea20a1b
src/contaminants.hpp: adding a header
andrewdavidsmith Sep 1, 2026
2d181f8
src/fastq_file.cpp: adding headers
andrewdavidsmith Sep 1, 2026
badab36
src/adapter_matcher.cpp: nolint and fixing the number of positions ou…
andrewdavidsmith Sep 1, 2026
37d4a61
src/falco_file_format.hcpp: includes
andrewdavidsmith Sep 1, 2026
4ce3f0e
src/duplication_results.hpp: explicit on single param constructor
andrewdavidsmith Sep 1, 2026
dcd8535
src/duplication_results.cpp: nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
cadffe0
src/results_collector.hpp: casting in an assert to avoid side effect …
andrewdavidsmith Sep 1, 2026
c26cde0
src/results_summary.cpp: fixing var name to avoid shadowing
andrewdavidsmith Sep 1, 2026
089c478
src/report.cpp: removing include and fixing to_string for encoding to…
andrewdavidsmith Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cppcheck_suppress
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,9 +35,12 @@ missingInclude
*:*CLI11.hpp
*:*json.hpp
*:*boost_unordered.hpp
*:fmt/*.h
# Problem caused by external files
toomanyconfigs
# More problems caused by external files -- with too many ifdefs
normalCheckLevelMaxBranches
# This seems not to work with the designs used here
duplInheritedMember
# Seems like iterator variables for std::views disagree with this
constStatement
15 changes: 9 additions & 6 deletions src/adapter_matcher.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -131,6 +131,7 @@ y: {},
type: "line",
name: "{}",
}})";
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
assert(std::size(groups) == std::size(adap_counts));
// calcualte the x axis first
const auto x = groups | std::views::transform([&](const auto &g) {
Expand All@@ -146,9 +147,9 @@ name: "{}",
std::ranges::transform(cumulative[curr], cumulative[prev],
std::begin(cumulative[curr]), std::plus{});
#endif
const auto n_pos = max_read_len + 1 >= adapter_size
? max_read_len - adapter_size + 1
: max_read_len;
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
const auto n_pos =
max_read_len + 1 > adapter_size ? (max_read_len + 1) - adapter_size : 0U;
const auto last_group_to_keep = std::ranges::find_if(
groups, [&](const auto &g) { return n_pos <= g.first; });
cumulative.resize(std::distance(std::cbegin(groups), last_group_to_keep));
Expand All@@ -164,13 +165,15 @@ name: "{}",
return pct_of_reads(cumul[adap_id]);
};
const auto y = cumulative | std::views::transform(make_y);
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
html_by_adapter.emplace_back(fmt::format(adapter_fmt, x, y, adap_name));
}
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter)));
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter));
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}

auto
Expand Down
3 changes: 2 additions & 1 deletion src/adapter_set.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,8 @@ load_adapters(const std::string &filename) {
// ADS: need to make sure this can't fail
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
6 changes: 4 additions & 2 deletions src/bam_file.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,9 @@
#include <stdexcept>
#include <string>
#include <system_error>
#include <tuple>
#include <utility>
#include <vector>

[[nodiscard]] auto
estimate_n_reads_bam(const std::string &filename)
Expand DownExpand Up@@ -63,8 +65,8 @@ estimate_n_reads_bam(const std::string &filename)
}

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t {
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t {
static constexpr auto complem = [](const auto x) {
return "TNGNNNCNNNNNNNNNNNNA"[x - 'A'];
};
Expand Down
9 changes: 6 additions & 3 deletions src/bam_file.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,7 +62,10 @@ class bam_file {
~bam_file() = default;
// clang-format on

[[nodiscard]] operator bool() const { return !had_last_chunks; }
[[nodiscard]]
operator bool() const {
return !had_last_chunks;
}

friend auto
reset(bam_file &reads_file) -> void;
Expand DownExpand Up@@ -121,8 +124,8 @@ estimate_n_reads_bam(const std::string &filename)
-> std::tuple<std::uint64_t, std::uint64_t, std::int64_t>;

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t;
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t;

inline auto
make_tasks(bam_file &reads_file, //
Expand Down
8 changes: 4 additions & 4 deletions src/base_groups.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,16 +23,16 @@ make_base_groups(const std::uint64_t n_bases, const std::uint64_t n_initial,
const std::uint64_t n_groups_target) -> base_group_vec;

[[nodiscard]] auto
get_default_base_groups(const std::uint64_t n_bases,
const bool make_groups) -> base_group_vec;
get_default_base_groups(const std::uint64_t n_bases, const bool make_groups)
-> base_group_vec;

[[nodiscard]] auto
make_group_tag(const base_group_t g) -> std::string;

[[nodiscard]] auto
make_group_tag_quoted(const base_group_t g) -> std::string;

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand All@@ -50,7 +50,7 @@ apply_base_groups(const base_group_vec &groups, auto &rows) {
rows.resize(current_row);
}

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows, const auto &adder) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand Down
5 changes: 4 additions & 1 deletion src/bgzf_reader.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@
#include <cassert>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <memory>
Expand All@@ -28,6 +29,7 @@ get_unaligned_le32(const auto p) -> std::int32_t {
get_isize(const auto data, const auto data_size) {
static constexpr decltype(data_size) isize_size = 4;
assert(data_size > isize_size);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
const auto data_isize = data + data_size - isize_size;
return data_size < isize_size ? 0 : get_unaligned_le32(data_isize);
}
Expand All@@ -50,7 +52,8 @@ bgzf_reader::bgzf_reader(const std::string &filename,
next_in{inbuf.get()}, //
end_in{inbuf.get()}, //
next_out{outbuf.get()}, //
end_out{outbuf.get() + buf_size} //
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
end_out{outbuf.get() + buf_size} //
{}

[[nodiscard]] auto
Expand Down
4 changes: 3 additions & 1 deletion src/contaminants.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include <stdexcept>
#include <string>
#include <string_view>
#include <tuple> // for std::get
#include <utility>
#include <vector>

Expand DownExpand Up@@ -197,7 +198,8 @@ load_contaminants(const std::string &filename) -> void {
continue;
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
1 change: 1 addition & 0 deletions src/contaminants.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@
#define SRC_CONTAMINANTS_HPP_

#include <cstdint>
#include <ranges> // for std::pair
#include <string>
#include <utility> // IWYU pragma: keep
#include <vector>
Expand Down
25 changes: 14 additions & 11 deletions src/duplication_results.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include "run_mode.hpp"

#define FMT_HEADER_ONLY
#include "fmt/base.h"
#include "fmt/format.h"
#include "fmt/ranges.h"

Expand DownExpand Up@@ -124,8 +125,8 @@ duplication_results::get_overrepresented(const std::uint64_t n_reads) const
}

auto
duplication_results::initialize(const run_mode &mode,
const file_info &info) -> void {
duplication_results::initialize(const run_mode &mode, const file_info &info)
-> void {
read_skip =
info.n_reads_est < max_n_reads_total
? 0
Expand DownExpand Up@@ -282,8 +283,8 @@ get_grade_duplication(const dup_summary_t &summary) -> std::string {
}

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto start_tag = ">>Sequence Duplication Levels\t{}\n"
"#Total Deduplicated Percentage\t{:.6f}\n";
Expand All@@ -305,9 +306,10 @@ duplication_report(const dup_summary_t &summary,
std::max(static_cast<std::uint64_t>(1), reduce(summary.hist_mass)));
auto r = std::format(start_tag, grades.grade(label), pct(frac_dedup));
r += header;
for (const auto [label, mass] :
for (const auto [bin_label, mass] :
std::views::zip(bin_labels, binned_mass_pct) | std::views::drop(1))
r += std::format("{}\t{:.3g}\n", label, mass); // Percentage format is .3g
r +=
std::format("{}\t{:.3g}\n", bin_label, mass); // Percentage format is .3g
return r + end_module_tag;
}

Expand DownExpand Up@@ -345,8 +347,8 @@ overrepresented_html(const std::vector<overrep_t> &overrep,
}

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto plot_format = R"(<div id="duplication_plot"></div>
<script>Plotly.newPlot("duplication_plot",
Expand DownExpand Up@@ -389,11 +391,12 @@ yaxis: {{title: "% of sequences"}},
};
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
fmt::format(plot_format, //
x, to_pct(summary.hist_mass) | std::views::drop(1), // y_tot,
x, to_pct(summary.hist_dedup) | std::views::drop(1), // y_dedup
x, x_text | std::views::drop(1) // tickvals
));
);
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}
10 changes: 5 additions & 5 deletions src/duplication_results.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ struct dups_init_t {
std::int64_t count_at_limit{};
dups_map_t dups_zero;
dups_init_t() = default;
dups_init_t(const dups_map_t &dups) {
explicit dups_init_t(const dups_map_t &dups) {
const auto vals = dups | std::views::values;
count_at_limit = static_cast<std::int64_t>(
std::reduce(std::cbegin(vals), std::cend(vals)));
Expand DownExpand Up@@ -113,12 +113,12 @@ struct duplication_results {
get_grade_duplication(const dup_summary_t &summary) -> std::string;

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
get_grade_overrepresented(const std::uint64_t n_reads,
Expand Down
3 changes: 2 additions & 1 deletion src/falco_analyzer.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
#include <mutex>
#include <ranges>
#include <thread>
#include <tuple> // for std::get (iwyu fp)
#include <utility>
#include <variant>
#include <vector>
Expand All@@ -34,7 +35,6 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
const std::int32_t n_files = static_cast<std::int32_t>(std::size(infos));
if (dups_init.empty())
dups_init.resize(n_files);
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::atomic_uint32_t n_active_files{static_cast<std::uint32_t>(n_files)};
auto results =
std::vector(n_threads, std::vector<results_collector>(n_files));
Expand All@@ -45,6 +45,7 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
tq.push(file_id, std::monostate{});

{ // scope to join jthreads
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::vector<std::jthread> workers;
for (const auto th_id : std::views::iota(0u, n_threads))
workers.emplace_back([&, n_threads, th_id] {
Expand Down
18 changes: 10 additions & 8 deletions src/falco_config.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,8 +41,8 @@ split(const std::string &s) {
}

auto
load_config_and_set_graders(const std::string &filename,
run_mode &mode) -> void {
load_config_and_set_graders(const std::string &filename, run_mode &mode)
-> void {
// ADS: (todo) handle carriage returns and other control chars
std::ifstream in(filename);
if (!in)
Expand All@@ -61,9 +61,10 @@ load_config_and_set_graders(const std::string &filename,
}

// modes
for (const auto &label : run_mode::get_labels())
std::ranges::for_each(run_mode::get_labels(), [&](const auto &label) {
if (json_in.contains(label) && !json_in[label].contains("ignore"))
throw std::runtime_error("invalid config: " + to_string(json_in[label]));
});

std::unordered_map<std::string, bool> modes_in;
try {
Expand All@@ -83,11 +84,12 @@ load_config_and_set_graders(const std::string &filename,
mode.assign(modes_in);

// grades
for (const auto &label : grade_labels)
if (json_in.contains(label) &&
!(json_in[label].contains("error") && json_in[label].contains("warn")))
throw std::runtime_error("missing config value for: " +
std::string(label));
std::ranges::for_each(grade_labels, [&](const auto &l) {
if (json_in.contains(l) &&
!(json_in[l].contains("error") && json_in[l].contains("warn")))
throw std::runtime_error("missing config value for: " + std::string(l));
});

std::unordered_map<std::string, grader> graders;
try {
for (const auto &label : grade_labels) {
Expand Down
4 changes: 4 additions & 0 deletions src/falco_file_format.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,7 +7,11 @@
#include <array>
#include <cstdlib>
#include <filesystem>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <string>
#include <tuple>

[[nodiscard]] auto
get_file_format(const std::string &filename)
Expand Down
2 changes: 0 additions & 2 deletions src/falco_file_format.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,8 +7,6 @@

#include <cstdint>
#include <format>
#include <iterator>
#include <memory>
#include <string>
#include <thread>
#include <tuple>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a48b5d3
src/quality_score.hcpp: renaming the to_string function because the a…
andrewdavidsmith Sep 1, 2026
3697635
.cppcheck_suppress: ignoring fmt and ignoring constStatement which se…
andrewdavidsmith Sep 1, 2026
6633d46
src/samrec.cpp: adding missing include
andrewdavidsmith Sep 1, 2026
c256b39
src/tile_processor.cpp: renaming variables to avoid shadowing
andrewdavidsmith Sep 1, 2026
7e962a2
src/bam_file.hcpp: headers and formatting for new clang-tidy
andrewdavidsmith Sep 1, 2026
d9a4f45
src/base_groups.hpp: removing nodiscard on void functions
andrewdavidsmith Sep 1, 2026
4a8c6f0
src/sam_file.cpp: adding includes and initializing cursor and last in…
andrewdavidsmith Sep 1, 2026
cd9127e
src/kmer_counter.hcpp: removing the apply_groups function which isn't…
andrewdavidsmith Sep 1, 2026
a39a7c8
src/original_duplicates.cpp: changed loop to alg
andrewdavidsmith Sep 1, 2026
5396c2e
src/falco_utils.hcpp: fixing nodiscards and an include
andrewdavidsmith Sep 1, 2026
d39f1df
src/falco_analyzer.cpp: adding an include for iwyu that seems wrong a…
andrewdavidsmith Sep 1, 2026
8cc60aa
src/bgzf_reader.cpp: static analysis
andrewdavidsmith Sep 1, 2026
646cd9c
src/falco_grade.hcpp: making a member function get_tile static and re…
andrewdavidsmith Sep 1, 2026
e79f931
src/adapter_set.cpp: iterating using itr = next(itr) for now when cle…
andrewdavidsmith Sep 1, 2026
0f5e495
src/html.cpp: headers and nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
2163c8f
src/fastq_gz_file.cpp: header and nolint on pointer arithmetic
andrewdavidsmith Sep 1, 2026
e3fb8ce
src/falco_config.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
77235a3
src/fastq_bgzf_file.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
9320554
src/falco_word.hpp: nolint on array bound
andrewdavidsmith Sep 1, 2026
7524af5
src/contaminants.cpp: iterating using itr = next(itr) for now when cl…
andrewdavidsmith Sep 1, 2026
ea20a1b
src/contaminants.hpp: adding a header
andrewdavidsmith Sep 1, 2026
2d181f8
src/fastq_file.cpp: adding headers
andrewdavidsmith Sep 1, 2026
badab36
src/adapter_matcher.cpp: nolint and fixing the number of positions ou…
andrewdavidsmith Sep 1, 2026
37d4a61
src/falco_file_format.hcpp: includes
andrewdavidsmith Sep 1, 2026
4ce3f0e
src/duplication_results.hpp: explicit on single param constructor
andrewdavidsmith Sep 1, 2026
dcd8535
src/duplication_results.cpp: nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
cadffe0
src/results_collector.hpp: casting in an assert to avoid side effect …
andrewdavidsmith Sep 1, 2026
c26cde0
src/results_summary.cpp: fixing var name to avoid shadowing
andrewdavidsmith Sep 1, 2026
089c478
src/report.cpp: removing include and fixing to_string for encoding to…
andrewdavidsmith Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cppcheck_suppress
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,9 +35,12 @@ missingInclude
*:*CLI11.hpp
*:*json.hpp
*:*boost_unordered.hpp
*:fmt/*.h
# Problem caused by external files
toomanyconfigs
# More problems caused by external files -- with too many ifdefs
normalCheckLevelMaxBranches
# This seems not to work with the designs used here
duplInheritedMember
# Seems like iterator variables for std::views disagree with this
constStatement
15 changes: 9 additions & 6 deletions src/adapter_matcher.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -131,6 +131,7 @@ y: {},
type: "line",
name: "{}",
}})";
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
assert(std::size(groups) == std::size(adap_counts));
// calcualte the x axis first
const auto x = groups | std::views::transform([&](const auto &g) {
Expand All@@ -146,9 +147,9 @@ name: "{}",
std::ranges::transform(cumulative[curr], cumulative[prev],
std::begin(cumulative[curr]), std::plus{});
#endif
const auto n_pos = max_read_len + 1 >= adapter_size
? max_read_len - adapter_size + 1
: max_read_len;
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
const auto n_pos =
max_read_len + 1 > adapter_size ? (max_read_len + 1) - adapter_size : 0U;
const auto last_group_to_keep = std::ranges::find_if(
groups, [&](const auto &g) { return n_pos <= g.first; });
cumulative.resize(std::distance(std::cbegin(groups), last_group_to_keep));
Expand All@@ -164,13 +165,15 @@ name: "{}",
return pct_of_reads(cumul[adap_id]);
};
const auto y = cumulative | std::views::transform(make_y);
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
html_by_adapter.emplace_back(fmt::format(adapter_fmt, x, y, adap_name));
}
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter)));
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter));
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}

auto
Expand Down
3 changes: 2 additions & 1 deletion src/adapter_set.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,8 @@ load_adapters(const std::string &filename) {
// ADS: need to make sure this can't fail
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
6 changes: 4 additions & 2 deletions src/bam_file.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,9 @@
#include <stdexcept>
#include <string>
#include <system_error>
#include <tuple>
#include <utility>
#include <vector>

[[nodiscard]] auto
estimate_n_reads_bam(const std::string &filename)
Expand DownExpand Up@@ -63,8 +65,8 @@ estimate_n_reads_bam(const std::string &filename)
}

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t {
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t {
static constexpr auto complem = [](const auto x) {
return "TNGNNNCNNNNNNNNNNNNA"[x - 'A'];
};
Expand Down
9 changes: 6 additions & 3 deletions src/bam_file.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,7 +62,10 @@ class bam_file {
~bam_file() = default;
// clang-format on

[[nodiscard]] operator bool() const { return !had_last_chunks; }
[[nodiscard]]
operator bool() const {
return !had_last_chunks;
}

friend auto
reset(bam_file &reads_file) -> void;
Expand DownExpand Up@@ -121,8 +124,8 @@ estimate_n_reads_bam(const std::string &filename)
-> std::tuple<std::uint64_t, std::uint64_t, std::int64_t>;

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t;
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t;

inline auto
make_tasks(bam_file &reads_file, //
Expand Down
8 changes: 4 additions & 4 deletions src/base_groups.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,16 +23,16 @@ make_base_groups(const std::uint64_t n_bases, const std::uint64_t n_initial,
const std::uint64_t n_groups_target) -> base_group_vec;

[[nodiscard]] auto
get_default_base_groups(const std::uint64_t n_bases,
const bool make_groups) -> base_group_vec;
get_default_base_groups(const std::uint64_t n_bases, const bool make_groups)
-> base_group_vec;

[[nodiscard]] auto
make_group_tag(const base_group_t g) -> std::string;

[[nodiscard]] auto
make_group_tag_quoted(const base_group_t g) -> std::string;

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand All@@ -50,7 +50,7 @@ apply_base_groups(const base_group_vec &groups, auto &rows) {
rows.resize(current_row);
}

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows, const auto &adder) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand Down
5 changes: 4 additions & 1 deletion src/bgzf_reader.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@
#include <cassert>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <memory>
Expand All@@ -28,6 +29,7 @@ get_unaligned_le32(const auto p) -> std::int32_t {
get_isize(const auto data, const auto data_size) {
static constexpr decltype(data_size) isize_size = 4;
assert(data_size > isize_size);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
const auto data_isize = data + data_size - isize_size;
return data_size < isize_size ? 0 : get_unaligned_le32(data_isize);
}
Expand All@@ -50,7 +52,8 @@ bgzf_reader::bgzf_reader(const std::string &filename,
next_in{inbuf.get()}, //
end_in{inbuf.get()}, //
next_out{outbuf.get()}, //
end_out{outbuf.get() + buf_size} //
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
end_out{outbuf.get() + buf_size} //
{}

[[nodiscard]] auto
Expand Down
4 changes: 3 additions & 1 deletion src/contaminants.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include <stdexcept>
#include <string>
#include <string_view>
#include <tuple> // for std::get
#include <utility>
#include <vector>

Expand DownExpand Up@@ -197,7 +198,8 @@ load_contaminants(const std::string &filename) -> void {
continue;
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
1 change: 1 addition & 0 deletions src/contaminants.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@
#define SRC_CONTAMINANTS_HPP_

#include <cstdint>
#include <ranges> // for std::pair
#include <string>
#include <utility> // IWYU pragma: keep
#include <vector>
Expand Down
25 changes: 14 additions & 11 deletions src/duplication_results.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include "run_mode.hpp"

#define FMT_HEADER_ONLY
#include "fmt/base.h"
#include "fmt/format.h"
#include "fmt/ranges.h"

Expand DownExpand Up@@ -124,8 +125,8 @@ duplication_results::get_overrepresented(const std::uint64_t n_reads) const
}

auto
duplication_results::initialize(const run_mode &mode,
const file_info &info) -> void {
duplication_results::initialize(const run_mode &mode, const file_info &info)
-> void {
read_skip =
info.n_reads_est < max_n_reads_total
? 0
Expand DownExpand Up@@ -282,8 +283,8 @@ get_grade_duplication(const dup_summary_t &summary) -> std::string {
}

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto start_tag = ">>Sequence Duplication Levels\t{}\n"
"#Total Deduplicated Percentage\t{:.6f}\n";
Expand All@@ -305,9 +306,10 @@ duplication_report(const dup_summary_t &summary,
std::max(static_cast<std::uint64_t>(1), reduce(summary.hist_mass)));
auto r = std::format(start_tag, grades.grade(label), pct(frac_dedup));
r += header;
for (const auto [label, mass] :
for (const auto [bin_label, mass] :
std::views::zip(bin_labels, binned_mass_pct) | std::views::drop(1))
r += std::format("{}\t{:.3g}\n", label, mass); // Percentage format is .3g
r +=
std::format("{}\t{:.3g}\n", bin_label, mass); // Percentage format is .3g
return r + end_module_tag;
}

Expand DownExpand Up@@ -345,8 +347,8 @@ overrepresented_html(const std::vector<overrep_t> &overrep,
}

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto plot_format = R"(<div id="duplication_plot"></div>
<script>Plotly.newPlot("duplication_plot",
Expand DownExpand Up@@ -389,11 +391,12 @@ yaxis: {{title: "% of sequences"}},
};
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
fmt::format(plot_format, //
x, to_pct(summary.hist_mass) | std::views::drop(1), // y_tot,
x, to_pct(summary.hist_dedup) | std::views::drop(1), // y_dedup
x, x_text | std::views::drop(1) // tickvals
));
);
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}
10 changes: 5 additions & 5 deletions src/duplication_results.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ struct dups_init_t {
std::int64_t count_at_limit{};
dups_map_t dups_zero;
dups_init_t() = default;
dups_init_t(const dups_map_t &dups) {
explicit dups_init_t(const dups_map_t &dups) {
const auto vals = dups | std::views::values;
count_at_limit = static_cast<std::int64_t>(
std::reduce(std::cbegin(vals), std::cend(vals)));
Expand DownExpand Up@@ -113,12 +113,12 @@ struct duplication_results {
get_grade_duplication(const dup_summary_t &summary) -> std::string;

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
get_grade_overrepresented(const std::uint64_t n_reads,
Expand Down
3 changes: 2 additions & 1 deletion src/falco_analyzer.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
#include <mutex>
#include <ranges>
#include <thread>
#include <tuple> // for std::get (iwyu fp)
#include <utility>
#include <variant>
#include <vector>
Expand All@@ -34,7 +35,6 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
const std::int32_t n_files = static_cast<std::int32_t>(std::size(infos));
if (dups_init.empty())
dups_init.resize(n_files);
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::atomic_uint32_t n_active_files{static_cast<std::uint32_t>(n_files)};
auto results =
std::vector(n_threads, std::vector<results_collector>(n_files));
Expand All@@ -45,6 +45,7 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
tq.push(file_id, std::monostate{});

{ // scope to join jthreads
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::vector<std::jthread> workers;
for (const auto th_id : std::views::iota(0u, n_threads))
workers.emplace_back([&, n_threads, th_id] {
Expand Down
18 changes: 10 additions & 8 deletions src/falco_config.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,8 +41,8 @@ split(const std::string &s) {
}

auto
load_config_and_set_graders(const std::string &filename,
run_mode &mode) -> void {
load_config_and_set_graders(const std::string &filename, run_mode &mode)
-> void {
// ADS: (todo) handle carriage returns and other control chars
std::ifstream in(filename);
if (!in)
Expand All@@ -61,9 +61,10 @@ load_config_and_set_graders(const std::string &filename,
}

// modes
for (const auto &label : run_mode::get_labels())
std::ranges::for_each(run_mode::get_labels(), [&](const auto &label) {
if (json_in.contains(label) && !json_in[label].contains("ignore"))
throw std::runtime_error("invalid config: " + to_string(json_in[label]));
});

std::unordered_map<std::string, bool> modes_in;
try {
Expand All@@ -83,11 +84,12 @@ load_config_and_set_graders(const std::string &filename,
mode.assign(modes_in);

// grades
for (const auto &label : grade_labels)
if (json_in.contains(label) &&
!(json_in[label].contains("error") && json_in[label].contains("warn")))
throw std::runtime_error("missing config value for: " +
std::string(label));
std::ranges::for_each(grade_labels, [&](const auto &l) {
if (json_in.contains(l) &&
!(json_in[l].contains("error") && json_in[l].contains("warn")))
throw std::runtime_error("missing config value for: " + std::string(l));
});

std::unordered_map<std::string, grader> graders;
try {
for (const auto &label : grade_labels) {
Expand Down
4 changes: 4 additions & 0 deletions src/falco_file_format.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,7 +7,11 @@
#include <array>
#include <cstdlib>
#include <filesystem>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <string>
#include <tuple>

[[nodiscard]] auto
get_file_format(const std::string &filename)
Expand Down
2 changes: 0 additions & 2 deletions src/falco_file_format.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,8 +7,6 @@

#include <cstdint>
#include <format>
#include <iterator>
#include <memory>
#include <string>
#include <thread>
#include <tuple>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a48b5d3
src/quality_score.hcpp: renaming the to_string function because the a…
andrewdavidsmith Sep 1, 2026
3697635
.cppcheck_suppress: ignoring fmt and ignoring constStatement which se…
andrewdavidsmith Sep 1, 2026
6633d46
src/samrec.cpp: adding missing include
andrewdavidsmith Sep 1, 2026
c256b39
src/tile_processor.cpp: renaming variables to avoid shadowing
andrewdavidsmith Sep 1, 2026
7e962a2
src/bam_file.hcpp: headers and formatting for new clang-tidy
andrewdavidsmith Sep 1, 2026
d9a4f45
src/base_groups.hpp: removing nodiscard on void functions
andrewdavidsmith Sep 1, 2026
4a8c6f0
src/sam_file.cpp: adding includes and initializing cursor and last in…
andrewdavidsmith Sep 1, 2026
cd9127e
src/kmer_counter.hcpp: removing the apply_groups function which isn't…
andrewdavidsmith Sep 1, 2026
a39a7c8
src/original_duplicates.cpp: changed loop to alg
andrewdavidsmith Sep 1, 2026
5396c2e
src/falco_utils.hcpp: fixing nodiscards and an include
andrewdavidsmith Sep 1, 2026
d39f1df
src/falco_analyzer.cpp: adding an include for iwyu that seems wrong a…
andrewdavidsmith Sep 1, 2026
8cc60aa
src/bgzf_reader.cpp: static analysis
andrewdavidsmith Sep 1, 2026
646cd9c
src/falco_grade.hcpp: making a member function get_tile static and re…
andrewdavidsmith Sep 1, 2026
e79f931
src/adapter_set.cpp: iterating using itr = next(itr) for now when cle…
andrewdavidsmith Sep 1, 2026
0f5e495
src/html.cpp: headers and nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
2163c8f
src/fastq_gz_file.cpp: header and nolint on pointer arithmetic
andrewdavidsmith Sep 1, 2026
e3fb8ce
src/falco_config.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
77235a3
src/fastq_bgzf_file.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
9320554
src/falco_word.hpp: nolint on array bound
andrewdavidsmith Sep 1, 2026
7524af5
src/contaminants.cpp: iterating using itr = next(itr) for now when cl…
andrewdavidsmith Sep 1, 2026
ea20a1b
src/contaminants.hpp: adding a header
andrewdavidsmith Sep 1, 2026
2d181f8
src/fastq_file.cpp: adding headers
andrewdavidsmith Sep 1, 2026
badab36
src/adapter_matcher.cpp: nolint and fixing the number of positions ou…
andrewdavidsmith Sep 1, 2026
37d4a61
src/falco_file_format.hcpp: includes
andrewdavidsmith Sep 1, 2026
4ce3f0e
src/duplication_results.hpp: explicit on single param constructor
andrewdavidsmith Sep 1, 2026
dcd8535
src/duplication_results.cpp: nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
cadffe0
src/results_collector.hpp: casting in an assert to avoid side effect …
andrewdavidsmith Sep 1, 2026
c26cde0
src/results_summary.cpp: fixing var name to avoid shadowing
andrewdavidsmith Sep 1, 2026
089c478
src/report.cpp: removing include and fixing to_string for encoding to…
andrewdavidsmith Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cppcheck_suppress
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,9 +35,12 @@ missingInclude
*:*CLI11.hpp
*:*json.hpp
*:*boost_unordered.hpp
*:fmt/*.h
# Problem caused by external files
toomanyconfigs
# More problems caused by external files -- with too many ifdefs
normalCheckLevelMaxBranches
# This seems not to work with the designs used here
duplInheritedMember
# Seems like iterator variables for std::views disagree with this
constStatement
15 changes: 9 additions & 6 deletions src/adapter_matcher.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -131,6 +131,7 @@ y: {},
type: "line",
name: "{}",
}})";
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
assert(std::size(groups) == std::size(adap_counts));
// calcualte the x axis first
const auto x = groups | std::views::transform([&](const auto &g) {
Expand All@@ -146,9 +147,9 @@ name: "{}",
std::ranges::transform(cumulative[curr], cumulative[prev],
std::begin(cumulative[curr]), std::plus{});
#endif
const auto n_pos = max_read_len + 1 >= adapter_size
? max_read_len - adapter_size + 1
: max_read_len;
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
const auto n_pos =
max_read_len + 1 > adapter_size ? (max_read_len + 1) - adapter_size : 0U;
const auto last_group_to_keep = std::ranges::find_if(
groups, [&](const auto &g) { return n_pos <= g.first; });
cumulative.resize(std::distance(std::cbegin(groups), last_group_to_keep));
Expand All@@ -164,13 +165,15 @@ name: "{}",
return pct_of_reads(cumul[adap_id]);
};
const auto y = cumulative | std::views::transform(make_y);
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
html_by_adapter.emplace_back(fmt::format(adapter_fmt, x, y, adap_name));
}
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter)));
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter));
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}

auto
Expand Down
3 changes: 2 additions & 1 deletion src/adapter_set.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,8 @@ load_adapters(const std::string &filename) {
// ADS: need to make sure this can't fail
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
6 changes: 4 additions & 2 deletions src/bam_file.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,9 @@
#include <stdexcept>
#include <string>
#include <system_error>
#include <tuple>
#include <utility>
#include <vector>

[[nodiscard]] auto
estimate_n_reads_bam(const std::string &filename)
Expand DownExpand Up@@ -63,8 +65,8 @@ estimate_n_reads_bam(const std::string &filename)
}

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t {
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t {
static constexpr auto complem = [](const auto x) {
return "TNGNNNCNNNNNNNNNNNNA"[x - 'A'];
};
Expand Down
9 changes: 6 additions & 3 deletions src/bam_file.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,7 +62,10 @@ class bam_file {
~bam_file() = default;
// clang-format on

[[nodiscard]] operator bool() const { return !had_last_chunks; }
[[nodiscard]]
operator bool() const {
return !had_last_chunks;
}

friend auto
reset(bam_file &reads_file) -> void;
Expand DownExpand Up@@ -121,8 +124,8 @@ estimate_n_reads_bam(const std::string &filename)
-> std::tuple<std::uint64_t, std::uint64_t, std::int64_t>;

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t;
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t;

inline auto
make_tasks(bam_file &reads_file, //
Expand Down
8 changes: 4 additions & 4 deletions src/base_groups.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,16 +23,16 @@ make_base_groups(const std::uint64_t n_bases, const std::uint64_t n_initial,
const std::uint64_t n_groups_target) -> base_group_vec;

[[nodiscard]] auto
get_default_base_groups(const std::uint64_t n_bases,
const bool make_groups) -> base_group_vec;
get_default_base_groups(const std::uint64_t n_bases, const bool make_groups)
-> base_group_vec;

[[nodiscard]] auto
make_group_tag(const base_group_t g) -> std::string;

[[nodiscard]] auto
make_group_tag_quoted(const base_group_t g) -> std::string;

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand All@@ -50,7 +50,7 @@ apply_base_groups(const base_group_vec &groups, auto &rows) {
rows.resize(current_row);
}

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows, const auto &adder) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand Down
5 changes: 4 additions & 1 deletion src/bgzf_reader.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@
#include <cassert>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <memory>
Expand All@@ -28,6 +29,7 @@ get_unaligned_le32(const auto p) -> std::int32_t {
get_isize(const auto data, const auto data_size) {
static constexpr decltype(data_size) isize_size = 4;
assert(data_size > isize_size);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
const auto data_isize = data + data_size - isize_size;
return data_size < isize_size ? 0 : get_unaligned_le32(data_isize);
}
Expand All@@ -50,7 +52,8 @@ bgzf_reader::bgzf_reader(const std::string &filename,
next_in{inbuf.get()}, //
end_in{inbuf.get()}, //
next_out{outbuf.get()}, //
end_out{outbuf.get() + buf_size} //
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
end_out{outbuf.get() + buf_size} //
{}

[[nodiscard]] auto
Expand Down
4 changes: 3 additions & 1 deletion src/contaminants.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include <stdexcept>
#include <string>
#include <string_view>
#include <tuple> // for std::get
#include <utility>
#include <vector>

Expand DownExpand Up@@ -197,7 +198,8 @@ load_contaminants(const std::string &filename) -> void {
continue;
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
1 change: 1 addition & 0 deletions src/contaminants.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@
#define SRC_CONTAMINANTS_HPP_

#include <cstdint>
#include <ranges> // for std::pair
#include <string>
#include <utility> // IWYU pragma: keep
#include <vector>
Expand Down
25 changes: 14 additions & 11 deletions src/duplication_results.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include "run_mode.hpp"

#define FMT_HEADER_ONLY
#include "fmt/base.h"
#include "fmt/format.h"
#include "fmt/ranges.h"

Expand DownExpand Up@@ -124,8 +125,8 @@ duplication_results::get_overrepresented(const std::uint64_t n_reads) const
}

auto
duplication_results::initialize(const run_mode &mode,
const file_info &info) -> void {
duplication_results::initialize(const run_mode &mode, const file_info &info)
-> void {
read_skip =
info.n_reads_est < max_n_reads_total
? 0
Expand DownExpand Up@@ -282,8 +283,8 @@ get_grade_duplication(const dup_summary_t &summary) -> std::string {
}

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto start_tag = ">>Sequence Duplication Levels\t{}\n"
"#Total Deduplicated Percentage\t{:.6f}\n";
Expand All@@ -305,9 +306,10 @@ duplication_report(const dup_summary_t &summary,
std::max(static_cast<std::uint64_t>(1), reduce(summary.hist_mass)));
auto r = std::format(start_tag, grades.grade(label), pct(frac_dedup));
r += header;
for (const auto [label, mass] :
for (const auto [bin_label, mass] :
std::views::zip(bin_labels, binned_mass_pct) | std::views::drop(1))
r += std::format("{}\t{:.3g}\n", label, mass); // Percentage format is .3g
r +=
std::format("{}\t{:.3g}\n", bin_label, mass); // Percentage format is .3g
return r + end_module_tag;
}

Expand DownExpand Up@@ -345,8 +347,8 @@ overrepresented_html(const std::vector<overrep_t> &overrep,
}

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto plot_format = R"(<div id="duplication_plot"></div>
<script>Plotly.newPlot("duplication_plot",
Expand DownExpand Up@@ -389,11 +391,12 @@ yaxis: {{title: "% of sequences"}},
};
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
fmt::format(plot_format, //
x, to_pct(summary.hist_mass) | std::views::drop(1), // y_tot,
x, to_pct(summary.hist_dedup) | std::views::drop(1), // y_dedup
x, x_text | std::views::drop(1) // tickvals
));
);
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}
10 changes: 5 additions & 5 deletions src/duplication_results.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ struct dups_init_t {
std::int64_t count_at_limit{};
dups_map_t dups_zero;
dups_init_t() = default;
dups_init_t(const dups_map_t &dups) {
explicit dups_init_t(const dups_map_t &dups) {
const auto vals = dups | std::views::values;
count_at_limit = static_cast<std::int64_t>(
std::reduce(std::cbegin(vals), std::cend(vals)));
Expand DownExpand Up@@ -113,12 +113,12 @@ struct duplication_results {
get_grade_duplication(const dup_summary_t &summary) -> std::string;

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
get_grade_overrepresented(const std::uint64_t n_reads,
Expand Down
3 changes: 2 additions & 1 deletion src/falco_analyzer.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
#include <mutex>
#include <ranges>
#include <thread>
#include <tuple> // for std::get (iwyu fp)
#include <utility>
#include <variant>
#include <vector>
Expand All@@ -34,7 +35,6 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
const std::int32_t n_files = static_cast<std::int32_t>(std::size(infos));
if (dups_init.empty())
dups_init.resize(n_files);
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::atomic_uint32_t n_active_files{static_cast<std::uint32_t>(n_files)};
auto results =
std::vector(n_threads, std::vector<results_collector>(n_files));
Expand All@@ -45,6 +45,7 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
tq.push(file_id, std::monostate{});

{ // scope to join jthreads
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::vector<std::jthread> workers;
for (const auto th_id : std::views::iota(0u, n_threads))
workers.emplace_back([&, n_threads, th_id] {
Expand Down
18 changes: 10 additions & 8 deletions src/falco_config.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,8 +41,8 @@ split(const std::string &s) {
}

auto
load_config_and_set_graders(const std::string &filename,
run_mode &mode) -> void {
load_config_and_set_graders(const std::string &filename, run_mode &mode)
-> void {
// ADS: (todo) handle carriage returns and other control chars
std::ifstream in(filename);
if (!in)
Expand All@@ -61,9 +61,10 @@ load_config_and_set_graders(const std::string &filename,
}

// modes
for (const auto &label : run_mode::get_labels())
std::ranges::for_each(run_mode::get_labels(), [&](const auto &label) {
if (json_in.contains(label) && !json_in[label].contains("ignore"))
throw std::runtime_error("invalid config: " + to_string(json_in[label]));
});

std::unordered_map<std::string, bool> modes_in;
try {
Expand All@@ -83,11 +84,12 @@ load_config_and_set_graders(const std::string &filename,
mode.assign(modes_in);

// grades
for (const auto &label : grade_labels)
if (json_in.contains(label) &&
!(json_in[label].contains("error") && json_in[label].contains("warn")))
throw std::runtime_error("missing config value for: " +
std::string(label));
std::ranges::for_each(grade_labels, [&](const auto &l) {
if (json_in.contains(l) &&
!(json_in[l].contains("error") && json_in[l].contains("warn")))
throw std::runtime_error("missing config value for: " + std::string(l));
});

std::unordered_map<std::string, grader> graders;
try {
for (const auto &label : grade_labels) {
Expand Down
4 changes: 4 additions & 0 deletions src/falco_file_format.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,7 +7,11 @@
#include <array>
#include <cstdlib>
#include <filesystem>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <string>
#include <tuple>

[[nodiscard]] auto
get_file_format(const std::string &filename)
Expand Down
2 changes: 0 additions & 2 deletions src/falco_file_format.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,8 +7,6 @@

#include <cstdint>
#include <format>
#include <iterator>
#include <memory>
#include <string>
#include <thread>
#include <tuple>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a48b5d3
src/quality_score.hcpp: renaming the to_string function because the a…
andrewdavidsmith Sep 1, 2026
3697635
.cppcheck_suppress: ignoring fmt and ignoring constStatement which se…
andrewdavidsmith Sep 1, 2026
6633d46
src/samrec.cpp: adding missing include
andrewdavidsmith Sep 1, 2026
c256b39
src/tile_processor.cpp: renaming variables to avoid shadowing
andrewdavidsmith Sep 1, 2026
7e962a2
src/bam_file.hcpp: headers and formatting for new clang-tidy
andrewdavidsmith Sep 1, 2026
d9a4f45
src/base_groups.hpp: removing nodiscard on void functions
andrewdavidsmith Sep 1, 2026
4a8c6f0
src/sam_file.cpp: adding includes and initializing cursor and last in…
andrewdavidsmith Sep 1, 2026
cd9127e
src/kmer_counter.hcpp: removing the apply_groups function which isn't…
andrewdavidsmith Sep 1, 2026
a39a7c8
src/original_duplicates.cpp: changed loop to alg
andrewdavidsmith Sep 1, 2026
5396c2e
src/falco_utils.hcpp: fixing nodiscards and an include
andrewdavidsmith Sep 1, 2026
d39f1df
src/falco_analyzer.cpp: adding an include for iwyu that seems wrong a…
andrewdavidsmith Sep 1, 2026
8cc60aa
src/bgzf_reader.cpp: static analysis
andrewdavidsmith Sep 1, 2026
646cd9c
src/falco_grade.hcpp: making a member function get_tile static and re…
andrewdavidsmith Sep 1, 2026
e79f931
src/adapter_set.cpp: iterating using itr = next(itr) for now when cle…
andrewdavidsmith Sep 1, 2026
0f5e495
src/html.cpp: headers and nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
2163c8f
src/fastq_gz_file.cpp: header and nolint on pointer arithmetic
andrewdavidsmith Sep 1, 2026
e3fb8ce
src/falco_config.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
77235a3
src/fastq_bgzf_file.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
9320554
src/falco_word.hpp: nolint on array bound
andrewdavidsmith Sep 1, 2026
7524af5
src/contaminants.cpp: iterating using itr = next(itr) for now when cl…
andrewdavidsmith Sep 1, 2026
ea20a1b
src/contaminants.hpp: adding a header
andrewdavidsmith Sep 1, 2026
2d181f8
src/fastq_file.cpp: adding headers
andrewdavidsmith Sep 1, 2026
badab36
src/adapter_matcher.cpp: nolint and fixing the number of positions ou…
andrewdavidsmith Sep 1, 2026
37d4a61
src/falco_file_format.hcpp: includes
andrewdavidsmith Sep 1, 2026
4ce3f0e
src/duplication_results.hpp: explicit on single param constructor
andrewdavidsmith Sep 1, 2026
dcd8535
src/duplication_results.cpp: nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
cadffe0
src/results_collector.hpp: casting in an assert to avoid side effect …
andrewdavidsmith Sep 1, 2026
c26cde0
src/results_summary.cpp: fixing var name to avoid shadowing
andrewdavidsmith Sep 1, 2026
089c478
src/report.cpp: removing include and fixing to_string for encoding to…
andrewdavidsmith Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cppcheck_suppress
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,9 +35,12 @@ missingInclude
*:*CLI11.hpp
*:*json.hpp
*:*boost_unordered.hpp
*:fmt/*.h
# Problem caused by external files
toomanyconfigs
# More problems caused by external files -- with too many ifdefs
normalCheckLevelMaxBranches
# This seems not to work with the designs used here
duplInheritedMember
# Seems like iterator variables for std::views disagree with this
constStatement
15 changes: 9 additions & 6 deletions src/adapter_matcher.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -131,6 +131,7 @@ y: {},
type: "line",
name: "{}",
}})";
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
assert(std::size(groups) == std::size(adap_counts));
// calcualte the x axis first
const auto x = groups | std::views::transform([&](const auto &g) {
Expand All@@ -146,9 +147,9 @@ name: "{}",
std::ranges::transform(cumulative[curr], cumulative[prev],
std::begin(cumulative[curr]), std::plus{});
#endif
const auto n_pos = max_read_len + 1 >= adapter_size
? max_read_len - adapter_size + 1
: max_read_len;
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
const auto n_pos =
max_read_len + 1 > adapter_size ? (max_read_len + 1) - adapter_size : 0U;
const auto last_group_to_keep = std::ranges::find_if(
groups, [&](const auto &g) { return n_pos <= g.first; });
cumulative.resize(std::distance(std::cbegin(groups), last_group_to_keep));
Expand All@@ -164,13 +165,15 @@ name: "{}",
return pct_of_reads(cumul[adap_id]);
};
const auto y = cumulative | std::views::transform(make_y);
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
html_by_adapter.emplace_back(fmt::format(adapter_fmt, x, y, adap_name));
}
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter)));
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter));
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}

auto
Expand Down
3 changes: 2 additions & 1 deletion src/adapter_set.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,8 @@ load_adapters(const std::string &filename) {
// ADS: need to make sure this can't fail
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
6 changes: 4 additions & 2 deletions src/bam_file.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,9 @@
#include <stdexcept>
#include <string>
#include <system_error>
#include <tuple>
#include <utility>
#include <vector>

[[nodiscard]] auto
estimate_n_reads_bam(const std::string &filename)
Expand DownExpand Up@@ -63,8 +65,8 @@ estimate_n_reads_bam(const std::string &filename)
}

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t {
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t {
static constexpr auto complem = [](const auto x) {
return "TNGNNNCNNNNNNNNNNNNA"[x - 'A'];
};
Expand Down
9 changes: 6 additions & 3 deletions src/bam_file.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,7 +62,10 @@ class bam_file {
~bam_file() = default;
// clang-format on

[[nodiscard]] operator bool() const { return !had_last_chunks; }
[[nodiscard]]
operator bool() const {
return !had_last_chunks;
}

friend auto
reset(bam_file &reads_file) -> void;
Expand DownExpand Up@@ -121,8 +124,8 @@ estimate_n_reads_bam(const std::string &filename)
-> std::tuple<std::uint64_t, std::uint64_t, std::int64_t>;

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t;
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t;

inline auto
make_tasks(bam_file &reads_file, //
Expand Down
8 changes: 4 additions & 4 deletions src/base_groups.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,16 +23,16 @@ make_base_groups(const std::uint64_t n_bases, const std::uint64_t n_initial,
const std::uint64_t n_groups_target) -> base_group_vec;

[[nodiscard]] auto
get_default_base_groups(const std::uint64_t n_bases,
const bool make_groups) -> base_group_vec;
get_default_base_groups(const std::uint64_t n_bases, const bool make_groups)
-> base_group_vec;

[[nodiscard]] auto
make_group_tag(const base_group_t g) -> std::string;

[[nodiscard]] auto
make_group_tag_quoted(const base_group_t g) -> std::string;

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand All@@ -50,7 +50,7 @@ apply_base_groups(const base_group_vec &groups, auto &rows) {
rows.resize(current_row);
}

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows, const auto &adder) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand Down
5 changes: 4 additions & 1 deletion src/bgzf_reader.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@
#include <cassert>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <memory>
Expand All@@ -28,6 +29,7 @@ get_unaligned_le32(const auto p) -> std::int32_t {
get_isize(const auto data, const auto data_size) {
static constexpr decltype(data_size) isize_size = 4;
assert(data_size > isize_size);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
const auto data_isize = data + data_size - isize_size;
return data_size < isize_size ? 0 : get_unaligned_le32(data_isize);
}
Expand All@@ -50,7 +52,8 @@ bgzf_reader::bgzf_reader(const std::string &filename,
next_in{inbuf.get()}, //
end_in{inbuf.get()}, //
next_out{outbuf.get()}, //
end_out{outbuf.get() + buf_size} //
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
end_out{outbuf.get() + buf_size} //
{}

[[nodiscard]] auto
Expand Down
4 changes: 3 additions & 1 deletion src/contaminants.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include <stdexcept>
#include <string>
#include <string_view>
#include <tuple> // for std::get
#include <utility>
#include <vector>

Expand DownExpand Up@@ -197,7 +198,8 @@ load_contaminants(const std::string &filename) -> void {
continue;
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
1 change: 1 addition & 0 deletions src/contaminants.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@
#define SRC_CONTAMINANTS_HPP_

#include <cstdint>
#include <ranges> // for std::pair
#include <string>
#include <utility> // IWYU pragma: keep
#include <vector>
Expand Down
25 changes: 14 additions & 11 deletions src/duplication_results.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include "run_mode.hpp"

#define FMT_HEADER_ONLY
#include "fmt/base.h"
#include "fmt/format.h"
#include "fmt/ranges.h"

Expand DownExpand Up@@ -124,8 +125,8 @@ duplication_results::get_overrepresented(const std::uint64_t n_reads) const
}

auto
duplication_results::initialize(const run_mode &mode,
const file_info &info) -> void {
duplication_results::initialize(const run_mode &mode, const file_info &info)
-> void {
read_skip =
info.n_reads_est < max_n_reads_total
? 0
Expand DownExpand Up@@ -282,8 +283,8 @@ get_grade_duplication(const dup_summary_t &summary) -> std::string {
}

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto start_tag = ">>Sequence Duplication Levels\t{}\n"
"#Total Deduplicated Percentage\t{:.6f}\n";
Expand All@@ -305,9 +306,10 @@ duplication_report(const dup_summary_t &summary,
std::max(static_cast<std::uint64_t>(1), reduce(summary.hist_mass)));
auto r = std::format(start_tag, grades.grade(label), pct(frac_dedup));
r += header;
for (const auto [label, mass] :
for (const auto [bin_label, mass] :
std::views::zip(bin_labels, binned_mass_pct) | std::views::drop(1))
r += std::format("{}\t{:.3g}\n", label, mass); // Percentage format is .3g
r +=
std::format("{}\t{:.3g}\n", bin_label, mass); // Percentage format is .3g
return r + end_module_tag;
}

Expand DownExpand Up@@ -345,8 +347,8 @@ overrepresented_html(const std::vector<overrep_t> &overrep,
}

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto plot_format = R"(<div id="duplication_plot"></div>
<script>Plotly.newPlot("duplication_plot",
Expand DownExpand Up@@ -389,11 +391,12 @@ yaxis: {{title: "% of sequences"}},
};
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
fmt::format(plot_format, //
x, to_pct(summary.hist_mass) | std::views::drop(1), // y_tot,
x, to_pct(summary.hist_dedup) | std::views::drop(1), // y_dedup
x, x_text | std::views::drop(1) // tickvals
));
);
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}
10 changes: 5 additions & 5 deletions src/duplication_results.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ struct dups_init_t {
std::int64_t count_at_limit{};
dups_map_t dups_zero;
dups_init_t() = default;
dups_init_t(const dups_map_t &dups) {
explicit dups_init_t(const dups_map_t &dups) {
const auto vals = dups | std::views::values;
count_at_limit = static_cast<std::int64_t>(
std::reduce(std::cbegin(vals), std::cend(vals)));
Expand DownExpand Up@@ -113,12 +113,12 @@ struct duplication_results {
get_grade_duplication(const dup_summary_t &summary) -> std::string;

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
get_grade_overrepresented(const std::uint64_t n_reads,
Expand Down
3 changes: 2 additions & 1 deletion src/falco_analyzer.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
#include <mutex>
#include <ranges>
#include <thread>
#include <tuple> // for std::get (iwyu fp)
#include <utility>
#include <variant>
#include <vector>
Expand All@@ -34,7 +35,6 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
const std::int32_t n_files = static_cast<std::int32_t>(std::size(infos));
if (dups_init.empty())
dups_init.resize(n_files);
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::atomic_uint32_t n_active_files{static_cast<std::uint32_t>(n_files)};
auto results =
std::vector(n_threads, std::vector<results_collector>(n_files));
Expand All@@ -45,6 +45,7 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
tq.push(file_id, std::monostate{});

{ // scope to join jthreads
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::vector<std::jthread> workers;
for (const auto th_id : std::views::iota(0u, n_threads))
workers.emplace_back([&, n_threads, th_id] {
Expand Down
18 changes: 10 additions & 8 deletions src/falco_config.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,8 +41,8 @@ split(const std::string &s) {
}

auto
load_config_and_set_graders(const std::string &filename,
run_mode &mode) -> void {
load_config_and_set_graders(const std::string &filename, run_mode &mode)
-> void {
// ADS: (todo) handle carriage returns and other control chars
std::ifstream in(filename);
if (!in)
Expand All@@ -61,9 +61,10 @@ load_config_and_set_graders(const std::string &filename,
}

// modes
for (const auto &label : run_mode::get_labels())
std::ranges::for_each(run_mode::get_labels(), [&](const auto &label) {
if (json_in.contains(label) && !json_in[label].contains("ignore"))
throw std::runtime_error("invalid config: " + to_string(json_in[label]));
});

std::unordered_map<std::string, bool> modes_in;
try {
Expand All@@ -83,11 +84,12 @@ load_config_and_set_graders(const std::string &filename,
mode.assign(modes_in);

// grades
for (const auto &label : grade_labels)
if (json_in.contains(label) &&
!(json_in[label].contains("error") && json_in[label].contains("warn")))
throw std::runtime_error("missing config value for: " +
std::string(label));
std::ranges::for_each(grade_labels, [&](const auto &l) {
if (json_in.contains(l) &&
!(json_in[l].contains("error") && json_in[l].contains("warn")))
throw std::runtime_error("missing config value for: " + std::string(l));
});

std::unordered_map<std::string, grader> graders;
try {
for (const auto &label : grade_labels) {
Expand Down
4 changes: 4 additions & 0 deletions src/falco_file_format.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,7 +7,11 @@
#include <array>
#include <cstdlib>
#include <filesystem>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <string>
#include <tuple>

[[nodiscard]] auto
get_file_format(const std::string &filename)
Expand Down
2 changes: 0 additions & 2 deletions src/falco_file_format.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,8 +7,6 @@

#include <cstdint>
#include <format>
#include <iterator>
#include <memory>
#include <string>
#include <thread>
#include <tuple>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a48b5d3
src/quality_score.hcpp: renaming the to_string function because the a…
andrewdavidsmith Sep 1, 2026
3697635
.cppcheck_suppress: ignoring fmt and ignoring constStatement which se…
andrewdavidsmith Sep 1, 2026
6633d46
src/samrec.cpp: adding missing include
andrewdavidsmith Sep 1, 2026
c256b39
src/tile_processor.cpp: renaming variables to avoid shadowing
andrewdavidsmith Sep 1, 2026
7e962a2
src/bam_file.hcpp: headers and formatting for new clang-tidy
andrewdavidsmith Sep 1, 2026
d9a4f45
src/base_groups.hpp: removing nodiscard on void functions
andrewdavidsmith Sep 1, 2026
4a8c6f0
src/sam_file.cpp: adding includes and initializing cursor and last in…
andrewdavidsmith Sep 1, 2026
cd9127e
src/kmer_counter.hcpp: removing the apply_groups function which isn't…
andrewdavidsmith Sep 1, 2026
a39a7c8
src/original_duplicates.cpp: changed loop to alg
andrewdavidsmith Sep 1, 2026
5396c2e
src/falco_utils.hcpp: fixing nodiscards and an include
andrewdavidsmith Sep 1, 2026
d39f1df
src/falco_analyzer.cpp: adding an include for iwyu that seems wrong a…
andrewdavidsmith Sep 1, 2026
8cc60aa
src/bgzf_reader.cpp: static analysis
andrewdavidsmith Sep 1, 2026
646cd9c
src/falco_grade.hcpp: making a member function get_tile static and re…
andrewdavidsmith Sep 1, 2026
e79f931
src/adapter_set.cpp: iterating using itr = next(itr) for now when cle…
andrewdavidsmith Sep 1, 2026
0f5e495
src/html.cpp: headers and nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
2163c8f
src/fastq_gz_file.cpp: header and nolint on pointer arithmetic
andrewdavidsmith Sep 1, 2026
e3fb8ce
src/falco_config.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
77235a3
src/fastq_bgzf_file.cpp: loop to alg
andrewdavidsmith Sep 1, 2026
9320554
src/falco_word.hpp: nolint on array bound
andrewdavidsmith Sep 1, 2026
7524af5
src/contaminants.cpp: iterating using itr = next(itr) for now when cl…
andrewdavidsmith Sep 1, 2026
ea20a1b
src/contaminants.hpp: adding a header
andrewdavidsmith Sep 1, 2026
2d181f8
src/fastq_file.cpp: adding headers
andrewdavidsmith Sep 1, 2026
badab36
src/adapter_matcher.cpp: nolint and fixing the number of positions ou…
andrewdavidsmith Sep 1, 2026
37d4a61
src/falco_file_format.hcpp: includes
andrewdavidsmith Sep 1, 2026
4ce3f0e
src/duplication_results.hpp: explicit on single param constructor
andrewdavidsmith Sep 1, 2026
dcd8535
src/duplication_results.cpp: nolint on optin.cplusplus.UninitObj
andrewdavidsmith Sep 1, 2026
cadffe0
src/results_collector.hpp: casting in an assert to avoid side effect …
andrewdavidsmith Sep 1, 2026
c26cde0
src/results_summary.cpp: fixing var name to avoid shadowing
andrewdavidsmith Sep 1, 2026
089c478
src/report.cpp: removing include and fixing to_string for encoding to…
andrewdavidsmith Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cppcheck_suppress
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,9 +35,12 @@ missingInclude
*:*CLI11.hpp
*:*json.hpp
*:*boost_unordered.hpp
*:fmt/*.h
# Problem caused by external files
toomanyconfigs
# More problems caused by external files -- with too many ifdefs
normalCheckLevelMaxBranches
# This seems not to work with the designs used here
duplInheritedMember
# Seems like iterator variables for std::views disagree with this
constStatement
15 changes: 9 additions & 6 deletions src/adapter_matcher.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -131,6 +131,7 @@ y: {},
type: "line",
name: "{}",
}})";
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
assert(std::size(groups) == std::size(adap_counts));
// calcualte the x axis first
const auto x = groups | std::views::transform([&](const auto &g) {
Expand All@@ -146,9 +147,9 @@ name: "{}",
std::ranges::transform(cumulative[curr], cumulative[prev],
std::begin(cumulative[curr]), std::plus{});
#endif
const auto n_pos = max_read_len + 1 >= adapter_size
? max_read_len - adapter_size + 1
: max_read_len;
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
const auto n_pos =
max_read_len + 1 > adapter_size ? (max_read_len + 1) - adapter_size : 0U;
const auto last_group_to_keep = std::ranges::find_if(
groups, [&](const auto &g) { return n_pos <= g.first; });
cumulative.resize(std::distance(std::cbegin(groups), last_group_to_keep));
Expand All@@ -164,13 +165,15 @@ name: "{}",
return pct_of_reads(cumul[adap_id]);
};
const auto y = cumulative | std::views::transform(make_y);
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
html_by_adapter.emplace_back(fmt::format(adapter_fmt, x, y, adap_name));
}
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter)));
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
std::format(plot_fmt, fmt::format("[{:n:}]", html_by_adapter));
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}

auto
Expand Down
3 changes: 2 additions & 1 deletion src/adapter_set.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,8 @@ load_adapters(const std::string &filename) {
// ADS: need to make sure this can't fail
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
6 changes: 4 additions & 2 deletions src/bam_file.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,9 @@
#include <stdexcept>
#include <string>
#include <system_error>
#include <tuple>
#include <utility>
#include <vector>

[[nodiscard]] auto
estimate_n_reads_bam(const std::string &filename)
Expand DownExpand Up@@ -63,8 +65,8 @@ estimate_n_reads_bam(const std::string &filename)
}

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t {
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t {
static constexpr auto complem = [](const auto x) {
return "TNGNNNCNNNNNNNNNNNNA"[x - 'A'];
};
Expand Down
9 changes: 6 additions & 3 deletions src/bam_file.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,7 +62,10 @@ class bam_file {
~bam_file() = default;
// clang-format on

[[nodiscard]] operator bool() const { return !had_last_chunks; }
[[nodiscard]]
operator bool() const {
return !had_last_chunks;
}

friend auto
reset(bam_file &reads_file) -> void;
Expand DownExpand Up@@ -121,8 +124,8 @@ estimate_n_reads_bam(const std::string &filename)
-> std::tuple<std::uint64_t, std::uint64_t, std::int64_t>;

[[nodiscard]] auto
init_dups(const std::string &filename,
const std::uint64_t n_unique) -> dups_map_t;
init_dups(const std::string &filename, const std::uint64_t n_unique)
-> dups_map_t;

inline auto
make_tasks(bam_file &reads_file, //
Expand Down
8 changes: 4 additions & 4 deletions src/base_groups.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,16 +23,16 @@ make_base_groups(const std::uint64_t n_bases, const std::uint64_t n_initial,
const std::uint64_t n_groups_target) -> base_group_vec;

[[nodiscard]] auto
get_default_base_groups(const std::uint64_t n_bases,
const bool make_groups) -> base_group_vec;
get_default_base_groups(const std::uint64_t n_bases, const bool make_groups)
-> base_group_vec;

[[nodiscard]] auto
make_group_tag(const base_group_t g) -> std::string;

[[nodiscard]] auto
make_group_tag_quoted(const base_group_t g) -> std::string;

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand All@@ -50,7 +50,7 @@ apply_base_groups(const base_group_vec &groups, auto &rows) {
rows.resize(current_row);
}

[[nodiscard]] auto
void
apply_base_groups(const base_group_vec &groups, auto &rows, const auto &adder) {
assert(std::size(rows) <= groups.back().second);
auto group_itr = std::cbegin(groups);
Expand Down
5 changes: 4 additions & 1 deletion src/bgzf_reader.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@
#include <cassert>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <memory>
Expand All@@ -28,6 +29,7 @@ get_unaligned_le32(const auto p) -> std::int32_t {
get_isize(const auto data, const auto data_size) {
static constexpr decltype(data_size) isize_size = 4;
assert(data_size > isize_size);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
const auto data_isize = data + data_size - isize_size;
return data_size < isize_size ? 0 : get_unaligned_le32(data_isize);
}
Expand All@@ -50,7 +52,8 @@ bgzf_reader::bgzf_reader(const std::string &filename,
next_in{inbuf.get()}, //
end_in{inbuf.get()}, //
next_out{outbuf.get()}, //
end_out{outbuf.get() + buf_size} //
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
end_out{outbuf.get() + buf_size} //
{}

[[nodiscard]] auto
Expand Down
4 changes: 3 additions & 1 deletion src/contaminants.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include <stdexcept>
#include <string>
#include <string_view>
#include <tuple> // for std::get
#include <utility>
#include <vector>

Expand DownExpand Up@@ -197,7 +198,8 @@ load_contaminants(const std::string &filename) -> void {
continue;
line.remove_suffix(std::size(line) - to_keep_suffix - 1);
std::string cleaned_line;
for (auto itr = std::cbegin(line); itr != std::cend(line); ++itr)
for (auto itr = std::cbegin(line); itr != std::cend(line);
itr = std::next(itr))
if (!std::isblank(*itr) ||
(std::next(itr) != std::cend(line) && *itr != *std::next(itr)))
cleaned_line += *itr;
Expand Down
1 change: 1 addition & 0 deletions src/contaminants.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@
#define SRC_CONTAMINANTS_HPP_

#include <cstdint>
#include <ranges> // for std::pair
#include <string>
#include <utility> // IWYU pragma: keep
#include <vector>
Expand Down
25 changes: 14 additions & 11 deletions src/duplication_results.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
#include "run_mode.hpp"

#define FMT_HEADER_ONLY
#include "fmt/base.h"
#include "fmt/format.h"
#include "fmt/ranges.h"

Expand DownExpand Up@@ -124,8 +125,8 @@ duplication_results::get_overrepresented(const std::uint64_t n_reads) const
}

auto
duplication_results::initialize(const run_mode &mode,
const file_info &info) -> void {
duplication_results::initialize(const run_mode &mode, const file_info &info)
-> void {
read_skip =
info.n_reads_est < max_n_reads_total
? 0
Expand DownExpand Up@@ -282,8 +283,8 @@ get_grade_duplication(const dup_summary_t &summary) -> std::string {
}

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto start_tag = ">>Sequence Duplication Levels\t{}\n"
"#Total Deduplicated Percentage\t{:.6f}\n";
Expand All@@ -305,9 +306,10 @@ duplication_report(const dup_summary_t &summary,
std::max(static_cast<std::uint64_t>(1), reduce(summary.hist_mass)));
auto r = std::format(start_tag, grades.grade(label), pct(frac_dedup));
r += header;
for (const auto [label, mass] :
for (const auto [bin_label, mass] :
std::views::zip(bin_labels, binned_mass_pct) | std::views::drop(1))
r += std::format("{}\t{:.3g}\n", label, mass); // Percentage format is .3g
r +=
std::format("{}\t{:.3g}\n", bin_label, mass); // Percentage format is .3g
return r + end_module_tag;
}

Expand DownExpand Up@@ -345,8 +347,8 @@ overrepresented_html(const std::vector<overrep_t> &overrep,
}

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string {
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string {
static constexpr auto label = "duplication";
static constexpr auto plot_format = R"(<div id="duplication_plot"></div>
<script>Plotly.newPlot("duplication_plot",
Expand DownExpand Up@@ -389,11 +391,12 @@ yaxis: {{title: "% of sequences"}},
};
const auto grade = grades.grade(label);
const auto title = grades.get_title(label);
return fmt::format(
html_module_fmt, grade, label, title, grade,
const auto the_plot =
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
fmt::format(plot_format, //
x, to_pct(summary.hist_mass) | std::views::drop(1), // y_tot,
x, to_pct(summary.hist_dedup) | std::views::drop(1), // y_dedup
x, x_text | std::views::drop(1) // tickvals
));
);
return fmt::format(html_module_fmt, grade, label, title, grade, the_plot);
}
10 changes: 5 additions & 5 deletions src/duplication_results.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ struct dups_init_t {
std::int64_t count_at_limit{};
dups_map_t dups_zero;
dups_init_t() = default;
dups_init_t(const dups_map_t &dups) {
explicit dups_init_t(const dups_map_t &dups) {
const auto vals = dups | std::views::values;
count_at_limit = static_cast<std::int64_t>(
std::reduce(std::cbegin(vals), std::cend(vals)));
Expand DownExpand Up@@ -113,12 +113,12 @@ struct duplication_results {
get_grade_duplication(const dup_summary_t &summary) -> std::string;

[[nodiscard]] auto
duplication_report(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_report(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
duplication_html(const dup_summary_t &summary,
const file_grades &grades) -> std::string;
duplication_html(const dup_summary_t &summary, const file_grades &grades)
-> std::string;

[[nodiscard]] auto
get_grade_overrepresented(const std::uint64_t n_reads,
Expand Down
3 changes: 2 additions & 1 deletion src/falco_analyzer.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
#include <mutex>
#include <ranges>
#include <thread>
#include <tuple> // for std::get (iwyu fp)
#include <utility>
#include <variant>
#include <vector>
Expand All@@ -34,7 +35,6 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
const std::int32_t n_files = static_cast<std::int32_t>(std::size(infos));
if (dups_init.empty())
dups_init.resize(n_files);
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::atomic_uint32_t n_active_files{static_cast<std::uint32_t>(n_files)};
auto results =
std::vector(n_threads, std::vector<results_collector>(n_files));
Expand All@@ -45,6 +45,7 @@ analyze(const std::uint32_t n_threads, const run_mode &mode,
tq.push(file_id, std::monostate{});

{ // scope to join jthreads
std::vector<std::atomic_int32_t> n_tasks(n_files);
std::vector<std::jthread> workers;
for (const auto th_id : std::views::iota(0u, n_threads))
workers.emplace_back([&, n_threads, th_id] {
Expand Down
18 changes: 10 additions & 8 deletions src/falco_config.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,8 +41,8 @@ split(const std::string &s) {
}

auto
load_config_and_set_graders(const std::string &filename,
run_mode &mode) -> void {
load_config_and_set_graders(const std::string &filename, run_mode &mode)
-> void {
// ADS: (todo) handle carriage returns and other control chars
std::ifstream in(filename);
if (!in)
Expand All@@ -61,9 +61,10 @@ load_config_and_set_graders(const std::string &filename,
}

// modes
for (const auto &label : run_mode::get_labels())
std::ranges::for_each(run_mode::get_labels(), [&](const auto &label) {
if (json_in.contains(label) && !json_in[label].contains("ignore"))
throw std::runtime_error("invalid config: " + to_string(json_in[label]));
});

std::unordered_map<std::string, bool> modes_in;
try {
Expand All@@ -83,11 +84,12 @@ load_config_and_set_graders(const std::string &filename,
mode.assign(modes_in);

// grades
for (const auto &label : grade_labels)
if (json_in.contains(label) &&
!(json_in[label].contains("error") && json_in[label].contains("warn")))
throw std::runtime_error("missing config value for: " +
std::string(label));
std::ranges::for_each(grade_labels, [&](const auto &l) {
if (json_in.contains(l) &&
!(json_in[l].contains("error") && json_in[l].contains("warn")))
throw std::runtime_error("missing config value for: " + std::string(l));
});

std::unordered_map<std::string, grader> graders;
try {
for (const auto &label : grade_labels) {
Expand Down
4 changes: 4 additions & 0 deletions src/falco_file_format.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,7 +7,11 @@
#include <array>
#include <cstdlib>
#include <filesystem>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <string>
#include <tuple>

[[nodiscard]] auto
get_file_format(const std::string &filename)
Expand Down
2 changes: 0 additions & 2 deletions src/falco_file_format.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,8 +7,6 @@

#include <cstdint>
#include <format>
#include <iterator>
#include <memory>
#include <string>
#include <thread>
#include <tuple>
Expand Down
Loading