Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 55 additions & 161 deletions src/sst/core/serialization/objectMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -733,8 +733,53 @@ class ObjectMapClass : public ObjectMapWithChildren
@return address of represented object
*/
void* getAddr() override { return addr_; }
};
}; // class ObjectMapClass

// Whether two types share a common type they can both be converted to
// Users are allowed to provide specializations for std::common_type<T1, T2> for user types
template <class T1, class T2, class = void>
struct have_common_type : std::false_type
{};

template <class T1, class T2>
struct have_common_type<T1, T2, std::void_t<std::common_type_t<T1, T2>>> : std::true_type
{};

// Comparison of two variables if they are convertible to a common type
template <typename T1, typename T2>
std::enable_if_t<have_common_type<T1, T2>::value, bool>
cmp(T1 t1, ObjectMapComparison::Op op, T2 t2)
{
using T = std::common_type_t<T1, T2>;
switch ( op ) {
case ObjectMapComparison::Op::LT:
return static_cast<T>(t1) < static_cast<T>(t2);
case ObjectMapComparison::Op::LTE:
return static_cast<T>(t1) <= static_cast<T>(t2);
case ObjectMapComparison::Op::GT:
return static_cast<T>(t1) > static_cast<T>(t2);
case ObjectMapComparison::Op::GTE:
return static_cast<T>(t1) >= static_cast<T>(t2);
case ObjectMapComparison::Op::EQ:
return static_cast<T>(t1) == static_cast<T>(t2);
case ObjectMapComparison::Op::NEQ:
case ObjectMapComparison::Op::CHANGED:
return static_cast<T>(t1) != static_cast<T>(t2);
default:
std::cout << "Invalid comparison operator\n";
return false;
}
}

// Comparison of two variables if they are not convertible to a common type
template <typename T1, typename T2>
std::enable_if_t<!have_common_type<T1, T2>::value, bool>
cmp(T1 UNUSED(t1), ObjectMapComparison::Op UNUSED(op), T2 UNUSED(t2))
{
// We shouldn't get here.... Can I throw an error somehow?
printf("ERROR: CMP: Does not support comparison of two types without a std::common_type\n");
return false;
}

/**
Template implementation of ObjectMapComparison for <var> <op> <value>
Expand Down Expand Up @@ -763,37 +808,13 @@ class ObjectMapComparison_impl : public ObjectMapComparison

bool compare() override
{
switch ( op_ ) {
case Op::LT:
return *var_ < comp_value_;
break;
case Op::LTE:
return *var_ <= comp_value_;
break;
case Op::GT:
return *var_ > comp_value_;
break;
case Op::GTE:
return *var_ >= comp_value_;
break;
case Op::EQ:
return *var_ == comp_value_;
break;
case Op::NEQ:
return *var_ != comp_value_;
break;
case Op::CHANGED:
{
// See if we've changed
bool ret = *var_ != comp_value_;
// Store the current value for the next test
comp_value_ = *var_;
return ret;
} break;
default:
return false;
break;
}
// Get the result of the comparison
bool ret = cmp(*var_, op_, comp_value_);

// For change detection, store the current value for the next test
if ( op_ == Op::CHANGED ) comp_value_ = static_cast<T>(*var_);

return ret;
}

std::string getCurrentValue() override { return SST::Core::to_string(*var_); }
Expand All @@ -815,131 +836,6 @@ class ObjectMapComparison_impl : public ObjectMapComparison
Op op_ = Op::INVALID;
}; // class ObjectMapComparison_impl

/**
Templated compareType implementations
Variables are currently cast to matching types before being passed to this function
*/
template <typename V1>
bool
cmp(V1 v, ObjectMapComparison::Op op, V1 w)
{
switch ( op ) {
case ObjectMapComparison::Op::LT:
return v < w;
break;
case ObjectMapComparison::Op::LTE:
return v <= w;
break;
case ObjectMapComparison::Op::GT:
return v > w;
break;
case ObjectMapComparison::Op::GTE:
return v >= w;
break;
case ObjectMapComparison::Op::EQ:
return v == w;
break;
case ObjectMapComparison::Op::NEQ:
return v != w;
break;
default:
std::cout << "Invalid comparison operator\n";
return false;
break;
}
}

// Comparison of two variables of the same type
template <typename U1, typename U2, std::enable_if_t<std::is_same_v<U1, U2>, int> = true>
bool
compareType(U1 v, ObjectMapComparison::Op op, U2 w)
{
// Handle same type - just compare
// printf(" CMP: Same type\n");
return cmp(v, op, w);
}

// Comparison of two variables with different arithmetic types
template <typename U1, typename U2,
std::enable_if_t<!std::is_same_v<U1, U2> && std::is_arithmetic_v<U1> && std::is_arithmetic_v<U2>, int> = true>
bool
compareType(U1 v, ObjectMapComparison::Op op, U2 w)
{
// printf(" CMP: Different types\n");
// Handle integrals (bool, char, flavors of int)
if ( std::is_integral_v<U1> && std::is_integral_v<U2> ) {
// both unsigned integrals - cast to unsigned long long
if ( std::is_unsigned_v<U1> && std::is_unsigned_v<U2> ) {
// printf(" CMP: Both unsigned integrals\n");
unsigned long long v1 = static_cast<unsigned long long>(v);
unsigned long long w1 = static_cast<unsigned long long>(w);
return cmp(v1, op, w1);
}
// both integers but at least one signed - cast to signed long long
else {
// printf(" CMP: Not both unsigned integrals\n");
long long v1 = static_cast<long long>(v);
long long w1 = static_cast<long long>(w);
return cmp(v1, op, w1);
}
}
// Handle float/double combinations - cast to long double
else if ( std::is_floating_point_v<U1> && std::is_floating_point_v<U2> ) {
// printf(" CMP: Both fp\n");
long double v1 = static_cast<long double>(v);
long double w1 = static_cast<long double>(w);
return cmp(v1, op, w1);
}
else { // Integral and FP comparison - cast integral to fp
// printf(" CMP: integral and fp\n");
if ( std::is_integral_v<U1> ) {
if ( std::is_same_v<U2, float> ) {
float v1 = static_cast<float>(v);
float w1 = static_cast<float>(w); // unnecessary but compiler needs to know they are the same
return cmp(v1, op, w1);
}
else if ( std::is_same_v<U2, double> ) {
double v1 = static_cast<double>(v);
double w1 = static_cast<double>(w); // unnecessary ...
return cmp(v1, op, w1);
}
else {
long double v1 = static_cast<long double>(v);
long double w1 = static_cast<long double>(w); // unnecessary ...
return cmp(v1, op, w1);
}
}
else {
if ( std::is_same_v<U1, float> ) {
float v1 = static_cast<float>(v); // unnecessary ...
float w1 = static_cast<float>(w);
return cmp(v1, op, w1);
}
else if ( std::is_same_v<U1, double> ) {
double v1 = static_cast<double>(v); // unnecessary ...
double w1 = static_cast<double>(w);
return cmp(v1, op, w1);
}
else {
long double v1 = static_cast<long double>(v); // unnecessary ...
long double w1 = static_cast<long double>(w);
return cmp(v1, op, w1);
}
}
}
}

// Comparison of two variables with at least one non-arithmetic type
template <typename U1, typename U2,
std::enable_if_t<(!std::is_same_v<U1, U2> && (!std::is_arithmetic_v<U1> || !std::is_arithmetic_v<U2>)), int> = true>
bool
compareType(U1 UNUSED(v), ObjectMapComparison::Op UNUSED(op), U2 UNUSED(w))
{
// We shouldn't get here.... Can I throw an error somehow?
printf(" ERROR: CMP: Does not support non-arithmetic types\n");
return false;
}


/**
Template implementation of ObjectMapComparison for <var> <op> <var>
Expand All @@ -960,7 +856,7 @@ class ObjectMapComparison_var : public ObjectMapComparison
{
T1 v1 = *var1_;
T2 v2 = *var2_;
return compareType(v1, op_, v2);
return cmp(v1, op_, v2);
}

std::string getCurrentValue() override { return SST::Core::to_string(*var1_) + " " + SST::Core::to_string(*var2_); }
Expand Down Expand Up @@ -1354,9 +1250,7 @@ class ObjectMapFundamental : public ObjectMap
{
// Ensure var2 is fundamental type
if ( !var2->isFundamental() ) {
printf("Triggers can only use fundamental types; %s is not "
"fundamental\n",
name2.c_str());
printf("Triggers can only use fundamental types; %s is not fundamental\n", name2.c_str());
return nullptr;
}

Expand Down
Loading