1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2013 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkTFitsIn_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define SkTFitsIn_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h" 12*c8dee2aaSAndroid Build Coastguard Worker 13*c8dee2aaSAndroid Build Coastguard Worker #include <limits> 14*c8dee2aaSAndroid Build Coastguard Worker #include <type_traits> 15*c8dee2aaSAndroid Build Coastguard Worker 16*c8dee2aaSAndroid Build Coastguard Worker /** 17*c8dee2aaSAndroid Build Coastguard Worker * std::underlying_type is only defined for enums. For integral types, we just want the type. 18*c8dee2aaSAndroid Build Coastguard Worker */ 19*c8dee2aaSAndroid Build Coastguard Worker template <typename T, class Enable = void> 20*c8dee2aaSAndroid Build Coastguard Worker struct sk_strip_enum { 21*c8dee2aaSAndroid Build Coastguard Worker typedef T type; 22*c8dee2aaSAndroid Build Coastguard Worker }; 23*c8dee2aaSAndroid Build Coastguard Worker 24*c8dee2aaSAndroid Build Coastguard Worker template <typename T> 25*c8dee2aaSAndroid Build Coastguard Worker struct sk_strip_enum<T, typename std::enable_if<std::is_enum<T>::value>::type> { 26*c8dee2aaSAndroid Build Coastguard Worker typedef typename std::underlying_type<T>::type type; 27*c8dee2aaSAndroid Build Coastguard Worker }; 28*c8dee2aaSAndroid Build Coastguard Worker 29*c8dee2aaSAndroid Build Coastguard Worker 30*c8dee2aaSAndroid Build Coastguard Worker /** 31*c8dee2aaSAndroid Build Coastguard Worker * In C++ an unsigned to signed cast where the source value cannot be represented in the destination 32*c8dee2aaSAndroid Build Coastguard Worker * type results in an implementation defined destination value. Unlike C, C++ does not allow a trap. 33*c8dee2aaSAndroid Build Coastguard Worker * This makes "(S)(D)s == s" a possibly useful test. However, there are two cases where this is 34*c8dee2aaSAndroid Build Coastguard Worker * incorrect: 35*c8dee2aaSAndroid Build Coastguard Worker * 36*c8dee2aaSAndroid Build Coastguard Worker * when testing if a value of a smaller signed type can be represented in a larger unsigned type 37*c8dee2aaSAndroid Build Coastguard Worker * (int8_t)(uint16_t)-1 == -1 => (int8_t)0xFFFF == -1 => [implementation defined] == -1 38*c8dee2aaSAndroid Build Coastguard Worker * 39*c8dee2aaSAndroid Build Coastguard Worker * when testing if a value of a larger unsigned type can be represented in a smaller signed type 40*c8dee2aaSAndroid Build Coastguard Worker * (uint16_t)(int8_t)0xFFFF == 0xFFFF => (uint16_t)-1 == 0xFFFF => 0xFFFF == 0xFFFF => true. 41*c8dee2aaSAndroid Build Coastguard Worker * 42*c8dee2aaSAndroid Build Coastguard Worker * Consider the cases: 43*c8dee2aaSAndroid Build Coastguard Worker * u = unsigned, less digits 44*c8dee2aaSAndroid Build Coastguard Worker * U = unsigned, more digits 45*c8dee2aaSAndroid Build Coastguard Worker * s = signed, less digits 46*c8dee2aaSAndroid Build Coastguard Worker * S = signed, more digits 47*c8dee2aaSAndroid Build Coastguard Worker * v is the value we're considering. 48*c8dee2aaSAndroid Build Coastguard Worker * 49*c8dee2aaSAndroid Build Coastguard Worker * u -> U: (u)(U)v == v, trivially true 50*c8dee2aaSAndroid Build Coastguard Worker * U -> u: (U)(u)v == v, both casts well defined, test works 51*c8dee2aaSAndroid Build Coastguard Worker * s -> S: (s)(S)v == v, trivially true 52*c8dee2aaSAndroid Build Coastguard Worker * S -> s: (S)(s)v == v, first cast implementation value, second cast defined, test works 53*c8dee2aaSAndroid Build Coastguard Worker * s -> U: (s)(U)v == v, *this is bad*, the second cast results in implementation defined value 54*c8dee2aaSAndroid Build Coastguard Worker * S -> u: (S)(u)v == v, the second cast is required to prevent promotion of rhs to unsigned 55*c8dee2aaSAndroid Build Coastguard Worker * u -> S: (u)(S)v == v, trivially true 56*c8dee2aaSAndroid Build Coastguard Worker * U -> s: (U)(s)v == v, *this is bad*, 57*c8dee2aaSAndroid Build Coastguard Worker * first cast results in implementation defined value, 58*c8dee2aaSAndroid Build Coastguard Worker * second cast is defined. However, this creates false positives 59*c8dee2aaSAndroid Build Coastguard Worker * uint16_t x = 0xFFFF 60*c8dee2aaSAndroid Build Coastguard Worker * (uint16_t)(int8_t)x == x 61*c8dee2aaSAndroid Build Coastguard Worker * => (uint16_t)-1 == x 62*c8dee2aaSAndroid Build Coastguard Worker * => 0xFFFF == x 63*c8dee2aaSAndroid Build Coastguard Worker * => true 64*c8dee2aaSAndroid Build Coastguard Worker * 65*c8dee2aaSAndroid Build Coastguard Worker * So for the eight cases three are trivially true, three more are valid casts, and two are special. 66*c8dee2aaSAndroid Build Coastguard Worker * The two 'full' checks which otherwise require two comparisons are valid cast checks. 67*c8dee2aaSAndroid Build Coastguard Worker * The two remaining checks s -> U [v >= 0] and U -> s [v <= max(s)] can be done with one op. 68*c8dee2aaSAndroid Build Coastguard Worker */ 69*c8dee2aaSAndroid Build Coastguard Worker 70*c8dee2aaSAndroid Build Coastguard Worker template <typename D, typename S> 71*c8dee2aaSAndroid Build Coastguard Worker static constexpr inline 72*c8dee2aaSAndroid Build Coastguard Worker typename std::enable_if<(std::is_integral<S>::value || std::is_enum<S>::value) && 73*c8dee2aaSAndroid Build Coastguard Worker (std::is_integral<D>::value || std::is_enum<D>::value), bool>::type 74*c8dee2aaSAndroid Build Coastguard Worker /*bool*/ SkTFitsIn(S src) { 75*c8dee2aaSAndroid Build Coastguard Worker // Ensure that is_signed and is_unsigned are passed the arithmetic underlyng types of enums. 76*c8dee2aaSAndroid Build Coastguard Worker using Sa = typename sk_strip_enum<S>::type; 77*c8dee2aaSAndroid Build Coastguard Worker using Da = typename sk_strip_enum<D>::type; 78*c8dee2aaSAndroid Build Coastguard Worker 79*c8dee2aaSAndroid Build Coastguard Worker // SkTFitsIn() is used in public headers, so needs to be written targeting at most C++11. 80*c8dee2aaSAndroid Build Coastguard Worker return 81*c8dee2aaSAndroid Build Coastguard Worker 82*c8dee2aaSAndroid Build Coastguard Worker // E.g. (int8_t)(uint8_t) int8_t(-1) == -1, but the uint8_t == 255, not -1. 83*c8dee2aaSAndroid Build Coastguard Worker (std::is_signed<Sa>::value && std::is_unsigned<Da>::value && sizeof(Sa) <= sizeof(Da)) ? 84*c8dee2aaSAndroid Build Coastguard Worker (S)0 <= src : 85*c8dee2aaSAndroid Build Coastguard Worker 86*c8dee2aaSAndroid Build Coastguard Worker // E.g. (uint8_t)(int8_t) uint8_t(255) == 255, but the int8_t == -1. 87*c8dee2aaSAndroid Build Coastguard Worker (std::is_signed<Da>::value && std::is_unsigned<Sa>::value && sizeof(Da) <= sizeof(Sa)) ? 88*c8dee2aaSAndroid Build Coastguard Worker src <= (S)std::numeric_limits<Da>::max() : 89*c8dee2aaSAndroid Build Coastguard Worker 90*c8dee2aaSAndroid Build Coastguard Worker // This trips up MSVC's /RTCc run-time checking, which we don't support. 91*c8dee2aaSAndroid Build Coastguard Worker (S)(D)src == src; 92*c8dee2aaSAndroid Build Coastguard Worker } 93*c8dee2aaSAndroid Build Coastguard Worker 94*c8dee2aaSAndroid Build Coastguard Worker #endif 95