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