Casting.h 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* vim: set ts=8 sts=2 et sw=2 tw=80: */
  3. /* This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6. /* Cast operations to supplement the built-in casting operations. */
  7. #ifndef mozilla_Casting_h
  8. #define mozilla_Casting_h
  9. #include "mozilla/Assertions.h"
  10. #include "mozilla/TypeTraits.h"
  11. #include <limits.h>
  12. namespace mozilla {
  13. /**
  14. * Sets the outparam value of type |To| with the same underlying bit pattern of
  15. * |aFrom|.
  16. *
  17. * |To| and |From| must be types of the same size; be careful of cross-platform
  18. * size differences, or this might fail to compile on some but not all
  19. * platforms.
  20. *
  21. * There is also a variant that returns the value directly. In most cases, the
  22. * two variants should be identical. However, in the specific case of x86
  23. * chips, the behavior differs: returning floating-point values directly is done
  24. * through the x87 stack, and x87 loads and stores turn signaling NaNs into
  25. * quiet NaNs... silently. Returning floating-point values via outparam,
  26. * however, is done entirely within the SSE registers when SSE2 floating-point
  27. * is enabled in the compiler, which has semantics-preserving behavior you would
  28. * expect.
  29. *
  30. * If preserving the distinction between signaling NaNs and quiet NaNs is
  31. * important to you, you should use the outparam version. In all other cases,
  32. * you should use the direct return version.
  33. */
  34. template<typename To, typename From>
  35. inline void
  36. BitwiseCast(const From aFrom, To* aResult)
  37. {
  38. static_assert(sizeof(From) == sizeof(To),
  39. "To and From must have the same size");
  40. union
  41. {
  42. From mFrom;
  43. To mTo;
  44. } u;
  45. u.mFrom = aFrom;
  46. *aResult = u.mTo;
  47. }
  48. template<typename To, typename From>
  49. inline To
  50. BitwiseCast(const From aFrom)
  51. {
  52. To temp;
  53. BitwiseCast<To, From>(aFrom, &temp);
  54. return temp;
  55. }
  56. namespace detail {
  57. enum ToSignedness { ToIsSigned, ToIsUnsigned };
  58. enum FromSignedness { FromIsSigned, FromIsUnsigned };
  59. template<typename From,
  60. typename To,
  61. FromSignedness = IsSigned<From>::value ? FromIsSigned : FromIsUnsigned,
  62. ToSignedness = IsSigned<To>::value ? ToIsSigned : ToIsUnsigned>
  63. struct BoundsCheckImpl;
  64. // Implicit conversions on operands to binary operations make this all a bit
  65. // hard to verify. Attempt to ease the pain below by *only* comparing values
  66. // that are obviously the same type (and will undergo no further conversions),
  67. // even when it's not strictly necessary, for explicitness.
  68. enum UUComparison { FromIsBigger, FromIsNotBigger };
  69. // Unsigned-to-unsigned range check
  70. template<typename From, typename To,
  71. UUComparison = (sizeof(From) > sizeof(To))
  72. ? FromIsBigger
  73. : FromIsNotBigger>
  74. struct UnsignedUnsignedCheck;
  75. template<typename From, typename To>
  76. struct UnsignedUnsignedCheck<From, To, FromIsBigger>
  77. {
  78. public:
  79. static bool checkBounds(const From aFrom)
  80. {
  81. return aFrom <= From(To(-1));
  82. }
  83. };
  84. template<typename From, typename To>
  85. struct UnsignedUnsignedCheck<From, To, FromIsNotBigger>
  86. {
  87. public:
  88. static bool checkBounds(const From aFrom)
  89. {
  90. return true;
  91. }
  92. };
  93. template<typename From, typename To>
  94. struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsUnsigned>
  95. {
  96. public:
  97. static bool checkBounds(const From aFrom)
  98. {
  99. return UnsignedUnsignedCheck<From, To>::checkBounds(aFrom);
  100. }
  101. };
  102. // Signed-to-unsigned range check
  103. template<typename From, typename To>
  104. struct BoundsCheckImpl<From, To, FromIsSigned, ToIsUnsigned>
  105. {
  106. public:
  107. static bool checkBounds(const From aFrom)
  108. {
  109. if (aFrom < 0) {
  110. return false;
  111. }
  112. if (sizeof(To) >= sizeof(From)) {
  113. return true;
  114. }
  115. return aFrom <= From(To(-1));
  116. }
  117. };
  118. // Unsigned-to-signed range check
  119. enum USComparison { FromIsSmaller, FromIsNotSmaller };
  120. template<typename From, typename To,
  121. USComparison = (sizeof(From) < sizeof(To))
  122. ? FromIsSmaller
  123. : FromIsNotSmaller>
  124. struct UnsignedSignedCheck;
  125. template<typename From, typename To>
  126. struct UnsignedSignedCheck<From, To, FromIsSmaller>
  127. {
  128. public:
  129. static bool checkBounds(const From aFrom)
  130. {
  131. return true;
  132. }
  133. };
  134. template<typename From, typename To>
  135. struct UnsignedSignedCheck<From, To, FromIsNotSmaller>
  136. {
  137. public:
  138. static bool checkBounds(const From aFrom)
  139. {
  140. const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
  141. return aFrom <= From(MaxValue);
  142. }
  143. };
  144. template<typename From, typename To>
  145. struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsSigned>
  146. {
  147. public:
  148. static bool checkBounds(const From aFrom)
  149. {
  150. return UnsignedSignedCheck<From, To>::checkBounds(aFrom);
  151. }
  152. };
  153. // Signed-to-signed range check
  154. template<typename From, typename To>
  155. struct BoundsCheckImpl<From, To, FromIsSigned, ToIsSigned>
  156. {
  157. public:
  158. static bool checkBounds(const From aFrom)
  159. {
  160. if (sizeof(From) <= sizeof(To)) {
  161. return true;
  162. }
  163. const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
  164. const To MinValue = -MaxValue - To(1);
  165. return From(MinValue) <= aFrom &&
  166. From(aFrom) <= From(MaxValue);
  167. }
  168. };
  169. template<typename From, typename To,
  170. bool TypesAreIntegral = IsIntegral<From>::value &&
  171. IsIntegral<To>::value>
  172. class BoundsChecker;
  173. template<typename From>
  174. class BoundsChecker<From, From, true>
  175. {
  176. public:
  177. static bool checkBounds(const From aFrom) { return true; }
  178. };
  179. template<typename From, typename To>
  180. class BoundsChecker<From, To, true>
  181. {
  182. public:
  183. static bool checkBounds(const From aFrom)
  184. {
  185. return BoundsCheckImpl<From, To>::checkBounds(aFrom);
  186. }
  187. };
  188. template<typename From, typename To>
  189. inline bool
  190. IsInBounds(const From aFrom)
  191. {
  192. return BoundsChecker<From, To>::checkBounds(aFrom);
  193. }
  194. } // namespace detail
  195. /**
  196. * Cast a value of integral type |From| to a value of integral type |To|,
  197. * asserting that the cast will be a safe cast per C++ (that is, that |to| is in
  198. * the range of values permitted for the type |From|).
  199. */
  200. template<typename To, typename From>
  201. inline To
  202. AssertedCast(const From aFrom)
  203. {
  204. MOZ_ASSERT((detail::IsInBounds<From, To>(aFrom)));
  205. return static_cast<To>(aFrom);
  206. }
  207. } // namespace mozilla
  208. #endif /* mozilla_Casting_h */