No longer depend on Boost.program_options.

This commit is contained in:
2019-09-25 12:56:57 +02:00
parent 90b067ce0d
commit 5b91fd4da3
3 changed files with 74 additions and 29 deletions

View File

@@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.12)
project(aoc2019)
find_package(Boost REQUIRED COMPONENTS program_options)
find_package(GTest REQUIRED)
add_library(AoCSolutions src/implementations.hpp src/implementations.cpp src/day01.cpp src/days.hpp)
@@ -10,7 +9,7 @@ target_compile_features(AoCSolutions PUBLIC cxx_std_17)
add_executable(runner src/runner.cpp)
target_compile_features(runner PUBLIC cxx_std_17)
target_link_libraries(runner AoCSolutions Boost::program_options)
target_link_libraries(runner AoCSolutions)
add_executable(unit_tests tests/test_solutions.cpp)
target_compile_features(unit_tests PUBLIC cxx_std_17)

View File

@@ -14,7 +14,6 @@ Install the dependencies:
by default tries to dynamically link GTest, and the Ubuntu packages
only provide a statically linked archive. You may need to compile it
for yourself.
- [Boost.Program_options](https://www.boost.org/doc/libs/1_71_0/doc/html/program_options.html)
```
mkdir build && cd build

View File

@@ -1,45 +1,92 @@
#include "implementations.hpp"
#include <charconv>
#include <chrono>
#include <iostream>
#include <boost/program_options.hpp>
namespace po = boost::program_options;
struct AoCOptions {
aoc2019::solution_t implementation;
bool run_timer;
};
static AoCOptions parse_options(const int argc, const char *argv[]) {
static AoCOptions parse_options(const int argc, const char* argv[]) {
using namespace std::string_view_literals;
AoCOptions options{};
int day;
bool part2;
po::options_description desc("Allowed options");
desc.add_options()
("day", po::value<int>(&day)->required(), "The day to run.")
("part2,2", po::bool_switch(&part2), "Whether to run part 2.")
("timer,t", po::bool_switch(&options.run_timer), "Show the execution time.");
po::positional_options_description positionals;
positionals.add("day", 1);
auto show_help = [argv] (int exit_status = 0) {
std::cerr << "Usage: " << argv[0] << " [--timer|-t] [--part2|-2] [--help|-h] DAY\n"
<< "\t--timer|-t: print execution time\n"
<< "\t--part2|-2: run part 2\n"
<< "\t --help|-h: show this message\n";
std::exit(exit_status);
};
try {
po::variables_map vm;
int day = -1;
bool part2 = false;
po::store(po::command_line_parser(argc, argv).options(desc).positional(positionals).run(), vm);
po::notify(vm);
// Here follows a manual implementation of getopt, since getopt doesn't work on windows…
for (int i = 1; i < argc; ++i) {
std::string_view arg(argv[i]);
if (arg[0] == '-') {
// Handle flag arguments
if (arg[1] != '-') {
// Shorthand flags
for (char c : arg.substr(1)) {
switch (c) {
case '2':
part2 = true;
break;
options.implementation = aoc2019::get_implementation(day, part2);
case 't':
options.run_timer = true;
break;
return options;
} catch (po::error &argument_error) {
std::cerr << argument_error.what() << std::endl;
std::exit(1);
} catch (std::out_of_range &) {
std::cerr << "Invalid day: " << day
<< ".\n Valid range: [1, 25].\n";
std::exit(1);
case 'h':
show_help();
break;
default:
std::cerr << "Unknown flag '" << c << "'.\n\n";
show_help(1);
}
}
} else {
// Handle long form versions
if (arg == "--timer"sv) {
part2 = true;
} else if (arg == "--timer"sv) {
options.run_timer = true;
} else if (arg == "--help"sv) {
show_help();
} else {
show_help(1);
}
}
} else {
if (day != -1) {
// Double date specification, bail.
show_help(1);
}
// Try to parse the date number
if (auto res = std::from_chars(arg.data(), arg.data() + arg.size(), day); res.ec != std::errc()) {
auto error_code = std::make_error_code(res.ec);
std::cerr << error_code.message() << "\n\n";
show_help(1);
}
}
}
if (day == -1) {
std::cerr << "Argument DAY is required.\n\n";
show_help(1);
} else if (day < 1 || day > 25) {
std::cerr << "Invalid day. Valid range: [1, 25]\n";
show_help(1);
}
options.implementation = aoc2019::get_implementation(day, part2);
return options;
}
int main(int argc, const char *argv[]) {