1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mfbt/Casting.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,202 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* Cast operations to supplement the built-in casting operations. */ 1.11 + 1.12 +#ifndef mozilla_Casting_h 1.13 +#define mozilla_Casting_h 1.14 + 1.15 +#include "mozilla/Assertions.h" 1.16 +#include "mozilla/TypeTraits.h" 1.17 + 1.18 +#include <limits.h> 1.19 + 1.20 +namespace mozilla { 1.21 + 1.22 +/** 1.23 + * Return a value of type |To|, containing the underlying bit pattern of |from|. 1.24 + * 1.25 + * |To| and |From| must be types of the same size; be careful of cross-platform 1.26 + * size differences, or this might fail to compile on some but not all 1.27 + * platforms. 1.28 + */ 1.29 +template<typename To, typename From> 1.30 +inline To 1.31 +BitwiseCast(const From from) 1.32 +{ 1.33 + static_assert(sizeof(From) == sizeof(To), 1.34 + "To and From must have the same size"); 1.35 + union { 1.36 + From from; 1.37 + To to; 1.38 + } u; 1.39 + u.from = from; 1.40 + return u.to; 1.41 +} 1.42 + 1.43 +namespace detail { 1.44 + 1.45 +enum ToSignedness { ToIsSigned, ToIsUnsigned }; 1.46 +enum FromSignedness { FromIsSigned, FromIsUnsigned }; 1.47 + 1.48 +template<typename From, 1.49 + typename To, 1.50 + FromSignedness = IsSigned<From>::value ? FromIsSigned : FromIsUnsigned, 1.51 + ToSignedness = IsSigned<To>::value ? ToIsSigned : ToIsUnsigned> 1.52 +struct BoundsCheckImpl; 1.53 + 1.54 +// Implicit conversions on operands to binary operations make this all a bit 1.55 +// hard to verify. Attempt to ease the pain below by *only* comparing values 1.56 +// that are obviously the same type (and will undergo no further conversions), 1.57 +// even when it's not strictly necessary, for explicitness. 1.58 + 1.59 +enum UUComparison { FromIsBigger, FromIsNotBigger }; 1.60 + 1.61 +// Unsigned-to-unsigned range check 1.62 + 1.63 +template<typename From, typename To, 1.64 + UUComparison = (sizeof(From) > sizeof(To)) ? FromIsBigger : FromIsNotBigger> 1.65 +struct UnsignedUnsignedCheck; 1.66 + 1.67 +template<typename From, typename To> 1.68 +struct UnsignedUnsignedCheck<From, To, FromIsBigger> 1.69 +{ 1.70 + public: 1.71 + static bool checkBounds(const From from) { 1.72 + return from <= From(To(-1)); 1.73 + } 1.74 +}; 1.75 + 1.76 +template<typename From, typename To> 1.77 +struct UnsignedUnsignedCheck<From, To, FromIsNotBigger> 1.78 +{ 1.79 + public: 1.80 + static bool checkBounds(const From from) { 1.81 + return true; 1.82 + } 1.83 +}; 1.84 + 1.85 +template<typename From, typename To> 1.86 +struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsUnsigned> 1.87 +{ 1.88 + public: 1.89 + static bool checkBounds(const From from) { 1.90 + return UnsignedUnsignedCheck<From, To>::checkBounds(from); 1.91 + } 1.92 +}; 1.93 + 1.94 +// Signed-to-unsigned range check 1.95 + 1.96 +template<typename From, typename To> 1.97 +struct BoundsCheckImpl<From, To, FromIsSigned, ToIsUnsigned> 1.98 +{ 1.99 + public: 1.100 + static bool checkBounds(const From from) { 1.101 + if (from < 0) 1.102 + return false; 1.103 + if (sizeof(To) >= sizeof(From)) 1.104 + return true; 1.105 + return from <= From(To(-1)); 1.106 + } 1.107 +}; 1.108 + 1.109 +// Unsigned-to-signed range check 1.110 + 1.111 +enum USComparison { FromIsSmaller, FromIsNotSmaller }; 1.112 + 1.113 +template<typename From, typename To, 1.114 + USComparison = (sizeof(From) < sizeof(To)) ? FromIsSmaller : FromIsNotSmaller> 1.115 +struct UnsignedSignedCheck; 1.116 + 1.117 +template<typename From, typename To> 1.118 +struct UnsignedSignedCheck<From, To, FromIsSmaller> 1.119 +{ 1.120 + public: 1.121 + static bool checkBounds(const From from) { 1.122 + return true; 1.123 + } 1.124 +}; 1.125 + 1.126 +template<typename From, typename To> 1.127 +struct UnsignedSignedCheck<From, To, FromIsNotSmaller> 1.128 +{ 1.129 + public: 1.130 + static bool checkBounds(const From from) { 1.131 + const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1); 1.132 + return from <= From(MaxValue); 1.133 + } 1.134 +}; 1.135 + 1.136 +template<typename From, typename To> 1.137 +struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsSigned> 1.138 +{ 1.139 + public: 1.140 + static bool checkBounds(const From from) { 1.141 + return UnsignedSignedCheck<From, To>::checkBounds(from); 1.142 + } 1.143 +}; 1.144 + 1.145 +// Signed-to-signed range check 1.146 + 1.147 +template<typename From, typename To> 1.148 +struct BoundsCheckImpl<From, To, FromIsSigned, ToIsSigned> 1.149 +{ 1.150 + public: 1.151 + static bool checkBounds(const From from) { 1.152 + if (sizeof(From) <= sizeof(To)) 1.153 + return true; 1.154 + const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1); 1.155 + const To MinValue = -MaxValue - To(1); 1.156 + return From(MinValue) <= from && 1.157 + From(from) <= From(MaxValue); 1.158 + } 1.159 +}; 1.160 + 1.161 +template<typename From, typename To, 1.162 + bool TypesAreIntegral = IsIntegral<From>::value && IsIntegral<To>::value> 1.163 +class BoundsChecker; 1.164 + 1.165 +template<typename From> 1.166 +class BoundsChecker<From, From, true> 1.167 +{ 1.168 + public: 1.169 + static bool checkBounds(const From from) { return true; } 1.170 +}; 1.171 + 1.172 +template<typename From, typename To> 1.173 +class BoundsChecker<From, To, true> 1.174 +{ 1.175 + public: 1.176 + static bool checkBounds(const From from) { 1.177 + return BoundsCheckImpl<From, To>::checkBounds(from); 1.178 + } 1.179 +}; 1.180 + 1.181 +template<typename From, typename To> 1.182 +inline bool 1.183 +IsInBounds(const From from) 1.184 +{ 1.185 + return BoundsChecker<From, To>::checkBounds(from); 1.186 +} 1.187 + 1.188 +} // namespace detail 1.189 + 1.190 +/** 1.191 + * Cast a value of integral type |From| to a value of integral type |To|, 1.192 + * asserting that the cast will be a safe cast per C++ (that is, that |to| is in 1.193 + * the range of values permitted for the type |From|). 1.194 + */ 1.195 +template<typename To, typename From> 1.196 +inline To 1.197 +SafeCast(const From from) 1.198 +{ 1.199 + MOZ_ASSERT((detail::IsInBounds<From, To>(from))); 1.200 + return static_cast<To>(from); 1.201 +} 1.202 + 1.203 +} // namespace mozilla 1.204 + 1.205 +#endif /* mozilla_Casting_h */