Unify container operations

This commit is contained in:
Stephan van Veen 2019-05-12 15:54:23 +02:00
parent cddde9f1b7
commit 94ca8e2552
4 changed files with 52 additions and 50 deletions

View File

@ -57,17 +57,6 @@ bool starts_with(const std::string& haystack, const std::string& needle) {
return needle.length() <= haystack.length() return needle.length() <= haystack.length()
&& std::equal(needle.begin(), needle.end(), haystack.begin()); && std::equal(needle.begin(), needle.end(), haystack.begin());
} }
// Get value at index from std::list
template <typename T>
T get_from_list(const std::list<T>& aList, size_t aIndex) {
if (aList.size() > aIndex) {
auto tIterator = aList.begin();
std::advance(tIterator, aIndex);
return *tIterator;
}
return T();
}
} }
class Argument { class Argument {
@ -150,33 +139,29 @@ public:
template <typename T> template <typename T>
typename std::enable_if<is_specialization<T, std::vector>::value, bool>::type typename std::enable_if<is_specialization<T, std::vector>::value, bool>::type
operator==(const T& aRhs) const { operator==(const T& aRhs) const {
using ValueType = typename T::value_type;
T tLhs = get<T>(); T tLhs = get<T>();
if (tLhs.size() != aRhs.size()) if (tLhs.size() != aRhs.size())
return false; return false;
else { else {
for (size_t i = 0; i < tLhs.size(); i++) { return std::equal(std::begin(tLhs), std::begin(tLhs), std::begin(aRhs), [](const auto& lhs, const auto& rhs) {
auto tValueAtIndex = std::any_cast<typename T::value_type>(tLhs[i]); return std::any_cast<ValueType>(lhs) == rhs;
if (tValueAtIndex != aRhs[i]) });
return false;
}
return true;
} }
} }
// Template specialization for std::list<...> // Template specialization for std::list<...>
template <typename T> template <typename T>
typename std::enable_if<is_specialization<T, std::list>::value, bool>::type typename std::enable_if<is_specialization<T, std::list>::value, bool>::type
operator==(const T& aRhs) const { operator==(const T& aRhs) const {
using ValueType = typename T::value_type;
T tLhs = get<T>(); T tLhs = get<T>();
if (tLhs.size() != aRhs.size()) if (tLhs.size() != aRhs.size())
return false; return false;
else { else {
for (size_t i = 0; i < tLhs.size(); i++) { return std::equal(std::begin(tLhs), std::begin(tLhs), std::begin(aRhs), [](const auto& lhs, const auto& rhs) {
auto tValueAtIndex = std::any_cast<typename T::value_type>(get_from_list(tLhs, i)); return std::any_cast<ValueType>(lhs) == rhs;
if (tValueAtIndex != get_from_list(aRhs, i)) });
return false;
}
return true;
} }
} }
@ -214,13 +199,13 @@ public:
template <typename T> template <typename T>
typename std::enable_if<is_specialization<T, std::vector>::value, T>::type typename std::enable_if<is_specialization<T, std::vector>::value, T>::type
get() const { get() const {
using ValueType = typename T::value_type;
T tResult; T tResult;
if (mValues.empty()) { if (mValues.empty()) {
if (mDefaultValue.has_value()) { if (mDefaultValue.has_value()) {
T tDefaultValues = std::any_cast<T>(mDefaultValue); T tDefaultValues = std::any_cast<T>(mDefaultValue);
for (size_t i = 0; i < tDefaultValues.size(); i++) { std::transform(std::begin(tDefaultValues), std::end(tDefaultValues),
tResult.emplace_back(std::any_cast<typename T::value_type>(tDefaultValues[i])); std::back_inserter(tResult), std::any_cast<ValueType>);
}
return tResult; return tResult;
} }
else else
@ -229,16 +214,15 @@ public:
else { else {
if (!mRawValues.empty()) { if (!mRawValues.empty()) {
for (const auto& mValue : mValues) { for (const auto& mValue : mValues) {
tResult.emplace_back(std::any_cast<typename T::value_type>(mValue)); tResult.emplace_back(std::any_cast<ValueType>(mValue));
} }
return tResult; return tResult;
} }
else { else {
if (mDefaultValue.has_value()) { if (mDefaultValue.has_value()) {
std::vector<T> tDefaultValues = std::any_cast<std::vector<T>>(mDefaultValue); auto tDefaultValues = std::any_cast<std::vector<T>>(mDefaultValue);
for (size_t i = 0; i < tDefaultValues.size(); i++) { std::transform(std::begin(tDefaultValues), std::end(tDefaultValues),
tResult.emplace_back(std::any_cast<typename T::value_type>(tDefaultValues[i])); std::back_inserter(tResult), std::any_cast<ValueType>);
}
return tResult; return tResult;
} }
else else
@ -251,13 +235,13 @@ public:
template <typename T> template <typename T>
typename std::enable_if<is_specialization<T, std::list>::value, T>::type typename std::enable_if<is_specialization<T, std::list>::value, T>::type
get() const { get() const {
using ValueType = typename T::value_type;
T tResult; T tResult;
if (mValues.empty()) { if (mValues.empty()) {
if (mDefaultValue.has_value()) { if (mDefaultValue.has_value()) {
T tDefaultValues = std::any_cast<T>(mDefaultValue); T tDefaultValues = std::any_cast<T>(mDefaultValue);
for (size_t i = 0; i < tDefaultValues.size(); i++) { std::transform(std::begin(tDefaultValues), std::end(tDefaultValues),
tResult.emplace_back(std::any_cast<typename T::value_type>(get_from_list(tDefaultValues, i))); std::back_inserter(tResult), std::any_cast<ValueType>);
}
return tResult; return tResult;
} }
else else
@ -266,16 +250,15 @@ public:
else { else {
if (!mRawValues.empty()) { if (!mRawValues.empty()) {
for (const auto& mValue : mValues) { for (const auto& mValue : mValues) {
tResult.emplace_back(std::any_cast<typename T::value_type>(mValue)); tResult.emplace_back(std::any_cast<ValueType>(mValue));
} }
return tResult; return tResult;
} }
else { else {
if (mDefaultValue.has_value()) { if (mDefaultValue.has_value()) {
std::list<T> tDefaultValues = std::any_cast<std::list<T>>(mDefaultValue); auto tDefaultValues = std::any_cast<std::list<T>>(mDefaultValue);
for (size_t i = 0; i < tDefaultValues.size(); i++) { std::transform(std::begin(tDefaultValues), std::end(tDefaultValues),
tResult.emplace_back(std::any_cast<typename T::value_type>(get_from_list(tDefaultValues, i))); std::back_inserter(tResult), std::any_cast<ValueType>);
}
return tResult; return tResult;
} }
else else

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <catch.hpp> #include <catch.hpp>
#include <argparse.hpp> #include <argparse.hpp>
#include <test_utility.hpp>
TEST_CASE("Parse compound toggle arguments with implicit values", "[compound_arguments]") { TEST_CASE("Parse compound toggle arguments with implicit values", "[compound_arguments]") {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
@ -97,9 +98,9 @@ TEST_CASE("Parse compound toggle arguments with implicit values and nargs and ot
REQUIRE(numbers[2] == 3); REQUIRE(numbers[2] == 3);
auto numbers_list = program.get<std::list<int>>("numbers"); auto numbers_list = program.get<std::list<int>>("numbers");
REQUIRE(numbers.size() == 3); REQUIRE(numbers.size() == 3);
REQUIRE(argparse::get_from_list(numbers_list, 0) == 1); REQUIRE(testutility::get_from_list(numbers_list, 0) == 1);
REQUIRE(argparse::get_from_list(numbers_list, 1) == 2); REQUIRE(testutility::get_from_list(numbers_list, 1) == 2);
REQUIRE(argparse::get_from_list(numbers_list, 2) == 3); REQUIRE(testutility::get_from_list(numbers_list, 2) == 3);
} }
TEST_CASE("Parse out-of-order compound arguments", "[compound_arguments]") { TEST_CASE("Parse out-of-order compound arguments", "[compound_arguments]") {

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <catch.hpp> #include <catch.hpp>
#include <argparse.hpp> #include <argparse.hpp>
#include <test_utility.hpp>
TEST_CASE("Parse vector of arguments", "[vector]") { TEST_CASE("Parse vector of arguments", "[vector]") {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
@ -24,8 +25,8 @@ TEST_CASE("Parse list of arguments", "[vector]") {
auto inputs = program.get<std::list<std::string>>("input"); auto inputs = program.get<std::list<std::string>>("input");
REQUIRE(inputs.size() == 2); REQUIRE(inputs.size() == 2);
REQUIRE(argparse::get_from_list(inputs, 0) == "rocket.mesh"); REQUIRE(testutility::get_from_list(inputs, 0) == "rocket.mesh");
REQUIRE(argparse::get_from_list(inputs, 1) == "thrust_profile.csv"); REQUIRE(testutility::get_from_list(inputs, 1) == "thrust_profile.csv");
} }
TEST_CASE("Parse list of arguments with default values", "[vector]") { TEST_CASE("Parse list of arguments with default values", "[vector]") {
@ -38,11 +39,11 @@ TEST_CASE("Parse list of arguments with default values", "[vector]") {
auto inputs = program.get<std::list<int>>("--input"); auto inputs = program.get<std::list<int>>("--input");
REQUIRE(inputs.size() == 5); REQUIRE(inputs.size() == 5);
REQUIRE(argparse::get_from_list(inputs, 0) == 1); REQUIRE(testutility::get_from_list(inputs, 0) == 1);
REQUIRE(argparse::get_from_list(inputs, 1) == 2); REQUIRE(testutility::get_from_list(inputs, 1) == 2);
REQUIRE(argparse::get_from_list(inputs, 2) == 3); REQUIRE(testutility::get_from_list(inputs, 2) == 3);
REQUIRE(argparse::get_from_list(inputs, 3) == 4); REQUIRE(testutility::get_from_list(inputs, 3) == 4);
REQUIRE(argparse::get_from_list(inputs, 4) == 5); REQUIRE(testutility::get_from_list(inputs, 4) == 5);
REQUIRE(program["--input"] == std::list<int>{1, 2, 3, 4, 5}); REQUIRE(program["--input"] == std::list<int>{1, 2, 3, 4, 5});
} }

17
test/test_utility.hpp Normal file
View File

@ -0,0 +1,17 @@
#ifndef ARGPARSE_TEST_UTILITY_HPP
#define ARGPARSE_TEST_UTILITY_HPP
namespace testutility {
// Get value at index from std::list
template <typename T>
T get_from_list(const std::list<T>& aList, size_t aIndex) {
if (aList.size() > aIndex) {
auto tIterator = aList.begin();
std::advance(tIterator, aIndex);
return *tIterator;
}
return T();
}
}
#endif //ARGPARSE_TEST_UTILITY_HPP