dom/bindings/PrimitiveConversions.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
michael@0 2 /* vim: set ts=2 sw=2 et tw=79: */
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 file,
michael@0 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /**
michael@0 8 * Conversions from jsval to primitive values
michael@0 9 */
michael@0 10
michael@0 11 #ifndef mozilla_dom_PrimitiveConversions_h
michael@0 12 #define mozilla_dom_PrimitiveConversions_h
michael@0 13
michael@0 14 #include <limits>
michael@0 15 #include <math.h>
michael@0 16 #include <stdint.h>
michael@0 17
michael@0 18 #include "jsapi.h"
michael@0 19 #include "mozilla/Assertions.h"
michael@0 20 #include "mozilla/ErrorResult.h"
michael@0 21 #include "mozilla/FloatingPoint.h"
michael@0 22
michael@0 23 namespace mozilla {
michael@0 24 namespace dom {
michael@0 25
michael@0 26 template<typename T>
michael@0 27 struct TypeName {
michael@0 28 };
michael@0 29
michael@0 30 template<>
michael@0 31 struct TypeName<int8_t> {
michael@0 32 static const char* value() {
michael@0 33 return "byte";
michael@0 34 }
michael@0 35 };
michael@0 36 template<>
michael@0 37 struct TypeName<uint8_t> {
michael@0 38 static const char* value() {
michael@0 39 return "octet";
michael@0 40 }
michael@0 41 };
michael@0 42 template<>
michael@0 43 struct TypeName<int16_t> {
michael@0 44 static const char* value() {
michael@0 45 return "short";
michael@0 46 }
michael@0 47 };
michael@0 48 template<>
michael@0 49 struct TypeName<uint16_t> {
michael@0 50 static const char* value() {
michael@0 51 return "unsigned short";
michael@0 52 }
michael@0 53 };
michael@0 54 template<>
michael@0 55 struct TypeName<int32_t> {
michael@0 56 static const char* value() {
michael@0 57 return "long";
michael@0 58 }
michael@0 59 };
michael@0 60 template<>
michael@0 61 struct TypeName<uint32_t> {
michael@0 62 static const char* value() {
michael@0 63 return "unsigned long";
michael@0 64 }
michael@0 65 };
michael@0 66 template<>
michael@0 67 struct TypeName<int64_t> {
michael@0 68 static const char* value() {
michael@0 69 return "long long";
michael@0 70 }
michael@0 71 };
michael@0 72 template<>
michael@0 73 struct TypeName<uint64_t> {
michael@0 74 static const char* value() {
michael@0 75 return "unsigned long long";
michael@0 76 }
michael@0 77 };
michael@0 78
michael@0 79
michael@0 80 enum ConversionBehavior {
michael@0 81 eDefault,
michael@0 82 eEnforceRange,
michael@0 83 eClamp
michael@0 84 };
michael@0 85
michael@0 86 template<typename T, ConversionBehavior B>
michael@0 87 struct PrimitiveConversionTraits {
michael@0 88 };
michael@0 89
michael@0 90 template<typename T>
michael@0 91 struct DisallowedConversion {
michael@0 92 typedef int jstype;
michael@0 93 typedef int intermediateType;
michael@0 94
michael@0 95 private:
michael@0 96 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
michael@0 97 jstype* retval) {
michael@0 98 MOZ_CRASH("This should never be instantiated!");
michael@0 99 }
michael@0 100 };
michael@0 101
michael@0 102 struct PrimitiveConversionTraits_smallInt {
michael@0 103 // The output of JS::ToInt32 is determined as follows:
michael@0 104 // 1) The value is converted to a double
michael@0 105 // 2) Anything that's not a finite double returns 0
michael@0 106 // 3) The double is rounded towards zero to the nearest integer
michael@0 107 // 4) The resulting integer is reduced mod 2^32. The output of this
michael@0 108 // operation is an integer in the range [0, 2^32).
michael@0 109 // 5) If the resulting number is >= 2^31, 2^32 is subtracted from it.
michael@0 110 //
michael@0 111 // The result of all this is a number in the range [-2^31, 2^31)
michael@0 112 //
michael@0 113 // WebIDL conversions for the 8-bit, 16-bit, and 32-bit integer types
michael@0 114 // are defined in the same way, except that step 4 uses reduction mod
michael@0 115 // 2^8 and 2^16 for the 8-bit and 16-bit types respectively, and step 5
michael@0 116 // is only done for the signed types.
michael@0 117 //
michael@0 118 // C/C++ define integer conversion semantics to unsigned types as taking
michael@0 119 // your input integer mod (1 + largest value representable in the
michael@0 120 // unsigned type). Since 2^32 is zero mod 2^8, 2^16, and 2^32,
michael@0 121 // converting to the unsigned int of the relevant width will correctly
michael@0 122 // perform step 4; in particular, the 2^32 possibly subtracted in step 5
michael@0 123 // will become 0.
michael@0 124 //
michael@0 125 // Once we have step 4 done, we're just going to assume 2s-complement
michael@0 126 // representation and cast directly to the type we really want.
michael@0 127 //
michael@0 128 // So we can cast directly for all unsigned types and for int32_t; for
michael@0 129 // the smaller-width signed types we need to cast through the
michael@0 130 // corresponding unsigned type.
michael@0 131 typedef int32_t jstype;
michael@0 132 typedef int32_t intermediateType;
michael@0 133 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
michael@0 134 jstype* retval) {
michael@0 135 return JS::ToInt32(cx, v, retval);
michael@0 136 }
michael@0 137 };
michael@0 138 template<>
michael@0 139 struct PrimitiveConversionTraits<int8_t, eDefault> : PrimitiveConversionTraits_smallInt {
michael@0 140 typedef uint8_t intermediateType;
michael@0 141 };
michael@0 142 template<>
michael@0 143 struct PrimitiveConversionTraits<uint8_t, eDefault> : PrimitiveConversionTraits_smallInt {
michael@0 144 };
michael@0 145 template<>
michael@0 146 struct PrimitiveConversionTraits<int16_t, eDefault> : PrimitiveConversionTraits_smallInt {
michael@0 147 typedef uint16_t intermediateType;
michael@0 148 };
michael@0 149 template<>
michael@0 150 struct PrimitiveConversionTraits<uint16_t, eDefault> : PrimitiveConversionTraits_smallInt {
michael@0 151 };
michael@0 152 template<>
michael@0 153 struct PrimitiveConversionTraits<int32_t, eDefault> : PrimitiveConversionTraits_smallInt {
michael@0 154 };
michael@0 155 template<>
michael@0 156 struct PrimitiveConversionTraits<uint32_t, eDefault> : PrimitiveConversionTraits_smallInt {
michael@0 157 };
michael@0 158
michael@0 159 template<>
michael@0 160 struct PrimitiveConversionTraits<int64_t, eDefault> {
michael@0 161 typedef int64_t jstype;
michael@0 162 typedef int64_t intermediateType;
michael@0 163 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
michael@0 164 jstype* retval) {
michael@0 165 return JS::ToInt64(cx, v, retval);
michael@0 166 }
michael@0 167 };
michael@0 168
michael@0 169 template<>
michael@0 170 struct PrimitiveConversionTraits<uint64_t, eDefault> {
michael@0 171 typedef uint64_t jstype;
michael@0 172 typedef uint64_t intermediateType;
michael@0 173 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
michael@0 174 jstype* retval) {
michael@0 175 return JS::ToUint64(cx, v, retval);
michael@0 176 }
michael@0 177 };
michael@0 178
michael@0 179 template<typename T>
michael@0 180 struct PrimitiveConversionTraits_Limits {
michael@0 181 static inline T min() {
michael@0 182 return std::numeric_limits<T>::min();
michael@0 183 }
michael@0 184 static inline T max() {
michael@0 185 return std::numeric_limits<T>::max();
michael@0 186 }
michael@0 187 };
michael@0 188
michael@0 189 template<>
michael@0 190 struct PrimitiveConversionTraits_Limits<int64_t> {
michael@0 191 static inline int64_t min() {
michael@0 192 return -(1LL << 53);
michael@0 193 }
michael@0 194 static inline int64_t max() {
michael@0 195 return (1LL << 53);
michael@0 196 }
michael@0 197 };
michael@0 198
michael@0 199 template<>
michael@0 200 struct PrimitiveConversionTraits_Limits<uint64_t> {
michael@0 201 static inline uint64_t min() {
michael@0 202 return 0;
michael@0 203 }
michael@0 204 static inline uint64_t max() {
michael@0 205 return (1LL << 53);
michael@0 206 }
michael@0 207 };
michael@0 208
michael@0 209 template<typename T, bool (*Enforce)(JSContext* cx, const double& d, T* retval)>
michael@0 210 struct PrimitiveConversionTraits_ToCheckedIntHelper {
michael@0 211 typedef T jstype;
michael@0 212 typedef T intermediateType;
michael@0 213
michael@0 214 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
michael@0 215 jstype* retval) {
michael@0 216 double intermediate;
michael@0 217 if (!JS::ToNumber(cx, v, &intermediate)) {
michael@0 218 return false;
michael@0 219 }
michael@0 220
michael@0 221 return Enforce(cx, intermediate, retval);
michael@0 222 }
michael@0 223 };
michael@0 224
michael@0 225 template<typename T>
michael@0 226 inline bool
michael@0 227 PrimitiveConversionTraits_EnforceRange(JSContext* cx, const double& d, T* retval)
michael@0 228 {
michael@0 229 static_assert(std::numeric_limits<T>::is_integer,
michael@0 230 "This can only be applied to integers!");
michael@0 231
michael@0 232 if (!mozilla::IsFinite(d)) {
michael@0 233 return ThrowErrorMessage(cx, MSG_ENFORCE_RANGE_NON_FINITE, TypeName<T>::value());
michael@0 234 }
michael@0 235
michael@0 236 bool neg = (d < 0);
michael@0 237 double rounded = floor(neg ? -d : d);
michael@0 238 rounded = neg ? -rounded : rounded;
michael@0 239 if (rounded < PrimitiveConversionTraits_Limits<T>::min() ||
michael@0 240 rounded > PrimitiveConversionTraits_Limits<T>::max()) {
michael@0 241 return ThrowErrorMessage(cx, MSG_ENFORCE_RANGE_OUT_OF_RANGE, TypeName<T>::value());
michael@0 242 }
michael@0 243
michael@0 244 *retval = static_cast<T>(rounded);
michael@0 245 return true;
michael@0 246 }
michael@0 247
michael@0 248 template<typename T>
michael@0 249 struct PrimitiveConversionTraits<T, eEnforceRange> :
michael@0 250 public PrimitiveConversionTraits_ToCheckedIntHelper<T, PrimitiveConversionTraits_EnforceRange<T> > {
michael@0 251 };
michael@0 252
michael@0 253 template<typename T>
michael@0 254 inline bool
michael@0 255 PrimitiveConversionTraits_Clamp(JSContext* cx, const double& d, T* retval)
michael@0 256 {
michael@0 257 static_assert(std::numeric_limits<T>::is_integer,
michael@0 258 "This can only be applied to integers!");
michael@0 259
michael@0 260 if (mozilla::IsNaN(d)) {
michael@0 261 *retval = 0;
michael@0 262 return true;
michael@0 263 }
michael@0 264 if (d >= PrimitiveConversionTraits_Limits<T>::max()) {
michael@0 265 *retval = PrimitiveConversionTraits_Limits<T>::max();
michael@0 266 return true;
michael@0 267 }
michael@0 268 if (d <= PrimitiveConversionTraits_Limits<T>::min()) {
michael@0 269 *retval = PrimitiveConversionTraits_Limits<T>::min();
michael@0 270 return true;
michael@0 271 }
michael@0 272
michael@0 273 MOZ_ASSERT(mozilla::IsFinite(d));
michael@0 274
michael@0 275 // Banker's rounding (round ties towards even).
michael@0 276 // We move away from 0 by 0.5f and then truncate. That gets us the right
michael@0 277 // answer for any starting value except plus or minus N.5. With a starting
michael@0 278 // value of that form, we now have plus or minus N+1. If N is odd, this is
michael@0 279 // the correct result. If N is even, plus or minus N is the correct result.
michael@0 280 double toTruncate = (d < 0) ? d - 0.5 : d + 0.5;
michael@0 281
michael@0 282 T truncated = static_cast<T>(toTruncate);
michael@0 283
michael@0 284 if (truncated == toTruncate) {
michael@0 285 /*
michael@0 286 * It was a tie (since moving away from 0 by 0.5 gave us the exact integer
michael@0 287 * we want). Since we rounded away from 0, we either already have an even
michael@0 288 * number or we have an odd number but the number we want is one closer to
michael@0 289 * 0. So just unconditionally masking out the ones bit should do the trick
michael@0 290 * to get us the value we want.
michael@0 291 */
michael@0 292 truncated &= ~1;
michael@0 293 }
michael@0 294
michael@0 295 *retval = truncated;
michael@0 296 return true;
michael@0 297 }
michael@0 298
michael@0 299 template<typename T>
michael@0 300 struct PrimitiveConversionTraits<T, eClamp> :
michael@0 301 public PrimitiveConversionTraits_ToCheckedIntHelper<T, PrimitiveConversionTraits_Clamp<T> > {
michael@0 302 };
michael@0 303
michael@0 304
michael@0 305 template<ConversionBehavior B>
michael@0 306 struct PrimitiveConversionTraits<bool, B> : public DisallowedConversion<bool> {};
michael@0 307
michael@0 308 template<>
michael@0 309 struct PrimitiveConversionTraits<bool, eDefault> {
michael@0 310 typedef bool jstype;
michael@0 311 typedef bool intermediateType;
michael@0 312 static inline bool converter(JSContext* /* unused */, JS::Handle<JS::Value> v,
michael@0 313 jstype* retval) {
michael@0 314 *retval = JS::ToBoolean(v);
michael@0 315 return true;
michael@0 316 }
michael@0 317 };
michael@0 318
michael@0 319
michael@0 320 template<ConversionBehavior B>
michael@0 321 struct PrimitiveConversionTraits<float, B> : public DisallowedConversion<float> {};
michael@0 322
michael@0 323 template<ConversionBehavior B>
michael@0 324 struct PrimitiveConversionTraits<double, B> : public DisallowedConversion<double> {};
michael@0 325
michael@0 326 struct PrimitiveConversionTraits_float {
michael@0 327 typedef double jstype;
michael@0 328 typedef double intermediateType;
michael@0 329 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
michael@0 330 jstype* retval) {
michael@0 331 return JS::ToNumber(cx, v, retval);
michael@0 332 }
michael@0 333 };
michael@0 334
michael@0 335 template<>
michael@0 336 struct PrimitiveConversionTraits<float, eDefault> : PrimitiveConversionTraits_float {
michael@0 337 };
michael@0 338 template<>
michael@0 339 struct PrimitiveConversionTraits<double, eDefault> : PrimitiveConversionTraits_float {
michael@0 340 };
michael@0 341
michael@0 342
michael@0 343 template<typename T, ConversionBehavior B>
michael@0 344 bool ValueToPrimitive(JSContext* cx, JS::Handle<JS::Value> v, T* retval)
michael@0 345 {
michael@0 346 typename PrimitiveConversionTraits<T, B>::jstype t;
michael@0 347 if (!PrimitiveConversionTraits<T, B>::converter(cx, v, &t))
michael@0 348 return false;
michael@0 349
michael@0 350 *retval = static_cast<T>(
michael@0 351 static_cast<typename PrimitiveConversionTraits<T, B>::intermediateType>(t));
michael@0 352 return true;
michael@0 353 }
michael@0 354
michael@0 355 } // namespace dom
michael@0 356 } // namespace mozilla
michael@0 357
michael@0 358 #endif /* mozilla_dom_PrimitiveConversions_h */

mercurial