Add optional length check when converting AnyValue to vector

This commit is contained in:
Ray Speth 2018-12-13 17:18:00 -05:00
parent 24d1e86440
commit 7a97ff9917
5 changed files with 72 additions and 26 deletions

View file

@ -86,9 +86,9 @@ public:
template<class T>
AnyValue& operator=(const std::vector<T>& value);
template<class T>
const std::vector<T>& asVector() const;
const std::vector<T>& asVector(size_t nMin=npos, size_t nMax=npos) const;
template<class T>
std::vector<T>& asVector();
std::vector<T>& asVector(size_t nMin=npos, size_t nMax=npos);
AnyValue& operator=(const AnyMap& value);
AnyValue& operator=(AnyMap&& value);
@ -105,6 +105,9 @@ public:
private:
std::string demangle(const std::type_info& type) const;
template<class T>
void checkSize(const std::vector<T>& v, size_t nMin, size_t nMax) const;
std::string m_key;
std::unique_ptr<boost::any> m_value;
static std::map<std::string, std::string> s_typenames;
@ -112,24 +115,24 @@ private:
// Implicit conversion to vector<AnyValue>
template<>
const std::vector<AnyValue>& AnyValue::asVector<AnyValue>() const;
const std::vector<AnyValue>& AnyValue::asVector<AnyValue>(size_t nMin, size_t nMax) const;
template<>
std::vector<AnyValue>& AnyValue::asVector<AnyValue>();
std::vector<AnyValue>& AnyValue::asVector<AnyValue>(size_t nMin, size_t nMax);
// Implicit conversion of long int to double if accessed as a vector<double>
template<>
const std::vector<double>& AnyValue::asVector<double>() const;
const std::vector<double>& AnyValue::asVector<double>(size_t nMin, size_t nMax) const;
template<>
std::vector<double>& AnyValue::asVector<double>();
std::vector<double>& AnyValue::asVector<double>(size_t nMin, size_t nMax);
// Implicit conversion of long int to double if accessed as a vector<vector<double>>
template<>
const std::vector<vector_fp>& AnyValue::asVector<vector_fp>() const;
const std::vector<vector_fp>& AnyValue::asVector<vector_fp>(size_t nMin, size_t nMax) const;
template<>
std::vector<vector_fp>& AnyValue::asVector<vector_fp>();
std::vector<vector_fp>& AnyValue::asVector<vector_fp>(size_t nMin, size_t nMax);
//! A map of string keys to values whose type can vary at runtime

View file

@ -65,13 +65,17 @@ AnyValue &AnyValue::operator=(const std::vector<T> &value) {
}
template<class T>
const std::vector<T> &AnyValue::asVector() const {
return as<std::vector<T>>();
const std::vector<T> &AnyValue::asVector(size_t nMin, size_t nMax) const {
const auto& v = as<std::vector<T>>();
checkSize(v, nMin, nMax);
return v;
}
template<class T>
std::vector<T> &AnyValue::asVector() {
return as<std::vector<T>>();
std::vector<T> &AnyValue::asVector(size_t nMin, size_t nMax) {
auto& v = as<std::vector<T>>();
checkSize(v, nMin, nMax);
return v;
}
template<class T>
@ -120,5 +124,20 @@ std::map<std::string, T> AnyValue::asMap() const
return dest;
}
template<class T>
void AnyValue::checkSize(const std::vector<T>& v, size_t nMin, size_t nMax) const
{
if (nMin != npos && nMax == npos && v.size() != nMin) {
throw CanteraError("AnyValue::checkSize", "Expected array '{}' "
"to have length {}, but found an array of length {}.",
m_key, nMin, v.size());
} else if (nMin != npos && nMax != npos
&& (v.size() < nMin || v.size() > nMax)) {
throw CanteraError("AnyValue::checkSize",
"Expected array '{}' to have from {} to {} elements, but found an "
" array of length {}.", m_key, nMin, nMax, v.size());
}
}
}
#endif

View file

@ -377,7 +377,7 @@ std::string AnyValue::demangle(const std::type_info& type) const
// Explicit template specializations to allow certain conversions
template<>
const std::vector<AnyValue>& AnyValue::asVector<AnyValue>() const
const std::vector<AnyValue>& AnyValue::asVector<AnyValue>(size_t nMin, size_t nMax) const
{
if (!is<std::vector<AnyValue>>()) {
std::vector<AnyValue> v;
@ -400,18 +400,22 @@ const std::vector<AnyValue>& AnyValue::asVector<AnyValue>() const
// If none of these special cases match, the value won't be replaced,
// and an exception will be thrown.
}
return as<std::vector<AnyValue>>();
const auto& vv = as<std::vector<AnyValue>>();
checkSize(vv, nMin, nMax);
return vv;
}
template<>
std::vector<AnyValue>& AnyValue::asVector<AnyValue>()
std::vector<AnyValue>& AnyValue::asVector<AnyValue>(size_t nMin, size_t nMax)
{
return const_cast<std::vector<AnyValue>&>(
auto& v = const_cast<std::vector<AnyValue>&>(
const_cast<const AnyValue*>(this)->asVector<AnyValue>());
checkSize(v, nMin, nMax);
return v;
}
template<>
const std::vector<double>& AnyValue::asVector<double>() const
const std::vector<double>& AnyValue::asVector<double>(size_t nMin, size_t nMax) const
{
if (is<std::vector<long int>>()) {
std::vector<double> v;
@ -420,11 +424,13 @@ const std::vector<double>& AnyValue::asVector<double>() const
}
*m_value = v;
}
return as<std::vector<double>>();
const auto& vv = as<std::vector<double>>();
checkSize(vv, nMin, nMax);
return vv;
}
template<>
std::vector<double>& AnyValue::asVector<double>()
std::vector<double>& AnyValue::asVector<double>(size_t nMin, size_t nMax)
{
if (is<std::vector<long int>>()) {
std::vector<double> v;
@ -433,11 +439,13 @@ std::vector<double>& AnyValue::asVector<double>()
}
*m_value = v;
}
return as<std::vector<double>>();
auto& vv = as<std::vector<double>>();
checkSize(vv, nMin, nMax);
return vv;
}
template<>
const std::vector<vector_fp>& AnyValue::asVector<vector_fp>() const
const std::vector<vector_fp>& AnyValue::asVector<vector_fp>(size_t nMin, size_t nMax) const
{
if (is<std::vector<std::vector<long int>>>()) {
std::vector<vector_fp> v;
@ -449,11 +457,13 @@ const std::vector<vector_fp>& AnyValue::asVector<vector_fp>() const
}
*m_value = v;
}
return as<std::vector<vector_fp>>();
const auto& vv = as<std::vector<vector_fp>>();
checkSize(vv, nMin, nMax);
return vv;
}
template<>
std::vector<vector_fp>& AnyValue::asVector<vector_fp>()
std::vector<vector_fp>& AnyValue::asVector<vector_fp>(size_t nMin, size_t nMax)
{
if (is<std::vector<std::vector<long int>>>()) {
std::vector<vector_fp> v;
@ -465,7 +475,9 @@ std::vector<vector_fp>& AnyValue::asVector<vector_fp>()
}
*m_value = v;
}
return as<std::vector<vector_fp>>();
auto& vv = as<std::vector<vector_fp>>();
checkSize(vv, nMin, nMax);
return vv;
}

View file

@ -314,7 +314,7 @@ Arrhenius readArrhenius(const Reaction& R, const AnyValue& rate,
len_dim += pressure_dependence * reaction_phase_ndim;
quantity_dim -= pressure_dependence;
auto& rate_vec = rate.asVector<AnyValue>();
auto& rate_vec = rate.asVector<AnyValue>(3);
double A = units.convert(rate_vec[0], Units(1.0, 0, len_dim, -1, 0, 0, quantity_dim));
double b = rate_vec[1].asDouble();
double Ta = units.convertMolarEnergy(rate_vec[2], "K");
@ -671,7 +671,7 @@ void setupPlogReaction(PlogReaction& R, const AnyMap& node,
setupReaction(R, node);
std::multimap<double, Arrhenius> rates;
for (const auto& rate : node.at("rate-constants").asVector<AnyValue>()) {
const auto& p_rate = rate.asVector<AnyValue>();
const auto& p_rate = rate.asVector<AnyValue>(2);
rates.insert({units.convert(p_rate[0], "Pa"),
readArrhenius(R, p_rate[1], kin, units)});
}

View file

@ -96,6 +96,18 @@ TEST(AnyMap, vector)
EXPECT_EQ(m["nested/item"].asVector<double>().size(), (size_t) 4);
}
TEST(AnyMap, vector_length)
{
AnyMap m;
m["foo"] = vector_fp{2.4, 9.6, 14.4, 28.8};
// Valid lengths
m["foo"].asVector<double>(4);
m["foo"].asVector<double>(2, 5);
// Invalid lengths
EXPECT_THROW(m["foo"].asVector<double>(3), CanteraError);
EXPECT_THROW(m["foo"].asVector<double>(5, 8), CanteraError);
}
TEST(AnyMap, getters_with_defaults)
{
AnyMap m;