Uint8Clamped.h (4974B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef vm_Uint8Clamped_h 8 #define vm_Uint8Clamped_h 9 10 #include <algorithm> 11 #include <limits> 12 #include <limits.h> 13 #include <stdint.h> 14 #include <type_traits> 15 16 namespace js { 17 18 extern uint32_t ClampDoubleToUint8(const double x); 19 20 class uint8_clamped final { 21 uint8_t val; 22 23 template <typename IntT> 24 static constexpr uint8_t ClampIntToUint8(IntT x) { 25 static_assert(std::is_integral_v<IntT>); 26 27 if constexpr (std::numeric_limits<IntT>::max() < 255) { 28 return std::clamp<IntT>(x, 0, std::numeric_limits<IntT>::max()); 29 } else { 30 return std::clamp<IntT>(x, 0, 255); 31 } 32 } 33 34 public: 35 constexpr uint8_clamped() = default; 36 constexpr uint8_clamped(const uint8_clamped&) = default; 37 38 constexpr explicit uint8_clamped(uint8_t x) : val(x) {} 39 constexpr explicit uint8_clamped(uint16_t x) : val(ClampIntToUint8(x)) {} 40 constexpr explicit uint8_clamped(uint32_t x) : val(ClampIntToUint8(x)) {} 41 constexpr explicit uint8_clamped(uint64_t x) : val(ClampIntToUint8(x)) {} 42 constexpr explicit uint8_clamped(int8_t x) : val(ClampIntToUint8(x)) {} 43 constexpr explicit uint8_clamped(int16_t x) : val(ClampIntToUint8(x)) {} 44 constexpr explicit uint8_clamped(int32_t x) : val(ClampIntToUint8(x)) {} 45 constexpr explicit uint8_clamped(int64_t x) : val(ClampIntToUint8(x)) {} 46 explicit uint8_clamped(double x) : val(uint8_t(ClampDoubleToUint8(x))) {} 47 48 constexpr uint8_clamped& operator=(const uint8_clamped&) = default; 49 50 // Invoke constructors for the assignment helpers. 51 52 constexpr uint8_clamped& operator=(uint8_t x) { 53 *this = uint8_clamped{x}; 54 return *this; 55 } 56 57 constexpr uint8_clamped& operator=(uint16_t x) { 58 *this = uint8_clamped{x}; 59 return *this; 60 } 61 62 constexpr uint8_clamped& operator=(uint32_t x) { 63 *this = uint8_clamped{x}; 64 return *this; 65 } 66 67 constexpr uint8_clamped& operator=(uint64_t x) { 68 *this = uint8_clamped{x}; 69 return *this; 70 } 71 72 constexpr uint8_clamped& operator=(int8_t x) { 73 *this = uint8_clamped{x}; 74 return *this; 75 } 76 77 constexpr uint8_clamped& operator=(int16_t x) { 78 *this = uint8_clamped{x}; 79 return *this; 80 } 81 82 constexpr uint8_clamped& operator=(int32_t x) { 83 *this = uint8_clamped{x}; 84 return *this; 85 } 86 87 constexpr uint8_clamped& operator=(int64_t x) { 88 *this = uint8_clamped{x}; 89 return *this; 90 } 91 92 uint8_clamped& operator=(const double x) { 93 *this = uint8_clamped{x}; 94 return *this; 95 } 96 97 constexpr operator uint8_t() const { return val; } 98 }; 99 100 static_assert(sizeof(uint8_clamped) == 1, 101 "uint8_clamped must be layout-compatible with uint8_t"); 102 103 static_assert(std::is_trivial_v<uint8_clamped>, 104 "uint8_clamped must be trivial to be eligible for memcpy/memset " 105 "optimizations"); 106 107 } // namespace js 108 109 template <> 110 class std::numeric_limits<js::uint8_clamped> { 111 public: 112 static constexpr bool is_specialized = true; 113 static constexpr bool is_signed = false; 114 static constexpr bool is_integer = true; 115 static constexpr bool is_exact = true; 116 static constexpr bool has_infinity = false; 117 static constexpr bool has_quiet_NaN = false; 118 static constexpr bool has_signaling_NaN = false; 119 static constexpr std::float_denorm_style has_denorm = std::denorm_absent; 120 static constexpr bool has_denorm_loss = false; 121 static constexpr std::float_round_style round_style = std::round_toward_zero; 122 static constexpr bool is_iec559 = false; 123 static constexpr bool is_bounded = true; 124 static constexpr bool is_modulo = false; 125 static constexpr int digits = CHAR_BIT; 126 static constexpr int digits10 = int(digits * /* std::log10(2) */ 0.30102999); 127 static constexpr int max_digits10 = 0; 128 static constexpr int radix = 2; 129 static constexpr int min_exponent = 0; 130 static constexpr int min_exponent10 = 0; 131 static constexpr int max_exponent = 0; 132 static constexpr int max_exponent10 = 0; 133 static constexpr bool traps = true; 134 static constexpr bool tinyness_before = false; 135 136 static constexpr auto min() noexcept { return js::uint8_clamped{0}; } 137 static constexpr auto lowest() noexcept { return min(); } 138 static constexpr auto max() noexcept { return js::uint8_clamped{255}; } 139 static constexpr auto epsilon() noexcept { return js::uint8_clamped{0}; } 140 static constexpr auto round_error() noexcept { return js::uint8_clamped{0}; } 141 static constexpr auto infinity() noexcept { return js::uint8_clamped{0}; } 142 static constexpr auto quiet_NaN() noexcept { return js::uint8_clamped{0}; } 143 static constexpr auto signaling_NaN() noexcept { 144 return js::uint8_clamped{0}; 145 } 146 static constexpr auto denorm_min() noexcept { return js::uint8_clamped{0}; } 147 }; 148 149 #endif // vm_Uint8Clamped_h