Merge pull request 'UInt24 class + tests' (#163) from uint24 into master

Reviewed-on: https://git.madvoxel.net/OpenVulkano/OpenVulkano/pulls/163
Reviewed-by: Georg Hagen <georg.hagen@madvoxel.com>
This commit is contained in:
Vladyslav_Baranovskyi_EXT
2024-11-10 19:01:39 +01:00
2 changed files with 276 additions and 0 deletions

View File

@@ -0,0 +1,166 @@
/*
* 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 <cinttypes>
#include <type_traits>
namespace OpenVulkano
{
class uint24 final
{
uint8_t m_internal[3];
public:
constexpr uint24() : m_internal{ 0, 0, 0 }
{}
constexpr uint24(const int val)
: m_internal{(uint8_t)(val & 0xff), (uint8_t)((val >> 8) & 0xff), (uint8_t)((val >> 16) & 0xff)}
{}
constexpr uint24(const uint24& val) : m_internal{ val.m_internal[0], val.m_internal[1], val.m_internal[2] }
{}
operator int() const { return (m_internal[2] << 16) | (m_internal[1] << 8) | (m_internal[0] << 0); }
operator float() const
{
return (float)this->operator int();
}
uint24& operator =(const uint24& input)
{
m_internal[0] = input.m_internal[0];
m_internal[1] = input.m_internal[1];
m_internal[2] = input.m_internal[2];
return *this;
}
uint24& 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<typename T, std::enable_if_t<std::is_convertible_v<T, int>, bool> = true> \
uint24 operator op(const T& val) const { return uint24( (int)*this op static_cast<int>(val) ); } \
template<typename T, std::enable_if_t<std::is_convertible_v<T, int>, bool> = true> \
uint24& operator op##=(const T& val ) { *this = *this op static_cast<int>(val); return *this; }
INT24_OPERATORS(+)
INT24_OPERATORS(-)
INT24_OPERATORS(*)
INT24_OPERATORS(/)
#undef INT24_OPERATORS
uint24 operator >>(const int val) const
{
return uint24( (int)*this >> val );
}
uint24 operator <<(const int val) const
{
return uint24( (int)*this << val );
}
uint24& operator >>=(const int val )
{
*this = *this >> val;
return *this;
}
uint24& operator <<=(const int val )
{
*this = *this << val;
return *this;
}
operator bool() const
{
return (int)*this != 0;
}
bool operator !() const
{
return !((int)*this);
}
uint24 operator -()
{
return uint24( -(int)*this );
}
template<typename T, std::enable_if_t<std::is_convertible_v<T, int>, bool> = true>
[[nodiscard]] bool operator==(const T& val) const
{
return static_cast<int>(*this) == static_cast<int>(val);
}
template<typename T, std::enable_if_t<std::is_convertible_v<T, int>, bool> = true>
[[nodiscard]] constexpr auto operator<=>(const T& other) const
{
return operator int() <=> static_cast<int>(other);
}
template<typename Key> friend
struct std::hash;
};
}
namespace std
{
template<>
struct hash<OpenVulkano::uint24>
{
std::size_t operator()(const OpenVulkano::uint24& value) const
{
return hash<int>()(static_cast<int>(value));
}
};
template <>
class numeric_limits<OpenVulkano::uint24>
{
public:
static const bool is_specialized = true;
static constexpr OpenVulkano::uint24 min() { return OpenVulkano::uint24(0); }
static constexpr OpenVulkano::uint24 max() { return OpenVulkano::uint24(0xFFFFFF); }
static const int radix = 2;
static const int digits = 24;
static const int digits10 = 7;
static const bool is_signed = false;
static const bool is_integer = true;
static const bool is_exact = true;
static const bool traps = false;
static const bool is_modulo = true;
static const bool is_bounded = true;
static constexpr OpenVulkano::uint24 epsilon() { return OpenVulkano::uint24(1); }
static constexpr OpenVulkano::uint24 round_error() { return OpenVulkano::uint24(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 uint24...
static constexpr OpenVulkano::uint24 denorm_min() { return OpenVulkano::uint24(0); }
static constexpr OpenVulkano::uint24 infinity() { return OpenVulkano::uint24(0); }
static constexpr OpenVulkano::uint24 quiet_NaN() { return OpenVulkano::uint24(0); }
static constexpr OpenVulkano::uint24 signaling_NaN() { return OpenVulkano::uint24(0); }
};
}

110
tests/Math/UInt24.cpp Normal file
View File

@@ -0,0 +1,110 @@
/*
* 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/.
*/
#include <catch2/catch_all.hpp>
#include "Math/UInt24.hpp"
using namespace OpenVulkano;
TEST_CASE("Default constructor", "[UInt24]")
{
uint24 a;
REQUIRE(static_cast<int>(a) == 0);
}
TEST_CASE("Integer constructor", "[UInt24]")
{
uint24 a(0x123456);
REQUIRE(static_cast<int>(a) == 0x123456);
uint24 b(-1);
REQUIRE(static_cast<int>(b) == 0xffffff);
}
TEST_CASE("Copy constructor", "[UInt24]")
{
uint24 a(0x123456);
uint24 b(a);
REQUIRE(static_cast<int>(b) == 0x123456);
}
TEST_CASE("Assignment operator", "[UInt24]")
{
uint24 a;
a = 0x123456;
REQUIRE(static_cast<int>(a) == 0x123456);
uint24 b;
b = a;
REQUIRE(static_cast<int>(b) == 0x123456);
}
TEST_CASE("Arithmetic operators", "[UInt24]")
{
uint24 a(0x10);
uint24 b(0x20);
REQUIRE(static_cast<int>(a + b) == 0x30);
REQUIRE(static_cast<int>(b - a) == 0x10);
REQUIRE(static_cast<int>(a * b) == 0x200);
REQUIRE(static_cast<int>(b / a) == 2);
}
TEST_CASE("Compound assignment operators", "[UInt24]")
{
uint24 a(0x10);
uint24 b(0x20);
a += b;
REQUIRE(static_cast<int>(a) == 0x30);
a -= b;
REQUIRE(static_cast<int>(a) == 0x10);
a *= b;
REQUIRE(static_cast<int>(a) == 0x200);
a /= b;
REQUIRE(static_cast<int>(a) == 0x10);
}
TEST_CASE("Comparison operators", "[UInt24]")
{
uint24 a(0x100000);
uint24 b(0x200000);
REQUIRE(a < b);
REQUIRE(b > a);
REQUIRE(a <= b);
REQUIRE(b >= a);
REQUIRE(a != b);
uint24 c(0x100000);
REQUIRE(a == c);
}
TEST_CASE("Shift operators", "[UInt24]")
{
uint24 a(0x123456);
REQUIRE(static_cast<int>(a << 1) == 0x2468ac);
REQUIRE(static_cast<int>(a >> 1) == 0x91a2b);
}
TEST_CASE("Boolean operators", "[UInt24]")
{
uint24 a(0);
uint24 b(1);
REQUIRE(!a);
REQUIRE(b);
}
TEST_CASE("Negation", "[UInt24]")
{
uint24 a(0x123456);
REQUIRE(static_cast<int>(-a) == 0xedcbaa);
}