fork download
  1. #include <iostream>
  2. #include <limits>
  3.  
  4. using namespace std;
  5.  
  6. #if defined(_MSC_VER) && _MSC_VER < 1900
  7. #define CONST_EXPPR
  8. #else
  9. #define CONST_EXPPR constexpr
  10. #endif
  11.  
  12. /*
  13. * Helper tempaltes which returns common minimum and maximum values for integer types
  14. */
  15. template<typename DestinationType, typename SourceType, bool commonSignes, bool DestSourceEqual>
  16. struct HelperCommonLimits
  17. {
  18. static CONST_EXPPR SourceType max()
  19. {
  20. return static_cast<SourceType>(std::numeric_limits<DestinationType>::max());
  21. }
  22. static CONST_EXPPR SourceType min()
  23. {
  24. return static_cast<SourceType>(std::numeric_limits<DestinationType>::min());
  25. }
  26. };
  27.  
  28. template<typename DestinationType, typename SourceType>
  29. struct HelperCommonLimits<DestinationType, SourceType, false, false>
  30. {
  31. static CONST_EXPPR SourceType max()
  32. {
  33. return static_cast<SourceType>(std::numeric_limits<DestinationType>::max());
  34. }
  35. static CONST_EXPPR SourceType min()
  36. {
  37. return 0;
  38. }
  39. };
  40.  
  41. template<typename DestinationType, typename SourceType>
  42. struct HelperCommonLimits<DestinationType, SourceType, false, true>
  43. {
  44. static CONST_EXPPR SourceType max()
  45. {
  46. return static_cast<SourceType>(std::numeric_limits<typename std::make_signed<DestinationType>::type>::max());
  47. }
  48. static CONST_EXPPR SourceType min()
  49. {
  50. return 0;
  51. }
  52. };
  53.  
  54. /*
  55. * Helper template used to detect if size on destination type is bigger.
  56. * If signs are same than simple casting is enough.
  57. * if sings are different zero minimum is applied
  58. */
  59. template<typename DestinationType, typename SourceType, bool singedToUnsigned, bool DestIsBigger>
  60. struct HelperNorrowCast
  61. {
  62. static CONST_EXPPR DestinationType Cast(SourceType arg)
  63. {
  64. using HelperType = HelperCommonLimits<DestinationType,
  65. SourceType,
  66. std::is_signed<SourceType>::value == std::is_signed<DestinationType>::value,
  67. (sizeof(DestinationType) == sizeof(SourceType))>;
  68.  
  69. return static_cast<DestinationType>(
  70. HelperType::min() >= arg ? HelperType::min() :
  71. HelperType::max() <= arg ? HelperType::max() :
  72. arg);
  73. }
  74. };
  75.  
  76. template<typename DestinationType, typename SourceType>
  77. struct HelperNorrowCast<DestinationType, SourceType, false, true>
  78. {
  79. static CONST_EXPPR DestinationType Cast(SourceType arg)
  80. {
  81. return static_cast<DestinationType>(arg);
  82. }
  83. };
  84.  
  85. template<typename DestinationType, typename SourceType>
  86. struct HelperNorrowCast<DestinationType, SourceType, true, true>
  87. {
  88. static CONST_EXPPR DestinationType Cast(SourceType arg)
  89. {
  90. return static_cast<DestinationType>(arg >= 0 ? arg : 0);
  91. }
  92. };
  93.  
  94. /**
  95. * Used to do integer casting in such way that if argument value exceeds destination type range
  96. * result value is returns respctivly maximum or minimum values of result type.
  97. */
  98. template<typename DestinationType, typename SourceType>
  99. CONST_EXPPR DestinationType narrow_cast(SourceType arg)
  100. {
  101. static_assert(std::is_integral<DestinationType>::value, "Only integer types are supported");
  102. static_assert(std::is_integral<SourceType>::value, "Only integer types are supported");
  103.  
  104. return HelperNorrowCast<DestinationType, SourceType,
  105. std::is_signed<SourceType>::value && std::is_unsigned<DestinationType>::value,
  106. (sizeof(DestinationType) > sizeof(SourceType))>::Cast(arg);
  107. }
  108.  
  109.  
  110. #define EXPECT_EQ(x, y) if (x != y) cout << "Failed test for " << #x \
  111. << "\nexpected: " << y \
  112. << "\n actual: " << x << endl; else
  113.  
  114. int main() {
  115. // to smaller type signed to signed
  116. EXPECT_EQ(narrow_cast<short>(100000), 32767);
  117. EXPECT_EQ(narrow_cast<short>(-100000), -32768);
  118. EXPECT_EQ(narrow_cast<short>(0), 0);
  119. EXPECT_EQ(narrow_cast<short>(-1), -1);
  120.  
  121. // to smaller type unsigned to unsigned
  122. EXPECT_EQ(narrow_cast<unsigned short>(100000u), 65535u);
  123. EXPECT_EQ(narrow_cast<unsigned short>(60000u), 60000u);
  124. EXPECT_EQ(narrow_cast<unsigned short>(0u), 0u);
  125. EXPECT_EQ(narrow_cast<unsigned short>(1u), 1u);
  126.  
  127. // to smaller type signed to signed to unsigned
  128. EXPECT_EQ(narrow_cast<unsigned short>(100000), 65535);
  129. EXPECT_EQ(narrow_cast<unsigned short>(-100000), 0);
  130. EXPECT_EQ(narrow_cast<unsigned short>(0), 0);
  131. EXPECT_EQ(narrow_cast<unsigned short>(-1), 0);
  132.  
  133. // to smaller type unsigned to signed
  134. EXPECT_EQ(narrow_cast<short>(100000u), 32767);
  135. EXPECT_EQ(narrow_cast<short>(60000u), 32767);
  136. EXPECT_EQ(narrow_cast<short>(0u), 0);
  137. EXPECT_EQ(narrow_cast<short>(1u), 1);
  138.  
  139. // to same size type signed to signed ////
  140. EXPECT_EQ(narrow_cast<int>(0x7fffffff), 0x7fffffff);
  141. EXPECT_EQ(narrow_cast<int>(-2147483648), -2147483648);
  142. EXPECT_EQ(narrow_cast<int>(0), 0);
  143. EXPECT_EQ(narrow_cast<int>(-1), -1);
  144.  
  145. // to same size type unsigned to unsigned
  146. EXPECT_EQ(narrow_cast<unsigned int>(0xffffffffu), 0xffffffffu);
  147. EXPECT_EQ(narrow_cast<unsigned int>(60000u), 60000u);
  148. EXPECT_EQ(narrow_cast<unsigned int>(0u), 0u);
  149. EXPECT_EQ(narrow_cast<unsigned int>(1u), 1u);
  150.  
  151. // to same size type signed to signed to unsigned
  152. EXPECT_EQ(narrow_cast<unsigned int>(0x7fffffff), 0x7fffffffu);
  153. EXPECT_EQ(narrow_cast<unsigned int>(-2147483648), 0u);
  154. EXPECT_EQ(narrow_cast<unsigned int>(0), 0u);
  155. EXPECT_EQ(narrow_cast<unsigned int>(-1), 0u);
  156.  
  157. // to same size type unsigned to signed
  158. EXPECT_EQ(narrow_cast<int>(0xffffffffu), 0x7fffffff);
  159. EXPECT_EQ(narrow_cast<int>(0x7fffffffu), 0x7fffffff);
  160. EXPECT_EQ(narrow_cast<int>(0x80000000u), 0x7fffffff);
  161. EXPECT_EQ(narrow_cast<int>(0u), 0);
  162. EXPECT_EQ(narrow_cast<int>(1u), 1);
  163.  
  164. // to bigger size type signed to signed ////
  165. EXPECT_EQ(narrow_cast<int64_t>(0x7fffffff), 0x7fffffffll);
  166. EXPECT_EQ(narrow_cast<int64_t>(-2147483648), -2147483648ll);
  167. EXPECT_EQ(narrow_cast<int64_t>(0), 0);
  168. EXPECT_EQ(narrow_cast<int64_t>(-1), -1ll);
  169.  
  170. // to bigger size type unsigned to unsigned
  171. EXPECT_EQ(narrow_cast<uint64_t>(0xffffffffu), 0xffffffffull);
  172. EXPECT_EQ(narrow_cast<uint64_t>(60000u), 60000ull);
  173. EXPECT_EQ(narrow_cast<uint64_t>(0u), 0ull);
  174. EXPECT_EQ(narrow_cast<uint64_t>(1u), 1ull);
  175.  
  176. // to bigger size type signed to signed to unsigned
  177. EXPECT_EQ(narrow_cast<uint64_t>(0x7fffffff), 0x7fffffffull);
  178. EXPECT_EQ(narrow_cast<uint64_t>(-2147483648), 0ull);
  179. EXPECT_EQ(narrow_cast<uint64_t>(0), 0ull);
  180. EXPECT_EQ(narrow_cast<uint64_t>(-1), 0ull);
  181.  
  182. // to bigger size type unsigned to signed
  183. EXPECT_EQ(narrow_cast<int64_t>(0xffffffffu), 0xffffffffll);
  184. EXPECT_EQ(narrow_cast<int64_t>(0x7fffffffu), 0x7fffffffll);
  185. EXPECT_EQ(narrow_cast<int64_t>(0x80000000u), 0x80000000ll);
  186. EXPECT_EQ(narrow_cast<int64_t>(0u), 0ll);
  187. EXPECT_EQ(narrow_cast<int64_t>(1u), 1ll);
  188.  
  189. return 0;
  190. }
Success #stdin #stdout 0s 16048KB
stdin
Standard input is empty
stdout
Standard output is empty