LCOV - code coverage report
Current view: top level - gfx/skia/skia/include/private - SkTFitsIn.h (source / functions) Hit Total Coverage
Test: output.info Lines: 17 17 100.0 %
Date: 2017-07-14 16:53:18 Functions: 57 109 52.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2013 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #ifndef SkTFitsIn_DEFINED
       9             : #define SkTFitsIn_DEFINED
      10             : 
      11             : #include "../private/SkTLogic.h"
      12             : #include <limits>
      13             : #include <type_traits>
      14             : 
      15             : namespace sktfitsin {
      16             : namespace Private {
      17             : 
      18             : /** SkTMux::type = (a && b) ? Both : (a) ? A : (b) ? B : Neither; */
      19             : template <bool a, bool b, typename Both, typename A, typename B, typename Neither>
      20             : struct SkTMux {
      21             :     using type = skstd::conditional_t<a, skstd::conditional_t<b, Both, A>,
      22             :                                          skstd::conditional_t<b, B, Neither>>;
      23             : };
      24             : 
      25             : /** SkTHasMoreDigits = (digits(A) >= digits(B)) ? true_type : false_type. */
      26             : template <typename A, typename B> struct SkTHasMoreDigits
      27             :     : skstd::bool_constant<std::numeric_limits<A>::digits >= std::numeric_limits<B>::digits>
      28             : { };
      29             : 
      30             : /** A high or low side predicate which is used when it is statically known
      31             :  *  that source values are in the range of the Destination.
      32             :  */
      33             : template <typename S> struct SkTOutOfRange_False {
      34             :     using can_be_true = std::false_type;
      35             :     using source_type = S;
      36       10411 :     static bool apply(S) {
      37       10411 :         return false;
      38             :     }
      39             : };
      40             : 
      41             : /** A low side predicate which tests if the source value < Min(D).
      42             :  *  Assumes that Min(S) <= Min(D).
      43             :  */
      44             : template <typename D, typename S> struct SkTOutOfRange_LT_MinD {
      45             :     using can_be_true = std::true_type;
      46             :     using source_type = S;
      47       29920 :     static bool apply(S s) {
      48             :         using precondition = SkTHasMoreDigits<S, D>;
      49             :         static_assert(precondition::value, "minS > minD");
      50             : 
      51       29920 :         return s < static_cast<S>((std::numeric_limits<D>::min)());
      52             :     }
      53             : };
      54             : 
      55             : /** A low side predicate which tests if the source value is less than 0. */
      56             : template <typename D, typename S> struct SkTOutOfRange_LT_Zero {
      57             :     using can_be_true = std::true_type;
      58             :     using source_type = S;
      59       10717 :     static bool apply(S s) {
      60       10717 :         return s < static_cast<S>(0);
      61             :     }
      62             : };
      63             : 
      64             : /** A high side predicate which tests if the source value > Max(D).
      65             :  *  Assumes that Max(S) >= Max(D).
      66             :  */
      67             : template <typename D, typename S> struct SkTOutOfRange_GT_MaxD {
      68             :     using can_be_true = std::true_type;
      69             :     using source_type = S;
      70      184174 :     static bool apply(S s) {
      71             :         using precondition = SkTHasMoreDigits<S, D>;
      72             :         static_assert(precondition::value, "maxS < maxD");
      73             : 
      74      184174 :         return s > static_cast<S>((std::numeric_limits<D>::max)());
      75             :     }
      76             : };
      77             : 
      78             : /** Composes two SkTOutOfRange predicates.
      79             :  *  First checks OutOfRange_Low then, if in range, OutOfRange_High.
      80             :  */
      81             : template <typename OutOfRange_Low, typename OutOfRange_High> struct SkTOutOfRange_Either {
      82             :     using can_be_true = std::true_type;
      83             :     using source_type = typename OutOfRange_Low::source_type;
      84       40637 :     static bool apply(source_type s) {
      85       40637 :         bool outOfRange = OutOfRange_Low::apply(s);
      86       40637 :         if (!outOfRange) {
      87       40637 :             outOfRange = OutOfRange_High::apply(s);
      88             :         }
      89       40637 :         return outOfRange;
      90             :     }
      91             : };
      92             : 
      93             : /** SkTCombineOutOfRange::type is an SkTOutOfRange_XXX type which is the
      94             :  *  optimal combination of OutOfRange_Low and OutOfRange_High.
      95             :  */
      96             : template <typename OutOfRange_Low, typename OutOfRange_High> struct SkTCombineOutOfRange {
      97             :     using Both = SkTOutOfRange_Either<OutOfRange_Low, OutOfRange_High>;
      98             :     using Neither = SkTOutOfRange_False<typename OutOfRange_Low::source_type>;
      99             : 
     100             :     using apply_low = typename OutOfRange_Low::can_be_true;
     101             :     using apply_high = typename OutOfRange_High::can_be_true;
     102             : 
     103             :     using type = typename SkTMux<apply_low::value, apply_high::value,
     104             :                                  Both, OutOfRange_Low, OutOfRange_High, Neither>::type;
     105             : };
     106             : 
     107             : template <typename D, typename S, typename OutOfRange_Low, typename OutOfRange_High>
     108             : struct SkTRangeChecker {
     109             :     /** This is the method which is called at runtime to do the range check. */
     110      194585 :     static bool OutOfRange(S s) {
     111             :         using Combined = typename SkTCombineOutOfRange<OutOfRange_Low, OutOfRange_High>::type;
     112      194585 :         return Combined::apply(s);
     113             :     }
     114             : };
     115             : 
     116             : /** SkTFitsIn_Unsigned2Unsiged::type is an SkTRangeChecker with an OutOfRange(S s) method
     117             :  *  the implementation of which is tailored for the source and destination types.
     118             :  *  Assumes that S and D are unsigned integer types.
     119             :  */
     120             : template <typename D, typename S> struct SkTFitsIn_Unsigned2Unsiged {
     121             :     using OutOfRange_Low = SkTOutOfRange_False<S>;
     122             :     using OutOfRange_High = SkTOutOfRange_GT_MaxD<D, S>;
     123             : 
     124             :     using HighSideOnlyCheck = SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High>;
     125             :     using NoCheck = SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>>;
     126             : 
     127             :     // If std::numeric_limits<D>::digits >= std::numeric_limits<S>::digits, nothing to check.
     128             :     // This also protects the precondition of SkTOutOfRange_GT_MaxD.
     129             :     using sourceFitsInDesitination = SkTHasMoreDigits<D, S>;
     130             :     using type = skstd::conditional_t<sourceFitsInDesitination::value, NoCheck, HighSideOnlyCheck>;
     131             : };
     132             : 
     133             : /** SkTFitsIn_Signed2Signed::type is an SkTRangeChecker with an OutOfRange(S s) method
     134             :  *  the implementation of which is tailored for the source and destination types.
     135             :  *  Assumes that S and D are signed integer types.
     136             :  */
     137             : template <typename D, typename S> struct SkTFitsIn_Signed2Signed {
     138             :     using OutOfRange_Low = SkTOutOfRange_LT_MinD<D, S>;
     139             :     using OutOfRange_High = SkTOutOfRange_GT_MaxD<D, S>;
     140             : 
     141             :     using FullCheck = SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High>;
     142             :     using NoCheck = SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>>;
     143             : 
     144             :     // If std::numeric_limits<D>::digits >= std::numeric_limits<S>::digits, nothing to check.
     145             :     // This also protects the precondition of SkTOutOfRange_LT_MinD and SkTOutOfRange_GT_MaxD.
     146             :     using sourceFitsInDesitination = SkTHasMoreDigits<D, S>;
     147             :     using type = skstd::conditional_t<sourceFitsInDesitination::value, NoCheck, FullCheck>;
     148             : };
     149             : 
     150             : /** SkTFitsIn_Signed2Unsigned::type is an SkTRangeChecker with an OutOfRange(S s) method
     151             :  *  the implementation of which is tailored for the source and destination types.
     152             :  *  Assumes that S is a signed integer type and D is an unsigned integer type.
     153             :  */
     154             : template <typename D, typename S> struct SkTFitsIn_Signed2Unsigned {
     155             :     using OutOfRange_Low = SkTOutOfRange_LT_Zero<D, S>;
     156             :     using OutOfRange_High = SkTOutOfRange_GT_MaxD<D, S>;
     157             : 
     158             :     using FullCheck = SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High>;
     159             :     using LowSideOnlyCheck = SkTRangeChecker<D, S, OutOfRange_Low, SkTOutOfRange_False<S>>;
     160             : 
     161             :     // If std::numeric_limits<D>::max() >= std::numeric_limits<S>::max(),
     162             :     // no need to check the high side. (Until C++11, assume more digits means greater max.)
     163             :     // This also protects the precondition of SkTOutOfRange_GT_MaxD.
     164             :     using sourceCannotExceedDest = SkTHasMoreDigits<D, S>;
     165             :     using type = skstd::conditional_t<sourceCannotExceedDest::value, LowSideOnlyCheck, FullCheck>;
     166             : };
     167             : 
     168             : /** SkTFitsIn_Unsigned2Signed::type is an SkTRangeChecker with an OutOfRange(S s) method
     169             :  *  the implementation of which is tailored for the source and destination types.
     170             :  *  Assumes that S is an usigned integer type and D is a signed integer type.
     171             :  */
     172             : template <typename D, typename S> struct SkTFitsIn_Unsigned2Signed {
     173             :     using OutOfRange_Low = SkTOutOfRange_False<S>;
     174             :     using OutOfRange_High = SkTOutOfRange_GT_MaxD<D, S>;
     175             : 
     176             :     using HighSideOnlyCheck = SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High>;
     177             :     using NoCheck = SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>>;
     178             : 
     179             :     // If std::numeric_limits<D>::max() >= std::numeric_limits<S>::max(), nothing to check.
     180             :     // (Until C++11, assume more digits means greater max.)
     181             :     // This also protects the precondition of SkTOutOfRange_GT_MaxD.
     182             :     using sourceCannotExceedDest = SkTHasMoreDigits<D, S>;
     183             :     using type = skstd::conditional_t<sourceCannotExceedDest::value, NoCheck, HighSideOnlyCheck>;
     184             : };
     185             : 
     186             : /** SkTFitsIn::type is an SkTRangeChecker with an OutOfRange(S s) method
     187             :  *  the implementation of which is tailored for the source and destination types.
     188             :  *  Assumes that S and D are integer types.
     189             :  */
     190             : template <typename D, typename S> struct SkTFitsIn {
     191             :     // One of the following will be the 'selector' type.
     192             :     using S2S = SkTFitsIn_Signed2Signed<D, S>;
     193             :     using S2U = SkTFitsIn_Signed2Unsigned<D, S>;
     194             :     using U2S = SkTFitsIn_Unsigned2Signed<D, S>;
     195             :     using U2U = SkTFitsIn_Unsigned2Unsiged<D, S>;
     196             : 
     197             :     using S_is_signed = skstd::bool_constant<std::numeric_limits<S>::is_signed>;
     198             :     using D_is_signed = skstd::bool_constant<std::numeric_limits<D>::is_signed>;
     199             : 
     200             :     using selector = typename SkTMux<S_is_signed::value, D_is_signed::value,
     201             :                                      S2S, S2U, U2S, U2U>::type;
     202             :     // This type is an SkTRangeChecker.
     203             :     using type = typename selector::type;
     204             : };
     205             : 
     206             : template <typename T, bool = std::is_enum<T>::value> struct underlying_type {
     207             :     using type = skstd::underlying_type_t<T>;
     208             : };
     209             : template <typename T> struct underlying_type<T, false> {
     210             :     using type = T;
     211             : };
     212             : 
     213             : } // namespace Private
     214             : } // namespace sktfitsin
     215             : 
     216             : /** Returns true if the integer source value 's' will fit in the integer destination type 'D'. */
     217      194585 : template <typename D, typename S> inline bool SkTFitsIn(S s) {
     218             :     static_assert(std::is_integral<S>::value || std::is_enum<S>::value, "S must be integral.");
     219             :     static_assert(std::is_integral<D>::value || std::is_enum<D>::value, "D must be integral.");
     220             : 
     221             :     using RealS = typename sktfitsin::Private::underlying_type<S>::type;
     222             :     using RealD = typename sktfitsin::Private::underlying_type<D>::type;
     223             : 
     224      194585 :     return !sktfitsin::Private::SkTFitsIn<RealD, RealS>::type::OutOfRange(s);
     225             : }
     226             : 
     227             : #endif

Generated by: LCOV version 1.13