|
- #pragma once
-
- #ifdef CPPCORE_CONVERT_CAST_ABORT
- # include <iostream>
- #endif
-
- #include <limits>
- #include <type_traits>
-
- #include <cppcore/config.h>
- #include <cppcore/misc/exception.h>
- #include <cppcore/misc/type_helper.h>
-
- #include "convert_cast.h"
-
- namespace cppcore
- {
-
- namespace __impl
- {
- template<typename T_to, typename T_from>
- void convert_cast_raise(T_from p_value)
- {
- #if defined(CPPCORE_CONVERT_CAST_THROW)
- using namespace std;
- throw convert_exception("Unable to convert "s
- + type_helper<T_from>::name()
- + "(" + std::to_string(p_value) + ") to "
- + type_helper<T_to>::name());
- #elif defined(CPPCORE_CONVERT_CAST_ABORT)
- std::cerr
- << "Unable to convert "
- << type_helper<T_from>::name()
- << "(" << p_value << ") to "
- << type_helper<T_to>::name()
- << std::endl;
- std::abort();
- #endif
- }
-
- template<typename T_from, typename T_to, typename T_enable = void>
- struct convert_cast_impl
- {
- constexpr T_to operator()(T_from p_value) const
- { static_assert(sizeof(T_from) < 0, "convert_cast is not available for the passed types!"); }
- };
-
- /**
- * types are equal => simple static cast
- */
- template<typename T>
- struct convert_cast_impl<T, T, void>
- {
- constexpr T operator()(T p_value) const
- { return p_value; }
- };
-
- /**
- * T_from does fit into T_to => simple static cast
- */
- template<typename T_from, typename T_to>
- struct convert_cast_impl<
- T_from,
- T_to,
- std::enable_if_t<
- (sizeof(T_from) < sizeof(T_to))
- && std::disjunction_v<
- std::conjunction<
- std::is_unsigned<std::decay_t<T_from>>,
- std::is_integral<std::decay_t<T_to>>
- >,
- std::conjunction<
- std::is_signed<std::decay_t<T_from>>,
- std::is_signed<std::decay_t<T_to>>
- >
- >
- >
- >
- {
- constexpr T_to operator()(T_from p_value) const
- { return static_cast<T_to>(p_value); }
- };
-
- /**
- * T_from does fit into T_to => check range and cast
- */
- template<typename T_from, typename T_to>
- struct convert_cast_impl<
- T_from,
- T_to,
- std::enable_if_t<
- (sizeof(T_from) > sizeof(T_to))
- && std::is_signed_v<std::decay_t<T_from>>
- && std::is_signed_v<std::decay_t<T_to>>
- >
- >
- {
- constexpr T_to operator()(T_from p_value) const
- {
- if (p_value < std::numeric_limits<T_to>::min())
- convert_cast_raise<T_to>(p_value);
- if (p_value > std::numeric_limits<T_to>::max())
- convert_cast_raise<T_to>(p_value);
- return static_cast<T_to>(p_value);
- }
- };
-
- /**
- * T_from does fit into T_to => check range and cast
- */
- template<typename T_from, typename T_to>
- struct convert_cast_impl<
- T_from,
- T_to,
- std::enable_if_t<
- ( (sizeof(T_from) >= sizeof(T_to))
- && std::is_unsigned_v<std::decay_t<T_from>>
- && std::is_signed_v<std::decay_t<T_to>>)
- || ( (sizeof(T_from) > sizeof(T_to))
- && std::is_unsigned_v<std::decay_t<T_from>>
- && std::is_unsigned_v<std::decay_t<T_to>>)
- >
- >
- {
- constexpr T_to operator()(T_from p_value) const
- {
- if (p_value > std::numeric_limits<T_to>::max())
- convert_cast_raise<T_to>(p_value);
- return static_cast<T_to>(p_value);
- }
- };
-
- /**
- * signed to unsigned cast => check lower range and cast
- */
- template<typename T_from, typename T_to>
- struct convert_cast_impl<
- T_from,
- T_to,
- std::enable_if_t<
- std::is_signed_v <std::decay_t<T_from>>
- && std::is_unsigned_v<std::decay_t<T_to >>>>
- {
- constexpr T_to operator()(T_from p_value) const
- {
- using unsigned_type = std::make_unsigned_t<T_from>;
- if (p_value < 0)
- convert_cast_raise<T_to>(p_value);
- return convert_cast<T_to>(static_cast<unsigned_type>(p_value));
- }
- };
-
- /**
- * enum to integral cast => static cast
- */
- template<typename T_from, typename T_to>
- struct convert_cast_impl<
- T_from,
- T_to,
- std::enable_if_t<
- std::is_enum_v <std::decay_t<T_from>>
- && std::is_integral_v<std::decay_t<T_to >>
- >>
- {
- constexpr T_to operator()(T_from p_value) const
- {
- using underlying_type = std::underlying_type_t<T_from>;
- return convert_cast<T_to>(static_cast<underlying_type>(p_value));
- }
- };
-
- }
-
- template<typename T_to, typename T_from>
- constexpr T_to convert_cast(T_from p_value)
- { return __impl::convert_cast_impl<T_from, T_to>()(p_value); }
-
- }
|