/* * 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 https://mozilla.org/MPL/2.0/. */ #pragma once #include #include namespace OpenVulkano { class int24 final { uint8_t m_internal[3]; public: constexpr int24() : m_internal{ 0, 0, 0 } {} constexpr int24(const int val) : m_internal{(uint8_t)(val & 0xff), (uint8_t)((val >> 8) & 0xff), (uint8_t)((val >> 16) & 0xff)} {} constexpr int24(const int24& val) : m_internal{ val.m_internal[0], val.m_internal[1], val.m_internal[2] } {} operator int() const { if (m_internal[2] & 0x80) { // Negative numbers return (0xff << 24) | (m_internal[2] << 16) | (m_internal[1] << 8) | (m_internal[0] << 0); } else { return (m_internal[2] << 16) | (m_internal[1] << 8) | (m_internal[0] << 0); } } operator float() const { return (float)this->operator int(); } int24& operator =(const int24& input) { m_internal[0] = input.m_internal[0]; m_internal[1] = input.m_internal[1]; m_internal[2] = input.m_internal[2]; return *this; } int24& operator =(const int input) { m_internal[0] = ((unsigned char*)&input)[0]; m_internal[1] = ((unsigned char*)&input)[1]; m_internal[2] = ((unsigned char*)&input)[2]; return *this; } #define INT24_OPERATORS(op) \ template, bool> = true> \ int24 operator op(const T& val) const { return int24( (int)*this op static_cast(val) ); } \ template, bool> = true> \ int24& operator op##=(const T& val ) { *this = *this op static_cast(val); return *this; } INT24_OPERATORS(+) INT24_OPERATORS(-) INT24_OPERATORS(*) INT24_OPERATORS(/) #undef INT24_OPERATORS int24 operator >>(const int val) const { return int24( (int)*this >> val ); } int24 operator <<(const int val) const { return int24( (int)*this << val ); } int24& operator >>=(const int val ) { *this = *this >> val; return *this; } int24& operator <<=(const int val ) { *this = *this << val; return *this; } operator bool() const { return (int)*this != 0; } bool operator !() const { return !((int)*this); } int24 operator -() { return int24( -(int)*this ); } template, bool> = true> [[nodiscard]] bool operator==(const T& val) const { return static_cast(*this) == static_cast(val); } template, bool> = true> [[nodiscard]] constexpr auto operator<=>(const T& other) const { return operator int() <=> static_cast(other); } }; } namespace std { template <> class numeric_limits { public: static const bool is_specialized = true; static constexpr OpenVulkano::int24 min() { return OpenVulkano::int24(0x800000); } static constexpr OpenVulkano::int24 max() { return OpenVulkano::int24(0x7FFFFF); } static const int radix = 2; static const int digits = 23; static const int digits10 = 6; static const bool is_signed = true; static const bool is_integer = true; static const bool is_exact = true; static const bool traps = false; static const bool is_modulo = false; static const bool is_bounded = true; static constexpr OpenVulkano::int24 epsilon() { return OpenVulkano::int24(1); } static constexpr OpenVulkano::int24 round_error() { return OpenVulkano::int24(0); } static const int min_exponent10 = 0; static const int max_exponent10 = 0; static const int min_exponent = 0; static const int max_exponent = 0; static const bool has_infinity = false; static const bool has_quiet_NaN = false; static const bool has_signaling_NaN = false; static const bool is_iec559 = false; static const bool has_denorm = false; static const bool tinyness_before = false; static const float_round_style round_style = round_toward_zero; // Not meaningful for int24... static constexpr OpenVulkano::int24 denorm_min() { return OpenVulkano::int24(0); } static constexpr OpenVulkano::int24 infinity() { return OpenVulkano::int24(0); } static constexpr OpenVulkano::int24 quiet_NaN() { return OpenVulkano::int24(0); } static constexpr OpenVulkano::int24 signaling_NaN() { return OpenVulkano::int24(0); } }; }