Skip to content

Commit

Permalink
start to deprecate add_complex
Browse files Browse the repository at this point in the history
  • Loading branch information
phlptp committed Feb 11, 2020
1 parent bfc6a8a commit 2200f3c
Show file tree
Hide file tree
Showing 3 changed files with 253 additions and 89 deletions.
23 changes: 22 additions & 1 deletion include/CLI/App.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ class App {
/// Add option for assigning to a variable
template <typename AssignTo,
typename ConvertTo = AssignTo,
enable_if_t<!std::is_const<ConvertTo>::value, detail::enabler> = detail::dummy>
enable_if_t<!std::is_const<ConvertTo>::value && !detail::is_complex<ConvertTo>::value, detail::enabler> = detail::dummy>
Option *add_option(std::string option_name,
AssignTo &variable, ///< The variable to set
std::string option_description = "",
Expand All @@ -616,6 +616,27 @@ class App {
return opt;
}

/// Add option for assigning to a complex variable
template <typename AssignTo,
typename ConvertTo = AssignTo,
enable_if_t<!std::is_const<ConvertTo>::value && detail::is_complex<ConvertTo>::value, detail::enabler> = detail::dummy>
Option *add_option(std::string option_name,
AssignTo &variable, ///< The variable to set
std::string option_description = "",
bool defaulted = false) {

auto fun = [&variable](const CLI::results_t &res) { // comment for spacing
return detail::lexical_conversion<AssignTo, ConvertTo>(res, variable);
};

Option *opt = add_option(option_name, fun, option_description, defaulted, [&variable]() {
return CLI::detail::checked_to_string<AssignTo, ConvertTo>(variable);
});
opt->type_name("COMPLEX");
opt->type_size(1, 2)->delimiter('+')->expected(1)->run_callback_for_default();
return opt;
}

/// Add option for assigning to a variable
template <typename AssignTo,
enable_if_t<!std::is_const<AssignTo>::value, detail::enabler> = detail::dummy>
Expand Down
174 changes: 87 additions & 87 deletions include/CLI/TypeTools.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,16 +186,16 @@ template <typename T, typename S = std::istringstream> class is_istreamable {
static constexpr bool value = decltype(test<T, S>(0))::value;
};

/// Check for complex
template <typename T> class is_complex {
template <typename TT>
static auto test(int) -> decltype(std::declval<TT>().real(), std::declval<TT>().imag(), std::true_type());
/// Check for complex
template <typename T> class is_complex {
template <typename TT>
static auto test(int) -> decltype(std::declval<TT>().real(), std::declval<TT>().imag(), std::true_type());

template <typename> static auto test(...)->std::false_type;
template <typename> static auto test(...) -> std::false_type;

public:
static constexpr bool value = decltype(test<T>(0))::value;
};
public:
static constexpr bool value = decltype(test<T>(0))::value;
};

/// Templated operation to get a value from a stream
template <typename T, enable_if_t<is_istreamable<T>::value, detail::enabler> = detail::dummy>
Expand All @@ -214,9 +214,9 @@ bool from_stream(const std::string & /*istring*/, T & /*obj*/) {
// check to see if an object is a mutable container (fail by default)
template <typename T, typename _ = void> struct is_mutable_container : std::false_type {};

/// type trait to test if a type is a container meaning it has a value_type, it has an iterator, a clear, and an en end
/// methods and an insert function. And for our purposes we exclude std::string and types that can be constructed from
/// a std::string
/// type trait to test if a type is a mutable container meaning it has a value_type, it has an iterator, a clear, and
/// end methods and an insert function. And for our purposes we exclude std::string and types that can be constructed
/// from a std::string
template <typename T>
struct is_mutable_container<
T,
Expand All @@ -239,12 +239,8 @@ template <typename T, typename _ = void> struct is_readable_container : std::fal
template <typename T>
struct is_readable_container<
T,
conditional_t<false,
void_t<decltype(std::declval<T>().end()),
decltype(std::declval<T>().begin())>,
void>>
: public std::true_type{};

conditional_t<false, void_t<decltype(std::declval<T>().end()), decltype(std::declval<T>().begin())>, void>>
: public std::true_type {};

// check to see if an object is a wrapper (fail by default)
template <typename T, typename _ = void> struct is_wrapper : std::false_type {};
Expand Down Expand Up @@ -291,21 +287,19 @@ std::string to_string(T &&value) {
}

/// If conversion is not supported, return an empty string (streaming is not supported for that type)
template <
typename T,
enable_if_t<!std::is_constructible<std::string, T>::value && !is_ostreamable<T>::value &&
!is_readable_container<typename std::remove_const<T>::type>::value,
detail::enabler> = detail::dummy>
template <typename T,
enable_if_t<!std::is_constructible<std::string, T>::value && !is_ostreamable<T>::value &&
!is_readable_container<typename std::remove_const<T>::type>::value,
detail::enabler> = detail::dummy>
std::string to_string(T &&) {
return std::string{};
}

/// convert a vector to a string
template <
typename T,
enable_if_t<!std::is_constructible<std::string, T>::value && !is_ostreamable<T>::value &&
is_readable_container<typename std::remove_const<T>::type>::value,
detail::enabler> = detail::dummy>
template <typename T,
enable_if_t<!std::is_constructible<std::string, T>::value && !is_ostreamable<T>::value &&
is_readable_container<typename std::remove_const<T>::type>::value,
detail::enabler> = detail::dummy>
std::string to_string(T &&variable) {
std::vector<std::string> defaults;
auto cval = variable.begin();
Expand Down Expand Up @@ -360,23 +354,31 @@ template <typename T> struct type_count<T, typename std::enable_if<is_tuple_like
};
/// Type size for regular object types that do not look like a tuple
template <typename T>
struct type_count<T,
typename std::enable_if<!is_mutable_container<T>::value && !is_wrapper<T>::value &&
!is_tuple_like<T>::value && !std::is_void<T>::value>::type> {
struct type_count<
T,
typename std::enable_if<!is_mutable_container<T>::value && !is_wrapper<T>::value && !is_tuple_like<T>::value &&
!is_complex<T>::value && !std::is_void<T>::value>::type> {
static constexpr int value{1};
};

/// Type size for complex since it sometimes looks like a wrapper
template <typename T> struct type_count<T, typename std::enable_if<is_complex<T>::value>::type> {
static constexpr int value{1};
};

/// Type size of types that look like a container
template <typename T> struct type_count<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
static constexpr int value{is_mutable_container<typename T::value_type>::value ? expected_max_vector_size
: type_count<typename T::value_type>::value};
static constexpr int value{is_mutable_container<typename T::value_type>::value
? expected_max_vector_size
: type_count<typename T::value_type>::value};
};

/// Type size for wrapper type that are not containers
template <typename T>
struct type_count<T,
typename std::enable_if<!is_mutable_container<T>::value && is_wrapper<T>::value && !is_tuple_like<T>::value &&
!std::is_void<T>::value>::type> {
struct type_count<
T,
typename std::enable_if<!is_mutable_container<T>::value && is_wrapper<T>::value && !is_complex<T>::value &&
!is_tuple_like<T>::value && !std::is_void<T>::value>::type> {
static constexpr int value{type_count<typename T::value_type>::value};
};

Expand All @@ -403,7 +405,7 @@ enum class object_category : int {
number_constructible = 12,
double_constructible = 14,
integer_constructible = 16,
complex_number=22,
complex_number = 22,
tuple_value = 35,
wrapper_value = 39,
container_value = 40,
Expand Down Expand Up @@ -468,7 +470,7 @@ template <typename T> struct classify_object<T, typename std::enable_if<std::is_
};

template <typename T> struct classify_object<T, typename std::enable_if<is_complex<T>::value>::type> {
static constexpr object_category value{ object_category::complex_number };
static constexpr object_category value{object_category::complex_number};
};

/// Handy helper to contain a bunch of checks that rule out many common types (integers, string like, floating point,
Expand All @@ -494,7 +496,7 @@ struct classify_object<T,
/// Assignable from double or int
template <typename T>
struct classify_object<T,
typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
!is_wrapper<T>::value && is_direct_constructible<T, double>::value &&
is_direct_constructible<T, int>::value>::type> {
static constexpr object_category value{object_category::number_constructible};
Expand All @@ -503,7 +505,7 @@ struct classify_object<T,
/// Assignable from int
template <typename T>
struct classify_object<T,
typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
!is_wrapper<T>::value && !is_direct_constructible<T, double>::value &&
is_direct_constructible<T, int>::value>::type> {
static constexpr object_category value{object_category::integer_constructible};
Expand All @@ -521,7 +523,7 @@ struct classify_object<T,
/// Tuple type
template <typename T>
struct classify_object<T,
typename std::enable_if<(type_count<T>::value >= 2 && !is_wrapper<T>::value ) ||
typename std::enable_if<(type_count<T>::value >= 2 && !is_wrapper<T>::value) ||
(is_tuple_like<T>::value && uncommon_type<T>::value &&
!is_direct_constructible<T, double>::value &&
!is_direct_constructible<T, int>::value)>::type> {
Expand Down Expand Up @@ -578,8 +580,8 @@ constexpr const char *type_name() {

/// Print name for enumeration types
template <typename T,
enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
constexpr const char *type_name() {
enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
constexpr const char *type_name() {
return "COMPLEX";
}

Expand Down Expand Up @@ -747,34 +749,31 @@ bool lexical_cast(const std::string &input, T &output) {

/// complex
template <typename T,
enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
bool lexical_cast(const std::string &input, T &output) {
using XC=typename conditional_t<is_wrapper<T>::value, typename T::value_type, double>;
enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
bool lexical_cast(const std::string &input, T &output) {
using XC = typename conditional_t<is_wrapper<T>::value, typename T::value_type, double>;
XC x, y;
auto str1 = input;
bool worked = false;
auto nloc = str1.find_last_of('-');
if (nloc != std::string::npos && nloc > 0) {
if(nloc != std::string::npos && nloc > 0) {
worked = detail::lexical_cast(str1.substr(0, nloc), x);
str1 = str1.substr(nloc);
if (str1.back() == 'i' || str1.back() == 'j')
if(str1.back() == 'i' || str1.back() == 'j')
str1.pop_back();
worked = worked && detail::lexical_cast(str1, y);
}
else {
if (str1.back() == 'i' || str1.back() == 'j') {
} else {
if(str1.back() == 'i' || str1.back() == 'j') {
str1.pop_back();
worked = detail::lexical_cast(str1, y);
x = XC{ 0 };
}
else {
x = XC{0};
} else {
worked = detail::lexical_cast(str1, x);
y = XC{ 0 };
y = XC{0};
}
}
if (worked)
{
output = T{ x,y };
if(worked) {
output = T{x, y};
return worked;
}
return from_stream(input, output);
Expand Down Expand Up @@ -933,6 +932,7 @@ bool lexical_assign(const std::string &input, T &output) {
template <typename T,
typename XC,
enable_if_t<!is_tuple_like<T>::value && !is_tuple_like<XC>::value && !is_mutable_container<T>::value &&
!is_complex<XC>::value &&
!(classify_object<XC>::value == object_category::wrapper_value ||
classify_object<XC>::value == object_category::container_value),
detail::enabler> = detail::dummy>
Expand All @@ -957,25 +957,6 @@ bool lexical_conversion(const std::vector<std ::string> &strings, T &output) {
return retval;
}

/// wrapper types interiar typesize==1
template <typename T,
class XC,
enable_if_t<classify_object<XC>::value == object_category::wrapper_value && type_count<XC>::value == 1,
detail::enabler> = detail::dummy>
bool lexical_conversion(const std::vector<std::string> &strings, T &output) {
if (strings.empty() || strings.front().empty())
{
output = XC{};
return true;
}
typename XC::value_type val;
if(lexical_conversion<typename XC::value_type, typename XC::value_type>(strings, val)) {
output = XC{val};
return true;
}
return false;
}

/// Lexical conversion of a container types
template <class T,
class XC,
Expand Down Expand Up @@ -1020,6 +1001,27 @@ bool lexical_conversion(const std::vector<std ::string> &strings, T &output) {
return (!output.empty());
}

/// Lexical conversion of a container types with type size of two
template <class T, class XC, enable_if_t<is_complex<XC>::value, detail::enabler> = detail::dummy>
bool lexical_conversion(const std::vector<std::string> &strings, T &output) {

if(strings.size() >= 2 && !strings[1].empty()) {
using XC2 = typename conditional_t<is_wrapper<XC>::value, typename XC::value_type, double>;
XC2 x, y;
auto str1 = strings[1];
if(str1.back() == 'i' || str1.back() == 'j') {
str1.pop_back();
}
auto worked = detail::lexical_cast(strings[0], x) && detail::lexical_cast(str1, y);
if(worked) {
output = XC{x, y};
}
return worked;
} else {
return lexical_assign<T, XC>(strings[0], output);
}
}

/// Conversion to a vector type using a particular single type as the conversion type
template <class T,
class XC,
Expand All @@ -1041,8 +1043,8 @@ bool lexical_conversion(const std::vector<std ::string> &strings, T &output) {
/// Lexical conversion if there is only one element but the conversion type is a mutable container
template <typename T,
typename XC,
enable_if_t<!is_tuple_like<T>::value && !is_mutable_container<T>::value && is_mutable_container<XC>::value, detail::enabler> =
detail::dummy>
enable_if_t<!is_tuple_like<T>::value && !is_mutable_container<T>::value && is_mutable_container<XC>::value,
detail::enabler> = detail::dummy>
bool lexical_conversion(const std::vector<std ::string> &strings, T &output) {

if(strings.size() > 1 || (!strings.empty() && !(strings.front().empty()))) {
Expand Down Expand Up @@ -1119,20 +1121,18 @@ bool lexical_conversion(const std::vector<std ::string> &strings, T &output) {
return retval;
}

/// wrapper types interiar typesize>1
/// wrapper types
template <typename T,
class XC,
enable_if_t<classify_object<XC>::value == object_category::wrapper_value && (type_count<XC>::value > 1),
detail::enabler> = detail::dummy>
bool lexical_conversion(const std::vector<std::string> &strings, T &output) {
if (strings.empty() || strings.front().empty())
{
class XC,
enable_if_t<classify_object<XC>::value == object_category::wrapper_value, detail::enabler> = detail::dummy>
bool lexical_conversion(const std::vector<std::string> &strings, T &output) {
if(strings.empty() || strings.front().empty()) {
output = XC{};
return true;
}
typename XC::value_type val;
if (lexical_conversion<typename XC::value_type, typename XC::value_type>(strings, val)) {
output = XC{ val };
if(lexical_conversion<typename XC::value_type, typename XC::value_type>(strings, val)) {
output = XC{val};
return true;
}
return false;
Expand Down
Loading

0 comments on commit 2200f3c

Please sign in to comment.