2026-03-25 00:42:04 +01:00
/*
Crafter ® Build
Copyright ( C ) 2026 Catcrafts ®
Catcrafts . net
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License version 3.0 as published by the Free Software Foundation ;
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# include <cmath>
import Crafter . Math ;
import std ;
using namespace Crafter ;
// Helper function to compare floating point values with tolerance
template < typename T >
2026-03-25 02:51:02 +01:00
constexpr bool FloatEquals ( T a , T b , T epsilon = 0.01f ) {
2026-03-25 00:42:04 +01:00
return std : : abs ( static_cast < float > ( a ) - static_cast < float > ( b ) ) < static_cast < float > ( epsilon ) ;
}
template < std : : uint8_t Len >
consteval std : : array < bool , Len > AlternateTrueFalse ( ) {
std : : array < bool , Len > result = { } ;
for ( std : : uint8_t i = 0 ; i < Len ; + + i ) {
result [ i ] = ( i % 2 = = 0 ) ; // Set true for even indices, false for odd indices
}
return result ;
}
template < typename T , template < std : : uint32_t , std : : uint32_t > class VectorType , std : : uint32_t MaxSize , std : : uint32_t Len = 1 , std : : uint32_t Packing = 1 >
std : : string * TestAllCombinations ( ) {
if constexpr ( Len > MaxSize ) {
return nullptr ;
} else if constexpr ( Len * Packing > MaxSize ) {
return TestAllCombinations < T , VectorType , MaxSize , Len + 1 , 1 > ( ) ;
} else {
T floats [ VectorType < Len , Packing > : : Alignment ] ;
T floats1 [ VectorType < Len , Packing > : : Alignment ] ;
T floats2 [ VectorType < Len , Packing > : : Alignment ] ;
for ( std : : uint32_t i = 0 ; i < VectorType < Len , Packing > : : Alignment ; i + + ) {
floats [ i ] = static_cast < T > ( i + 1 ) ;
}
for ( std : : uint32_t i = 0 ; i < Packing * Len ; i + + ) {
floats1 [ i ] = static_cast < T > ( i + 1 ) ;
}
for ( std : : uint32_t i = 0 ; i < Packing * Len ; i + + ) {
floats2 [ i ] = static_cast < T > ( i + 1 + Len ) ;
}
for ( std : : uint32_t i = Len * Packing ; i < VectorType < Len , Packing > : : Alignment ; i + + ) {
floats1 [ i ] = 0 ;
floats2 [ i ] = 0 ;
}
std : : string * result = nullptr ;
constexpr auto total = Len * Packing ;
if constexpr ( total > 0 & & ( total & ( total - 1 ) ) = = 0 ) {
{
VectorType < Len , Packing > vec ( floats ) ;
Vector < T , Len * Packing , VectorType < Len , Packing > : : Alignment > stored = vec . Store ( ) ;
for ( std : : uint32_t i = 0 ; i < Len * Packing ; i + + ) {
if ( ! FloatEquals ( stored . v [ i ] , floats [ i ] ) ) {
return new std : : string ( std : : format ( " Load/Store mismatch at Len={} Packing={}, Expected: {}, Got: {} " , Len , Packing , ( float ) ( floats [ i ] ) , ( float ) stored . v [ i ] ) ) ;
}
}
}
{
VectorType < Len , Packing > vec ( floats ) ;
vec = vec + vec ;
Vector < T , Len * Packing , VectorType < Len , Packing > : : Alignment > stored = vec . Store ( ) ;
for ( std : : uint32_t i = 0 ; i < Len * Packing ; i + + ) {
if ( ! FloatEquals ( stored . v [ i ] , floats [ i ] + floats [ i ] ) ) {
return new std : : string ( std : : format ( " Add mismatch at Len={} Packing={}, Expected: {}, Got: {} " , Len , Packing , ( float ) ( floats [ i ] + floats [ i ] ) , ( float ) stored . v [ i ] ) ) ;
}
}
}
{
VectorType < Len , Packing > vec ( floats ) ;
vec = vec - vec ;
Vector < T , Len * Packing , VectorType < Len , Packing > : : Alignment > stored = vec . Store ( ) ;
for ( std : : uint32_t i = 0 ; i < Len * Packing ; i + + ) {
if ( ! FloatEquals ( stored . v [ i ] , T ( 0 ) ) ) {
return new std : : string ( std : : format ( " Subtract mismatch at Len={} Packing={}, Expected: 0, Got: {} " , Len , Packing , ( float ) stored . v [ i ] ) ) ;
}
}
}
{
VectorType < Len , Packing > vec ( floats ) ;
vec = vec * vec ;
Vector < T , Len * Packing , VectorType < Len , Packing > : : Alignment > stored = vec . Store ( ) ;
for ( std : : uint32_t i = 0 ; i < Len * Packing ; i + + ) {
if ( ! FloatEquals ( stored . v [ i ] , floats [ i ] * floats [ i ] ) ) {
return new std : : string ( std : : format ( " Multiply mismatch at Len={} Packing={}, Expected: {}, Got: {} " , Len , Packing , ( float ) ( floats [ i ] * floats [ i ] ) , ( float ) stored . v [ i ] ) ) ;
}
}
}
{
VectorType < Len , Packing > vec ( floats ) ;
vec = vec / vec ;
Vector < T , Len * Packing , VectorType < Len , Packing > : : Alignment > stored = vec . Store ( ) ;
for ( std : : uint32_t i = 0 ; i < Len * Packing ; i + + ) {
if ( ! FloatEquals ( stored . v [ i ] , T ( 1 ) ) ) {
return new std : : string ( std : : format ( " Divide mismatch at Len={} Packing={}, Expected: 1, Got: {} " , Len , Packing , ( float ) stored . v [ i ] ) ) ;
}
}
}
{
VectorType < Len , Packing > vec ( floats ) ;
vec = vec + T ( 2 ) ;
Vector < T , Len * Packing , VectorType < Len , Packing > : : Alignment > stored = vec . Store ( ) ;
for ( std : : uint32_t i = 0 ; i < Len * Packing ; i + + ) {
if ( ! FloatEquals ( stored . v [ i ] , floats [ i ] + T ( 2 ) ) ) {
return new std : : string ( std : : format ( " Scalar add mismatch at Len={} Packing={}, Expected: {}, Got: {} " , Len , Packing , ( float ) ( floats [ i ] + T ( 2 ) ) , ( float ) stored . v [ i ] ) ) ;
}
}
}
{
VectorType < Len , Packing > vec ( floats ) ;
vec = vec - T ( 2 ) ;
Vector < T , Len * Packing , VectorType < Len , Packing > : : Alignment > stored = vec . Store ( ) ;
for ( std : : uint32_t i = 0 ; i < Len * Packing ; i + + ) {
if ( ! FloatEquals ( stored . v [ i ] , floats [ i ] - T ( 2 ) ) ) {
return new std : : string ( std : : format ( " Scalar add mismatch at Len={} Packing={}, Expected: {}, Got: {} " , Len , Packing , ( float ) ( floats [ i ] + T ( 2 ) ) , ( float ) stored . v [ i ] ) ) ;
}
}
}
{
VectorType < Len , Packing > vec ( floats ) ;
vec = vec * T ( 2 ) ;
Vector < T , Len * Packing , VectorType < Len , Packing > : : Alignment > stored = vec . Store ( ) ;
for ( std : : uint32_t i = 0 ; i < Len * Packing ; i + + ) {
if ( ! FloatEquals ( stored . v [ i ] , floats [ i ] * T ( 2 ) ) ) {
return new std : : string ( std : : format ( " Scalar multiply mismatch at Len={} Packing={}, Expected: {}, Got: {} " , Len , Packing , ( float ) ( floats [ i ] * T ( 2 ) ) , ( float ) stored . v [ i ] ) ) ;
}
}
}
{
VectorType < Len , Packing > vec ( floats ) ;
vec = vec / T ( 2 ) ;
Vector < T , Len * Packing , VectorType < Len , Packing > : : Alignment > stored = vec . Store ( ) ;
for ( std : : uint32_t i = 0 ; i < Len * Packing ; i + + ) {
if ( ! FloatEquals ( stored . v [ i ] , floats [ i ] / T ( 2 ) ) ) {
return new std : : string ( std : : format ( " Scalar multiply mismatch at Len={} Packing={}, Expected: {}, Got: {} " , Len , Packing , ( float ) ( floats [ i ] * T ( 2 ) ) , ( float ) stored . v [ i ] ) ) ;
}
}
}
{
VectorType < Len , Packing > vec1 ( floats ) ;
VectorType < Len , Packing > vec2 ( floats ) ;
if ( ! ( vec1 = = vec2 ) ) {
return new std : : string ( std : : format ( " Equality 1 test failed at Len={} Packing={} " , Len , Packing ) ) ;
}
}
{
VectorType < Len , Packing > vec1 ( floats ) ;
VectorType < Len , Packing > vec2 ( floats ) ;
vec2 * = 2 ;
if ( vec1 = = vec2 ) {
return new std : : string ( std : : format ( " Equality 2 test failed at Len={} Packing={} " , Len , Packing ) ) ;
}
}
{
VectorType < Len , Packing > vec1 ( floats ) ;
VectorType < Len , Packing > vec2 ( floats ) ;
if ( ( vec1 ! = vec2 ) ) {
return new std : : string ( std : : format ( " Inequality 1 test failed at Len={} Packing={} " , Len , Packing ) ) ;
}
}
{
VectorType < Len , Packing > vec1 ( floats ) ;
VectorType < Len , Packing > vec2 ( floats ) ;
vec2 * = 2 ;
if ( ! ( vec1 ! = vec2 ) ) {
return new std : : string ( std : : format ( " Inequality 2 test failed at Len={} Packing={} " , Len , Packing ) ) ;
}
}
{
VectorType < Len , Packing > vec ( floats ) ;
vec = - vec ;
Vector < T , Len * Packing , VectorType < Len , Packing > : : Alignment > result = vec . Store ( ) ;
for ( std : : uint32_t i = 0 ; i < Len * Packing ; i + + ) {
if ( ! FloatEquals ( result . v [ i ] , - floats [ i ] ) ) {
return new std : : string ( std : : format ( " Negate mismatch at Len={} Packing={}, Expected: {}, Got: {} " , Len , Packing , ( float ) ( - floats [ i ] ) , ( float ) result . v [ i ] ) ) ;
}
}
}
{
VectorType < Len , Packing > vecA ( floats1 ) ;
VectorType < Len , Packing > vecB ( floats2 ) ;
VectorType < Len , Packing > result = VectorType < Len , Packing > : : template Blend < AlternateTrueFalse < Len > ( ) > ( vecA , vecB ) ;
Vector < T , Len * Packing , VectorType < Len , Packing > : : Alignment > stored = result . Store ( ) ;
for ( std : : uint32_t i = 0 ; i < Len ; i + + ) {
bool useB = ( i % 2 = = 0 ) ;
T expected = useB ? floats2 [ i ] : floats1 [ i ] ;
if ( ! FloatEquals ( stored . v [ i ] , expected ) ) {
return new std : : string ( std : : format ( " Blend mismatch at Len={} Packing={}, Index={}, Expected: {}, Got: {} " , Len , Packing , i , ( float ) expected , ( float ) stored . v [ i ] ) ) ;
}
}
}
{
VectorType < Len , Packing > vecA ( floats ) ;
VectorType < Len , Packing > vecB ( floats ) ;
VectorType < Len , Packing > vecAdd ( floats ) ;
VectorType < Len , Packing > result = VectorType < Len , Packing > : : MulitplyAdd ( vecA , vecB , vecAdd ) ;
Vector < T , Len * Packing , VectorType < Len , Packing > : : Alignment > stored = result . Store ( ) ;
for ( std : : uint32_t i = 0 ; i < Len ; i + + ) {
T expected = floats [ i ] * floats [ i ] + floats [ i ] ;
if ( ! FloatEquals ( stored . v [ i ] , expected ) ) {
return new std : : string ( std : : format ( " MulitplyAdd mismatch at Len={} Packing={}, Index={}, Expected: {}, Got: {} " , Len , Packing , i , ( float ) expected , ( float ) stored . v [ i ] ) ) ;
}
}
}
{
VectorType < Len , Packing > vecA ( floats ) ;
VectorType < Len , Packing > vecB ( floats ) ;
VectorType < Len , Packing > vecSub ( floats ) ;
VectorType < Len , Packing > result = VectorType < Len , Packing > : : MulitplySub ( vecA , vecB , vecSub ) ;
Vector < T , Len * Packing , VectorType < Len , Packing > : : Alignment > stored = result . Store ( ) ;
for ( std : : uint32_t i = 0 ; i < Len ; i + + ) {
T expected = floats [ i ] * floats [ i ] - floats [ i ] ;
if ( ! FloatEquals ( stored . v [ i ] , expected ) ) {
return new std : : string ( std : : format ( " MulitplySub mismatch at Len={} Packing={}, Index={}, Expected: {}, Got: {} " , Len , Packing , i , ( float ) expected , ( float ) stored . v [ i ] ) ) ;
}
}
}
2026-03-25 02:51:02 +01:00
if constexpr ( Len > 2 ) {
VectorType < Len , Packing > vec ( floats ) ;
VectorType < Len - 1 , Packing > result = vec . template ExtractLo < Len - 1 > ( ) ;
Vector < T , ( Len - 1 ) * Packing , VectorType < Len - 1 , Packing > : : Alignment > stored = result . Store ( ) ;
for ( std : : uint32_t i2 = 0 ; i2 < Packing ; i2 + + ) {
for ( std : : uint32_t i = 0 ; i < Len - 1 ; i + + ) {
T expected = floats [ i2 * ( Len ) + i ] ;
if ( ! FloatEquals ( stored . v [ i2 * ( Len - 1 ) + i ] , expected ) ) {
return new std : : string ( std : : format ( " ExtractLo mismatch at Len={} Packing={}, Index={}, Expected: {}, Got: {} " , Len , Packing , i , ( float ) expected , ( float ) stored . v [ i2 * ( Len - 1 ) + i ] ) ) ;
}
}
}
}
2026-03-25 00:42:04 +01:00
}
if constexpr ( Packing = = 1 ) {
T expectedLengthSq = T ( 0 ) ;
for ( std : : uint32_t i = 0 ; i < VectorType < Len , Packing > : : Alignment ; i + + ) {
expectedLengthSq + = floats [ i ] * floats [ i ] ;
}
{
VectorType < Len , Packing > vec ( floats ) ;
T dot = VectorType < Len , Packing > : : Dot ( vec , vec ) ;
if ( ! FloatEquals ( dot , expectedLengthSq ) ) {
return new std : : string ( std : : format ( " Dot product mismatch at Len={} Packing={}, Expected: {}, Got: {} " , Len , Packing , ( float ) expectedLengthSq , ( float ) dot ) ) ;
}
}
{
VectorType < Len , Packing > vec ( floats ) ;
T lengthSq = vec . LengthSq ( ) ;
if ( ! FloatEquals ( lengthSq , expectedLengthSq ) ) {
return new std : : string ( std : : format ( " LengthSq mismatch at Len={} Packing={}, Expected: {}, Got: {} " , Len , Packing , ( float ) expectedLengthSq , ( float ) lengthSq ) ) ;
}
}
{
VectorType < Len , Packing > vec ( floats ) ;
T length = vec . Length ( ) ;
2026-03-25 02:51:02 +01:00
T expected = static_cast < T > ( std : : sqrtf ( static_cast < float > ( expectedLengthSq ) ) ) ;
if ( ! FloatEquals ( length , expected ) ) {
return new std : : string ( std : : format ( " Length mismatch at Len={} Packing={}, Expected: {}, Got: {} " , Len , Packing , ( float ) expected , ( float ) length ) ) ;
2026-03-25 00:42:04 +01:00
}
}
{
VectorType < Len , Packing > vec ( floats ) ;
vec . Normalize ( ) ;
T length = vec . Length ( ) ;
if ( ! FloatEquals ( length , static_cast < T > ( 1 ) ) ) {
return new std : : string ( std : : format ( " Normalize mismatch at Len={} Packing={}, Expected: {}, Got: {} " , Len , Packing , 1 , ( float ) length ) ) ;
}
}
}
2026-03-25 02:51:02 +01:00
// if constexpr(Len == 3) {
// {
// VectorType<Len, Packing> vec1(floats1);
// VectorType<Len, Packing> vec2(floats2);
// VectorType<Len, Packing> result = VectorType<Len, Packing>::Cross(vec1, vec2);
// Vector<T, Len*Packing, VectorType<Len, Packing>::Alignment> stored = result.Store();
// if (!FloatEquals(stored.v[0], T(-3)) || !FloatEquals(stored.v[1], T(6)) || !FloatEquals(stored.v[2], T(-3))) {
// return new std::string(std::format("Cross mismatch at Len={} Packing={}, Expected: -3,6,-3, Got: {},{},{}", Len, Packing, (float)stored.v[0], (float)stored.v[1], (float)stored.v[2]));
// }
// }
// // if constexpr(4 * Packing < VectorType<1, 1>::MaxSize) {
// // T qData[VectorType<4, Packing>::Alignment];
// // qData[0] = T(1);
// // qData[1] = T(0);
// // qData[2] = T(0);
// // qData[3] = T(0);
2026-03-25 00:42:04 +01:00
2026-03-25 02:51:02 +01:00
// // VectorType<3, Packing> vecV(floats);
// // VectorType<4, Packing> vecQ(qData);
// // VectorType<3, Packing> result = VectorType<3, Packing>::Rotate(vecV, vecQ);
// // Vector<T, 3*Packing, VectorType<3, Packing>::Alignment> stored = result.Store();
2026-03-25 00:42:04 +01:00
2026-03-25 02:51:02 +01:00
// // for (std::uint32_t i = 0; i < 3; i++) {
// // if (!FloatEquals(stored.v[i], floats[i])) {
// // return new std::string(std::format("Rotate mismatch at Len={} Packing={}, Index={}, Expected: {}, Got: {}", Len, Packing, i, (float)floats[i], (float)stored.v[i]));
// // }
// // }
// // }
// }
2026-03-25 00:42:04 +01:00
// // Test QuanternionFromEuler() static method (Len == 4 only)
// if constexpr(Len == 4) {
// T eulerData[3] = {T(0), T(0), T(0)}; // Zero rotation
// VectorType<3, 1> eulerVec(eulerData);
// VectorType<4, 1> result = VectorType<4, 1>::QuanternionFromEuler(eulerVec);
// Vector<T, 4, 8> stored = result.Store();
// // Identity quaternion should be (1, 0, 0, 0)
// if (!FloatEquals(stored.v[0], T(1)) || !FloatEquals(stored.v[1], T(0)) ||
// !FloatEquals(stored.v[2], T(0)) || !FloatEquals(stored.v[3], T(0))) {
// return new std::string(std::format("QuanternionFromEuler mismatch at Len={} Packing={}, Expected: 1,0,0,0, Got: {},{},{},{}", Len, Packing, (float)stored.v[0], (float)stored.v[1], (float)stored.v[2], (float)stored.v[3]));
// }
// }
// // Test batch Normalize() for 2 vectors (Len == 2)
// if constexpr(Len == 2) {
// T aData[2] = {T(3), T(4)};
// T eData[2] = {T(6), T(8)};
// VectorType<2, 1> vecA(aData);
// VectorType<2, 1> vecE(eData);
// auto result = VectorType<2, 1>::Normalize(vecA, vecE);
// Vector<T, 2, 8> storedA = std::get<0>(result).Store();
// Vector<T, 2, 8> storedE = std::get<1>(result).Store();
// // Normalize (3,4) -> (0.6, 0.8)
// for (std::uint32_t i = 0; i < 2; i++) {
// if (!FloatEquals(storedA.v[i], static_cast<T>(0.6f + i * 0.2f))) {
// return new std::string(std::format("Normalize 2 vec test failed (A) at index {}, Expected: {}, Got: {}", i, (float)(0.6f + i * 0.2f), (float)storedA.v[i]));
// }
// }
// // Normalize (6,8) -> (0.6, 0.8)
// for (std::uint32_t i = 0; i < 2; i++) {
// if (!FloatEquals(storedE.v[i], static_cast<T>(0.6f + i * 0.2f))) {
// return new std::string(std::format("Normalize 2 vec test failed (E) at index {}, Expected: {}, Got: {}", i, (float)(0.6f + i * 0.2f), (float)storedE.v[i]));
// }
// }
// }
// // Test batch LengthSq() for 2 vectors (Len == 2)
// if constexpr(Len == 2) {
// T aData[2] = {T(3), T(4)};
// T eData[2] = {T(5), T(12)};
// VectorType<2, 1> vecA(aData);
// VectorType<2, 1> vecE(eData);
// VectorType<2, 1> result = VectorType<2, 1>::LengthSq(vecA, vecE);
// Vector<T, 2, 8> stored = result.Store();
// // LengthSq of (3,4) = 9+16 = 25
// // LengthSq of (5,12) = 25+144 = 169
// if (!FloatEquals(stored.v[0], T(25)) || !FloatEquals(stored.v[1], T(169))) {
// return new std::string(std::format("LengthSq 2 vec test failed at Len={} Packing={}, Expected: 25,169, Got: {},{}", Len, Packing, (float)stored.v[0], (float)stored.v[1]));
// }
// }
// // Test batch Dot() for 2 vectors (Len == 2)
// if constexpr(Len == 2) {
// T a0Data[2] = {T(1), T(2)};
// T a1Data[2] = {T(3), T(4)};
// T e0Data[2] = {T(5), T(6)};
// T e1Data[2] = {T(7), T(8)};
// VectorType<2, 1> vecA0(a0Data);
// VectorType<2, 1> vecA1(a1Data);
// VectorType<2, 1> vecE0(e0Data);
// VectorType<2, 1> vecE1(e1Data);
// VectorType<2, 1> result = VectorType<2, 1>::Dot(vecA0, vecA1, vecE0, vecE1);
// Vector<T, 2, 8> stored = result.Store();
// // Dot (1,2) with (3,4) = 3+8=11
// // Dot (5,6) with (7,8) = 35+48=83
// if (!FloatEquals(stored.v[0], T(11)) || !FloatEquals(stored.v[1], T(83))) {
// return new std::string(std::format("Dot 2 vec test failed at Len={} Packing={}, Expected: 11,83, Got: {},{}", Len, Packing, (float)stored.v[0], (float)stored.v[1]));
// }
// }
return TestAllCombinations < T , VectorType , MaxSize , Len , Packing + 1 > ( ) ;
}
}
extern " C " {
std : : string * RunTest ( ) {
std : : string * err = TestAllCombinations < _Float16 , VectorF16 , VectorF16 < 1 , 1 > : : MaxSize > ( ) ;
if ( err ) {
return err ;
}
return nullptr ;
}
}