Merge mozilla-b2g34 to 2.1s. a=merge
[gecko.git] / mfbt / Casting.h
blob176e54dcf244470157de49624321ae8f63a7fe69
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 <limits.h>
17 namespace mozilla {
19 /**
20 * Return a value of type |To|, containing the underlying bit pattern of
21 * |aFrom|.
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
25 * platforms.
27 template<typename To, typename From>
28 inline To
29 BitwiseCast(const From aFrom)
31 static_assert(sizeof(From) == sizeof(To),
32 "To and From must have the same size");
33 union
35 From mFrom;
36 To mTo;
37 } u;
38 u.mFrom = aFrom;
39 return u.mTo;
42 namespace detail {
44 enum ToSignedness { ToIsSigned, ToIsUnsigned };
45 enum FromSignedness { FromIsSigned, FromIsUnsigned };
47 template<typename From,
48 typename To,
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))
64 ? FromIsBigger
65 : FromIsNotBigger>
66 struct UnsignedUnsignedCheck;
68 template<typename From, typename To>
69 struct UnsignedUnsignedCheck<From, To, FromIsBigger>
71 public:
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>
81 public:
82 static bool checkBounds(const From aFrom)
84 return true;
88 template<typename From, typename To>
89 struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsUnsigned>
91 public:
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>
103 public:
104 static bool checkBounds(const From aFrom)
106 if (aFrom < 0) {
107 return false;
109 if (sizeof(To) >= sizeof(From)) {
110 return true;
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))
122 ? FromIsSmaller
123 : FromIsNotSmaller>
124 struct UnsignedSignedCheck;
126 template<typename From, typename To>
127 struct UnsignedSignedCheck<From, To, FromIsSmaller>
129 public:
130 static bool checkBounds(const From aFrom)
132 return true;
136 template<typename From, typename To>
137 struct UnsignedSignedCheck<From, To, FromIsNotSmaller>
139 public:
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>
150 public:
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>
162 public:
163 static bool checkBounds(const From aFrom)
165 if (sizeof(From) <= sizeof(To)) {
166 return true;
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>
178 class BoundsChecker;
180 template<typename From>
181 class BoundsChecker<From, From, true>
183 public:
184 static bool checkBounds(const From aFrom) { return true; }
187 template<typename From, typename To>
188 class BoundsChecker<From, To, true>
190 public:
191 static bool checkBounds(const From aFrom)
193 return BoundsCheckImpl<From, To>::checkBounds(aFrom);
197 template<typename From, typename To>
198 inline bool
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>
212 inline To
213 AssertedCast(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 */