1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/utils/SkTFitsIn.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,209 @@ 1.4 +/* 1.5 + * Copyright 2013 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#ifndef SkTFitsIn_DEFINED 1.12 +#define SkTFitsIn_DEFINED 1.13 + 1.14 +#include "SkTypes.h" 1.15 +#include "SkTLogic.h" 1.16 +#include <limits> 1.17 + 1.18 +namespace sktfitsin { 1.19 +namespace Private { 1.20 + 1.21 +/** SkTHasMoreDigits::type = (digits(A) >= digits(B)) ? SkTrue : SkFalse. */ 1.22 +template<typename A, typename B> struct SkTHasMoreDigits { 1.23 + typedef SkTBool<std::numeric_limits<A>::digits >= std::numeric_limits<B>::digits> type; 1.24 +}; 1.25 + 1.26 +/** A high or low side predicate which is used when it is statically known 1.27 + * that source values are in the range of the Destination. 1.28 + */ 1.29 +template <typename S> struct SkTOutOfRange_False { 1.30 + typedef SkFalse can_be_true; 1.31 + typedef S source_type; 1.32 + static bool apply(S s) { 1.33 + return false; 1.34 + } 1.35 +}; 1.36 + 1.37 +/** A low side predicate which tests if the source value < Min(D). 1.38 + * Assumes that Min(S) <= Min(D). 1.39 + */ 1.40 +template <typename D, typename S> struct SkTOutOfRange_LT_MinD { 1.41 + typedef SkTrue can_be_true; 1.42 + typedef S source_type; 1.43 + static bool apply(S s) { 1.44 + typedef typename SkTHasMoreDigits<S, D>::type precondition; 1.45 + SK_COMPILE_ASSERT(precondition::value, SkTOutOfRange_LT_MinD__minS_gt_minD); 1.46 + 1.47 + return s < static_cast<S>((std::numeric_limits<D>::min)()); 1.48 + } 1.49 +}; 1.50 + 1.51 +/** A low side predicate which tests if the source value is less than 0. */ 1.52 +template <typename D, typename S> struct SkTOutOfRange_LT_Zero { 1.53 + typedef SkTrue can_be_true; 1.54 + typedef S source_type; 1.55 + static bool apply(S s) { 1.56 + return s < static_cast<S>(0); 1.57 + } 1.58 +}; 1.59 + 1.60 +/** A high side predicate which tests if the source value > Max(D). 1.61 + * Assumes that Max(S) >= Max(D). 1.62 + */ 1.63 +template <typename D, typename S> struct SkTOutOfRange_GT_MaxD { 1.64 + typedef SkTrue can_be_true; 1.65 + typedef S source_type; 1.66 + static bool apply(S s) { 1.67 + typedef typename SkTHasMoreDigits<S, D>::type precondition; 1.68 + SK_COMPILE_ASSERT(precondition::value, SkTOutOfRange_GT_MaxD__maxS_lt_maxD); 1.69 + 1.70 + return s > static_cast<S>((std::numeric_limits<D>::max)()); 1.71 + } 1.72 +}; 1.73 + 1.74 +/** Composes two SkTOutOfRange predicates. 1.75 + * First checks OutOfRange_Low then, if in range, OutOfRange_High. 1.76 + */ 1.77 +template<class OutOfRange_Low, class OutOfRange_High> struct SkTOutOfRange_Either { 1.78 + typedef SkTrue can_be_true; 1.79 + typedef typename OutOfRange_Low::source_type source_type; 1.80 + static bool apply(source_type s) { 1.81 + bool outOfRange = OutOfRange_Low::apply(s); 1.82 + if (!outOfRange) { 1.83 + outOfRange = OutOfRange_High::apply(s); 1.84 + } 1.85 + return outOfRange; 1.86 + } 1.87 +}; 1.88 + 1.89 +/** SkTCombineOutOfRange::type is an SkTOutOfRange_XXX type which is the 1.90 + * optimal combination of OutOfRange_Low and OutOfRange_High. 1.91 + */ 1.92 +template<class OutOfRange_Low, class OutOfRange_High> struct SkTCombineOutOfRange { 1.93 + typedef SkTOutOfRange_Either<OutOfRange_Low, OutOfRange_High> Both; 1.94 + typedef SkTOutOfRange_False<typename OutOfRange_Low::source_type> Neither; 1.95 + 1.96 + typedef typename OutOfRange_Low::can_be_true apply_low; 1.97 + typedef typename OutOfRange_High::can_be_true apply_high; 1.98 + 1.99 + typedef typename SkTMux<apply_low, apply_high, 1.100 + Both, OutOfRange_Low, OutOfRange_High, Neither>::type type; 1.101 +}; 1.102 + 1.103 +template<typename D, typename S, class OutOfRange_Low, class OutOfRange_High> 1.104 +struct SkTRangeChecker { 1.105 + /** This is the method which is called at runtime to do the range check. */ 1.106 + static bool OutOfRange(S s) { 1.107 + typedef typename SkTCombineOutOfRange<OutOfRange_Low, OutOfRange_High>::type Combined; 1.108 + return Combined::apply(s); 1.109 + } 1.110 +}; 1.111 + 1.112 +/** SkTFitsIn_Unsigned2Unsiged::type is an SkTRangeChecker with an OutOfRange(S s) method 1.113 + * the implementation of which is tailored for the source and destination types. 1.114 + * Assumes that S and D are unsigned integer types. 1.115 + */ 1.116 +template<typename D, typename S> struct SkTFitsIn_Unsigned2Unsiged { 1.117 + typedef SkTOutOfRange_False<S> OutOfRange_Low; 1.118 + typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; 1.119 + 1.120 + typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> HighSideOnlyCheck; 1.121 + typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S> > NoCheck; 1.122 + 1.123 + // If std::numeric_limits<D>::digits >= std::numeric_limits<S>::digits, nothing to check. 1.124 + // This also protects the precondition of SkTOutOfRange_GT_MaxD. 1.125 + typedef typename SkTHasMoreDigits<D, S>::type sourceFitsInDesitination; 1.126 + typedef typename SkTIf<sourceFitsInDesitination, NoCheck, HighSideOnlyCheck>::type type; 1.127 +}; 1.128 + 1.129 +/** SkTFitsIn_Signed2Signed::type is an SkTRangeChecker with an OutOfRange(S s) method 1.130 + * the implementation of which is tailored for the source and destination types. 1.131 + * Assumes that S and D are signed integer types. 1.132 + */ 1.133 +template<typename D, typename S> struct SkTFitsIn_Signed2Signed { 1.134 + typedef SkTOutOfRange_LT_MinD<D, S> OutOfRange_Low; 1.135 + typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; 1.136 + 1.137 + typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> FullCheck; 1.138 + typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S> > NoCheck; 1.139 + 1.140 + // If std::numeric_limits<D>::digits >= std::numeric_limits<S>::digits, nothing to check. 1.141 + // This also protects the precondition of SkTOutOfRange_LT_MinD and SkTOutOfRange_GT_MaxD. 1.142 + typedef typename SkTHasMoreDigits<D, S>::type sourceFitsInDesitination; 1.143 + typedef typename SkTIf<sourceFitsInDesitination, NoCheck, FullCheck>::type type; 1.144 +}; 1.145 + 1.146 +/** SkTFitsIn_Signed2Unsigned::type is an SkTRangeChecker with an OutOfRange(S s) method 1.147 + * the implementation of which is tailored for the source and destination types. 1.148 + * Assumes that S is a signed integer type and D is an unsigned integer type. 1.149 + */ 1.150 +template<typename D, typename S> struct SkTFitsIn_Signed2Unsigned { 1.151 + typedef SkTOutOfRange_LT_Zero<D, S> OutOfRange_Low; 1.152 + typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; 1.153 + 1.154 + typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> FullCheck; 1.155 + typedef SkTRangeChecker<D, S, OutOfRange_Low, SkTOutOfRange_False<S> > LowSideOnlyCheck; 1.156 + 1.157 + // If std::numeric_limits<D>::max() >= std::numeric_limits<S>::max(), 1.158 + // no need to check the high side. (Until C++11, assume more digits means greater max.) 1.159 + // This also protects the precondition of SkTOutOfRange_GT_MaxD. 1.160 + typedef typename SkTHasMoreDigits<D, S>::type sourceCannotExceedDesitination; 1.161 + typedef typename SkTIf<sourceCannotExceedDesitination, LowSideOnlyCheck, FullCheck>::type type; 1.162 +}; 1.163 + 1.164 +/** SkTFitsIn_Unsigned2Signed::type is an SkTRangeChecker with an OutOfRange(S s) method 1.165 + * the implementation of which is tailored for the source and destination types. 1.166 + * Assumes that S is an usigned integer type and D is a signed integer type. 1.167 + */ 1.168 +template<typename D, typename S> struct SkTFitsIn_Unsigned2Signed { 1.169 + typedef SkTOutOfRange_False<S> OutOfRange_Low; 1.170 + typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; 1.171 + 1.172 + typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> HighSideOnlyCheck; 1.173 + typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S> > NoCheck; 1.174 + 1.175 + // If std::numeric_limits<D>::max() >= std::numeric_limits<S>::max(), nothing to check. 1.176 + // (Until C++11, assume more digits means greater max.) 1.177 + // This also protects the precondition of SkTOutOfRange_GT_MaxD. 1.178 + typedef typename SkTHasMoreDigits<D, S>::type sourceCannotExceedDesitination; 1.179 + typedef typename SkTIf<sourceCannotExceedDesitination, NoCheck, HighSideOnlyCheck>::type type; 1.180 +}; 1.181 + 1.182 +/** SkTFitsIn::type is an SkTRangeChecker with an OutOfRange(S s) method 1.183 + * the implementation of which is tailored for the source and destination types. 1.184 + * Assumes that S and D are integer types. 1.185 + */ 1.186 +template<typename D, typename S> struct SkTFitsIn { 1.187 + // One of the following will be the 'selector' type. 1.188 + typedef SkTFitsIn_Signed2Signed<D, S> S2S; 1.189 + typedef SkTFitsIn_Signed2Unsigned<D, S> S2U; 1.190 + typedef SkTFitsIn_Unsigned2Signed<D, S> U2S; 1.191 + typedef SkTFitsIn_Unsigned2Unsiged<D, S> U2U; 1.192 + 1.193 + typedef SkTBool<std::numeric_limits<S>::is_signed> S_is_signed; 1.194 + typedef SkTBool<std::numeric_limits<D>::is_signed> D_is_signed; 1.195 + 1.196 + typedef typename SkTMux<S_is_signed, D_is_signed, S2S, S2U, U2S, U2U>::type selector; 1.197 + // This type is an SkTRangeChecker. 1.198 + typedef typename selector::type type; 1.199 +}; 1.200 + 1.201 +} // namespace Private 1.202 +} // namespace sktfitsin 1.203 + 1.204 +/** Returns true if the integer source value 's' will fit in the integer destination type 'D'. */ 1.205 +template <typename D, typename S> inline bool SkTFitsIn(S s) { 1.206 + SK_COMPILE_ASSERT(std::numeric_limits<S>::is_integer, SkTFitsIn_source_must_be_integer); 1.207 + SK_COMPILE_ASSERT(std::numeric_limits<D>::is_integer, SkTFitsIn_destination_must_be_integer); 1.208 + 1.209 + return !sktfitsin::Private::SkTFitsIn<D, S>::type::OutOfRange(s); 1.210 +} 1.211 + 1.212 +#endif