From 672f50f388d479567f8fcdb0bab43db278f8f79b Mon Sep 17 00:00:00 2001 From: Karn Kaul Date: Fri, 22 Nov 2024 22:10:59 -0800 Subject: [PATCH 1/2] Fix readme, remove shared counter ownership --- README.md | 4 +++- cli/src/app.cpp | 2 +- cli/src/counter.cpp | 8 ++++---- lib/include/locc/file_filter.hpp | 2 +- lib/include/locc/instance.hpp | 4 +--- lib/src/file_filter.cpp | 2 +- lib/src/instance.cpp | 9 ++------- 7 files changed, 13 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 9245d73..4363eec 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,9 @@ locc-lib clap ktask djson ``` -`djson` deals with parsing JSONs and is used for grammar IO. `ktask` is a lightweight task execution queue, `locc-lib` enqueues a counter task for each file using it. This _counter_ task is internal to `locc-lib` and not exposed to users. Users utilize a single `locc::LineCounter` wrapper task, which reports progress / status, and supports waiting (blocking) until all individual counters have completed (or if any counter has been dropped). It can be used by direct ownership, or shared ownership through `locc::Instance`, which owns a `ktask::Queue`. Using the instance is convenient when the queue isn't needed for any other tasks, otherwise own the queue and line counters yourself. As is evident, multiple line counters can share the same task queue, which can also have other tasks interleaved. +`djson` deals with parsing JSONs and is used for grammar IO. `ktask` is a lightweight task execution queue, `locc-lib` enqueues a counter task for each file using it. This _counter_ task is internal to `locc-lib` and not exposed to users. Users utilize a single `locc::LineCounter` wrapper task, which reports progress / status, and supports waiting (blocking) until all individual counters have completed (or if any counter has been dropped). It can be used directly or through a `locc::Instance`. Using the instance is convenient when all line counters use the same grammars and file filters. As is evident, multiple line counters can share the same task queue, which can also have other tasks interleaved. + +`clap` is a command line argument parser, which `locc-cli` uses. * [clap](https://github.com/karnkaul/clap) * [ktask](https://github.com/karnkaul/ktask) diff --git a/cli/src/app.cpp b/cli/src/app.cpp index 87fc18b..c1243cf 100644 --- a/cli/src/app.cpp +++ b/cli/src/app.cpp @@ -71,7 +71,7 @@ auto App::execute() -> int { } auto csv = Csv{m_params.exclude_patterns}; - for (auto pattern = std::string_view{}; csv(pattern);) { m_filter.skip_patterns.push_back(pattern); } + for (auto pattern = std::string_view{}; csv(pattern);) { m_filter.exclude_patterns.push_back(pattern); } Counter{m_params, std::move(ici)}.run(); return EXIT_SUCCESS; diff --git a/cli/src/counter.cpp b/cli/src/counter.cpp index 4a0f623..cbb5611 100644 --- a/cli/src/counter.cpp +++ b/cli/src/counter.cpp @@ -32,7 +32,7 @@ void Counter::run() { if (m_params.verbose) { print_params(); } auto line_counter = m_locc.start_count(m_params.path); - if (!line_counter) { return; } + if (line_counter.get_status() == LineCounter::Status::None) { return; } if (!m_params.no_progress) { std::println(); @@ -41,12 +41,12 @@ void Counter::run() { } if (m_params.no_progress) { - line_counter->wait(); + line_counter.wait(); } else { - print_progress_until_ready(*line_counter); + print_progress_until_ready(line_counter); } - auto rows = line_counter->to_rows(); + auto rows = line_counter.to_rows(); auto const sort_by = to_metric(m_params.sort_by); if (sort_by == by_file_type) { sort_by_file_type(rows); diff --git a/lib/include/locc/file_filter.hpp b/lib/include/locc/file_filter.hpp index 682def6..89eeb80 100644 --- a/lib/include/locc/file_filter.hpp +++ b/lib/include/locc/file_filter.hpp @@ -17,7 +17,7 @@ class IFileFilter { }; struct DefaultFileFilter : IFileFilter { - std::vector skip_patterns{"build/", "out/", ".cache/", ".git/"}; + std::vector exclude_patterns{"build/", "out/", ".cache/", ".git/"}; [[nodiscard]] auto should_count(std::string_view path) const -> bool override; diff --git a/lib/include/locc/instance.hpp b/lib/include/locc/instance.hpp index fc19cb5..b41af96 100644 --- a/lib/include/locc/instance.hpp +++ b/lib/include/locc/instance.hpp @@ -14,14 +14,12 @@ class Instance { explicit Instance(ktask::Queue& queue, CreateInfo create_info = {}); - [[nodiscard]] auto start_count(std::string_view path) -> std::shared_ptr; + [[nodiscard]] auto start_count(std::string_view path) -> LineCounter; private: ktask::Queue* m_queue; std::vector m_grammars; IFileFilter const* m_filter; - - std::vector> m_line_counters{}; }; } // namespace locc diff --git a/lib/src/file_filter.cpp b/lib/src/file_filter.cpp index a4b51e6..dce7cb8 100644 --- a/lib/src/file_filter.cpp +++ b/lib/src/file_filter.cpp @@ -3,7 +3,7 @@ namespace locc { auto DefaultFileFilter::should_count(std::string_view const path) const -> bool { - return !std::ranges::any_of(skip_patterns, [path](std::string_view const s) { return path.contains(s); }); + return !std::ranges::any_of(exclude_patterns, [path](std::string_view const s) { return path.contains(s); }); } auto DefaultFileFilter::get_instance() -> DefaultFileFilter const& { diff --git a/lib/src/instance.cpp b/lib/src/instance.cpp index 31a41eb..9fe8d52 100644 --- a/lib/src/instance.cpp +++ b/lib/src/instance.cpp @@ -6,17 +6,12 @@ namespace locc { Instance::Instance(ktask::Queue& queue, CreateInfo create_info) : m_queue(&queue), m_grammars(std::move(create_info.grammars)), m_filter(create_info.file_filter) {} -auto Instance::start_count(std::string_view const path) -> std::shared_ptr { - if (m_grammars.empty()) { return {}; } +auto Instance::start_count(std::string_view const path) -> LineCounter { auto const query = Query{ .grammars = m_grammars, .path = path, .filter = m_filter, }; - auto ret = std::make_shared(*m_queue, query); - m_line_counters.push_back(ret); - m_queue->enqueue(*ret); - std::erase_if(m_line_counters, [](auto const& counter) { return !counter->is_busy(); }); - return ret; + return LineCounter{*m_queue, query}; } } // namespace locc From 1177d592f0c86aa7cebfa08dac9c4d9663160226 Mon Sep 17 00:00:00 2001 From: Karn Kaul Date: Fri, 22 Nov 2024 22:35:43 -0800 Subject: [PATCH 2/2] Add sort direction, fixup readme --- README.md | 35 +++++++++++++++-------------------- cli/src/app.cpp | 3 ++- cli/src/counter.cpp | 30 ++++++++++++++++-------------- cli/src/params.hpp | 3 ++- lib/include/locc/instance.hpp | 2 +- lib/include/locc/row.hpp | 6 ++++-- lib/src/instance.cpp | 7 +++++-- lib/src/row.cpp | 32 +++++++++++++++++++++++--------- 8 files changed, 68 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 4363eec..67a67e8 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ locc [OPTIONS...] ## Output -Examples of output (may be out of date until release): +Examples of output: Linux kernel (36 million lines counted) @@ -54,34 +54,29 @@ sys 0m1.076s This repo (v0.1) ``` -$ ./locc-cli -vpe=ext . +$ out/ubsan/cli/Debug/locc-cli -vpe=ext --sort-column=Comments --sort-ascend params: - sort by : - exclude : ext - grammars : - threads : 16 - no progress : true - verbose : true - path : . + sort by : Comments + exclude : ext + grammars : + threads : 16 + sort ascend : true + no progress : true + verbose : true + path : . ----------------------------------------------------------- | File Type | Files | Lines | Code | Comments | Empty | ----------------------------------------------------------- -| C++ | 17 | 1,262 | 1,068 | 16 | 178 | -| JSON | 3 | 742 | 739 | 3 | 0 | -| C++ header | 19 | 447 | 344 | 5 | 98 | | CMake script | 4 | 192 | 160 | 0 | 32 | -| Markdown | 1 | 128 | 96 | 0 | 32 | -| Plain Text | 1 | 2 | 0 | 0 | 0 | -| Total | 45 | 2,773 | 2,407 | 24 | 340 | +| Markdown | 1 | 126 | 93 | 0 | 33 | +| JSON | 3 | 634 | 631 | 3 | 0 | +| C++ header | 19 | 448 | 345 | 5 | 98 | +| C++ | 17 | 1,279 | 1,083 | 16 | 180 | +| Total | 44 | 2,679 | 2,312 | 24 | 343 | ----------------------------------------------------------- - -real 0m0.013s -user 0m0.011s -sys 0m0.006s - ``` ## Building diff --git a/cli/src/app.cpp b/cli/src/app.cpp index c1243cf..fd751e8 100644 --- a/cli/src/app.cpp +++ b/cli/src/app.cpp @@ -31,10 +31,11 @@ auto App::run(int const argc, char const* const* argv) -> int { auto default_grammars = false; auto const args = std::array{ - clap::option(m_params.sort_by, "s,sort", "sort by COLUMN_NAME (default Lines)"), + clap::option(m_params.sort_column, "c,sort-column", "sort by COLUMN_NAME (default Lines)"), clap::option(m_params.exclude_patterns, "e,exclude", "comma-separated exclude list (will not be counted)"), clap::option(m_params.grammars_json, "g,grammars", "path to JSON containing an array of custom grammars"), clap::option(m_params.thread_count, "t,threads", "number of threads to use"), + clap::flag(m_params.sort_ascending, "a,sort-ascend", "sort in ascending order"), clap::flag(m_params.no_progress, "p,no-progress", "do not print progress while counting"), clap::flag(default_grammars, "default-grammars", "output default grammars as JSON and exit"), clap::flag(m_params.verbose, "v,verbose", "verbose output"), diff --git a/cli/src/counter.cpp b/cli/src/counter.cpp index cbb5611..2a92b43 100644 --- a/cli/src/counter.cpp +++ b/cli/src/counter.cpp @@ -32,7 +32,7 @@ void Counter::run() { if (m_params.verbose) { print_params(); } auto line_counter = m_locc.start_count(m_params.path); - if (line_counter.get_status() == LineCounter::Status::None) { return; } + if (!line_counter || line_counter->get_status() == LineCounter::Status::None) { return; } if (!m_params.no_progress) { std::println(); @@ -41,17 +41,18 @@ void Counter::run() { } if (m_params.no_progress) { - line_counter.wait(); + line_counter->wait(); } else { - print_progress_until_ready(line_counter); + print_progress_until_ready(*line_counter); } - auto rows = line_counter.to_rows(); - auto const sort_by = to_metric(m_params.sort_by); + auto rows = line_counter->to_rows(); + auto const sort_by = to_metric(m_params.sort_column); + auto const sort_dir = m_params.sort_ascending ? SortDir::Ascending : SortDir::Descending; if (sort_by == by_file_type) { - sort_by_file_type(rows); + sort_by_file_type(rows, sort_dir); } else { - sort_by_metric(rows, sort_by); + sort_by_metric(rows, sort_by, sort_dir); } rows.push_back(Row::aggregate(rows)); @@ -61,13 +62,14 @@ void Counter::run() { void Counter::print_params() const { std::println("params:"); auto const print_param = [](std::string_view left, auto const& right) { std::println(" {}: {}", left, right); }; - print_param("sort by\t\t", m_params.sort_by); - print_param("exclude\t\t", m_params.exclude_patterns); - print_param("grammars\t\t", m_params.grammars_json); - print_param("threads\t\t", m_params.thread_count); - print_param("no progress\t\t", m_params.no_progress); - print_param("verbose\t\t", m_params.verbose); - print_param("path\t\t\t", m_params.path); + print_param("sort by\t", m_params.sort_column); + print_param("exclude\t", m_params.exclude_patterns); + print_param("grammars\t", m_params.grammars_json); + print_param("threads\t", m_params.thread_count); + print_param("sort ascend\t", m_params.sort_ascending); + print_param("no progress\t", m_params.no_progress); + print_param("verbose\t", m_params.verbose); + print_param("path\t\t", m_params.path); std::println(); } diff --git a/cli/src/params.hpp b/cli/src/params.hpp index f5f09c1..6ab996d 100644 --- a/cli/src/params.hpp +++ b/cli/src/params.hpp @@ -4,11 +4,12 @@ namespace locc::cli { struct Params { - std::string_view sort_by{}; + std::string_view sort_column{}; std::string_view exclude_patterns{}; std::string_view grammars_json{}; std::uint8_t thread_count{}; + bool sort_ascending{}; bool no_progress{}; bool verbose{}; diff --git a/lib/include/locc/instance.hpp b/lib/include/locc/instance.hpp index b41af96..ec0ad5d 100644 --- a/lib/include/locc/instance.hpp +++ b/lib/include/locc/instance.hpp @@ -14,7 +14,7 @@ class Instance { explicit Instance(ktask::Queue& queue, CreateInfo create_info = {}); - [[nodiscard]] auto start_count(std::string_view path) -> LineCounter; + [[nodiscard]] auto start_count(std::string_view path) -> std::unique_ptr; private: ktask::Queue* m_queue; diff --git a/lib/include/locc/row.hpp b/lib/include/locc/row.hpp index 2666643..d40eb50 100644 --- a/lib/include/locc/row.hpp +++ b/lib/include/locc/row.hpp @@ -4,6 +4,8 @@ #include namespace locc { +enum class SortDir : std::uint8_t { Descending, Ascending }; + struct Row { std::string file_type{}; LineCount line_count{}; @@ -13,6 +15,6 @@ struct Row { [[nodiscard]] auto beautify(std::uint64_t num) -> std::string; -void sort_by_metric(std::span rows, LineCount::Metric metric); -void sort_by_file_type(std::span rows); +void sort_by_metric(std::span rows, LineCount::Metric metric, SortDir dir = SortDir::Descending); +void sort_by_file_type(std::span rows, SortDir dir = SortDir::Descending); } // namespace locc diff --git a/lib/src/instance.cpp b/lib/src/instance.cpp index 9fe8d52..3878795 100644 --- a/lib/src/instance.cpp +++ b/lib/src/instance.cpp @@ -6,12 +6,15 @@ namespace locc { Instance::Instance(ktask::Queue& queue, CreateInfo create_info) : m_queue(&queue), m_grammars(std::move(create_info.grammars)), m_filter(create_info.file_filter) {} -auto Instance::start_count(std::string_view const path) -> LineCounter { +auto Instance::start_count(std::string_view const path) -> std::unique_ptr { + if (m_grammars.empty()) { return {}; } auto const query = Query{ .grammars = m_grammars, .path = path, .filter = m_filter, }; - return LineCounter{*m_queue, query}; + auto ret = std::make_unique(*m_queue, query); + m_queue->enqueue(*ret); + return ret; } } // namespace locc diff --git a/lib/src/row.cpp b/lib/src/row.cpp index 3dbac23..c1e5c4a 100644 --- a/lib/src/row.cpp +++ b/lib/src/row.cpp @@ -4,6 +4,23 @@ #include namespace locc { +namespace { +template