/* * Copyright 2013 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkTFitsIn_DEFINED #define SkTFitsIn_DEFINED #include "SkTypes.h" #include "SkTLogic.h" #include namespace sktfitsin { namespace Private { /** SkTHasMoreDigits::type = (digits(A) >= digits(B)) ? SkTrue : SkFalse. */ template struct SkTHasMoreDigits { typedef SkTBool::digits >= std::numeric_limits::digits> type; }; /** A high or low side predicate which is used when it is statically known * that source values are in the range of the Destination. */ template struct SkTOutOfRange_False { typedef SkFalse can_be_true; typedef S source_type; static bool apply(S s) { return false; } }; /** A low side predicate which tests if the source value < Min(D). * Assumes that Min(S) <= Min(D). */ template struct SkTOutOfRange_LT_MinD { typedef SkTrue can_be_true; typedef S source_type; static bool apply(S s) { typedef typename SkTHasMoreDigits::type precondition; SK_COMPILE_ASSERT(precondition::value, SkTOutOfRange_LT_MinD__minS_gt_minD); return s < static_cast((std::numeric_limits::min)()); } }; /** A low side predicate which tests if the source value is less than 0. */ template struct SkTOutOfRange_LT_Zero { typedef SkTrue can_be_true; typedef S source_type; static bool apply(S s) { return s < static_cast(0); } }; /** A high side predicate which tests if the source value > Max(D). * Assumes that Max(S) >= Max(D). */ template struct SkTOutOfRange_GT_MaxD { typedef SkTrue can_be_true; typedef S source_type; static bool apply(S s) { typedef typename SkTHasMoreDigits::type precondition; SK_COMPILE_ASSERT(precondition::value, SkTOutOfRange_GT_MaxD__maxS_lt_maxD); return s > static_cast((std::numeric_limits::max)()); } }; /** Composes two SkTOutOfRange predicates. * First checks OutOfRange_Low then, if in range, OutOfRange_High. */ template struct SkTOutOfRange_Either { typedef SkTrue can_be_true; typedef typename OutOfRange_Low::source_type source_type; static bool apply(source_type s) { bool outOfRange = OutOfRange_Low::apply(s); if (!outOfRange) { outOfRange = OutOfRange_High::apply(s); } return outOfRange; } }; /** SkTCombineOutOfRange::type is an SkTOutOfRange_XXX type which is the * optimal combination of OutOfRange_Low and OutOfRange_High. */ template struct SkTCombineOutOfRange { typedef SkTOutOfRange_Either Both; typedef SkTOutOfRange_False Neither; typedef typename OutOfRange_Low::can_be_true apply_low; typedef typename OutOfRange_High::can_be_true apply_high; typedef typename SkTMux::type type; }; template struct SkTRangeChecker { /** This is the method which is called at runtime to do the range check. */ static bool OutOfRange(S s) { typedef typename SkTCombineOutOfRange::type Combined; return Combined::apply(s); } }; /** SkTFitsIn_Unsigned2Unsiged::type is an SkTRangeChecker with an OutOfRange(S s) method * the implementation of which is tailored for the source and destination types. * Assumes that S and D are unsigned integer types. */ template struct SkTFitsIn_Unsigned2Unsiged { typedef SkTOutOfRange_False OutOfRange_Low; typedef SkTOutOfRange_GT_MaxD OutOfRange_High; typedef SkTRangeChecker HighSideOnlyCheck; typedef SkTRangeChecker, SkTOutOfRange_False > NoCheck; // If std::numeric_limits::digits >= std::numeric_limits::digits, nothing to check. // This also protects the precondition of SkTOutOfRange_GT_MaxD. typedef typename SkTHasMoreDigits::type sourceFitsInDesitination; typedef typename SkTIf::type type; }; /** SkTFitsIn_Signed2Signed::type is an SkTRangeChecker with an OutOfRange(S s) method * the implementation of which is tailored for the source and destination types. * Assumes that S and D are signed integer types. */ template struct SkTFitsIn_Signed2Signed { typedef SkTOutOfRange_LT_MinD OutOfRange_Low; typedef SkTOutOfRange_GT_MaxD OutOfRange_High; typedef SkTRangeChecker FullCheck; typedef SkTRangeChecker, SkTOutOfRange_False > NoCheck; // If std::numeric_limits::digits >= std::numeric_limits::digits, nothing to check. // This also protects the precondition of SkTOutOfRange_LT_MinD and SkTOutOfRange_GT_MaxD. typedef typename SkTHasMoreDigits::type sourceFitsInDesitination; typedef typename SkTIf::type type; }; /** SkTFitsIn_Signed2Unsigned::type is an SkTRangeChecker with an OutOfRange(S s) method * the implementation of which is tailored for the source and destination types. * Assumes that S is a signed integer type and D is an unsigned integer type. */ template struct SkTFitsIn_Signed2Unsigned { typedef SkTOutOfRange_LT_Zero OutOfRange_Low; typedef SkTOutOfRange_GT_MaxD OutOfRange_High; typedef SkTRangeChecker FullCheck; typedef SkTRangeChecker > LowSideOnlyCheck; // If std::numeric_limits::max() >= std::numeric_limits::max(), // no need to check the high side. (Until C++11, assume more digits means greater max.) // This also protects the precondition of SkTOutOfRange_GT_MaxD. typedef typename SkTHasMoreDigits::type sourceCannotExceedDesitination; typedef typename SkTIf::type type; }; /** SkTFitsIn_Unsigned2Signed::type is an SkTRangeChecker with an OutOfRange(S s) method * the implementation of which is tailored for the source and destination types. * Assumes that S is an usigned integer type and D is a signed integer type. */ template struct SkTFitsIn_Unsigned2Signed { typedef SkTOutOfRange_False OutOfRange_Low; typedef SkTOutOfRange_GT_MaxD OutOfRange_High; typedef SkTRangeChecker HighSideOnlyCheck; typedef SkTRangeChecker, SkTOutOfRange_False > NoCheck; // If std::numeric_limits::max() >= std::numeric_limits::max(), nothing to check. // (Until C++11, assume more digits means greater max.) // This also protects the precondition of SkTOutOfRange_GT_MaxD. typedef typename SkTHasMoreDigits::type sourceCannotExceedDesitination; typedef typename SkTIf::type type; }; /** SkTFitsIn::type is an SkTRangeChecker with an OutOfRange(S s) method * the implementation of which is tailored for the source and destination types. * Assumes that S and D are integer types. */ template struct SkTFitsIn { // One of the following will be the 'selector' type. typedef SkTFitsIn_Signed2Signed S2S; typedef SkTFitsIn_Signed2Unsigned S2U; typedef SkTFitsIn_Unsigned2Signed U2S; typedef SkTFitsIn_Unsigned2Unsiged U2U; typedef SkTBool::is_signed> S_is_signed; typedef SkTBool::is_signed> D_is_signed; typedef typename SkTMux::type selector; // This type is an SkTRangeChecker. typedef typename selector::type type; }; } // namespace Private } // namespace sktfitsin /** Returns true if the integer source value 's' will fit in the integer destination type 'D'. */ template inline bool SkTFitsIn(S s) { SK_COMPILE_ASSERT(std::numeric_limits::is_integer, SkTFitsIn_source_must_be_integer); SK_COMPILE_ASSERT(std::numeric_limits::is_integer, SkTFitsIn_destination_must_be_integer); return !sktfitsin::Private::SkTFitsIn::type::OutOfRange(s); } #endif