From d29a0f18b1fb9c4a278a80696d6469086d5c7773 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 12 Jun 2015 00:02:59 -0700 Subject: [PATCH] fix pixel_cast by avoiding comparing across sign<->unsigned - refs #2893 --- include/mapnik/pixel_cast.hpp | 119 ++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 6 deletions(-) diff --git a/include/mapnik/pixel_cast.hpp b/include/mapnik/pixel_cast.hpp index efa76d9bc..d5c022d37 100644 --- a/include/mapnik/pixel_cast.hpp +++ b/include/mapnik/pixel_cast.hpp @@ -23,23 +23,130 @@ #ifndef MAPNIK_PIXEL_CAST_HPP #define MAPNIK_PIXEL_CAST_HPP +#include #include namespace mapnik { +namespace detail { + + template + struct numeric_compare; + + template + struct numeric_compare_same_sign + { + using sizeup = typename std::conditional= sizeof(S), T, S>::type; + + static inline bool less(T t, S s) { + return static_cast(t) < static_cast(s); + } + + static inline bool greater(T t, S s) { + return static_cast(t) > static_cast(s); + } + }; + + template + struct numeric_compare::value && !std::is_floating_point::value && + ((std::is_unsigned::value && std::is_unsigned::value) + || (std::is_signed::value && std::is_signed::value))> + ::type> : numeric_compare_same_sign + {}; + + + template + struct numeric_compare::value && !std::is_floating_point::value && + std::is_integral::value && std::is_signed::value && std::is_unsigned::value>::type> + { + static inline bool less(T t, S s) { + return (t < static_cast(0)) ? true : static_cast(t) < static_cast(s); + } + + static inline bool greater(T t, S s) { + return (t < static_cast(0)) ? false : static_cast(t) > static_cast(s); + } + }; + + template + struct numeric_compare::value && !std::is_floating_point::value && + std::is_integral::value && std::is_unsigned::value && std::is_signed::value>::type> + { + static inline bool less(T t, S s) { + return (s < static_cast(0)) ? false : static_cast(t) < static_cast(s); + } + + static inline bool greater(T t, S s) { + return (s < static_cast(0)) ? true : static_cast(t) > static_cast(s); + } + }; + + template + struct numeric_compare::value && std::is_floating_point::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 + struct numeric_compare::value && std::is_integral::value>::type> + { + static inline bool less(T t, S s) { + return less(static_cast(t),static_cast(s)); + } + + static inline bool greater(T t, S s) { + return greater(static_cast(t),static_cast(s)); + } + }; + + + template + struct numeric_compare::value && std::is_floating_point::value>::type> + { + static inline bool less(T t, S s) { + return less(static_cast(t),static_cast(s)); + } + + static inline bool greater(T t, S s) { + return greater(static_cast(t),static_cast(s)); + } + }; + + template + inline bool less(T t, S s) { + return numeric_compare::less(t,s); + } + + template + inline bool greater(T t, S s) { + return numeric_compare::greater(t,s); + } +} + + template inline T pixel_cast(S s) { - using namespace boost::numeric; - if (s > bounds::highest() ) + static T max_val = boost::numeric::bounds::highest(); + if (detail::greater(s,max_val)) { - return bounds::highest(); + return max_val; } - else if (s < bounds::lowest()) + static T min_val = boost::numeric::bounds::lowest(); + if (detail::less(s,min_val)) { - return bounds::lowest(); + return min_val; + } + else + { + return static_cast(s); } - else return static_cast(s); } } // ns mapnik