176 lines
5.5 KiB
C++
176 lines
5.5 KiB
C++
#ifndef ARGPARSE_DEFAULT_CONVERTER_HPP
|
|
#define ARGPARSE_DEFAULT_CONVERTER_HPP
|
|
#include <sstream>
|
|
#include <vector>
|
|
#include <typeinfo>
|
|
#include "argparse_error.hpp"
|
|
#include "argparse_util.hpp"
|
|
#include "argparse_value.hpp"
|
|
|
|
namespace argparse {
|
|
|
|
/*
|
|
* Get a useful description of the argument type
|
|
*/
|
|
//Signed Integer
|
|
template<typename T>
|
|
typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, std::string>::type
|
|
arg_type() { return "integer"; }
|
|
|
|
//Unsigned Integer
|
|
template<typename T>
|
|
typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, std::string>::type
|
|
arg_type() { return "non-negative integer"; }
|
|
|
|
//Float
|
|
template<typename T>
|
|
typename std::enable_if<std::is_floating_point<T>::value, std::string>::type
|
|
arg_type() { return "float"; }
|
|
|
|
//Unkown
|
|
template<typename T>
|
|
typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value, std::string>::type
|
|
arg_type() { return ""; } //Empty
|
|
|
|
/*
|
|
* Default Conversions to/from strings
|
|
*/
|
|
template<typename T>
|
|
class DefaultConverter {
|
|
public:
|
|
ConvertedValue<T> from_str(std::string str) {
|
|
std::stringstream ss(str);
|
|
|
|
T val = T();
|
|
ss >> val;
|
|
|
|
bool eof = ss.eof();
|
|
bool fail = ss.fail();
|
|
bool converted_ok = eof && !fail;
|
|
|
|
ConvertedValue<T> converted_value;
|
|
if (!converted_ok) {
|
|
std::stringstream msg;
|
|
msg << "Invalid conversion from '" << str << "'";
|
|
std::string arg_type_str = arg_type<T>();
|
|
if (!arg_type_str.empty()) {
|
|
msg << " to " << arg_type_str;
|
|
}
|
|
converted_value.set_error(msg.str());
|
|
} else {
|
|
converted_value.set_value(val);
|
|
|
|
}
|
|
|
|
return converted_value;
|
|
}
|
|
|
|
ConvertedValue<std::string> to_str(T val) {
|
|
std::stringstream ss;
|
|
ss << val;
|
|
|
|
bool converted_ok = ss.eof() && !ss.fail();
|
|
|
|
ConvertedValue<std::string> converted_value;
|
|
if (!converted_ok) {
|
|
std::stringstream msg;
|
|
msg << "Invalid conversion from '" << val << "' to string";
|
|
converted_value.set_error(msg.str());
|
|
} else {
|
|
converted_value.set_value(ss.str());
|
|
}
|
|
return converted_value;
|
|
}
|
|
std::vector<std::string> default_choices() { return {}; }
|
|
};
|
|
|
|
//DefaultConverter specializations for bool
|
|
// By default std::stringstream doesn't accept "true" or "false"
|
|
// as boolean values.
|
|
template<>
|
|
class DefaultConverter<bool> {
|
|
public:
|
|
ConvertedValue<bool> from_str(std::string str) {
|
|
ConvertedValue<bool> converted_value;
|
|
|
|
str = tolower(str);
|
|
if (str == "0" || str == "false") {
|
|
converted_value.set_value(false);
|
|
} else if (str == "1" || str == "true") {
|
|
converted_value.set_value(true);
|
|
} else {
|
|
converted_value.set_error("Unexpected value '" + str + "' (expected one of: " + join(default_choices(), ", ") + ")");
|
|
}
|
|
return converted_value;
|
|
}
|
|
|
|
ConvertedValue<std::string> to_str(bool val) {
|
|
ConvertedValue<std::string> converted_value;
|
|
if (val) converted_value.set_value("true");
|
|
else converted_value.set_value("false");
|
|
return converted_value;
|
|
}
|
|
|
|
std::vector<std::string> default_choices() {
|
|
return {"true", "false"};
|
|
}
|
|
};
|
|
|
|
//DefaultConverter specializations for std::string
|
|
// The default conversion checks for eof() which is not set for empty strings,
|
|
// nessesitating the specialization
|
|
template<>
|
|
class DefaultConverter<std::string> {
|
|
public:
|
|
ConvertedValue<std::string> from_str(std::string str) {
|
|
ConvertedValue<std::string> converted_value;
|
|
converted_value.set_value(str);
|
|
return converted_value;
|
|
}
|
|
ConvertedValue<std::string> to_str(std::string val) {
|
|
ConvertedValue<std::string> converted_value;
|
|
converted_value.set_value(val);
|
|
return converted_value;
|
|
}
|
|
std::vector<std::string> default_choices() { return {}; }
|
|
};
|
|
|
|
//DefaultConverter specializations for const char*
|
|
// This allocates memory that the user is responsible for freeing
|
|
template<>
|
|
class DefaultConverter<const char*> {
|
|
public:
|
|
ConvertedValue<const char*> from_str(std::string str) {
|
|
ConvertedValue<const char*> val;
|
|
val.set_value(strdup(str.c_str()));
|
|
return val;
|
|
}
|
|
ConvertedValue<std::string> to_str(const char* val) {
|
|
ConvertedValue<std::string> converted_value;
|
|
converted_value.set_value(val);
|
|
return converted_value;
|
|
}
|
|
std::vector<std::string> default_choices() { return {}; }
|
|
};
|
|
|
|
//DefaultConverter specializations for char*
|
|
// This allocates memory that the user is responsible for freeing
|
|
template<>
|
|
class DefaultConverter<char*> {
|
|
public:
|
|
ConvertedValue<char*> from_str(std::string str) {
|
|
ConvertedValue<char*> val;
|
|
val.set_value(strdup(str.c_str()));
|
|
return val;
|
|
}
|
|
ConvertedValue<std::string> to_str(const char* val) {
|
|
ConvertedValue<std::string> converted_value;
|
|
converted_value.set_value(val);
|
|
return converted_value;
|
|
}
|
|
std::vector<std::string> default_choices() { return {}; }
|
|
};
|
|
} //namespace
|
|
|
|
#endif
|