Home | History | Annotate | Download | only in utils
      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 "SkTypes.h"
     12 #include "SkTLogic.h"
     13 #include <limits>
     14 
     15 namespace sktfitsin {
     16 namespace Private {
     17 
     18 /** SkTHasMoreDigits::type = (digits(A) >= digits(B)) ? SkTrue : SkFalse. */
     19 template<typename A, typename B> struct SkTHasMoreDigits {
     20     typedef SkTBool<std::numeric_limits<A>::digits >= std::numeric_limits<B>::digits> type;
     21 };
     22 
     23 /** A high or low side predicate which is used when it is statically known
     24  *  that source values are in the range of the Destination.
     25  */
     26 template <typename S> struct SkTOutOfRange_False {
     27     typedef SkFalse can_be_true;
     28     typedef S source_type;
     29     static bool apply(S s) {
     30         return false;
     31     }
     32 };
     33 
     34 /** A low side predicate which tests if the source value < Min(D).
     35  *  Assumes that Min(S) <= Min(D).
     36  */
     37 template <typename D, typename S> struct SkTOutOfRange_LT_MinD {
     38     typedef SkTrue can_be_true;
     39     typedef S source_type;
     40     static bool apply(S s) {
     41         typedef typename SkTHasMoreDigits<S, D>::type precondition;
     42         SK_COMPILE_ASSERT(precondition::value, SkTOutOfRange_LT_MinD__minS_gt_minD);
     43 
     44         return s < static_cast<S>((std::numeric_limits<D>::min)());
     45     }
     46 };
     47 
     48 /** A low side predicate which tests if the source value is less than 0. */
     49 template <typename D, typename S> struct SkTOutOfRange_LT_Zero {
     50     typedef SkTrue can_be_true;
     51     typedef S source_type;
     52     static bool apply(S s) {
     53         return s < static_cast<S>(0);
     54     }
     55 };
     56 
     57 /** A high side predicate which tests if the source value > Max(D).
     58  *  Assumes that Max(S) >= Max(D).
     59  */
     60 template <typename D, typename S> struct SkTOutOfRange_GT_MaxD {
     61     typedef SkTrue can_be_true;
     62     typedef S source_type;
     63     static bool apply(S s) {
     64         typedef typename SkTHasMoreDigits<S, D>::type precondition;
     65         SK_COMPILE_ASSERT(precondition::value, SkTOutOfRange_GT_MaxD__maxS_lt_maxD);
     66 
     67         return s > static_cast<S>((std::numeric_limits<D>::max)());
     68     }
     69 };
     70 
     71 /** Composes two SkTOutOfRange predicates.
     72  *  First checks OutOfRange_Low then, if in range, OutOfRange_High.
     73  */
     74 template<class OutOfRange_Low, class OutOfRange_High> struct SkTOutOfRange_Either {
     75     typedef SkTrue can_be_true;
     76     typedef typename OutOfRange_Low::source_type source_type;
     77     static bool apply(source_type s) {
     78         bool outOfRange = OutOfRange_Low::apply(s);
     79         if (!outOfRange) {
     80             outOfRange = OutOfRange_High::apply(s);
     81         }
     82         return outOfRange;
     83     }
     84 };
     85 
     86 /** SkTCombineOutOfRange::type is an SkTOutOfRange_XXX type which is the
     87  *  optimal combination of OutOfRange_Low and OutOfRange_High.
     88  */
     89 template<class OutOfRange_Low, class OutOfRange_High> struct SkTCombineOutOfRange {
     90     typedef SkTOutOfRange_Either<OutOfRange_Low, OutOfRange_High> Both;
     91     typedef SkTOutOfRange_False<typename OutOfRange_Low::source_type> Neither;
     92 
     93     typedef typename OutOfRange_Low::can_be_true apply_low;
     94     typedef typename OutOfRange_High::can_be_true apply_high;
     95 
     96     typedef typename SkTMux<apply_low, apply_high,
     97                             Both, OutOfRange_Low, OutOfRange_High, Neither>::type type;
     98 };
     99 
    100 template<typename D, typename S, class OutOfRange_Low, class OutOfRange_High>
    101 struct SkTRangeChecker {
    102     /** This is the method which is called at runtime to do the range check. */
    103     static bool OutOfRange(S s) {
    104         typedef typename SkTCombineOutOfRange<OutOfRange_Low, OutOfRange_High>::type Combined;
    105         return Combined::apply(s);
    106     }
    107 };
    108 
    109 /** SkTFitsIn_Unsigned2Unsiged::type is an SkTRangeChecker with an OutOfRange(S s) method
    110  *  the implementation of which is tailored for the source and destination types.
    111  *  Assumes that S and D are unsigned integer types.
    112  */
    113 template<typename D, typename S> struct SkTFitsIn_Unsigned2Unsiged {
    114     typedef SkTOutOfRange_False<S> OutOfRange_Low;
    115     typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High;
    116 
    117     typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> HighSideOnlyCheck;
    118     typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S> > NoCheck;
    119 
    120     // If std::numeric_limits<D>::digits >= std::numeric_limits<S>::digits, nothing to check.
    121     // This also protects the precondition of SkTOutOfRange_GT_MaxD.
    122     typedef typename SkTHasMoreDigits<D, S>::type sourceFitsInDesitination;
    123     typedef typename SkTIf<sourceFitsInDesitination, NoCheck, HighSideOnlyCheck>::type type;
    124 };
    125 
    126 /** SkTFitsIn_Signed2Signed::type is an SkTRangeChecker with an OutOfRange(S s) method
    127  *  the implementation of which is tailored for the source and destination types.
    128  *  Assumes that S and D are signed integer types.
    129  */
    130 template<typename D, typename S> struct SkTFitsIn_Signed2Signed {
    131     typedef SkTOutOfRange_LT_MinD<D, S> OutOfRange_Low;
    132     typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High;
    133 
    134     typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> FullCheck;
    135     typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S> > NoCheck;
    136 
    137     // If std::numeric_limits<D>::digits >= std::numeric_limits<S>::digits, nothing to check.
    138     // This also protects the precondition of SkTOutOfRange_LT_MinD and SkTOutOfRange_GT_MaxD.
    139     typedef typename SkTHasMoreDigits<D, S>::type sourceFitsInDesitination;
    140     typedef typename SkTIf<sourceFitsInDesitination, NoCheck, FullCheck>::type type;
    141 };
    142 
    143 /** SkTFitsIn_Signed2Unsigned::type is an SkTRangeChecker with an OutOfRange(S s) method
    144  *  the implementation of which is tailored for the source and destination types.
    145  *  Assumes that S is a signed integer type and D is an unsigned integer type.
    146  */
    147 template<typename D, typename S> struct SkTFitsIn_Signed2Unsigned {
    148     typedef SkTOutOfRange_LT_Zero<D, S> OutOfRange_Low;
    149     typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High;
    150 
    151     typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> FullCheck;
    152     typedef SkTRangeChecker<D, S, OutOfRange_Low, SkTOutOfRange_False<S> > LowSideOnlyCheck;
    153 
    154     // If std::numeric_limits<D>::max() >= std::numeric_limits<S>::max(),
    155     // no need to check the high side. (Until C++11, assume more digits means greater max.)
    156     // This also protects the precondition of SkTOutOfRange_GT_MaxD.
    157     typedef typename SkTHasMoreDigits<D, S>::type sourceCannotExceedDesitination;
    158     typedef typename SkTIf<sourceCannotExceedDesitination, LowSideOnlyCheck, FullCheck>::type type;
    159 };
    160 
    161 /** SkTFitsIn_Unsigned2Signed::type is an SkTRangeChecker with an OutOfRange(S s) method
    162  *  the implementation of which is tailored for the source and destination types.
    163  *  Assumes that S is an usigned integer type and D is a signed integer type.
    164  */
    165 template<typename D, typename S> struct SkTFitsIn_Unsigned2Signed {
    166     typedef SkTOutOfRange_False<S> OutOfRange_Low;
    167     typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High;
    168 
    169     typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> HighSideOnlyCheck;
    170     typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S> > NoCheck;
    171 
    172     // If std::numeric_limits<D>::max() >= std::numeric_limits<S>::max(), nothing to check.
    173     // (Until C++11, assume more digits means greater max.)
    174     // This also protects the precondition of SkTOutOfRange_GT_MaxD.
    175     typedef typename SkTHasMoreDigits<D, S>::type sourceCannotExceedDesitination;
    176     typedef typename SkTIf<sourceCannotExceedDesitination, NoCheck, HighSideOnlyCheck>::type type;
    177 };
    178 
    179 /** SkTFitsIn::type is an SkTRangeChecker with an OutOfRange(S s) method
    180  *  the implementation of which is tailored for the source and destination types.
    181  *  Assumes that S and D are integer types.
    182  */
    183 template<typename D, typename S> struct SkTFitsIn {
    184     // One of the following will be the 'selector' type.
    185     typedef SkTFitsIn_Signed2Signed<D, S> S2S;
    186     typedef SkTFitsIn_Signed2Unsigned<D, S> S2U;
    187     typedef SkTFitsIn_Unsigned2Signed<D, S> U2S;
    188     typedef SkTFitsIn_Unsigned2Unsiged<D, S> U2U;
    189 
    190     typedef SkTBool<std::numeric_limits<S>::is_signed> S_is_signed;
    191     typedef SkTBool<std::numeric_limits<D>::is_signed> D_is_signed;
    192 
    193     typedef typename SkTMux<S_is_signed, D_is_signed, S2S, S2U, U2S, U2U>::type selector;
    194     // This type is an SkTRangeChecker.
    195     typedef typename selector::type type;
    196 };
    197 
    198 } // namespace Private
    199 } // namespace sktfitsin
    200 
    201 /** Returns true if the integer source value 's' will fit in the integer destination type 'D'. */
    202 template <typename D, typename S> inline bool SkTFitsIn(S s) {
    203     SK_COMPILE_ASSERT(std::numeric_limits<S>::is_integer, SkTFitsIn_source_must_be_integer);
    204     SK_COMPILE_ASSERT(std::numeric_limits<D>::is_integer, SkTFitsIn_destination_must_be_integer);
    205 
    206     return !sktfitsin::Private::SkTFitsIn<D, S>::type::OutOfRange(s);
    207 }
    208 
    209 #endif
    210