the idea is to prevent conversion to float with ofMin/Max (and maybe applicable to other) for the benefit of end users that mix/match types (typically floats (as returned by many OF functions), double (as dotted-decimals are interpreted in C++ source code) and int, also as textual interpretations).
comparing different types is not evident, especially when unsigned is thrown in (I guess that's why std::min does not attempt it, but our use case is probably defined enough to tackle in a specific way).
the logic:
if the args are same time, simply pass to std::min (which accepts anything that operates on <)
if args are different, find the std::common_type, then
if one of the members is size_t or uint64_t, treat it differently (there is no common type that can hold both uint64_t and anything signed, for instance, and it's undefined behaviour (no throw)) but in our case we don't need to return as such a common type as in the context of getting the minimum, the "result" will not be in the high uint64_t range (implicit, as the other arg is not size_t, it will be smaller).
if signed vs unsigned, check if the signed is < 0 before attempting cast of the "other" to prevent overflow of negatives.
template<typename T>
T ofMin(const T & t1, const T & t2) const { return std::min(t1, t2); }
template<typename T, typename Q>
auto ofMin(const T & t, const Q & q) const {
using CommonType = typename std::common_type<T, Q>::type;
if constexpr ((std::is_same_v<T, uint64_t> or std::is_same_v<T, size_t>) && std::is_signed_v) {
if (q < 0) {
return q;
} else {
return std::min(static_cast(t), q);
}
} else if constexpr ((std::is_same_v<Q, uint64_t> or std::is_same_v<Q, size_t>) && std::is_signed_v) {
if (t < 0) {
return t;
} else {
return std::min(t, static_cast(q));
}
} else if constexpr (std::is_signed_v && std::is_unsigned_v) {
if (t < 0 || q > static_cast(std::numeric_limits::max())) {
return static_cast(t);
} else {
return std::min(static_cast(t), static_cast(q));
}
} else if constexpr (std::is_signed_v && std::is_unsigned_v){
if (q < 0 || t > static_cast(std::numeric_limits::max())) {
return static_cast(q);
} else {
return std::min(static_cast(t), static_cast(q));
}
} else {
return std::min(static_cast(t), static_cast(q));
}
}
from #7918
the idea is to prevent conversion to float with ofMin/Max (and maybe applicable to other) for the benefit of end users that mix/match types (typically floats (as returned by many OF functions), double (as dotted-decimals are interpreted in C++ source code) and int, also as textual interpretations).
comparing different types is not evident, especially when unsigned is thrown in (I guess that's why std::min does not attempt it, but our use case is probably defined enough to tackle in a specific way).
the logic:
template<typename T, typename Q> auto ofMin(const T & t, const Q & q) const { using CommonType = typename std::common_type<T, Q>::type; if constexpr ((std::is_same_v<T, uint64_t> or std::is_same_v<T, size_t>) && std::is_signed_v