Skip to content

Commit

Permalink
Merge pull request #9 from bialger/dev
Browse files Browse the repository at this point in the history
Add aliases for custom types
  • Loading branch information
bialger authored Aug 16, 2024
2 parents d473a82 + 1a1df4b commit c233f79
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 24 deletions.
6 changes: 4 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ cmake_minimum_required(VERSION 3.12)

project(
ArgParser
VERSION 1.2.0
DESCRIPTION "C++ argument parser"
VERSION 1.2.5
DESCRIPTION "C++ CLI argument parser library"
LANGUAGES CXX
)

set(CMAKE_CXX_STANDARD 20)

message(STATUS "Building ${PROJECT_DESCRIPTION} ${PROJECT_NAME}, version ${PROJECT_VERSION}")

if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif ()
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ AddArgumentType(Action, ParseAction);

int main(int argc, char *argv[]) {
ArgumentParser::ArgParser parser("TestArgParser", PassArgumentTypes(Action));
parser.SetAliasForType<Action>("Action");
parser.AddHelp('h', "help", "This program is an ArgParser FetchContent example.");
parser.AddArgument<Action>('a', "action", "action type");
parser.AddFlag('t', "test", "test argument");
Expand Down
1 change: 1 addition & 0 deletions bin/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ int main(int argc, char** argv) {
Action action{};

ArgumentParser::ArgParser parser("Program", PassArgumentTypes(Action));
parser.SetAliasForType<Action>("Action");
parser.AddIntArgument("N").MultiValue(1).Positional().StoreValues(values);
parser.AddArgument<Action>('a', "action", "Action type").StoreValue(action);
parser.AddHelp('h', "help", "Program accumulate arguments");
Expand Down
10 changes: 5 additions & 5 deletions lib/argparser/ArgParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ bool ArgumentParser::ArgParser::Parse(int argc, char** argv, ConditionalOutput e
return Parse_(args, error_output);
}

bool ArgumentParser::ArgParser::Help() {
bool ArgumentParser::ArgParser::Help() const {
if (help_index_ == std::string::npos) {
return false;
}

return GetValue<bool>(arguments_[help_index_]->GetInfo().long_key);
}

std::string ArgumentParser::ArgParser::HelpDescription() {
std::string ArgumentParser::ArgParser::HelpDescription() const {
if (help_index_ == std::string::npos) {
return {};
}
Expand All @@ -44,7 +44,7 @@ std::string ArgumentParser::ArgParser::HelpDescription() {
std::string type_name = allowed_typenames_[i];
std::string output_type_name = allowed_typenames_for_help_[i];

for (const auto& iterator : arguments_by_type_[type_name]) {
for (const auto& iterator : arguments_by_type_.at(type_name)) {
if (iterator.second == help_index_) {
continue;
}
Expand Down Expand Up @@ -185,7 +185,7 @@ bool ArgumentParser::ArgParser::Parse_(const std::vector<std::string>& args, Con
return HandleErrors(error_output);
}

std::vector<std::string> ArgumentParser::ArgParser::GetLongKeys(const std::string& current_argument) {
std::vector<std::string> ArgumentParser::ArgParser::GetLongKeys(const std::string& current_argument) const {
std::vector<std::string> long_keys = {current_argument.substr(2)};

if (long_keys[0].find('=') != std::string::npos) {
Expand Down Expand Up @@ -248,7 +248,7 @@ void ArgumentParser::ArgParser::RefreshArguments() {
}
}

bool ArgumentParser::ArgParser::HandleErrors(ConditionalOutput error_output) {
bool ArgumentParser::ArgParser::HandleErrors(ConditionalOutput error_output) const {
std::string error_string;
bool is_correct = true;

Expand Down
50 changes: 37 additions & 13 deletions lib/argparser/ArgParser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ struct ArgumentTypes {
class ArgParser {
public:
template<ProperArgumentType ... Args>
ArgParser(const char* name = "", ArgumentTypes<Args ...> types = {});
explicit ArgParser(const char* name = "", ArgumentTypes<Args ...> types = {});

ArgParser(const ArgParser& other) = delete;
ArgParser& operator=(const ArgParser& other) = delete;
Expand All @@ -37,8 +37,8 @@ class ArgParser {
bool Parse(const std::vector<std::string>& args, ConditionalOutput error_output = {});
bool Parse(int argc, char** argv, ConditionalOutput error_output = {});

bool Help();
std::string HelpDescription();
[[nodiscard]] bool Help() const;
[[nodiscard]] std::string HelpDescription() const;

ConcreteArgumentBuilder<bool>& AddHelp(char short_name, const char* long_name, const char* description = "");
ConcreteArgumentBuilder<bool>& AddHelp(const char* long_name, const char* description);
Expand All @@ -50,7 +50,10 @@ class ArgParser {
ConcreteArgumentBuilder<T>& AddArgument(const char* long_name, const char* description = "");

template<ProperArgumentType T>
T GetValue(const char* long_name, size_t index = 0);
T GetValue(const char* long_name, size_t index = 0) const;

template<ProperArgumentType T>
void SetAliasForType(const std::string& alias);

ALIAS_TEMPLATE_FUNCTION(AddShortArgument, AddArgument<int16_t>);
ALIAS_TEMPLATE_FUNCTION(AddIntArgument, AddArgument<int32_t>);
Expand Down Expand Up @@ -92,19 +95,19 @@ class ArgParser {

bool Parse_(const std::vector<std::string>& args, ConditionalOutput error_output);

std::vector<std::string> GetLongKeys(const std::string& current_argument);
[[nodiscard]] std::vector<std::string> GetLongKeys(const std::string& current_argument) const;

void ParsePositionalArguments(const std::vector<std::string>& argv, const std::vector<size_t>& used_positions);

bool HandleErrors(ConditionalOutput error_output);
bool HandleErrors(ConditionalOutput error_output) const;

void RefreshArguments();

template<ProperArgumentType T>
ConcreteArgumentBuilder<T>& AddArgument_(char short_name, const char* long_name, const char* description);

template<ProperArgumentType T>
T GetValue_(const char* long_name, size_t index);
T GetValue_(const char* long_name, size_t index) const;
};

template<ProperArgumentType... Args>
Expand Down Expand Up @@ -147,33 +150,54 @@ ConcreteArgumentBuilder<T>& ArgParser::AddArgument(const char* long_name, const
}

template<ProperArgumentType T>
T ArgParser::GetValue(const char* long_name, size_t index) {
T ArgParser::GetValue(const char* long_name, size_t index) const {
return GetValue_<T>(long_name, index);
}

template<ProperArgumentType T>
ConcreteArgumentBuilder<T>& ArgParser::AddArgument_(char short_name, const char* long_name, const char* description) {
std::map<std::string, size_t>* t_arguments = &arguments_by_type_.at(typeid(T).name());
std::map<std::string, size_t>& t_arguments = arguments_by_type_.at(typeid(T).name());

if (short_name != kBadChar) {
short_to_long_names_[short_name] = long_name;
}

(*t_arguments)[long_name] = argument_builders_.size();
t_arguments[long_name] = argument_builders_.size();
auto* argument_builder = new ConcreteArgumentBuilder<T>(short_name, long_name, description);
argument_builders_.push_back(argument_builder);

return *argument_builder;
}

template<ProperArgumentType T>
T ArgParser::GetValue_(const char* long_name, size_t index) {
std::map<std::string, size_t>* t_arguments = &arguments_by_type_.at(typeid(T).name());
size_t argument_index = t_arguments->at(long_name);
T ArgParser::GetValue_(const char* long_name, size_t index) const {
const std::map<std::string, size_t>& t_arguments = arguments_by_type_.at(typeid(T).name());
size_t argument_index = t_arguments.at(long_name);
auto* argument = static_cast<ConcreteArgument<T>*>(arguments_.at(argument_index));
return argument->GetValue(index);
}

template<ProperArgumentType T>
void ArgumentParser::ArgParser::SetAliasForType(const std::string& alias) {
auto it = std::find(allowed_typenames_.begin(), allowed_typenames_.end(), typeid(T).name());
if (it == allowed_typenames_.end()) {
return;
}

auto output_it = allowed_typenames_for_help_.begin() + (it - allowed_typenames_.begin());
auto alias_end_it = alias.begin();

while (alias_end_it != alias.end()) {
if (!std::isalnum(*alias_end_it)) {
break;
}

++alias_end_it;
}

*output_it = std::string(alias.begin(), alias_end_it);
}

static_assert(ProperArgumentType<int8_t>);
static_assert(ProperArgumentType<int16_t>);
static_assert(ProperArgumentType<int32_t>);
Expand Down
4 changes: 4 additions & 0 deletions lib/argparser/basic/ConditionalOutput.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ struct ConditionalOutput {
bool print_messages = false;

template<typename T>
requires requires(T t, std::ostream& os) {
{ os << t } -> std::same_as<std::ostream&>;
}
ConditionalOutput& operator<<(const T& t) {
if (print_messages) {
out_stream << t;
}

return *this;
}
};
Expand Down
22 changes: 18 additions & 4 deletions lib/argparser/docs/ArgParser.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@

Принимает имя программы и типы добавленных пользователем аргументов.
Типы добавленных аргументов должны быть представлены в виде `ArgumentTypes<Args ...>`, где Args... - типы аргументов.
Аргументы должны удовлетворять концепту `ProperArgumentType`.
Аргументы должны удовлетворять концепту `ProperArgumentType`, то есть:
* Иметь конструктор без параметров и конструктор копирования
* Иметь оператор присваивания с копированием
* Должен быть определен оператор `std::ostream& operator<<(std::ostream& os, const T& t)`

Ожидается вызов пользователем именно его.

```cpp
Expand Down Expand Up @@ -79,15 +83,15 @@ bool Parse(int argc, char** argv, ConditionalOutput error_output = {std::cout, f
негативного значения после парсинга.

```cpp
bool Help();
[[nodiscard]] bool Help() const;
```

### HelpDescription

Функция, возвращающая `std::string`, содержащую помощь для пользователя.

```cpp
std::string HelpDescription();
[[nodiscard]] std::string HelpDescription() const;
```

Пример вывода возвращаемого значения:
Expand Down Expand Up @@ -116,7 +120,7 @@ OPTIONS:

```cpp
template<ProperArgumentType T>
T GetValue(const char* long_name, size_t index = 0);
[[nodiscard]] T GetValue(const char* long_name, size_t index = 0) const;
```
### AddArgument<T\>
Expand Down Expand Up @@ -159,6 +163,16 @@ ConcreteArgumentBuilder<bool>& AddHelp(char short_name, const char* long_name, c
ConcreteArgumentBuilder<bool>& AddHelp(const char* long_name, const char* description);
```
### SetAliasForType<T\>
Функция, переопределяющая псевдоним для типа `T`.
Разрешены только латинские буквы и цифры.
```cpp
template<ProperArgumentType T>
void SetAliasForType(const std::string& alias);
```

### GetFlag, GetShortValue, ... GetStringValue, GetCompositeValue

Функции-псевдонимы для соответственно `GetValue<bool>`, `GetValue<int16_t>`,
Expand Down
1 change: 1 addition & 0 deletions lib/argparser/docs/dev/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ classDiagram
+AddArgument~T~(char short_name, const char[] long_name, const char[] description="") ConcreteArgumentBuilder~T~ &
+AddArgument~T~(const char[] long_name, const char[] description="") ConcreteArgumentBuilder~T~ &
+GetValue~T~(const char[] long_name, size_t index=0) T
+SeSetAliasForType~T~(string alias) void
-Parse_(vector~string~ args, ConditionalOutput error_output) bool
-GetLongKeys(string current_argument) vector~string~
-ParsePositionalArguments(vector~string~ argv, const vector~size_t~ & used_positions) void
Expand Down

0 comments on commit c233f79

Please sign in to comment.