This commit is contained in:
2024-02-04 20:14:31 +08:00
parent 8c6b747fda
commit 63928e86ff
7 changed files with 431 additions and 0 deletions

2
.gitignore vendored
View File

@@ -31,4 +31,6 @@
*.exe *.exe
*.out *.out
*.app *.app
cmake-build-*
.idea

23
CMakeLists.txt Normal file
View File

@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.22)
project(parameter)
set(CMAKE_CXX_STANDARD 17)
include_directories(include)
add_library(order
src/Options.cpp
src/Order.cpp
include/Order.h
)
add_executable(myTest
test_main.cpp
)
enable_testing()
find_package(GTest REQUIRED)
target_link_libraries(myTest PRIVATE GTest::GTest GTest::Main order)
set(GTEST_LIB gtest gtest_main)
add_test(NAME myTest COMMAND myTest)

35
include/Options.h Normal file
View File

@@ -0,0 +1,35 @@
//
// Created by ling on 24-2-4.
//
#ifndef OPTIONS_H
#define OPTIONS_H
#include <string>
#include <vector>
#include <Order.h>
namespace ling {
class Order;
class Options {
private:
Order *ptr = nullptr;
int id;
public:
Options(int id, Order *ptr);
[[nodiscard]] int64_t getInt64() const;
[[nodiscard]] double getDouble() const;
[[nodiscard]] const std::string &getString() const;
[[nodiscard]] bool isOption() const;
[[nodiscard]] bool isExistence() const;
};
} // ling
#endif //OPTIONS_H

86
include/Order.h Normal file
View File

@@ -0,0 +1,86 @@
//
// Created by ling on 24-2-4.
//
#ifndef ORDER_H
#define ORDER_H
#include <Options.h>
#include <unordered_map>
namespace ling {
class Options;
class Order {
public:
enum Type {
OPT,
STRING,
INT,
DOUBLE,
};
private:
struct DataStruct {
std::vector<std::string> options;
int id = 0;
Type type;
std::string memage;
DataStruct(const std::vector<std::string> &option, int id, Type type, const std::string &memage);
DataStruct();
};
std::vector<std::string> cmd;
//选项
std::unordered_map<int, bool> options;
//各种类型的参数
std::unordered_map<int, std::string> opt_str;
std::unordered_map<int, int64_t> opt_int;
std::unordered_map<int, double> opt_double;
//参数类型索引
std::unordered_map<int, Type> type;
//匿名参数
std::vector<std::string> anonymity;
//预定义参数规则
std::unordered_map<std::string, DataStruct> data;
//匿名参数数量
int anonymityNumber = 0;
int nextID = 1;
std::string errStr;
protected:
int64_t getInt64(int id) const;
double getDouble(int id) const;
const std::string &getString(int id) const;
bool getOption(int id) const;
bool isExistence(int id) const;
public:
explicit Order(const std::vector<std::string> &temp);
Options addOption(const std::vector<std::string> &opt, const std::string &message = "");
Options addOption(const std::vector<std::string> &opt, Type type, const std::string &message = "");
/// 添加匿名参数
void addAnonymity(int number);
/// 获取匿名参数列表
const std::vector<std::string> &getAnonymity() const;
/// 解析
void analysis();
friend class Options;
};
} // ling
#endif //ORDER_H

32
src/Options.cpp Normal file
View File

@@ -0,0 +1,32 @@
//
// Created by ling on 24-2-4.
//
#include "Options.h"
namespace ling {
Options::Options(const int id, Order *const ptr) {
this->id = id;
this->ptr = ptr;
}
int64_t Options::getInt64() const {
return ptr->getInt64(id);
}
double Options::getDouble() const {
return ptr->getDouble(id);
}
const std::string &Options::getString() const {
return ptr->getString(id);
}
bool Options::isOption() const {
return ptr->getOption(id);
}
bool Options::isExistence() const {
return ptr->isExistence(id);
}
} // ling

140
src/Order.cpp Normal file
View File

@@ -0,0 +1,140 @@
//
// Created by ling on 24-2-4.
//
#include "../include/Order.h"
#include <stdexcept>
namespace ling {
Order::DataStruct::DataStruct(const std::vector<std::string> &option, const int id, const Type type, const std::string &memage) {
this->options = option;
this->id = id;
this->type = type;
this->memage = memage;
}
Order::DataStruct::DataStruct() = default;
int64_t Order::getInt64(const int id) const {
const auto it = opt_int.find(id);
if (it == opt_int.end()) {
return 0;
}
return it->second;
}
double Order::getDouble(int id) const {
const auto it = opt_double.find(id);
if (it == opt_double.end()) {
return 0;
}
return it->second;
}
const std::string &Order::getString(const int id) const {
const auto it = opt_str.find(id);
if (it == opt_str.end()) {
return errStr;
}
return it->second;
}
bool Order::getOption(const int id) const {
const auto it = options.find(id);
if (it == options.end())
throw std::runtime_error("无效键");
return it->second;
}
bool Order::isExistence(const int id) const {
if (options.find(id) != options.end()) {
return options.find(id)->second;
}
if (opt_int.find(id) != opt_int.end())
return true;
if (opt_double.find(id) != opt_double.end())
return true;
if (opt_str.find(id) != opt_str.end())
return true;
return false;
}
Order::Order(const std::vector<std::string> &temp) {
this->cmd = temp;
}
Options Order::addOption(const std::vector<std::string> &opt, const std::string &message) {
return addOption(opt, OPT, message);
}
Options Order::addOption(const std::vector<std::string> &opt, Type type, const std::string &message) {
const int id = nextID++;
for (const auto &in: opt)
data[in] = DataStruct(opt, id, type, message);
if (type == OPT)
options[id] = false;
return {id, this};
}
void Order::addAnonymity(const int number) {
this->anonymityNumber = number;
}
const std::vector<std::string> &Order::getAnonymity() const {
return anonymity;
}
void Order::analysis() {
for (auto it = cmd.begin(); it != cmd.end(); ++it) {
auto rules = data.find(*it);
if (rules == data.end()) {
//检查匿名参数数量
if (anonymity.size() >= anonymityNumber)
throw std::runtime_error("无法解析的参数:" + *it);
anonymity.push_back(*it);
continue;
}
if (it->at(0) != '-')
throw std::runtime_error("无法解析的参数:" + *it);
switch (rules->second.type) {
case OPT:
if (options[rules->second.id])
throw std::runtime_error("重复提供参数:" + *it);
options[rules->second.id] = true;
break;
case STRING:
if (opt_str.find(rules->second.id) != opt_str.end())
throw std::runtime_error("重复提供参数:" + *it);
if (std::next(it) == cmd.end())
throw std::runtime_error("参数不足!" + *it + " 需要提供参数");
if (std::next(it)->at(0) == '-')
throw std::runtime_error("参数不足!" + *it + " 需要提供参数");
++it;
opt_str[rules->second.id] = *it;
break;
case INT:
if (opt_int.find(rules->second.id) != opt_int.end())
throw std::runtime_error("重复提供参数:" + *it);
if (std::next(it) == cmd.end())
throw std::runtime_error("参数不足!" + *it + " 需要提供参数");
if (std::next(it)->at(0) == '-')
throw std::runtime_error("参数不足!" + *it + " 需要提供参数");
++it;
opt_int[rules->second.id] = std::stoll(*it);
break;
case DOUBLE:
if (opt_double.find(rules->second.id) != opt_double.end())
throw std::runtime_error("重复提供参数:" + *it);
if (std::next(it) == cmd.end())
throw std::runtime_error("参数不足!" + *it + " 需要提供参数");
if (std::next(it)->at(0) == '-')
throw std::runtime_error("参数不足!" + *it + " 需要提供参数");
++it;
opt_double[rules->second.id] = std::stod(*it);
break;
}
}
}
} // ling

113
test_main.cpp Normal file
View File

@@ -0,0 +1,113 @@
//
// Created by ling on 24-2-4.
//
#include <gtest/gtest.h>
#include <Options.h>
#include <Order.h>
TEST(Option, ) {
try {
ling::Order order({"-pts", "--all", "--ok"});
const auto pts = order.addOption({"-pts", "--pts"});
const auto all = order.addOption({"-all", "--all"});
const auto ok = order.addOption({"--ok", "-ok"});
const auto cancel = order.addOption({"--cancel"});
order.analysis();
ASSERT_TRUE(pts.isOption());
ASSERT_TRUE(all.isOption());
ASSERT_TRUE(ok.isOption());
ASSERT_FALSE(cancel.isOption());
} catch (const std::runtime_error &e) {
std::cout << e.what() << std::endl;
ASSERT_FALSE("解析出错!");
}
}
TEST(Option, ) {
try {
ling::Order order({"-pts", "hello world!", "--all", "--ok"});
const auto pts = order.addOption({"-pts", "--pts"}, ling::Order::Type::STRING);
const auto all = order.addOption({"-all", "--all"});
const auto ok = order.addOption({"--ok", "-ok"});
const auto cancel = order.addOption({"--cancel"});
order.analysis();
ASSERT_TRUE(all.isOption());
ASSERT_TRUE(ok.isOption());
ASSERT_FALSE(cancel.isOption());
ASSERT_TRUE(pts.getString() == "hello world!");
} catch (const std::runtime_error &e) {
std::cout << e.what() << std::endl;
ASSERT_FALSE("解析出错!");
}
}
TEST(Option, ) {
try {
ling::Order order({"-pts", "--all", "--ok"});
const auto pts = order.addOption({"-pts", "--pts"}, ling::Order::Type::STRING);
const auto all = order.addOption({"-all", "--all"});
const auto ok = order.addOption({"--ok", "-ok"});
const auto cancel = order.addOption({"--cancel"});
order.analysis();
ASSERT_FALSE("纠正出错!");
} catch (const std::runtime_error &e) {
}
}
TEST(Option, ) {
try {
ling::Order order({"-pts", "hello world!", "hello!", "--all", "--ok"});
order.addAnonymity(1);
const auto pts = order.addOption({"-pts", "--pts"}, ling::Order::Type::STRING);
const auto all = order.addOption({"-all", "--all"});
const auto ok = order.addOption({"--ok", "-ok"});
const auto cancel = order.addOption({"--cancel"});
order.analysis();
ASSERT_TRUE(all.isOption());
ASSERT_TRUE(ok.isOption());
ASSERT_FALSE(cancel.isOption());
ASSERT_TRUE(pts.getString() == "hello world!");
ASSERT_TRUE(order.getAnonymity().size() == 1);
ASSERT_TRUE(order.getAnonymity()[0] == "hello!");
} catch (const std::runtime_error &e) {
std::cout << e.what() << std::endl;
ASSERT_FALSE("解析出错!");
}
}
TEST(Option, 2) {
try {
ling::Order order({"-pts", "hello world!", "hello!", "--all", "--ok", "world"});
order.addAnonymity(2);
const auto pts = order.addOption({"-pts", "--pts"}, ling::Order::Type::STRING);
const auto all = order.addOption({"-all", "--all"});
const auto ok = order.addOption({"--ok", "-ok"});
const auto cancel = order.addOption({"--cancel"});
order.analysis();
ASSERT_TRUE(all.isOption());
ASSERT_TRUE(ok.isOption());
ASSERT_FALSE(cancel.isOption());
ASSERT_TRUE(pts.getString() == "hello world!");
ASSERT_TRUE(order.getAnonymity().size() == 2);
ASSERT_TRUE(order.getAnonymity()[0] == "hello!");
ASSERT_TRUE(order.getAnonymity()[1] == "world");
} catch (const std::runtime_error &e) {
std::cout << e.what() << std::endl;
ASSERT_FALSE("解析出错!");
}
}
TEST(Option, 3) {
try {
ling::Order order({"-pts", "hello world!", "hello!", "--all", "--ok", "world"});
order.addAnonymity(1);
const auto pts = order.addOption({"-pts", "--pts"}, ling::Order::Type::STRING);
const auto all = order.addOption({"-all", "--all"});
const auto ok = order.addOption({"--ok", "-ok"});
const auto cancel = order.addOption({"--cancel"});
order.analysis();
ASSERT_FALSE("匿名参数数量超出限制,但是没有抛出异常!");
} catch (const std::runtime_error &e) {
}
}