feat: add arg parser feature but not finished
This commit is contained in:
parent
f997990af6
commit
35318505e4
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.23)
|
||||
project(YYCC
|
||||
VERSION 1.1.0
|
||||
VERSION 1.2.0
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
|
|
204
src/ArgParser.cpp
Normal file
204
src/ArgParser.cpp
Normal file
|
@ -0,0 +1,204 @@
|
|||
#include "ArgParser.hpp"
|
||||
|
||||
#include "EncodingHelper.hpp"
|
||||
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
#include "WinImportPrefix.hpp"
|
||||
#include <Windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <processenv.h>
|
||||
#include "WinImportSuffix.hpp"
|
||||
#endif
|
||||
|
||||
namespace YYCC::ArgParser {
|
||||
|
||||
#pragma region Arguments List
|
||||
|
||||
ArgumentList ArgumentList::CreateFromStd(int argc, char* argv[]) {
|
||||
std::vector<yycc_u8string> args;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (argv[i] != nullptr)
|
||||
args.emplace_back(yycc_u8string(YYCC::EncodingHelper::ToUTF8(argv[i])));
|
||||
}
|
||||
return ArgumentList(std::move(args));
|
||||
}
|
||||
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
ArgumentList ArgumentList::CreateFromWin32() {
|
||||
// Reference: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw
|
||||
|
||||
// prepare list
|
||||
std::vector<yycc_u8string> args;
|
||||
|
||||
// try fetching from Win32 functions
|
||||
int argc;
|
||||
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
if (argv != NULL) {
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (argv[i] != nullptr) {
|
||||
yycc_u8string u8_argv;
|
||||
if (YYCC::EncodingHelper::WcharToUTF8(argv[i], u8_argv))
|
||||
args.emplace_back(std::move(u8_argv));
|
||||
}
|
||||
}
|
||||
}
|
||||
LocalFree(argv);
|
||||
|
||||
// return result
|
||||
return ArgumentList(std::move(args));
|
||||
}
|
||||
#endif
|
||||
|
||||
ArgumentList::ArgumentList(std::vector<yycc_u8string>&& arguments) :
|
||||
m_Arguments(arguments), m_ArgumentsIterator(m_Arguments.begin()) {}
|
||||
|
||||
void ArgumentList::Prev() {
|
||||
if (m_ArgumentsIterator == m_Arguments.begin())
|
||||
throw std::runtime_error("attempt to move on the head of iterator.");
|
||||
--m_ArgumentsIterator;
|
||||
}
|
||||
|
||||
void ArgumentList::Next() {
|
||||
if (IsEOF()) throw std::runtime_error("attempt to move on the tail of iterator.");
|
||||
++m_ArgumentsIterator;
|
||||
}
|
||||
|
||||
static bool IsLongName(const yycc_u8string& param, yycc_u8string_view* name_part) {
|
||||
if (param.find(AbstractArgument::DOUBLE_DASH) != 0u) return false;
|
||||
if (name_part != nullptr)
|
||||
*name_part = yycc_u8string_view(param).substr(2u);
|
||||
return true;
|
||||
}
|
||||
static bool IsShortName(const yycc_u8string& param, yycc_char8_t* name_part) {
|
||||
if (param.size() != 2u ||
|
||||
param[0] != AbstractArgument::DASH ||
|
||||
param[1] == AbstractArgument::DASH ||
|
||||
param[1] < AbstractArgument::MIN_SHORT_NAME || param[1] > AbstractArgument::MAX_SHORT_NAME) {
|
||||
return false;
|
||||
}
|
||||
if (name_part != nullptr)
|
||||
*name_part = param[1];
|
||||
return true;
|
||||
}
|
||||
bool ArgumentList::IsSwitch(
|
||||
bool* is_long_name = nullptr,
|
||||
yycc_u8string_view* long_name = nullptr,
|
||||
yycc_char8_t* short_name = nullptr) const {
|
||||
// get argument first
|
||||
if (IsEOF()) throw std::runtime_error("attempt to fetch data on the tail of iterator.");
|
||||
const auto& param = *m_ArgumentsIterator;
|
||||
// check long name first, then check short name
|
||||
if (IsLongName(param, long_name)) {
|
||||
if (is_long_name != nullptr) *is_long_name = true;
|
||||
return true;
|
||||
}
|
||||
if (IsShortName(param, short_name)) {
|
||||
if (is_long_name != nullptr) *is_long_name = false;
|
||||
return true;
|
||||
}
|
||||
// not matched
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ArgumentList::IsValue() const { return !IsSwitch(); }
|
||||
|
||||
bool ArgumentList::IsEOF() const { return m_ArgumentsIterator == m_Arguments.end(); }
|
||||
|
||||
void ArgumentList::Reset() { m_ArgumentsIterator = m_Arguments.begin(); }
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Abstract Argument
|
||||
|
||||
const yycc_u8string AbstractArgument::DOUBLE_DASH = YYCC_U8("--");
|
||||
const yycc_char8_t AbstractArgument::DASH = YYCC_U8_CHAR('-');
|
||||
const yycc_char8_t AbstractArgument::NO_SHORT_NAME = YYCC_U8_CHAR(0);
|
||||
const yycc_char8_t AbstractArgument::MIN_SHORT_NAME = YYCC_U8_CHAR('!');
|
||||
const yycc_char8_t AbstractArgument::MAX_SHORT_NAME = YYCC_U8_CHAR('~');
|
||||
|
||||
AbstractArgument::AbstractArgument(
|
||||
const yycc_char8_t* long_name, yycc_char8_t short_name,
|
||||
const yycc_char8_t* description, const yycc_char8_t* argument_example,
|
||||
bool is_optional) :
|
||||
m_LongName(), m_ShortName(NO_SHORT_NAME), m_Description(), m_ArgumentExample(),
|
||||
m_IsOptional(is_optional), m_IsCaptured(false) {
|
||||
|
||||
// try to assign long name
|
||||
if (long_name != nullptr) m_LongName = long_name;
|
||||
// try to assign short name
|
||||
if (short_name == AbstractArgument::DASH ||
|
||||
short_name < AbstractArgument::MIN_SHORT_NAME ||
|
||||
short_name > AbstractArgument::MAX_SHORT_NAME) {
|
||||
throw std::invalid_argument("given short name character is invalid.");
|
||||
}
|
||||
m_ShortName = short_name;
|
||||
// check short name and long name
|
||||
if (!HasShortName() && !HasLongName())
|
||||
throw std::invalid_argument("you must specify an one of long name or short name.");
|
||||
|
||||
// try to assign other string values
|
||||
if (description != nullptr) m_Description = description;
|
||||
if (argument_example != nullptr) m_ArgumentExample = argument_example;
|
||||
}
|
||||
|
||||
AbstractArgument::~AbstractArgument() {}
|
||||
|
||||
bool AbstractArgument::HasLongName() const { return !m_LongName.empty(); }
|
||||
const yycc_u8string& AbstractArgument::GetLongName() const { return m_LongName; }
|
||||
bool AbstractArgument::HasShortName() const { return m_ShortName != NO_SHORT_NAME; }
|
||||
yycc_char8_t AbstractArgument::GetShortName() const { return m_ShortName; }
|
||||
bool AbstractArgument::HasDescription() const { return !m_Description.empty(); }
|
||||
const yycc_u8string& AbstractArgument::GetDescription() const { return m_Description; }
|
||||
bool AbstractArgument::HasArgumentExample() const { return !m_ArgumentExample.empty(); }
|
||||
const yycc_u8string& AbstractArgument::GetArgumentExample() const { return m_ArgumentExample; }
|
||||
bool AbstractArgument::IsOptional() const { return m_IsOptional; }
|
||||
|
||||
bool AbstractArgument::IsCaptured() const { return m_IsCaptured; }
|
||||
void AbstractArgument::SetCaptured(bool is_captured) { m_IsCaptured = is_captured; }
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Option Context
|
||||
|
||||
OptionContext::OptionContext(
|
||||
const yycc_char8_t* summary, const yycc_char8_t* description,
|
||||
std::initializer_list<AbstractArgument*> arguments) :
|
||||
m_Summary(), m_Description() {
|
||||
// assign summary and description
|
||||
if (summary != nullptr) m_Summary = summary;
|
||||
if (description != nullptr) m_Description = description;
|
||||
|
||||
// insert argument list and check them
|
||||
for (auto* arg : arguments) {
|
||||
// insert into long name map if necessary
|
||||
if (arg->HasLongName()) {
|
||||
auto result = m_LongNameMap.try_emplace(arg->GetLongName(), arg);
|
||||
if (!result.second) throw std::invalid_argument("duplicated long name!");
|
||||
}
|
||||
// insert into short name map if necessary
|
||||
if (arg->HasShortName()) {
|
||||
auto result = m_ShortNameMap.try_emplace(arg->GetShortName(), arg);
|
||||
if (!result.second) throw std::invalid_argument("duplicated short name!");
|
||||
}
|
||||
// insert into argument list
|
||||
m_Arguments.emplace_back(arg);
|
||||
}
|
||||
}
|
||||
|
||||
OptionContext::~OptionContext() {}
|
||||
|
||||
bool OptionContext::Parse(ArgumentList* al) {
|
||||
return false; //todo
|
||||
}
|
||||
|
||||
void OptionContext::Reset() {
|
||||
for (auto* arg : m_Arguments) {
|
||||
// clear user data and unset captured
|
||||
arg->Reset();
|
||||
arg->SetCaptured(false);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
}
|
176
src/ArgParser.hpp
Normal file
176
src/ArgParser.hpp
Normal file
|
@ -0,0 +1,176 @@
|
|||
#pragma once
|
||||
#include "YYCCInternal.hpp"
|
||||
|
||||
#include "Constraints.hpp"
|
||||
#include "EncodingHelper.hpp"
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace YYCC::ArgParser {
|
||||
|
||||
class ArgumentList {
|
||||
public:
|
||||
static ArgumentList CreateFromStd(int argc, char* argv[]);
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
static ArgumentList CreateFromWin32();
|
||||
#endif
|
||||
private:
|
||||
ArgumentList(std::vector<yycc_u8string>&& arguments);
|
||||
|
||||
public:
|
||||
void Prev();
|
||||
void Next();
|
||||
bool IsSwitch(
|
||||
bool* is_long_name = nullptr,
|
||||
yycc_u8string_view* long_name = nullptr,
|
||||
yycc_char8_t* short_name = nullptr) const;
|
||||
bool IsValue() const;
|
||||
bool IsEOF() const;
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
std::vector<yycc_u8string> m_Arguments;
|
||||
std::vector<yycc_u8string>::const_iterator m_ArgumentsIterator;
|
||||
};
|
||||
|
||||
class AbstractArgument {
|
||||
friend class OptionContext;
|
||||
public:
|
||||
static const yycc_u8string DOUBLE_DASH;
|
||||
static const yycc_char8_t DASH;
|
||||
static const yycc_char8_t NO_SHORT_NAME;
|
||||
static const yycc_char8_t MIN_SHORT_NAME;
|
||||
static const yycc_char8_t MAX_SHORT_NAME;
|
||||
public:
|
||||
AbstractArgument(
|
||||
const yycc_char8_t* long_name, yycc_char8_t short_name = AbstractArgument::NO_SHORT_NAME,
|
||||
const yycc_char8_t* description = nullptr, const yycc_char8_t* argument_example = nullptr,
|
||||
bool is_optional = false);
|
||||
virtual ~AbstractArgument();
|
||||
|
||||
protected:
|
||||
virtual bool Parse(ArgumentList& al) = 0;
|
||||
virtual void Reset() = 0;
|
||||
|
||||
public:
|
||||
bool HasLongName() const;
|
||||
const yycc_u8string& GetLongName() const;
|
||||
bool HasShortName() const;
|
||||
yycc_char8_t GetShortName() const;
|
||||
bool HasDescription() const;
|
||||
const yycc_u8string& GetDescription() const;
|
||||
bool HasArgumentExample() const;
|
||||
const yycc_u8string& GetArgumentExample() const;
|
||||
bool IsOptional() const;
|
||||
private:
|
||||
yycc_u8string m_LongName;
|
||||
yycc_char8_t m_ShortName;
|
||||
yycc_u8string m_Description;
|
||||
yycc_u8string m_ArgumentExample;
|
||||
bool m_IsOptional;
|
||||
|
||||
public:
|
||||
bool IsCaptured() const;
|
||||
private:
|
||||
void SetCaptured(bool is_captured);
|
||||
bool m_IsCaptured;
|
||||
};
|
||||
|
||||
class OptionContext {
|
||||
public:
|
||||
OptionContext(
|
||||
const yycc_char8_t* summary, const yycc_char8_t* description,
|
||||
std::initializer_list<AbstractArgument*> arguments);
|
||||
~OptionContext();
|
||||
|
||||
public:
|
||||
bool Parse(ArgumentList* al);
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
yycc_u8string m_Summary;
|
||||
yycc_u8string m_Description;
|
||||
|
||||
std::vector<AbstractArgument*> m_Arguments;
|
||||
std::map<yycc_u8string, AbstractArgument*> m_LongNameMap;
|
||||
std::map<yycc_char8_t, AbstractArgument*> m_ShortNameMap;
|
||||
};
|
||||
|
||||
#pragma region Argument Presets
|
||||
|
||||
template<typename _Ty, std::enable_if_t<std::is_arithmetic_v<_Ty> && !std::is_same_v<_Ty, bool>, int> = 0>
|
||||
class NumberArgument : public AbstractArgument {
|
||||
public:
|
||||
NumberArgument(
|
||||
const yycc_char8_t* long_name, yycc_char8_t short_name,
|
||||
const yycc_char8_t* description = nullptr, const yycc_char8_t* argument_example = nullptr,
|
||||
bool is_optional = false,
|
||||
Constraints::Constraint<_Ty> constraint = Constraints::Constraint<_Ty> {}) :
|
||||
AbstractArgument(long_name, short_name, description, argument_example, is_optional), m_Data(), m_Constraint(constraint) {}
|
||||
virtual ~NumberArgument() {}
|
||||
|
||||
public:
|
||||
_Ty Get() const {
|
||||
if (!IsCaptured()) throw std::runtime_error("try fetching data from a not captured argument.");
|
||||
return m_Data;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool Parse(ArgumentList& al) override {} // todo
|
||||
virtual void Reset() override {}// todo
|
||||
|
||||
protected:
|
||||
_Ty m_Data;
|
||||
Constraints::Constraint<_Ty> m_Constraint;
|
||||
};
|
||||
|
||||
class SwitchArgument : public AbstractArgument {
|
||||
public:
|
||||
SwitchArgument(
|
||||
const yycc_char8_t* long_name, yycc_char8_t short_name,
|
||||
const yycc_char8_t* description = nullptr, const yycc_char8_t* argument_example = nullptr) :
|
||||
AbstractArgument(long_name, short_name, description, argument_example, true), m_Data(false) {} // bool switch must be optional, because it is false if no given switch.
|
||||
virtual ~SwitchArgument() {}
|
||||
|
||||
public:
|
||||
bool Get() const { return m_Data; }
|
||||
|
||||
protected:
|
||||
virtual bool Parse(ArgumentList& al) override { m_Data = true; }
|
||||
virtual void Reset() override { m_Data = false; }
|
||||
|
||||
protected:
|
||||
bool m_Data;
|
||||
};
|
||||
|
||||
class StringArgument : public AbstractArgument {
|
||||
public:
|
||||
StringArgument(
|
||||
const yycc_char8_t* long_name, yycc_char8_t short_name,
|
||||
const yycc_char8_t* description = nullptr, const yycc_char8_t* argument_example = nullptr,
|
||||
bool is_optional = false,
|
||||
Constraints::Constraint<yycc_u8string_view> constraint = Constraints::Constraint<yycc_u8string_view> {}) :
|
||||
AbstractArgument(long_name, short_name, description, argument_example, is_optional), m_Data(), m_Constraint(constraint) {}
|
||||
virtual ~StringArgument() {}
|
||||
|
||||
public:
|
||||
const yycc_u8string& Get() const {
|
||||
if (!IsCaptured()) throw std::runtime_error("try fetching data from a not captured argument.");
|
||||
return m_Data;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool Parse(ArgumentList& al) override {} // todo
|
||||
virtual void Reset() override {}// todo
|
||||
|
||||
protected:
|
||||
yycc_u8string m_Data;
|
||||
Constraints::Constraint<yycc_u8string_view> m_Constraint;
|
||||
};
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
}
|
|
@ -5,6 +5,7 @@ target_sources(YYCCommonplace
|
|||
PRIVATE
|
||||
# Sources
|
||||
COMHelper.cpp
|
||||
ArgParser.cpp
|
||||
ConfigManager.cpp
|
||||
ConsoleHelper.cpp
|
||||
DialogHelper.cpp
|
||||
|
@ -23,7 +24,9 @@ FILE_SET HEADERS
|
|||
FILES
|
||||
# Headers
|
||||
# Common headers
|
||||
Constraints.hpp
|
||||
COMHelper.hpp
|
||||
ArgParser.hpp
|
||||
ConfigManager.hpp
|
||||
ConsoleHelper.hpp
|
||||
DialogHelper.hpp
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include "YYCCInternal.hpp"
|
||||
|
||||
#include "Constraints.hpp"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
@ -17,46 +18,6 @@
|
|||
*/
|
||||
namespace YYCC::ConfigManager {
|
||||
|
||||
/**
|
||||
* @brief The constraint applied to settings to limit its stored value.
|
||||
* @tparam _Ty The internal data type stroed in corresponding setting.
|
||||
*/
|
||||
template<typename _Ty>
|
||||
struct Constraint {
|
||||
using CheckFct_t = std::function<bool(const _Ty&)>;
|
||||
//using CorrectFct_t = std::function<_Ty(const _Ty&)>;
|
||||
CheckFct_t m_CheckFct;
|
||||
//CorrectFct_t m_CorrectFct;
|
||||
|
||||
bool IsValid() const {
|
||||
return m_CheckFct != nullptr/* && m_CorrectFct != nullptr*/;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The namespace containing functions generating common used constraint.
|
||||
*/
|
||||
namespace ConstraintPresets {
|
||||
|
||||
/**
|
||||
* @brief Get constraint for arithmetic values by minimum and maximum value range.
|
||||
* @tparam _Ty The underlying arithmetic type.
|
||||
* @param[in] min_value The minimum value of range (inclusive).
|
||||
* @param[in] max_value The maximum value of range (inclusive).
|
||||
* @return The generated constraint instance which can be directly applied.
|
||||
*/
|
||||
template<typename _Ty, std::enable_if_t<std::is_arithmetic_v<_Ty> && !std::is_enum_v<_Ty> && !std::is_same_v<_Ty, bool>, int> = 0>
|
||||
Constraint<_Ty> GetNumberRangeConstraint(_Ty min_value, _Ty max_value) {
|
||||
if (min_value > max_value)
|
||||
throw std::invalid_argument("invalid min max value for NumberRangeConstraint");
|
||||
return Constraint<_Ty> {
|
||||
[min_value, max_value](const _Ty& val) -> bool { return (val <= max_value) && (val >= min_value); }
|
||||
/*[min_value, max_value](const _Ty& val) -> _Ty { return std::clamp(val, min_value, max_value); }*/
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @brief The base class of every setting.
|
||||
/// @details Programmer can inherit this class and implement essential to create custom setting.
|
||||
class AbstractSetting {
|
||||
|
@ -166,7 +127,9 @@ namespace YYCC::ConfigManager {
|
|||
* @param[in] default_value The default value of this setting.
|
||||
* @param[in] constraint The constraint applied to this setting.
|
||||
*/
|
||||
NumberSetting(const yycc_char8_t* name, _Ty default_value, Constraint<_Ty> constraint = Constraint<_Ty> {}) :
|
||||
NumberSetting(
|
||||
const yycc_char8_t* name, _Ty default_value,
|
||||
Constraints::Constraint<_Ty> constraint = Constraints::Constraint<_Ty> {}) :
|
||||
AbstractSetting(name), m_Data(default_value), m_DefaultData(default_value), m_Constraint(constraint) {}
|
||||
virtual ~NumberSetting() {}
|
||||
|
||||
|
@ -208,7 +171,7 @@ namespace YYCC::ConfigManager {
|
|||
}
|
||||
|
||||
_Ty m_Data, m_DefaultData;
|
||||
Constraint<_Ty> m_Constraint;
|
||||
Constraints::Constraint<_Ty> m_Constraint;
|
||||
};
|
||||
|
||||
/// @brief String type setting
|
||||
|
@ -220,7 +183,9 @@ namespace YYCC::ConfigManager {
|
|||
* @param[in] default_value The default value of this setting.
|
||||
* @param[in] constraint The constraint applied to this setting.
|
||||
*/
|
||||
StringSetting(const yycc_char8_t* name, const yycc_u8string_view& default_value, Constraint<yycc_u8string_view> constraint = Constraint<yycc_u8string_view> {}) :
|
||||
StringSetting(
|
||||
const yycc_char8_t* name, const yycc_u8string_view& default_value,
|
||||
Constraints::Constraint<yycc_u8string_view> constraint = Constraints::Constraint<yycc_u8string_view> {}) :
|
||||
AbstractSetting(name), m_Data(), m_DefaultData(), m_Constraint(constraint) {
|
||||
m_Data = default_value;
|
||||
m_DefaultData = default_value;
|
||||
|
@ -279,7 +244,7 @@ namespace YYCC::ConfigManager {
|
|||
}
|
||||
|
||||
yycc_u8string m_Data, m_DefaultData;
|
||||
Constraint<yycc_u8string_view> m_Constraint;
|
||||
Constraints::Constraint<yycc_u8string_view> m_Constraint;
|
||||
};
|
||||
|
||||
#pragma endregion
|
||||
|
|
84
src/Constraints.hpp
Normal file
84
src/Constraints.hpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
#pragma once
|
||||
#include "YYCCInternal.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
#include <set>
|
||||
#include <initializer_list>
|
||||
|
||||
/**
|
||||
* @brief The namespace containing constraint declaration
|
||||
* and functions generating common used constraint.
|
||||
*/
|
||||
namespace YYCC::Constraints {
|
||||
|
||||
/**
|
||||
* @brief The constraint applied to settings to limit its stored value.
|
||||
* @tparam _Ty The internal data type stroed in corresponding setting.
|
||||
*/
|
||||
template<typename _Ty>
|
||||
struct Constraint {
|
||||
/// @brief Return true if value is legal, otherwise false.
|
||||
using CheckFct_t = std::function<bool(const _Ty&)>;
|
||||
/// @brief The function pointer used for checking whether given value is valid.
|
||||
CheckFct_t m_CheckFct;
|
||||
|
||||
/**
|
||||
* @brief Check whether this Constraint is valid for using.
|
||||
* @return
|
||||
* True if this Constraint is valid, otherwise false.
|
||||
* You should not use this Constraint if this function return false.
|
||||
*/
|
||||
bool IsValid() const {
|
||||
return m_CheckFct != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get constraint for arithmetic or enum values by minimum and maximum value range.
|
||||
* @tparam _Ty An arithmetic or enum type (except bool) of underlying stored value.
|
||||
* @param[in] min_value The minimum value of range (inclusive).
|
||||
* @param[in] max_value The maximum value of range (inclusive).
|
||||
* @return The generated constraint instance which can be directly applied.
|
||||
*/
|
||||
template<typename _Ty, std::enable_if_t<std::is_arithmetic_v<_Ty> && !std::is_same_v<_Ty, bool>, int> = 0>
|
||||
Constraint<_Ty> GetMinMaxRangeConstraint(_Ty min_value, _Ty max_value) {
|
||||
if (min_value > max_value)
|
||||
throw std::invalid_argument("invalid min max value for NumberRangeConstraint");
|
||||
return Constraint<_Ty> {
|
||||
[min_value, max_value](const _Ty& val) -> bool { return (val <= max_value) && (val >= min_value); }
|
||||
/*[min_value, max_value](const _Ty& val) -> _Ty { return std::clamp(val, min_value, max_value); }*/
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get constraint for enum values by enumerate all possible values.
|
||||
* @tparam _Ty An enum type (except bool) of underlying stored value.
|
||||
* @param[in] il An initializer list storing all possible values.
|
||||
* @return The generated constraint instance which can be directly applied.
|
||||
*/
|
||||
template<typename _Ty, std::enable_if_t<std::is_enum_v<_Ty>, int> = 0>
|
||||
Constraint<_Ty> GetEnumEnumerationConstraint(const std::initializer_list<_Ty>& il) {
|
||||
std::set<_Ty> data(il);
|
||||
return Constraint<_Ty> {
|
||||
[data](const _Ty& val) -> bool { return data.find(val) != data.end(); }
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get constraint for string values by enumerate all possible values.
|
||||
* @param[in] il An initializer list storing all possible values.
|
||||
* @return The generated constraint instance which can be directly applied.
|
||||
* @remarks
|
||||
* Caller must make sure that the string view passed in initializer list is valid until this Constraint life time gone.
|
||||
* Becasue this generator will not copy your given string view into string.
|
||||
*/
|
||||
Constraint<yycc_u8string_view> GetStringEnumerationConstraint(const std::initializer_list<yycc_u8string_view>& il) {
|
||||
std::set<yycc_u8string_view> data(il);
|
||||
return Constraint<yycc_u8string_view> {
|
||||
[data](const yycc_u8string_view& val) -> bool { return data.find(val) != data.end(); }
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -402,7 +402,7 @@ namespace YYCCTestbench {
|
|||
m_FloatSetting(YYCC_U8("float-setting"), 0.0f),
|
||||
m_StringSetting(YYCC_U8("string-setting"), YYCC_U8("")),
|
||||
m_BoolSetting(YYCC_U8("bool-setting"), false),
|
||||
m_ClampedFloatSetting(YYCC_U8("clamped-float-setting"), 0.0f, YYCC::ConfigManager::ConstraintPresets::GetNumberRangeConstraint<float>(-1.0f, 1.0f)),
|
||||
m_ClampedFloatSetting(YYCC_U8("clamped-float-setting"), 0.0f, YYCC::Constraints::GetMinMaxRangeConstraint<float>(-1.0f, 1.0f)),
|
||||
m_EnumSetting(YYCC_U8("enum-setting"), TestEnum::Test1),
|
||||
m_CoreManager(YYCC_U8("test.cfg"), UINT64_C(0), {
|
||||
&m_IntSetting, &m_FloatSetting, &m_StringSetting, &m_BoolSetting, &m_ClampedFloatSetting, &m_EnumSetting
|
||||
|
|
Loading…
Reference in New Issue
Block a user