-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
cli_impl.hpp
138 lines (115 loc) · 3.92 KB
/
cli_impl.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/**
* @file cli_impl.hpp
* @author Matthew Amidon
*
* Implementation of templated functions of the CLI class.
*/
#ifndef MLPACK_CORE_UTIL_CLI_IMPL_HPP
#define MLPACK_CORE_UTIL_CLI_IMPL_HPP
// In case it has not already been included.
#include "cli.hpp"
#include "prefixedoutstream.hpp"
// Include option.hpp here because it requires CLI but is also templated.
#include "option.hpp"
// Color code escape sequences.
#ifndef _WIN32
#define BASH_RED "\033[0;31m"
#define BASH_CLEAR "\033[0m"
#else
#define BASH_RED ""
#define BASH_CLEAR ""
#endif
namespace mlpack {
/**
* @brief Adds a parameter to CLI, making it accessibile via GetParam &
* CheckValue.
*
* @tparam T The type of the parameter.
* @param identifier The name of the parameter, eg foo in bar/foo.
* @param description A string description of the parameter.
* @param parent The name of the parent of the parameter,
* eg bar/foo in bar/foo/buzz.
* @param required If required, the program will refuse to run
* unless the parameter is specified.
*/
template<typename T>
void CLI::Add(const std::string& identifier,
const std::string& description,
const std::string& alias,
bool required)
{
// Temporary outstream object for detecting duplicate identifiers
util::PrefixedOutStream outstr(std::cerr,
BASH_RED "[FATAL] " BASH_CLEAR, false, true /* fatal */);
// identifier and alias maps
gmap_t& gmap = GetSingleton().globalValues;
amap_t& amap = GetSingleton().aliasValues;
// if found in current map, print fatal error and terminate the program.
if (gmap.count(identifier))
outstr << "Parameter --" << identifier << "(-" << alias << ") "
<< "is defined multiple times with same identifiers." << std::endl;
if (amap.count(alias))
outstr << "Parameter --" << identifier << "(-" << alias << ") "
<< "is defined multiple times with same alias." << std::endl;
po::options_description& desc = CLI::GetSingleton().desc;
// Must make use of boost syntax here.
std::string progOptId =
alias.length() ? identifier + "," + alias : identifier;
// Add the alias, if necessary
AddAlias(alias, identifier);
// Add the option to boost program_options.
desc.add_options()(progOptId.c_str(), po::value<T>(), description.c_str());
// Make sure the appropriate metadata is inserted into gmap.
ParamData data;
T tmp = T();
data.desc = description;
data.name = identifier;
data.tname = TYPENAME(T);
data.value = boost::any(tmp);
data.wasPassed = false;
gmap[identifier] = data;
// If the option is required, add it to the required options list.
if (required)
GetSingleton().requiredOptions.push_front(identifier);
}
// We specialize this in cli.cpp.
template<>
bool& CLI::GetParam<bool>(const std::string& identifier);
/**
* @brief Returns the value of the specified parameter.
* If the parameter is unspecified, an undefined but
* more or less valid value is returned.
*
* @tparam T The type of the parameter.
* @param identifier The full name of the parameter.
*
* @return The value of the parameter. Use CLI::CheckValue to determine if it's
* valid.
*/
template<typename T>
T& CLI::GetParam(const std::string& identifier)
{
// Used to ensure we have a valid value.
T tmp = T();
// Used to index into the globalValues map.
std::string key = std::string(identifier);
gmap_t& gmap = GetSingleton().globalValues;
// Now check if we have an alias.
amap_t& amap = GetSingleton().aliasValues;
if (amap.count(key))
key = amap[key];
// What if we don't actually have any value?
if (!gmap.count(key))
{
gmap[key] = ParamData();
gmap[key].value = boost::any(tmp);
*boost::any_cast<T>(&gmap[key].value) = tmp;
}
// What if we have meta-data, but no data?
boost::any val = gmap[key].value;
if (val.empty())
gmap[key].value = boost::any(tmp);
return *boost::any_cast<T>(&gmap[key].value);
}
} // namespace mlpack
#endif