Added ProgramArguments util and test; Added ProgramArgument parser to concurrent benchmark tests
This commit is contained in:
parent
b21661191f
commit
228ae4cc72
include/utils/command_line
tests
benchmark/data_structures/concurrent
unit
@ -1,52 +1,158 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "utils/option.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace {
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-function"
|
||||
|
||||
auto all_arguments(int argc, char *argv[])
|
||||
{
|
||||
return std::vector<std::string>(argv + 1, argv + argc);
|
||||
class ProgramArgumentException : public std::exception {
|
||||
public:
|
||||
virtual const char *what() const throw() {
|
||||
return "Invalid Command Line Arguments";
|
||||
}
|
||||
} arg_exception;
|
||||
|
||||
class ProgramArguments {
|
||||
private:
|
||||
std::map<std::string, std::vector<std::string>> arguments_;
|
||||
std::vector<std::string> required_arguments_;
|
||||
std::mutex mutex_;
|
||||
|
||||
bool is_flag(const std::string &arg) { return arg[0] == '-'; }
|
||||
|
||||
bool is_valid() {
|
||||
for (const auto &arg : required_arguments_)
|
||||
for (const auto &a : arguments_)
|
||||
if (!arguments_.count(arg)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
ProgramArguments() {}
|
||||
~ProgramArguments() {}
|
||||
|
||||
public:
|
||||
class Argument {
|
||||
private:
|
||||
std::string arg_;
|
||||
|
||||
public:
|
||||
Argument(const std::string &arg) : arg_(arg) {}
|
||||
std::string GetString() { return arg_; }
|
||||
int GetInteger() { return std::atoi(arg_.c_str()); };
|
||||
float GetFloat() { return std::atof(arg_.c_str()); };
|
||||
long GetLong() { return std::atol(arg_.c_str()); }
|
||||
};
|
||||
|
||||
static ProgramArguments &instance() {
|
||||
static ProgramArguments instance_;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
ProgramArguments(ProgramArguments const &) = delete;
|
||||
ProgramArguments(ProgramArguments &&) = delete;
|
||||
ProgramArguments &operator=(ProgramArguments const &) = delete;
|
||||
ProgramArguments &operator=(ProgramArguments &&) = delete;
|
||||
|
||||
void register_args(int argc, char *argv[]) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string flag(*(argv + i));
|
||||
if (is_flag(flag)) {
|
||||
arguments_[flag] = {};
|
||||
while (i < argc - 1) {
|
||||
i++;
|
||||
std::string arg(*(argv + i));
|
||||
if (!is_flag(arg))
|
||||
arguments_[flag].push_back(arg);
|
||||
else {
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (required_arguments_.empty()) return;
|
||||
|
||||
if (!is_valid()) throw arg_exception;
|
||||
}
|
||||
|
||||
void register_required_args(std::vector<std::string> args) {
|
||||
required_arguments_ = args;
|
||||
|
||||
if (arguments_.empty()) return;
|
||||
|
||||
if (!is_valid()) throw arg_exception;
|
||||
}
|
||||
|
||||
bool contains_flag(const std::string &flag) {
|
||||
return arguments_.count(flag) > 0;
|
||||
}
|
||||
|
||||
auto get_arg(const std::string &flag, const std::string &default_value) {
|
||||
if (contains_flag(flag)) return Argument(arguments_[flag][0]);
|
||||
return Argument(default_value);
|
||||
}
|
||||
|
||||
auto get_arg_list(const std::string &flag,
|
||||
const std::vector<std::string> &default_value) {
|
||||
std::vector<Argument> ret;
|
||||
if (contains_flag(flag)) {
|
||||
for (const auto &arg : arguments_[flag]) ret.emplace_back(arg);
|
||||
} else
|
||||
for (const auto &arg : default_value) ret.emplace_back(arg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
arguments_.clear();
|
||||
required_arguments_.clear();
|
||||
}
|
||||
};
|
||||
|
||||
auto all_arguments(int argc, char *argv[]) {
|
||||
return std::vector<std::string>(argv + 1, argv + argc);
|
||||
}
|
||||
|
||||
bool contains_argument(const std::vector<std::string> &all,
|
||||
const std::string &flag)
|
||||
{
|
||||
return std::find(all.begin(), all.end(), flag) != all.end();
|
||||
const std::string &flag) {
|
||||
return std::find(all.begin(), all.end(), flag) != all.end();
|
||||
}
|
||||
|
||||
// just returns argument value
|
||||
auto get_argument(const std::vector<std::string> &all, const std::string &flag,
|
||||
const std::string &default_value)
|
||||
{
|
||||
auto it = std::find(all.begin(), all.end(), flag);
|
||||
const std::string &default_value) {
|
||||
auto it = std::find(all.begin(), all.end(), flag);
|
||||
|
||||
if (it == all.end()) return default_value;
|
||||
if (it == all.end()) return default_value;
|
||||
|
||||
return all[std::distance(all.begin(), it) + 1];
|
||||
return all[std::distance(all.begin(), it) + 1];
|
||||
}
|
||||
|
||||
// removes argument value from the all vector
|
||||
Option<std::string> take_argument(std::vector<std::string> &all,
|
||||
const std::string &flag)
|
||||
{
|
||||
auto it = std::find(all.begin(), all.end(), flag);
|
||||
const std::string &flag) {
|
||||
auto it = std::find(all.begin(), all.end(), flag);
|
||||
|
||||
if (it == all.end()) return make_option<std::string>();
|
||||
if (it == all.end()) return make_option<std::string>();
|
||||
|
||||
auto s = std::string(all[std::distance(all.begin(), it) + 1]);
|
||||
it++;
|
||||
it++;
|
||||
all.erase(std::find(all.begin(), all.end(), flag), it);
|
||||
auto s = std::string(all[std::distance(all.begin(), it) + 1]);
|
||||
it++;
|
||||
it++;
|
||||
all.erase(std::find(all.begin(), all.end(), flag), it);
|
||||
|
||||
return make_option<std::string>(std::move(s));
|
||||
return make_option<std::string>(std::move(s));
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
@ -107,15 +107,20 @@ auto BM_ContainsValue = [](benchmark::State& state, auto* map, auto elements) {
|
||||
-string-length number
|
||||
*/
|
||||
void parse_arguments(int argc, char** argv) {
|
||||
auto para = all_arguments(argc, argv);
|
||||
ProgramArguments::instance().register_args(argc, argv);
|
||||
|
||||
RANGE_START = std::stoi(get_argument(para, "-start", "0"));
|
||||
RANGE_END = std::stoi(get_argument(para, "-end", "1000000000"));
|
||||
RANGE_START =
|
||||
ProgramArguments::instance().get_arg("-start", "0").GetInteger();
|
||||
RANGE_END =
|
||||
ProgramArguments::instance().get_arg("-end", "1000000000").GetInteger();
|
||||
|
||||
THREADS = std::min(std::stoi(get_argument(para, "-threads", "1")),
|
||||
(int)std::thread::hardware_concurrency());
|
||||
THREADS = std::min(
|
||||
ProgramArguments::instance().get_arg("-threads", "1").GetInteger(),
|
||||
(int)std::thread::hardware_concurrency());
|
||||
|
||||
STRING_LENGTH = std::stoi(get_argument(para, "-string-length", "128"));
|
||||
STRING_LENGTH = ProgramArguments::instance()
|
||||
.get_arg("-string-length", "128")
|
||||
.GetInteger();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
@ -36,11 +36,10 @@ static void Rape(benchmark::State& state, ConcurrentMap<int, int>* map,
|
||||
auto accessor = map->access();
|
||||
|
||||
for (int start = 0; start < state.range(0); start++) {
|
||||
float current_percentage = (float)start / (float)number_of_elements;
|
||||
if (current_percentage * 100 < (float)INSERT_PERC) {
|
||||
float current_percentage = (float)start / (float)number_of_elements * 100;
|
||||
if (current_percentage < (float)INSERT_PERC) {
|
||||
accessor.insert(elements[start].first, elements[start].second);
|
||||
} else if (current_percentage * 100 <
|
||||
(float)CONTAINS_PERC + INSERT_PERC) {
|
||||
} else if (current_percentage < (float)CONTAINS_PERC + INSERT_PERC) {
|
||||
accessor.contains(elements[start].first);
|
||||
} else {
|
||||
accessor.remove(elements[start].first);
|
||||
@ -78,11 +77,14 @@ auto BM_Rape = [](benchmark::State& state, auto* map, auto& elements) {
|
||||
-threads number
|
||||
*/
|
||||
void parse_arguments(int argc, char** argv) {
|
||||
auto para = all_arguments(argc, argv);
|
||||
ProgramArguments::instance().register_args(argc, argv);
|
||||
|
||||
INSERT_PERC = std::stoi(get_argument(para, "-insert", "50"));
|
||||
DELETE_PERC = std::stoi(get_argument(para, "-delete", "20"));
|
||||
CONTAINS_PERC = std::stoi(get_argument(para, "-find", "30"));
|
||||
INSERT_PERC =
|
||||
ProgramArguments::instance().get_arg("-insert", "50").GetInteger();
|
||||
DELETE_PERC =
|
||||
ProgramArguments::instance().get_arg("-delete", "20").GetInteger();
|
||||
CONTAINS_PERC =
|
||||
ProgramArguments::instance().get_arg("-find", "30").GetInteger();
|
||||
|
||||
if (INSERT_PERC + DELETE_PERC + CONTAINS_PERC != 100) {
|
||||
std::cout << "Invalid percentage" << std::endl;
|
||||
@ -90,12 +92,15 @@ void parse_arguments(int argc, char** argv) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
RANGE_START = std::stoi(get_argument(para, "-start", "0"));
|
||||
RANGE_END = std::stoi(get_argument(para, "-end", "1000000000"));
|
||||
RANGE_START =
|
||||
ProgramArguments::instance().get_arg("-start", "0").GetInteger();
|
||||
|
||||
std::cout << "start" << RANGE_START << std::endl;
|
||||
THREADS = std::min(std::stoi(get_argument(para, "-threads", "1")),
|
||||
(int)std::thread::hardware_concurrency());
|
||||
RANGE_END =
|
||||
ProgramArguments::instance().get_arg("-end", "1000000000").GetInteger();
|
||||
|
||||
THREADS = std::min(
|
||||
ProgramArguments::instance().get_arg("-threads", "1").GetInteger(),
|
||||
(int)std::thread::hardware_concurrency());
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
95
tests/unit/program_argument.cpp
Normal file
95
tests/unit/program_argument.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "utils/command_line/arguments.hpp"
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wwritable-strings"
|
||||
|
||||
TEST_CASE("ProgramArgument FlagOnly Test") {
|
||||
ProgramArguments::instance().clear();
|
||||
|
||||
int argc = 2;
|
||||
|
||||
char* argv[] = {"ProgramArgument FlagOnly Test", "-test"};
|
||||
|
||||
ProgramArguments::instance().register_args(argc, argv);
|
||||
ProgramArguments::instance().register_required_args({"-test"});
|
||||
|
||||
REQUIRE(ProgramArguments::instance().contains_flag("-test") == true);
|
||||
}
|
||||
|
||||
TEST_CASE("ProgramArgument Single Entry Test") {
|
||||
ProgramArguments::instance().clear();
|
||||
|
||||
int argc = 3;
|
||||
|
||||
char* argv[] = {"ProgramArgument Single Entry Test", "-bananas", "99"};
|
||||
|
||||
ProgramArguments::instance().register_required_args({"-bananas"});
|
||||
ProgramArguments::instance().register_args(argc, argv);
|
||||
|
||||
REQUIRE(
|
||||
ProgramArguments::instance().get_arg("-bananas", "100").GetInteger() ==
|
||||
99);
|
||||
}
|
||||
|
||||
TEST_CASE("ProgramArgument Multiple Entries Test") {
|
||||
ProgramArguments::instance().clear();
|
||||
|
||||
int argc = 4;
|
||||
|
||||
char* argv[] = {"ProgramArgument Multiple Entries Test", "-files",
|
||||
"first_file.txt", "second_file.txt"};
|
||||
|
||||
ProgramArguments::instance().register_args(argc, argv);
|
||||
|
||||
auto files = ProgramArguments::instance().get_arg_list("-files", {});
|
||||
|
||||
REQUIRE(files[0].GetString() == "first_file.txt");
|
||||
}
|
||||
|
||||
TEST_CASE("ProgramArgument Combination Test") {
|
||||
ProgramArguments::instance().clear();
|
||||
|
||||
int argc = 14;
|
||||
|
||||
char* argv[] = {"ProgramArgument Combination Test",
|
||||
"-run_tests",
|
||||
"-tests",
|
||||
"Test1",
|
||||
"Test2",
|
||||
"Test3",
|
||||
"-run_times",
|
||||
"10",
|
||||
"-export",
|
||||
"test1.txt",
|
||||
"test2.txt",
|
||||
"test3.txt",
|
||||
"-import",
|
||||
"data.txt"};
|
||||
|
||||
ProgramArguments::instance().register_args(argc, argv);
|
||||
|
||||
REQUIRE(ProgramArguments::instance().contains_flag("-run_tests") == true);
|
||||
|
||||
auto tests = ProgramArguments::instance().get_arg_list("-tests", {});
|
||||
REQUIRE(tests[0].GetString() == "Test1");
|
||||
REQUIRE(tests[1].GetString() == "Test2");
|
||||
REQUIRE(tests[2].GetString() == "Test3");
|
||||
|
||||
REQUIRE(
|
||||
ProgramArguments::instance().get_arg("-run_times", "0").GetInteger() ==
|
||||
10);
|
||||
|
||||
auto exports = ProgramArguments::instance().get_arg_list("-export", {});
|
||||
REQUIRE(exports[0].GetString() == "test1.txt");
|
||||
REQUIRE(exports[1].GetString() == "test2.txt");
|
||||
REQUIRE(exports[2].GetString() == "test3.txt");
|
||||
|
||||
REQUIRE(
|
||||
ProgramArguments::instance().get_arg("-import", "test.txt").GetString() ==
|
||||
"data.txt");
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
Loading…
Reference in New Issue
Block a user