Use threads if more than one input file is searched.
Use 75% of the available threads (rounded up). Closes: #4
This commit is contained in:
parent
554caebcef
commit
fc0aa02bc9
|
@ -38,6 +38,7 @@ if(NOT termcolor_FOUND)
|
||||||
message(FATAL_ERROR "Termcolor was not found.")
|
message(FATAL_ERROR "Termcolor was not found.")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,9 @@ target_link_libraries(${PROJECT_NAME}_lib
|
||||||
Boost::regex
|
Boost::regex
|
||||||
std::filesystem
|
std::filesystem
|
||||||
fmt::fmt
|
fmt::fmt
|
||||||
termcolor::termcolor)
|
termcolor::termcolor
|
||||||
|
Threads::Threads
|
||||||
|
m)
|
||||||
|
|
||||||
if(${CMAKE_VERSION} VERSION_LESS 3.17)
|
if(${CMAKE_VERSION} VERSION_LESS 3.17)
|
||||||
target_link_libraries(${PROJECT_NAME}_lib
|
target_link_libraries(${PROJECT_NAME}_lib
|
||||||
|
|
199
src/main.cpp
199
src/main.cpp
|
@ -21,16 +21,21 @@
|
||||||
#include <boost/locale/message.hpp>
|
#include <boost/locale/message.hpp>
|
||||||
#include <boost/program_options/errors.hpp>
|
#include <boost/program_options/errors.hpp>
|
||||||
#include <boost/program_options/variables_map.hpp>
|
#include <boost/program_options/variables_map.hpp>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <fmt/ostream.h> // For compatibility with fmt 4.
|
||||||
#include <termcolor/termcolor.hpp>
|
#include <termcolor/termcolor.hpp>
|
||||||
|
|
||||||
#include <clocale>
|
#include <clocale>
|
||||||
|
#include <cmath>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
#include <future>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <typeinfo>
|
#include <string_view>
|
||||||
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
@ -39,8 +44,11 @@ int main(int argc, char *argv[])
|
||||||
using namespace epubgrep;
|
using namespace epubgrep;
|
||||||
|
|
||||||
using boost::locale::translate;
|
using boost::locale::translate;
|
||||||
|
using fmt::format;
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::cout;
|
using std::cout;
|
||||||
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
// locale_generator("").name.c_str() returns "*" instead of "". That's why
|
// locale_generator("").name.c_str() returns "*" instead of "". That's why
|
||||||
// the global C locale isn't changed. So we have to set it additionally.
|
// the global C locale isn't changed. So we have to set it additionally.
|
||||||
|
@ -74,84 +82,143 @@ int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
cout << "NO INPUT FILE\n";
|
cout << "NO INPUT FILE\n";
|
||||||
// TODO: Read data from stdin.
|
// TODO: Read data from stdin.
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
search::options opts;
|
|
||||||
if (vm.count("basic-regexp") > 0)
|
|
||||||
{
|
|
||||||
opts.regex = search::regex_kind::basic;
|
|
||||||
}
|
|
||||||
if (vm.count("extended-regexp") > 0)
|
|
||||||
{
|
|
||||||
opts.regex = search::regex_kind::extended;
|
|
||||||
}
|
|
||||||
if (vm.count("perl-regexp") > 0)
|
|
||||||
{
|
|
||||||
opts.regex = search::regex_kind::perl;
|
|
||||||
}
|
|
||||||
if (vm.count("grep") > 0)
|
|
||||||
{
|
|
||||||
opts.grep_like = true;
|
|
||||||
}
|
|
||||||
if (vm.count("ignore-case") > 0)
|
|
||||||
{
|
|
||||||
opts.ignore_case = true;
|
|
||||||
}
|
|
||||||
if (vm.count("raw") > 0)
|
|
||||||
{
|
|
||||||
opts.raw = true;
|
|
||||||
}
|
|
||||||
opts.context = vm["context"].as<std::uint64_t>();
|
|
||||||
|
|
||||||
for (const auto &filepath :
|
int return_code{EXIT_SUCCESS};
|
||||||
vm["input-file"].as<std::vector<std::string>>())
|
|
||||||
|
search::options opts;
|
||||||
|
if (vm.count("basic-regexp") > 0)
|
||||||
|
{
|
||||||
|
opts.regex = search::regex_kind::basic;
|
||||||
|
}
|
||||||
|
if (vm.count("extended-regexp") > 0)
|
||||||
|
{
|
||||||
|
opts.regex = search::regex_kind::extended;
|
||||||
|
}
|
||||||
|
if (vm.count("perl-regexp") > 0)
|
||||||
|
{
|
||||||
|
opts.regex = search::regex_kind::perl;
|
||||||
|
}
|
||||||
|
if (vm.count("grep") > 0)
|
||||||
|
{
|
||||||
|
opts.grep_like = true;
|
||||||
|
}
|
||||||
|
if (vm.count("ignore-case") > 0)
|
||||||
|
{
|
||||||
|
opts.ignore_case = true;
|
||||||
|
}
|
||||||
|
if (vm.count("raw") > 0)
|
||||||
|
{
|
||||||
|
opts.raw = true;
|
||||||
|
}
|
||||||
|
opts.context = vm["context"].as<std::uint64_t>();
|
||||||
|
|
||||||
|
vector<vector<search::match>> matches_all;
|
||||||
|
vector<std::future<int>> futurepool;
|
||||||
|
|
||||||
|
auto search_file{
|
||||||
|
[&vm, &matches_all, &opts](std::string_view filepath)
|
||||||
{
|
{
|
||||||
for (const auto ®ex :
|
for (const auto ®ex : vm["regexp"].as<vector<string>>())
|
||||||
vm["regexp"].as<std::vector<std::string>>())
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
for (const auto &match :
|
matches_all.emplace_back(
|
||||||
search::search(filepath, regex, opts))
|
search::search(filepath, regex, opts));
|
||||||
{
|
|
||||||
if (vm.count("no-filename") == 0)
|
|
||||||
{
|
|
||||||
cout << match.filepath;
|
|
||||||
}
|
|
||||||
if (!match.headline.empty())
|
|
||||||
{
|
|
||||||
if (vm.count("no-filename") == 0)
|
|
||||||
{
|
|
||||||
cout << ", ";
|
|
||||||
}
|
|
||||||
cout << match.headline;
|
|
||||||
}
|
|
||||||
if (!match.page.empty())
|
|
||||||
{
|
|
||||||
cout << ", page " << match.page;
|
|
||||||
}
|
|
||||||
cout << ": " << match.context.first;
|
|
||||||
if (vm.count("nocolor") == 0)
|
|
||||||
{
|
|
||||||
cout << termcolor::bright_magenta << match.text
|
|
||||||
<< termcolor::reset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cout << match.text;
|
|
||||||
}
|
|
||||||
cout << match.context.second << '\n';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{ // Unknown errors.
|
{ // Unknown errors.
|
||||||
cerr << '\n' << translate("ERROR: ") << e.what() << '\n';
|
cerr << '\n' << translate("ERROR: ") << e.what() << '\n';
|
||||||
cerr << translate("Error while searching.") << '\n';
|
cerr << format(translate("Error while searching {0:s}.")
|
||||||
// NOTE: Maybe we should continue with the next regex/file?
|
.str()
|
||||||
|
.data(),
|
||||||
|
filepath)
|
||||||
|
<< '\n';
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}};
|
||||||
|
|
||||||
|
auto futures_cleanup{
|
||||||
|
[&futurepool, &return_code](const bool wait = false)
|
||||||
|
{
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
for (auto it{futurepool.begin()}; it != futurepool.end();)
|
||||||
|
{
|
||||||
|
if (!wait && it->wait_for(100ms) != std::future_status::ready)
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (int ret{}; (ret = it->get()) != EXIT_SUCCESS)
|
||||||
|
{
|
||||||
|
cerr << "ERROR\n";
|
||||||
|
return_code = ret;
|
||||||
|
}
|
||||||
|
futurepool.erase(it);
|
||||||
|
cerr << "ERASED\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}};
|
||||||
|
|
||||||
|
const auto max_threads{
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
auto n{static_cast<double>(std::thread::hardware_concurrency())};
|
||||||
|
return static_cast<std::uint32_t>(std::ceil(n / 2 + n / 4));
|
||||||
|
}()};
|
||||||
|
|
||||||
|
for (const auto &filepath : vm["input-file"].as<vector<string>>())
|
||||||
|
{
|
||||||
|
if (futurepool.size() >= max_threads)
|
||||||
|
{
|
||||||
|
futures_cleanup();
|
||||||
|
}
|
||||||
|
futurepool.emplace_back(
|
||||||
|
std::async(std::launch::async, search_file, filepath));
|
||||||
|
cerr << "EMPLACED\n";
|
||||||
|
}
|
||||||
|
futures_cleanup(true);
|
||||||
|
|
||||||
|
for (const auto &matches_file : matches_all)
|
||||||
|
{
|
||||||
|
for (const auto &match : matches_file)
|
||||||
|
{
|
||||||
|
if (vm.count("no-filename") == 0)
|
||||||
|
{
|
||||||
|
cout << match.filepath;
|
||||||
|
}
|
||||||
|
if (!match.headline.empty())
|
||||||
|
{
|
||||||
|
if (vm.count("no-filename") == 0)
|
||||||
|
{
|
||||||
|
cout << ", ";
|
||||||
|
}
|
||||||
|
cout << match.headline;
|
||||||
|
}
|
||||||
|
if (!match.page.empty())
|
||||||
|
{
|
||||||
|
cout << ", page " << match.page;
|
||||||
|
}
|
||||||
|
cout << ": " << match.context.first;
|
||||||
|
if (vm.count("nocolor") == 0)
|
||||||
|
{
|
||||||
|
cout << termcolor::bright_magenta << match.text
|
||||||
|
<< termcolor::reset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cout << match.text;
|
||||||
|
}
|
||||||
|
cout << match.context.second << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return return_code;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue