Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 

179 rindas
5.6 KiB

  1. #pragma once
  2. #ifdef CPPCORE_CONVERT_CAST_ABORT
  3. # include <iostream>
  4. #endif
  5. #include <limits>
  6. #include <type_traits>
  7. #include <cppcore/config.h>
  8. #include <cppcore/misc/exception.h>
  9. #include <cppcore/misc/type_helper.h>
  10. #include "convert_cast.h"
  11. namespace cppcore
  12. {
  13. namespace __impl
  14. {
  15. template<typename T_to, typename T_from>
  16. void convert_cast_raise(T_from p_value)
  17. {
  18. #if defined(CPPCORE_CONVERT_CAST_THROW)
  19. using namespace std;
  20. throw convert_exception("Unable to convert "s
  21. + type_helper<T_from>::name()
  22. + "(" + std::to_string(p_value) + ") to "
  23. + type_helper<T_to>::name());
  24. #elif defined(CPPCORE_CONVERT_CAST_ABORT)
  25. std::cerr
  26. << "Unable to convert "
  27. << type_helper<T_from>::name()
  28. << "(" << p_value << ") to "
  29. << type_helper<T_to>::name()
  30. << std::endl;
  31. std::abort();
  32. #endif
  33. }
  34. template<typename T_from, typename T_to, typename T_enable = void>
  35. struct convert_cast_impl
  36. {
  37. constexpr T_to operator()(T_from p_value) const
  38. { static_assert(sizeof(T_from) < 0, "convert_cast is not available for the passed types!"); }
  39. };
  40. /**
  41. * types are equal => simple static cast
  42. */
  43. template<typename T>
  44. struct convert_cast_impl<T, T, void>
  45. {
  46. constexpr T operator()(T p_value) const
  47. { return p_value; }
  48. };
  49. /**
  50. * T_from does fit into T_to => simple static cast
  51. */
  52. template<typename T_from, typename T_to>
  53. struct convert_cast_impl<
  54. T_from,
  55. T_to,
  56. std::enable_if_t<
  57. (sizeof(T_from) < sizeof(T_to))
  58. && std::disjunction_v<
  59. std::conjunction<
  60. std::is_unsigned<std::decay_t<T_from>>,
  61. std::is_integral<std::decay_t<T_to>>
  62. >,
  63. std::conjunction<
  64. std::is_signed<std::decay_t<T_from>>,
  65. std::is_signed<std::decay_t<T_to>>
  66. >
  67. >
  68. >
  69. >
  70. {
  71. constexpr T_to operator()(T_from p_value) const
  72. { return static_cast<T_to>(p_value); }
  73. };
  74. /**
  75. * T_from does fit into T_to => check range and cast
  76. */
  77. template<typename T_from, typename T_to>
  78. struct convert_cast_impl<
  79. T_from,
  80. T_to,
  81. std::enable_if_t<
  82. (sizeof(T_from) > sizeof(T_to))
  83. && std::is_signed_v<std::decay_t<T_from>>
  84. && std::is_signed_v<std::decay_t<T_to>>
  85. >
  86. >
  87. {
  88. constexpr T_to operator()(T_from p_value) const
  89. {
  90. if (p_value < std::numeric_limits<T_to>::min())
  91. convert_cast_raise<T_to>(p_value);
  92. if (p_value > std::numeric_limits<T_to>::max())
  93. convert_cast_raise<T_to>(p_value);
  94. return static_cast<T_to>(p_value);
  95. }
  96. };
  97. /**
  98. * T_from does fit into T_to => check range and cast
  99. */
  100. template<typename T_from, typename T_to>
  101. struct convert_cast_impl<
  102. T_from,
  103. T_to,
  104. std::enable_if_t<
  105. ( (sizeof(T_from) >= sizeof(T_to))
  106. && std::is_unsigned_v<std::decay_t<T_from>>
  107. && std::is_signed_v<std::decay_t<T_to>>)
  108. || ( (sizeof(T_from) > sizeof(T_to))
  109. && std::is_unsigned_v<std::decay_t<T_from>>
  110. && std::is_unsigned_v<std::decay_t<T_to>>)
  111. >
  112. >
  113. {
  114. constexpr T_to operator()(T_from p_value) const
  115. {
  116. if (p_value > std::numeric_limits<T_to>::max())
  117. convert_cast_raise<T_to>(p_value);
  118. return static_cast<T_to>(p_value);
  119. }
  120. };
  121. /**
  122. * signed to unsigned cast => check lower range and cast
  123. */
  124. template<typename T_from, typename T_to>
  125. struct convert_cast_impl<
  126. T_from,
  127. T_to,
  128. std::enable_if_t<
  129. std::is_signed_v <std::decay_t<T_from>>
  130. && std::is_unsigned_v<std::decay_t<T_to >>>>
  131. {
  132. constexpr T_to operator()(T_from p_value) const
  133. {
  134. using unsigned_type = std::make_unsigned_t<T_from>;
  135. if (p_value < 0)
  136. convert_cast_raise<T_to>(p_value);
  137. return convert_cast<T_to>(static_cast<unsigned_type>(p_value));
  138. }
  139. };
  140. /**
  141. * enum to integral cast => static cast
  142. */
  143. template<typename T_from, typename T_to>
  144. struct convert_cast_impl<
  145. T_from,
  146. T_to,
  147. std::enable_if_t<
  148. std::is_enum_v <std::decay_t<T_from>>
  149. && std::is_integral_v<std::decay_t<T_to >>
  150. >>
  151. {
  152. constexpr T_to operator()(T_from p_value) const
  153. {
  154. using underlying_type = std::underlying_type_t<T_from>;
  155. return convert_cast<T_to>(static_cast<underlying_type>(p_value));
  156. }
  157. };
  158. }
  159. template<typename T_to, typename T_from>
  160. constexpr T_to convert_cast(T_from p_value)
  161. { return __impl::convert_cast_impl<T_from, T_to>()(p_value); }
  162. }