154 lines
5 KiB
C++
154 lines
5 KiB
C++
/*****************************************************************************
|
|
*
|
|
* This file is part of Mapnik (c++ mapping toolkit)
|
|
*
|
|
* Copyright (C) 2015 Artem Pavlenko
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#ifndef MAPNIK_SAFE_CAST_HPP
|
|
#define MAPNIK_SAFE_CAST_HPP
|
|
|
|
#include <limits>
|
|
#include <type_traits>
|
|
#include <cstdint>
|
|
|
|
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<std::uint64_t>(t) < static_cast<std::uint64_t>(s);
|
|
}
|
|
|
|
static inline bool greater(T t, S s) {
|
|
return (t < static_cast<T>(0)) ? false : static_cast<std::uint64_t>(t) > static_cast<std::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<std::uint64_t>(t) < static_cast<std::uint64_t>(s);
|
|
}
|
|
|
|
static inline bool greater(T t, S s) {
|
|
return (s < static_cast<S>(0)) ? true : static_cast<std::uint64_t>(t) > static_cast<std::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) ||
|
|
(std::is_integral<T>::value && std::is_floating_point<S>::value)>::type>
|
|
{
|
|
static inline bool less(T t, S s) {
|
|
return numeric_compare<double,double>::less(static_cast<double>(t),static_cast<double>(s));
|
|
}
|
|
|
|
static inline bool greater(T t, S s) {
|
|
return numeric_compare<double,double>::greater(static_cast<double>(t),static_cast<double>(s));
|
|
}
|
|
};
|
|
|
|
// floats
|
|
template <typename T, typename Enable = void>
|
|
struct bounds
|
|
{
|
|
static const T lowest() { return static_cast<T>(-std::numeric_limits<T>::max());}
|
|
static const T highest() { return std::numeric_limits<T>::max();}
|
|
};
|
|
|
|
// integers
|
|
template <typename T>
|
|
struct bounds<T, typename std::enable_if<std::numeric_limits<T>::is_integer>::type >
|
|
{
|
|
static const T lowest() { return std::numeric_limits<T>::min();}
|
|
static const T highest() { return std::numeric_limits<T>::max();}
|
|
};
|
|
|
|
} // ns detail
|
|
|
|
|
|
template <typename T, typename S>
|
|
inline T safe_cast(S s)
|
|
{
|
|
static const auto max_val = detail::bounds<T>::highest();
|
|
static const auto min_val = detail::bounds<T>::lowest();
|
|
|
|
if (detail::numeric_compare<S,T>::greater(s,max_val))
|
|
{
|
|
return max_val;
|
|
}
|
|
else if (detail::numeric_compare<S,T>::less(s,min_val))
|
|
{
|
|
return min_val;
|
|
}
|
|
else
|
|
{
|
|
return static_cast<T>(s);
|
|
}
|
|
}
|
|
|
|
} // ns mapnik
|
|
|
|
|
|
|
|
#endif // MAPNIK_SAFE_CAST_HPP
|