Skip to content

Commit 98687d5

Browse files
author
Giulio Ermanno Pibiri
authored
Merge pull request #2 from Certseeds/dev
now can run in windows/msvc.
2 parents a2bc0aa + 2df505d commit 98687d5

File tree

7 files changed

+214
-154
lines changed

7 files changed

+214
-154
lines changed

.github/workflows/c_cpp_build.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Build Cpp By CMake
2+
3+
on:
4+
[ push,pull_request ]
5+
6+
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
7+
jobs:
8+
# This workflow contains a single job called "build"
9+
build:
10+
name: cpp-test
11+
# The type of runner that the job will run on
12+
runs-on: ${{ matrix.os }}
13+
strategy:
14+
matrix:
15+
os: [ ubuntu-latest,windows-latest,macos-latest ]
16+
# Steps represent a sequence of tasks that will be executed as part of the job
17+
steps:
18+
19+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
20+
- name: checkout code
21+
uses: actions/checkout@v2
22+
23+
- name: ensure the cmake
24+
run: cmake --version
25+
26+
- name: prepare folder
27+
run: cmake -E make_directory ./CMAKE_DEBUG_PATH
28+
29+
- name: cmake prepare for compile
30+
working-directory: ./CMAKE_DEBUG_PATH
31+
run: cmake .. -DCMAKE_BUILD_TYPE=Release
32+
33+
- name: cmake prepare for compile
34+
working-directory: ./CMAKE_DEBUG_PATH
35+
run: cmake --build . --config Release
36+
37+
- name: cmake ctest
38+
working-directory: ./CMAKE_DEBUG_PATH
39+
run: ctest
40+

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
/src/build
2-
.DS_Store
2+
.DS_Store
3+
.idea/
4+
[Cc]make-*/

CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
cmake_minimum_required(VERSION 2.8)
2+
project(CMD_LINE_PARSER)
3+
4+
enable_testing()
5+
6+
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src)
7+
8+
add_library(${PROJECT_NAME} INTERFACE)
9+
target_include_directories(${PROJECT_NAME}
10+
INTERFACE
11+
${CMAKE_CURRENT_SOURCE_DIR}/include)

include/parser.hpp

Lines changed: 123 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -10,150 +10,147 @@
1010

1111
namespace cmd_line_parser {
1212

13-
struct parser {
14-
inline static const std::string empty = "";
13+
struct parser {
14+
inline static const std::string empty;
1515

16-
parser(int argc, char** argv)
17-
: m_argc(argc)
18-
, m_argv(argv)
19-
, m_required(0) {}
16+
parser(int argc, char **argv)
17+
: m_argc(argc), m_argv(argv), m_required(0) {}
2018

21-
struct cmd {
22-
std::string shorthand, value, descr;
23-
bool is_boolean;
24-
};
19+
struct cmd {
20+
std::string shorthand, value, descr;
21+
bool is_boolean;
22+
};
2523

26-
bool parse() {
27-
if (size_t(m_argc - 1) < m_required) return abort();
28-
size_t k = 0;
29-
for (int i = 1; i != m_argc; ++i, ++k) {
30-
std::string parsed(m_argv[i]);
31-
if (parsed == "-h" or parsed == "--help") return abort();
32-
size_t id = k;
33-
bool is_optional = id >= m_required;
34-
if (is_optional) {
35-
auto it = m_shorthands.find(parsed);
36-
if (it == m_shorthands.end()) {
37-
std::cerr << "== error: shorthand '" + parsed + "' not found" << std::endl;
38-
return abort();
24+
bool parse() {
25+
if (m_argc - 1 < m_required) { return abort(); }
26+
for (size_t i{1}, k{0}; i != m_argc; ++i, ++k) {
27+
std::string parsed(m_argv[i]);
28+
if (parsed == "-h" || parsed == "--help") { return abort(); }
29+
size_t id{k};
30+
bool is_optional = id >= m_required;
31+
if (is_optional) {
32+
if (const auto it = m_shorthands.find(parsed);it == m_shorthands.end()) {
33+
std::cerr << "== error: shorthand '" + parsed + "' not found" << std::endl;
34+
return abort();
35+
} else {
36+
id = (*it).second;
37+
}
3938
}
40-
id = (*it).second;
41-
}
42-
assert(id < m_names.size());
43-
auto const& name = m_names[id];
44-
auto& c = m_cmds[name];
45-
if (is_optional) {
46-
if (c.is_boolean) {
47-
parsed = "true";
48-
} else {
49-
++i;
50-
if (i == m_argc) return abort();
51-
parsed = m_argv[i];
39+
assert(id < m_names.size());
40+
auto const &name = m_names[id];
41+
auto &c = m_cmds[name];
42+
if (is_optional) {
43+
if (c.is_boolean) {
44+
parsed = "true";
45+
} else {
46+
++i;
47+
if (i == m_argc) { return abort(); }
48+
parsed = m_argv[i];
49+
}
5250
}
51+
c.value = parsed;
5352
}
54-
c.value = parsed;
53+
return true;
5554
}
56-
return true;
57-
}
5855

59-
void help() const {
60-
std::cerr << "Usage: " << m_argv[0] << " [-h,--help]";
61-
auto print = [this](bool with_description) {
62-
for (size_t i = 0; i != m_names.size(); ++i) {
63-
auto const& c = m_cmds.at(m_names[i]);
64-
bool is_optional = i >= m_required;
65-
if (is_optional) std::cerr << " [" << c.shorthand;
66-
if (!c.is_boolean) std::cerr << " " << m_names[i];
67-
if (is_optional) std::cerr << "]";
68-
if (with_description) std::cerr << "\n\t" << c.descr << "\n\n";
69-
}
70-
};
71-
print(false);
72-
std::cerr << "\n\n";
73-
print(true);
74-
std::cerr << " [-h,--help]\n\tPrint this help text and silently exits." << std::endl;
75-
}
56+
void help() const {
57+
std::cerr << "Usage: " << m_argv[0] << " [-h,--help]";
58+
const auto print = [this](bool with_description) {
59+
for (size_t i = 0; i != m_names.size(); ++i) {
60+
auto const &c = m_cmds.at(m_names[i]);
61+
bool is_optional = i >= m_required;
62+
if (is_optional) { std::cerr << " [" << c.shorthand; }
63+
if (!c.is_boolean) { std::cerr << " " << m_names[i]; }
64+
if (is_optional) { std::cerr << "]"; }
65+
if (with_description) { std::cerr << "\n\t" << c.descr << "\n\n"; }
66+
}
67+
};
68+
print(false);
69+
std::cerr << "\n\n";
70+
print(true);
71+
std::cerr << " [-h,--help]\n\tPrint this help text and silently exits." << std::endl;
72+
}
7673

77-
bool add(std::string const& name, std::string const& descr) {
78-
bool ret = m_cmds.emplace(name, cmd{empty, empty, descr, false}).second;
79-
if (ret) {
80-
m_names.push_back(name);
81-
m_required += 1;
74+
bool add(std::string const &name, std::string const &descr) {
75+
bool ret = m_cmds.emplace(name, cmd{empty, empty, descr, false}).second;
76+
if (ret) {
77+
m_names.push_back(name);
78+
m_required += 1;
79+
}
80+
return ret;
8281
}
83-
return ret;
84-
}
8582

86-
bool add(std::string const& name, std::string const& descr, std::string const& shorthand,
87-
bool is_boolean = true) {
88-
bool ret =
89-
m_cmds.emplace(name, cmd{shorthand, is_boolean ? "false" : empty, descr, is_boolean})
90-
.second;
91-
if (ret) {
92-
m_names.push_back(name);
93-
m_shorthands.emplace(shorthand, m_names.size() - 1);
83+
bool add(std::string const &name, std::string const &descr, std::string const &shorthand,
84+
bool is_boolean = true) {
85+
bool ret =
86+
m_cmds.emplace(name, cmd{shorthand, is_boolean ? "false" : empty, descr, is_boolean})
87+
.second;
88+
if (ret) {
89+
m_names.push_back(name);
90+
m_shorthands.emplace(shorthand, m_names.size() - 1);
91+
}
92+
return ret;
9493
}
95-
return ret;
96-
}
9794

98-
template <typename T>
99-
T get(std::string const& name) const {
100-
auto it = m_cmds.find(name);
101-
if (it == m_cmds.end()) throw std::runtime_error("error: '" + name + "' not found");
102-
auto const& value = (*it).second.value;
103-
return parse<T>(value);
104-
}
95+
template<typename T>
96+
T get(std::string const &name) const {
97+
auto it = m_cmds.find(name);
98+
if (it == m_cmds.end()) throw std::runtime_error("error: '" + name + "' not found");
99+
auto const &value = (*it).second.value;
100+
return parse < T > (value);
101+
}
105102

106-
bool parsed(std::string const& name) const {
107-
auto it = m_cmds.find(name);
108-
if (it == m_cmds.end() or (*it).second.value == empty) return false;
109-
return true;
110-
}
103+
bool parsed(std::string const &name) const {
104+
auto it = m_cmds.find(name);
105+
if (it == m_cmds.end() || (*it).second.value == empty) { return false; }
106+
return true;
107+
}
111108

112-
template <typename T>
113-
T parse(std::string const& value) const {
114-
if constexpr (std::is_same<T, std::string>::value) {
115-
return value;
116-
} else if constexpr (std::is_same<T, char>::value or std::is_same<T, signed char>::value or
117-
std::is_same<T, unsigned char>::value) {
118-
return value.front();
119-
} else if constexpr (std::is_same<T, unsigned int>::value or std::is_same<T, int>::value or
120-
std::is_same<T, unsigned short int>::value or
121-
std::is_same<T, short int>::value) {
122-
return std::atoi(value.c_str());
123-
} else if constexpr (std::is_same<T, unsigned long int>::value or
124-
std::is_same<T, long int>::value or
125-
std::is_same<T, unsigned long long int>::value or
126-
std::is_same<T, long long int>::value) {
127-
return std::atoll(value.c_str());
128-
} else if constexpr (std::is_same<T, float>::value or std::is_same<T, double>::value or
129-
std::is_same<T, long double>::value) {
130-
return std::atof(value.c_str());
131-
} else if constexpr (std::is_same<T, bool>::value) {
132-
std::istringstream stream(value);
133-
bool ret;
134-
if (value == "true" or value == "false") {
135-
stream >> std::boolalpha >> ret;
136-
} else {
137-
stream >> std::noboolalpha >> ret;
109+
template<typename T>
110+
T parse(std::string const &value) const {
111+
if constexpr (std::is_same<T, std::string>::value) {
112+
return value;
113+
} else if constexpr (std::is_same<T, char>::value || std::is_same<T, signed char>::value ||
114+
std::is_same<T, unsigned char>::value) {
115+
return value.front();
116+
} else if constexpr (std::is_same<T, unsigned int>::value || std::is_same<T, int>::value ||
117+
std::is_same<T, unsigned short int>::value ||
118+
std::is_same<T, short int>::value) {
119+
return std::strtol(value.c_str(), nullptr, 10);
120+
} else if constexpr (std::is_same<T, unsigned long int>::value ||
121+
std::is_same<T, long int>::value ||
122+
std::is_same<T, unsigned long long int>::value ||
123+
std::is_same<T, long long int>::value) {
124+
return std::strtoll(value.c_str(), nullptr, 10);
125+
} else if constexpr (std::is_same<T, float>::value || std::is_same<T, double>::value ||
126+
std::is_same<T, long double>::value) {
127+
return std::strtod(value.c_str(), nullptr);
128+
} else if constexpr (std::is_same<T, bool>::value) {
129+
std::istringstream stream(value);
130+
bool ret;
131+
if (value == "true" || value == "false") {
132+
stream >> std::boolalpha >> ret;
133+
} else {
134+
stream >> std::noboolalpha >> ret;
135+
}
136+
return ret;
138137
}
139-
return ret;
138+
assert(false); // should never happen
139+
throw std::runtime_error("unsupported type");
140140
}
141-
assert(false); // should never happen
142-
throw std::runtime_error("unsupported type");
143-
}
144141

145-
private:
146-
int m_argc;
147-
char** m_argv;
148-
size_t m_required;
149-
std::unordered_map<std::string, cmd> m_cmds;
150-
std::unordered_map<std::string, int> m_shorthands;
151-
std::vector<std::string> m_names;
142+
private:
143+
size_t m_argc;
144+
char **m_argv;
145+
size_t m_required;
146+
std::unordered_map<std::string, cmd> m_cmds;
147+
std::unordered_map<std::string, int> m_shorthands;
148+
std::vector<std::string> m_names;
152149

153-
bool abort() const {
154-
help();
155-
return false;
156-
}
157-
};
150+
bool abort() const {
151+
help();
152+
return false;
153+
}
154+
};
158155

159156
} // namespace cmd_line_parser

src/CMakeLists.txt

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
11
cmake_minimum_required(VERSION 2.8)
22
project(CMD_PARSER)
3+
set(CMAKE_CXX_STANDARD 17)
34

4-
if(NOT CMAKE_BUILD_TYPE)
5-
set(CMAKE_BUILD_TYPE "Release")
6-
endif()
7-
MESSAGE( STATUS "CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE} )
5+
if (NOT CMAKE_BUILD_TYPE)
6+
set(CMAKE_BUILD_TYPE "Release")
7+
endif ()
8+
MESSAGE(STATUS "CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE})
89

910
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
1011

11-
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
12-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
12+
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
13+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
1314
endif ()
15+
if (UNIX)
16+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
17+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
18+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
19+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-missing-braces")
20+
if (USE_SANITIZERS)
21+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
22+
endif ()
1423

15-
if(UNIX)
16-
17-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
18-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
19-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
20-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
21-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-missing-braces")
24+
endif ()
2225

23-
if(USE_SANITIZERS)
24-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
25-
endif()
26+
enable_testing()
27+
add_executable(example ${CMAKE_CURRENT_SOURCE_DIR}/example.cpp)
28+
target_link_libraries(example PUBLIC CMD_LINE_PARSER)
2629

27-
endif()
30+
add_executable(test_parse ${CMAKE_CURRENT_SOURCE_DIR}/test_parse.cpp)
2831

29-
add_executable(example example.cpp)
30-
add_executable(test_parse test_parse.cpp)
32+
add_test(test_parse_CTEST ${CMAKE_BINARY_DIR}/test_parse)

0 commit comments

Comments
 (0)