LCOV - code coverage report
Current view: top level - dom/bindings - PrimitiveConversions.h (source / functions) Hit Total Coverage
Test: output.info Lines: 11 68 16.2 %
Date: 2017-07-14 16:53:18 Functions: 9 51 17.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13