mfbt/Casting.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial