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:
166
openVulkanoCpp/Math/UInt24.hpp
Normal file
166
openVulkanoCpp/Math/UInt24.hpp
Normal 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
110
tests/Math/UInt24.cpp
Normal 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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user