Bug 1499346 [wpt PR 13540] - Use a common blank reference for wpt/css., a=testonly
[gecko.git] / mfbt / Casting.h
blob6648b1488db2eb93cba4a54dd2bfcddfd5d4f33d
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/. */
7 /* Cast operations to supplement the built-in casting operations. */
9 #ifndef mozilla_Casting_h
10 #define mozilla_Casting_h
12 #include "mozilla/Assertions.h"
13 #include "mozilla/TypeTraits.h"
15 #include <cstring>
16 #include <limits.h>
17 #include <type_traits>
19 namespace mozilla {
21 /**
22 * Sets the outparam value of type |To| with the same underlying bit pattern of
23 * |aFrom|.
25 * |To| and |From| must be types of the same size; be careful of cross-platform
26 * size differences, or this might fail to compile on some but not all
27 * platforms.
29 * There is also a variant that returns the value directly. In most cases, the
30 * two variants should be identical. However, in the specific case of x86
31 * chips, the behavior differs: returning floating-point values directly is done
32 * through the x87 stack, and x87 loads and stores turn signaling NaNs into
33 * quiet NaNs... silently. Returning floating-point values via outparam,
34 * however, is done entirely within the SSE registers when SSE2 floating-point
35 * is enabled in the compiler, which has semantics-preserving behavior you would
36 * expect.
38 * If preserving the distinction between signaling NaNs and quiet NaNs is
39 * important to you, you should use the outparam version. In all other cases,
40 * you should use the direct return version.
42 template<typename To, typename From>
43 inline void
44 BitwiseCast(const From aFrom, To* aResult)
46 static_assert(sizeof(From) == sizeof(To),
47 "To and From must have the same size");
49 // We could maybe downgrade these to std::is_trivially_copyable, but the
50 // various STLs we use don't all provide it.
51 static_assert(std::is_trivial<From>::value,
52 "shouldn't bitwise-copy a type having non-trivial "
53 "initialization");
54 static_assert(std::is_trivial<To>::value,
55 "shouldn't bitwise-copy a type having non-trivial "
56 "initialization");
58 std::memcpy(static_cast<void*>(aResult),
59 static_cast<const void*>(&aFrom),
60 sizeof(From));
63 template<typename To, typename From>
64 inline To
65 BitwiseCast(const From aFrom)
67 To temp;
68 BitwiseCast<To, From>(aFrom, &temp);
69 return temp;
72 namespace detail {
74 enum ToSignedness { ToIsSigned, ToIsUnsigned };
75 enum FromSignedness { FromIsSigned, FromIsUnsigned };
77 template<typename From,
78 typename To,
79 FromSignedness = IsSigned<From>::value ? FromIsSigned : FromIsUnsigned,
80 ToSignedness = IsSigned<To>::value ? ToIsSigned : ToIsUnsigned>
81 struct BoundsCheckImpl;
83 // Implicit conversions on operands to binary operations make this all a bit
84 // hard to verify. Attempt to ease the pain below by *only* comparing values
85 // that are obviously the same type (and will undergo no further conversions),
86 // even when it's not strictly necessary, for explicitness.
88 enum UUComparison { FromIsBigger, FromIsNotBigger };
90 // Unsigned-to-unsigned range check
92 template<typename From, typename To,
93 UUComparison = (sizeof(From) > sizeof(To))
94 ? FromIsBigger
95 : FromIsNotBigger>
96 struct UnsignedUnsignedCheck;
98 template<typename From, typename To>
99 struct UnsignedUnsignedCheck<From, To, FromIsBigger>
101 public:
102 static bool checkBounds(const From aFrom)
104 return aFrom <= From(To(-1));
108 template<typename From, typename To>
109 struct UnsignedUnsignedCheck<From, To, FromIsNotBigger>
111 public:
112 static bool checkBounds(const From aFrom)
114 return true;
118 template<typename From, typename To>
119 struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsUnsigned>
121 public:
122 static bool checkBounds(const From aFrom)
124 return UnsignedUnsignedCheck<From, To>::checkBounds(aFrom);
128 // Signed-to-unsigned range check
130 template<typename From, typename To>
131 struct BoundsCheckImpl<From, To, FromIsSigned, ToIsUnsigned>
133 public:
134 static bool checkBounds(const From aFrom)
136 if (aFrom < 0) {
137 return false;
139 if (sizeof(To) >= sizeof(From)) {
140 return true;
142 return aFrom <= From(To(-1));
146 // Unsigned-to-signed range check
148 enum USComparison { FromIsSmaller, FromIsNotSmaller };
150 template<typename From, typename To,
151 USComparison = (sizeof(From) < sizeof(To))
152 ? FromIsSmaller
153 : FromIsNotSmaller>
154 struct UnsignedSignedCheck;
156 template<typename From, typename To>
157 struct UnsignedSignedCheck<From, To, FromIsSmaller>
159 public:
160 static bool checkBounds(const From aFrom)
162 return true;
166 template<typename From, typename To>
167 struct UnsignedSignedCheck<From, To, FromIsNotSmaller>
169 public:
170 static bool checkBounds(const From aFrom)
172 const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
173 return aFrom <= From(MaxValue);
177 template<typename From, typename To>
178 struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsSigned>
180 public:
181 static bool checkBounds(const From aFrom)
183 return UnsignedSignedCheck<From, To>::checkBounds(aFrom);
187 // Signed-to-signed range check
189 template<typename From, typename To>
190 struct BoundsCheckImpl<From, To, FromIsSigned, ToIsSigned>
192 public:
193 static bool checkBounds(const From aFrom)
195 if (sizeof(From) <= sizeof(To)) {
196 return true;
198 const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
199 const To MinValue = -MaxValue - To(1);
200 return From(MinValue) <= aFrom &&
201 From(aFrom) <= From(MaxValue);
205 template<typename From, typename To,
206 bool TypesAreIntegral = IsIntegral<From>::value &&
207 IsIntegral<To>::value>
208 class BoundsChecker;
210 template<typename From>
211 class BoundsChecker<From, From, true>
213 public:
214 static bool checkBounds(const From aFrom) { return true; }
217 template<typename From, typename To>
218 class BoundsChecker<From, To, true>
220 public:
221 static bool checkBounds(const From aFrom)
223 return BoundsCheckImpl<From, To>::checkBounds(aFrom);
227 template<typename From, typename To>
228 inline bool
229 IsInBounds(const From aFrom)
231 return BoundsChecker<From, To>::checkBounds(aFrom);
234 } // namespace detail
237 * Cast a value of integral type |From| to a value of integral type |To|,
238 * asserting that the cast will be a safe cast per C++ (that is, that |to| is in
239 * the range of values permitted for the type |From|).
241 template<typename To, typename From>
242 inline To
243 AssertedCast(const From aFrom)
245 MOZ_ASSERT((detail::IsInBounds<From, To>(aFrom)));
246 return static_cast<To>(aFrom);
250 * Cast a value of integral type |From| to a value of integral type |To|,
251 * release asserting that the cast will be a safe cast per C++ (that is, that
252 * |to| is in the range of values permitted for the type |From|).
254 template<typename To, typename From>
255 inline To
256 ReleaseAssertedCast(const From aFrom)
258 MOZ_RELEASE_ASSERT((detail::IsInBounds<From, To>(aFrom)));
259 return static_cast<To>(aFrom);
262 } // namespace mozilla
264 #endif /* mozilla_Casting_h */