Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef vm_Uint8Clamped_h
#define vm_Uint8Clamped_h
#include <algorithm>
#include <limits>
#include <limits.h>
#include <stdint.h>
#include <type_traits>
namespace js {
extern uint32_t ClampDoubleToUint8(const double x);
class uint8_clamped final {
uint8_t val;
template <typename IntT>
static constexpr uint8_t ClampIntToUint8(IntT x) {
static_assert(std::is_integral_v<IntT>);
if constexpr (std::numeric_limits<IntT>::max() < 255) {
return std::clamp<IntT>(x, 0, std::numeric_limits<IntT>::max());
} else {
return std::clamp<IntT>(x, 0, 255);
}
}
public:
// The default constructor can be 'constexpr' when we switch to C++20.
//
// C++17 requires explicit initialization of all members when using a
// 'constexpr' default constructor. That means `val` needs to be initialized
// through a member initializer. But adding a member initializer makes the
// class no longer trivial, which breaks memcpy/memset optimizations.
/* constexpr */ uint8_clamped() = default;
constexpr uint8_clamped(const uint8_clamped&) = default;
constexpr explicit uint8_clamped(uint8_t x) : val(x) {}
constexpr explicit uint8_clamped(uint16_t x) : val(ClampIntToUint8(x)) {}
constexpr explicit uint8_clamped(uint32_t x) : val(ClampIntToUint8(x)) {}
constexpr explicit uint8_clamped(uint64_t x) : val(ClampIntToUint8(x)) {}
constexpr explicit uint8_clamped(int8_t x) : val(ClampIntToUint8(x)) {}
constexpr explicit uint8_clamped(int16_t x) : val(ClampIntToUint8(x)) {}
constexpr explicit uint8_clamped(int32_t x) : val(ClampIntToUint8(x)) {}
constexpr explicit uint8_clamped(int64_t x) : val(ClampIntToUint8(x)) {}
explicit uint8_clamped(double x) : val(uint8_t(ClampDoubleToUint8(x))) {}
constexpr uint8_clamped& operator=(const uint8_clamped&) = default;
// Invoke constructors for the assignment helpers.
constexpr uint8_clamped& operator=(uint8_t x) {
*this = uint8_clamped{x};
return *this;
}
constexpr uint8_clamped& operator=(uint16_t x) {
*this = uint8_clamped{x};
return *this;
}
constexpr uint8_clamped& operator=(uint32_t x) {
*this = uint8_clamped{x};
return *this;
}
constexpr uint8_clamped& operator=(uint64_t x) {
*this = uint8_clamped{x};
return *this;
}
constexpr uint8_clamped& operator=(int8_t x) {
*this = uint8_clamped{x};
return *this;
}
constexpr uint8_clamped& operator=(int16_t x) {
*this = uint8_clamped{x};
return *this;
}
constexpr uint8_clamped& operator=(int32_t x) {
*this = uint8_clamped{x};
return *this;
}
constexpr uint8_clamped& operator=(int64_t x) {
*this = uint8_clamped{x};
return *this;
}
uint8_clamped& operator=(const double x) {
*this = uint8_clamped{x};
return *this;
}
constexpr operator uint8_t() const { return val; }
};
static_assert(sizeof(uint8_clamped) == 1,
"uint8_clamped must be layout-compatible with uint8_t");
static_assert(std::is_trivial_v<uint8_clamped>,
"uint8_clamped must be trivial to be eligible for memcpy/memset "
"optimizations");
} // namespace js
template <>
class std::numeric_limits<js::uint8_clamped> {
public:
static constexpr bool is_specialized = true;
static constexpr bool is_signed = false;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_NaN = false;
static constexpr bool has_signaling_NaN = false;
static constexpr std::float_denorm_style has_denorm = std::denorm_absent;
static constexpr bool has_denorm_loss = false;
static constexpr std::float_round_style round_style = std::round_toward_zero;
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = false;
static constexpr int digits = CHAR_BIT;
static constexpr int digits10 = int(digits * /* std::log10(2) */ 0.30102999);
static constexpr int max_digits10 = 0;
static constexpr int radix = 2;
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr bool traps = true;
static constexpr bool tinyness_before = false;
static constexpr auto min() noexcept { return js::uint8_clamped{0}; }
static constexpr auto lowest() noexcept { return min(); }
static constexpr auto max() noexcept { return js::uint8_clamped{255}; }
static constexpr auto epsilon() noexcept { return js::uint8_clamped{0}; }
static constexpr auto round_error() noexcept { return js::uint8_clamped{0}; }
static constexpr auto infinity() noexcept { return js::uint8_clamped{0}; }
static constexpr auto quiet_NaN() noexcept { return js::uint8_clamped{0}; }
static constexpr auto signaling_NaN() noexcept {
return js::uint8_clamped{0};
}
static constexpr auto denorm_min() noexcept { return js::uint8_clamped{0}; }
};
#endif // vm_Uint8Clamped_h