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"
20 * Return a value of type |To|, containing the underlying bit pattern of
23 * |To| and |From| must be types of the same size; be careful of cross-platform
24 * size differences, or this might fail to compile on some but not all
27 template<typename To
, typename From
>
29 BitwiseCast(const From aFrom
)
31 static_assert(sizeof(From
) == sizeof(To
),
32 "To and From must have the same size");
44 enum ToSignedness
{ ToIsSigned
, ToIsUnsigned
};
45 enum FromSignedness
{ FromIsSigned
, FromIsUnsigned
};
47 template<typename From
,
49 FromSignedness
= IsSigned
<From
>::value
? FromIsSigned
: FromIsUnsigned
,
50 ToSignedness
= IsSigned
<To
>::value
? ToIsSigned
: ToIsUnsigned
>
51 struct BoundsCheckImpl
;
53 // Implicit conversions on operands to binary operations make this all a bit
54 // hard to verify. Attempt to ease the pain below by *only* comparing values
55 // that are obviously the same type (and will undergo no further conversions),
56 // even when it's not strictly necessary, for explicitness.
58 enum UUComparison
{ FromIsBigger
, FromIsNotBigger
};
60 // Unsigned-to-unsigned range check
62 template<typename From
, typename To
,
63 UUComparison
= (sizeof(From
) > sizeof(To
))
66 struct UnsignedUnsignedCheck
;
68 template<typename From
, typename To
>
69 struct UnsignedUnsignedCheck
<From
, To
, FromIsBigger
>
72 static bool checkBounds(const From aFrom
)
74 return aFrom
<= From(To(-1));
78 template<typename From
, typename To
>
79 struct UnsignedUnsignedCheck
<From
, To
, FromIsNotBigger
>
82 static bool checkBounds(const From aFrom
)
88 template<typename From
, typename To
>
89 struct BoundsCheckImpl
<From
, To
, FromIsUnsigned
, ToIsUnsigned
>
92 static bool checkBounds(const From aFrom
)
94 return UnsignedUnsignedCheck
<From
, To
>::checkBounds(aFrom
);
98 // Signed-to-unsigned range check
100 template<typename From
, typename To
>
101 struct BoundsCheckImpl
<From
, To
, FromIsSigned
, ToIsUnsigned
>
104 static bool checkBounds(const From aFrom
)
109 if (sizeof(To
) >= sizeof(From
)) {
112 return aFrom
<= From(To(-1));
116 // Unsigned-to-signed range check
118 enum USComparison
{ FromIsSmaller
, FromIsNotSmaller
};
120 template<typename From
, typename To
,
121 USComparison
= (sizeof(From
) < sizeof(To
))
124 struct UnsignedSignedCheck
;
126 template<typename From
, typename To
>
127 struct UnsignedSignedCheck
<From
, To
, FromIsSmaller
>
130 static bool checkBounds(const From aFrom
)
136 template<typename From
, typename To
>
137 struct UnsignedSignedCheck
<From
, To
, FromIsNotSmaller
>
140 static bool checkBounds(const From aFrom
)
142 const To MaxValue
= To((1ULL << (CHAR_BIT
* sizeof(To
) - 1)) - 1);
143 return aFrom
<= From(MaxValue
);
147 template<typename From
, typename To
>
148 struct BoundsCheckImpl
<From
, To
, FromIsUnsigned
, ToIsSigned
>
151 static bool checkBounds(const From aFrom
)
153 return UnsignedSignedCheck
<From
, To
>::checkBounds(aFrom
);
157 // Signed-to-signed range check
159 template<typename From
, typename To
>
160 struct BoundsCheckImpl
<From
, To
, FromIsSigned
, ToIsSigned
>
163 static bool checkBounds(const From aFrom
)
165 if (sizeof(From
) <= sizeof(To
)) {
168 const To MaxValue
= To((1ULL << (CHAR_BIT
* sizeof(To
) - 1)) - 1);
169 const To MinValue
= -MaxValue
- To(1);
170 return From(MinValue
) <= aFrom
&&
171 From(aFrom
) <= From(MaxValue
);
175 template<typename From
, typename To
,
176 bool TypesAreIntegral
= IsIntegral
<From
>::value
&&
177 IsIntegral
<To
>::value
>
180 template<typename From
>
181 class BoundsChecker
<From
, From
, true>
184 static bool checkBounds(const From aFrom
) { return true; }
187 template<typename From
, typename To
>
188 class BoundsChecker
<From
, To
, true>
191 static bool checkBounds(const From aFrom
)
193 return BoundsCheckImpl
<From
, To
>::checkBounds(aFrom
);
197 template<typename From
, typename To
>
199 IsInBounds(const From aFrom
)
201 return BoundsChecker
<From
, To
>::checkBounds(aFrom
);
204 } // namespace detail
207 * Cast a value of integral type |From| to a value of integral type |To|,
208 * asserting that the cast will be a safe cast per C++ (that is, that |to| is in
209 * the range of values permitted for the type |From|).
211 template<typename To
, typename From
>
213 SafeCast(const From aFrom
)
215 MOZ_ASSERT((detail::IsInBounds
<From
, To
>(aFrom
)));
216 return static_cast<To
>(aFrom
);
219 } // namespace mozilla
221 #endif /* mozilla_Casting_h */