fix pixel_cast by avoiding comparing across sign<->unsigned - refs #2893
This commit is contained in:
parent
62b0d2b06e
commit
d29a0f18b1
1 changed files with 113 additions and 6 deletions
|
@ -23,23 +23,130 @@
|
||||||
#ifndef MAPNIK_PIXEL_CAST_HPP
|
#ifndef MAPNIK_PIXEL_CAST_HPP
|
||||||
#define MAPNIK_PIXEL_CAST_HPP
|
#define MAPNIK_PIXEL_CAST_HPP
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
#include <boost/numeric/conversion/bounds.hpp>
|
#include <boost/numeric/conversion/bounds.hpp>
|
||||||
|
|
||||||
namespace mapnik {
|
namespace mapnik {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T, typename S, typename E = void>
|
||||||
|
struct numeric_compare;
|
||||||
|
|
||||||
|
template<typename T, typename S>
|
||||||
|
struct numeric_compare_same_sign
|
||||||
|
{
|
||||||
|
using sizeup = typename std::conditional<sizeof(T) >= sizeof(S), T, S>::type;
|
||||||
|
|
||||||
|
static inline bool less(T t, S s) {
|
||||||
|
return static_cast<sizeup>(t) < static_cast<sizeup>(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool greater(T t, S s) {
|
||||||
|
return static_cast<sizeup>(t) > static_cast<sizeup>(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename S>
|
||||||
|
struct numeric_compare<T,S,typename std::enable_if<!std::is_floating_point<T>::value && !std::is_floating_point<S>::value &&
|
||||||
|
((std::is_unsigned<T>::value && std::is_unsigned<S>::value)
|
||||||
|
|| (std::is_signed<T>::value && std::is_signed<S>::value))>
|
||||||
|
::type> : numeric_compare_same_sign<T,S>
|
||||||
|
{};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T, typename S>
|
||||||
|
struct numeric_compare<T,S,typename std::enable_if<!std::is_floating_point<T>::value && !std::is_floating_point<S>::value &&
|
||||||
|
std::is_integral<T>::value && std::is_signed<T>::value && std::is_unsigned<S>::value>::type>
|
||||||
|
{
|
||||||
|
static inline bool less(T t, S s) {
|
||||||
|
return (t < static_cast<T>(0)) ? true : static_cast<uint64_t>(t) < static_cast<uint64_t>(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool greater(T t, S s) {
|
||||||
|
return (t < static_cast<T>(0)) ? false : static_cast<uint64_t>(t) > static_cast<uint64_t>(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename S>
|
||||||
|
struct numeric_compare<T,S,typename std::enable_if<!std::is_floating_point<T>::value && !std::is_floating_point<S>::value &&
|
||||||
|
std::is_integral<T>::value && std::is_unsigned<T>::value && std::is_signed<S>::value>::type>
|
||||||
|
{
|
||||||
|
static inline bool less(T t, S s) {
|
||||||
|
return (s < static_cast<S>(0)) ? false : static_cast<uint64_t>(t) < static_cast<uint64_t>(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool greater(T t, S s) {
|
||||||
|
return (s < static_cast<S>(0)) ? true : static_cast<uint64_t>(t) > static_cast<uint64_t>(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename S>
|
||||||
|
struct numeric_compare<T,S,typename std::enable_if<std::is_floating_point<T>::value && std::is_floating_point<S>::value>::type>
|
||||||
|
{
|
||||||
|
static inline bool less(T t, S s) {
|
||||||
|
return t < s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool greater(T t, S s) {
|
||||||
|
return t > s;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename S>
|
||||||
|
struct numeric_compare<T,S,typename std::enable_if<std::is_floating_point<T>::value && std::is_integral<S>::value>::type>
|
||||||
|
{
|
||||||
|
static inline bool less(T t, S s) {
|
||||||
|
return less(static_cast<double>(t),static_cast<double>(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool greater(T t, S s) {
|
||||||
|
return greater(static_cast<double>(t),static_cast<double>(s));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T, typename S>
|
||||||
|
struct numeric_compare<T,S,typename std::enable_if<std::is_integral<T>::value && std::is_floating_point<S>::value>::type>
|
||||||
|
{
|
||||||
|
static inline bool less(T t, S s) {
|
||||||
|
return less(static_cast<double>(t),static_cast<double>(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool greater(T t, S s) {
|
||||||
|
return greater(static_cast<double>(t),static_cast<double>(s));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename S>
|
||||||
|
inline bool less(T t, S s) {
|
||||||
|
return numeric_compare<T,S>::less(t,s);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename S>
|
||||||
|
inline bool greater(T t, S s) {
|
||||||
|
return numeric_compare<T,S>::greater(t,s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T, typename S>
|
template <typename T, typename S>
|
||||||
inline T pixel_cast(S s)
|
inline T pixel_cast(S s)
|
||||||
{
|
{
|
||||||
using namespace boost::numeric;
|
static T max_val = boost::numeric::bounds<T>::highest();
|
||||||
if (s > bounds<T>::highest() )
|
if (detail::greater(s,max_val))
|
||||||
{
|
{
|
||||||
return bounds<T>::highest();
|
return max_val;
|
||||||
}
|
}
|
||||||
else if (s < bounds<T>::lowest())
|
static T min_val = boost::numeric::bounds<T>::lowest();
|
||||||
|
if (detail::less(s,min_val))
|
||||||
{
|
{
|
||||||
return bounds<T>::lowest();
|
return min_val;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return static_cast<T>(s);
|
||||||
}
|
}
|
||||||
else return static_cast<T>(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // ns mapnik
|
} // ns mapnik
|
||||||
|
|
Loading…
Reference in a new issue