123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800 |
- #include "simple/geom/vector.hpp"
- #include "simple/geom/bool_algebra.hpp"
- #include <cmath>
- #include <cassert>
- #include <cstdio>
- using namespace simple;
- using geom::vector;
- using float4 = vector<float, 4>;
- using int4 = vector<int, 4>;
- void ZeroConstruction()
- {
- float4::array control{};
- float4 p{};
- float4 p2 = {};
- float4 p3 = float4();
- assert(control == static_cast<const float4::array>(p));
- assert(control == static_cast<const float4::array>(p2));
- assert(control == static_cast<const float4::array>(p3));
- assert(control == static_cast<const float4::array>(float4::zero()));
- // NOTE: can't really test for random garbage since random garbage can be anything, including all zeros
- // also UB, great -_-
- bool anyGarbage = false;
- std::array<float4, 100> garbagePile;
- for (auto& garbage : garbagePile)
- {
- anyGarbage |= (control != static_cast<float4::array>(garbage));
- if(anyGarbage) break;
- }
- assert(anyGarbage);
- }
- void EqualityComparison()
- {
- int4 p(1, 2, 3, 4);
- int4 p2(1, 2, 3, 4);
- int4 p3(4, 3, 2, 1);
- assert(p == p2);
- assert(p != p3);
- assert( vector(1,2,3,4,5) != vector(0,0,0,0,5) ); // at some point this wasn't the case, and no other test caught it -_-
- assert( !(vector(1,2,3,4,5) == vector(0,0,0,0,5)) );
- assert( ~(vector(1,2,3,4,5) == vector(0,0,0,0,5)) );
- }
- void OtherConstruction()
- {
- float4 p(1.0f, 2.0f, 3.0f, 4.0f);
- float4 p2{1.0f, 2.0f, 3.0f, 4.0f};
- float4 p3{{1.0f, 2.0f, 3.0f, 4.0f}};
- float4 p4{float4::array{1.0f, 2.0f, 3.0f, 4.0f}};
- float4 p5(float4::array{1.0f, 2.0f, 3.0f, 4.0f});
- float4 p6 = float4(int4(1, 2, 3, 4));
- float4 p7 {{1, 2, 3, 4}};
- float4 p8 (p7);
- float4 p9 = {p8};
- assert(p == p2);
- assert(p2 == p3);
- assert(p3 == p4);
- assert(p4 == p5);
- assert(p5 == p6);
- assert(p6 == p7);
- assert(p7 == p8);
- assert(p8 == p9);
- assert(p9 != float4::zero());
- static_assert(int4(1,1,1,1) == int4::one(), "");
- static_assert(int4(4,4,4,4) == int4::one(4), "");
- static_assert(float4(1.0f,1.0f,1.0f,1.0f) == float4::one(), "");
- static_assert(int4(1,0,0,0) == int4::i(), "");
- static_assert(int4(0,1,0,0) == int4::j(), "");
- static_assert(int4(0,0,1,0) == int4::k(), "");
- static_assert(int4(0,0,0,1) == int4::l(), "");
- static_assert(int4(4,0,0,0) == int4::i(4), "");
- static_assert(int4(0,4,0,0) == int4::j(4), "");
- static_assert(int4(0,0,4,0) == int4::k(4), "");
- static_assert(int4(0,0,0,4) == int4::l(4), "");
- static_assert(int4(-1,1,-1,-1) == int4::unit<1>(1,-1), "");
- }
- bool is_int3(vector<char, 3>) { return false; }
- bool is_int3(vector<int, 3>) { return true; }
- struct char_constructible
- {
- char a;
- char_constructible() {}
- explicit char_constructible(char a): a(a) {}
- bool operator==(char o) const { return o == a; };
- };
- void ImplicitConversion()
- {
- vector<char,3> c {'a','b','c'};
- vector<int,3> i{};
- i = c;
- assert(( i == vector{int('a'), int('b'), int('c')} ));
- assert(( i == vector{'a', 'b', 'c'} ));
- assert(( is_int3(i) ));
- assert(( not is_int3(c) ));
- vector<char_constructible, 3> b{};
- // b = c; // TODO: need no-compile tests
- b = vector<char_constructible,3>{c};
- assert(( b == vector{'a', 'b', 'c'} ));
- }
- void Transformation()
- {
- float4 p {1.3f, 1.5f, 2.1f, 4.6f};
- int4 p2 {1, 2, 2, 5};
- int4 p3 {1, 1, 2, 4};
- assert( p2 == p.transformed( [](auto x) -> int { return std::round(x); } ));
- assert( p3 == p.transformed( [](auto x) { return int(x); } ));
- }
- void Mixing()
- {
- int4 p {1, 2, 3, 4};
- assert( (geom::vector<int, 2>{1,2} == p.mix<0,1>()) );
- assert( (geom::vector<int, 2>{1,2} == p.mix<2>({0,1})) );
- assert( (geom::vector<int, 3>{2,3,4} == p.mix<1,2,3>()) );
- assert( (geom::vector<int, 3>{2,3,4} == p.mix<3>({1,2,3})) );
- assert( (geom::vector<int, 6>{3,3,3,2,2,1} == p.mix<2,2,2,1,1,0>()) );
- assert( (geom::vector<int, 6>{3,3,3,2,2,1} == p.mix<6>({2,2,2,1,1,0})) );
- assert( (geom::vector<int, 3>{1,2,0} == p.mix<0,1,4>(0)) );
- assert( (geom::vector<int, 3>{1,2,0} == p.mix<3>({0,1,4}, 0)) );
- assert( (vector(1,2) == p.first<2>()) );
- assert( (vector(2,3,4) == p.last<3>()) );
- assert( vector(1,2,3,4,5,6) == p.concat(vector(5,6)) );
- assert( vector(-1,0,1,2,3,4) == vector(-1,0).concat(p) );
- vector<int, 2, std::index_sequence<1,0>> revector{2,3};
- assert(( vector(0,1).concat(revector) == vector<int, 4, std::index_sequence<0,1,3,2>>(0,1,2,3) ));
- assert(( revector.concat(vector(4,5,6)) == vector<int, 5, std::index_sequence<1,0,2,3,4>>(2,3,4,5,6) ));
- }
- void MultidimensionalElementAccess()
- {
- auto spiral_walk = [](auto room)
- {
- constexpr auto csize = decltype(room)::meta::template dimensions<int>;
- vector <
- std::remove_reference_t<decltype(room[csize-1])>,
- csize.x()*csize.y()
- > ret{};
- auto size = csize;
- size_t i = 0;
- auto direction = 1;
- auto begin = vector(-1,0);
- while(size > vector(0,0))
- {
- auto end = begin + direction * (size - vector(0,1)) ;
- do
- {
- begin.x() += direction;
- ret[i++] = room[begin];
- }
- while(begin.x() != end.x());
- while(begin.y() != end.y())
- {
- begin.y() += direction;
- ret[i++] = room[begin];
- }
- //do
- --size;
- direction = -direction;
- }
- return ret;
- };
- assert( spiral_walk(vector(
- vector(1,2,3),
- vector(4,5,6),
- vector(7,8,9)
- )) == vector(1,2,3,6,9,8,7,4,5));
- assert( spiral_walk(vector(
- vector(1),
- vector(2)
- )) == vector(1,2));
- assert( spiral_walk(vector(
- vector(1)
- )) == vector(1));
- assert( spiral_walk(vector(
- vector(1,2)
- )) == vector(1,2));
- // // well clang really doesn't like zero size vectors so...
- // assert( spiral_walk(vector(
- // vector<int,0>()
- // )) == (vector<int,0>{}));
- //
- // assert( spiral_walk(vector(
- // vector<int,0>(),
- // vector<int,0>(),
- // vector<int,0>(),
- // vector<int,0>()
- // )) == (vector<int,0>{}));
- //
- // assert( spiral_walk(vector<vector<int,10>,0>()
- // ) == (vector<int,0>{}));
- assert( spiral_walk(vector(
- vector(1,2),
- vector(3,4)
- )) == vector(1,2,4,3));
- assert( spiral_walk(vector(
- vector( 1, 2, 3, 4),
- vector( 5, 6, 7, 8),
- vector( 9,10,11,12)
- )) == vector(1,2,3,4,8,12,11,10,9,5,6,7));
- assert( spiral_walk(vector(
- vector( 1, 2, 3),
- vector( 4, 5, 6),
- vector( 7, 8, 9),
- vector(10,11,12)
- )) == vector(1,2,3,6,9,12,11,10,7,4,5,8));
- assert( spiral_walk(vector(
- vector( 1, 2, 3, 4),
- vector( 5, 6, 7, 8),
- vector( 9,10,11,12),
- vector(13,14,15,16)
- )) == vector(1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10));
- }
- void RangeBasedLooping()
- {
- const float4 p{1.0f, 2.0f, 3.0f, 4.0f};
- float4 p2;
- int num = 1;
- for(auto& coord : p2)
- {
- coord = num;
- num += 1;
- }
- assert(p == p2);
- num = 1;
- for(auto coord : p)
- {
- assert(coord == num);
- num += 1;
- }
- }
- void Arithmetic()
- {
- float4 p{{1, 2, 3, 4}};
- float4 p2 = p;
- float4 sum{{2, 4, 6, 8}};
- float4 inc{{2, 3, 4, 5}};
- float4 dec{{0, 1, 2, 3}};
- assert(p + p2 == sum);
- assert(p + 1 == inc);
- assert(1 + p == inc);
- assert(p - 1 == dec);
- assert(p - dec == float4::one());
- assert(p - p2 == float4::zero());
- assert(-p == float4(int4(-1, -2, -3, -4)));
- assert(p2++ == p);
- assert(p2 == p+1);
- p2 = p;
- assert(++p2 == p+1);
- assert(p2 == p+1);
- p2 = p;
- assert(p2-- == p);
- assert(p2 == p-1);
- p2 = p;
- assert(--p2 == p-1);
- assert(p2 == p-1);
- p2 = p;
- p2 += p;
- assert(p2 == p+p);
- p2 -= p;
- assert(p2 == p);
- p2 -= p;
- assert(p2 == float4::zero());
- p2 = p;
- p2 += 3;
- assert(p2 == p + 3);
- p2 -= 1.5f;
- assert(p2 == p + 1.5f);
- assert( p + p == p * 2);
- assert( p * p == float4(1.0f, 4.0f, 9.0f, 16.0f));
- assert( (p + p)/2 == p);
- assert( p / (float4::one() * 2) == float4(0.5f, 1.0f, 1.5f, 2.0f) );
- assert( p / p == float4::one());
- p2 = p;
- p2 *= 2;
- assert(p2 == p*2);
- p2 *= p;
- assert(p2 == p*p*2);
- p2 /= p;
- assert(p2 == p*2);
- p2 /= 2;
- assert(p2 == p);
- p = {1.f, 2.f, 3.f, 4.f};
- p2 = {1.f, 0.f, 1.f, 0.f};
- float4 p3 = {1.f, 2.f, 0.f, 1.f};
- assert(p%2.f == p2);
- assert(p%float4::one(2.f) == p2);
- p %= 3.f;
- assert(p == p3);
- p = {1.f, 2.f, 3.f, 4.f};
- p3 = {4.f, 5.f, 7.f, 9.f};
- p2 = {3.f, 3.f, 4.f, 5.f};
- assert(p3 % p2 == p);
- p3 %= p2;
- assert(p3 == p);
- }
- // discrete? what?
- // TODO: used unsigned and if constexpr guard implied sizes
- void DiscreteArithmetic()
- {
- // %
- int4 p(1, 2, 3, 4);
- int4 p2(1, 0, 1, 0);
- int4 p3(1, 2, 0, 1);
- assert(p%2 == p2);
- p %= 3;
- assert(p == p3);
- p = {1, 2, 3, 4};
- p3 = {4, 5, 7, 9};
- p2 = {3, 3, 4, 5};
- assert(p3 % p2 == p);
- p3 %= p2;
- assert(p3 == p);
- // <<
- p = {0xA, 0xB0, 0xC00, 0xD000};
- p2 = {0xA0, 0xB00, 0xC000, 0xD0000};
- assert((p << 4) == p2);
- p <<= 4;
- assert(p == p2);
- p = {0xA, 0xB0, 0xC00, 0xD000};
- p2 = {0xA, 0xB, 0xC, 0xD};
- p3 = {0, 1, 2, 3};
- assert((p2 << (p3*4)) == p);
- p2 <<= (p3*4);
- assert(p2 == p);
- // >>
- p = {0xA, 0xB0, 0xC00, 0xD000};
- p2 = {0xA0, 0xB00, 0xC000, 0xD0000};
- assert((p2 >> 4) == p);
- p2 >>= 4;
- assert(p == p2);
- p = {0xA, 0xB0, 0xC00, 0xD000};
- p2 = {0xA, 0xB, 0xC, 0xD};
- p3 = {0, 1, 2, 3};
- assert((p >> (p3*4)) == p2);
- p >>= (p3*4);
- assert(p == p2);
- // &
- p = {0b0101, 0b1010, 0b1111, 0b0000};
- p2 = {0b0101, 0b0000, 0b0101, 0b0000};
- assert((p & 0b101) == p2);
- p &= 0b0101;
- assert(p == p2);
- p = {0b0101, 0b1010, 0b1111, 0b0000};
- p2 = {0b0110, 0b0111, 0b1001, 0b1111};
- p3 = {0b0100, 0b0010, 0b1001, 0b0000};
- assert((p & p2) == p3);
- p &= p2;
- assert(p == p3);
- // |
- p = {0b0101, 0b1010, 0b1111, 0b0000};
- p2 = {0b0101, 0b1111, 0b1111, 0b0101};
- assert((p | 0b0101) == p2);
- p |= 0b0101;
- assert(p == p2);
- p = {0b0101, 0b1010, 0b1111, 0b0000};
- p2 = {0b0110, 0b0111, 0b1001, 0b1111};
- p3 = {0b0111, 0b1111, 0b1111, 0b1111};
- assert((p | p2) == p3);
- p |= p2;
- assert(p == p3);
- // ^
- p = {0b0101, 0b1010, 0b1111, 0b0000};
- p2 = {0b0000, 0b1111, 0b1010, 0b0101};
- assert((p ^ 0b0101) == p2);
- p ^= 0b0101;
- assert(p == p2);
- p = {0b0101, 0b1010, 0b1111, 0b0000};
- p2 = {0b0110, 0b0111, 0b1001, 0b1111};
- p3 = {0b0011, 0b1101, 0b0110, 0b1111};
- assert((p ^ p2) == p3);
- p ^= p2;
- assert(p == p3);
- // ~
- p = {0b0101, 0b1010, 0b1111, 0b0000};
- assert( (~p & 0b1111) == int4(0b1010, 0b0101, 0b0000, 0b1111));
- // ~ for vector<bool>
- assert( ~vector(true, false, true, false) == vector(false, true, false, true) );
- assert( ~vector(true, true, false, false) == vector(false, false, true, true) );
- assert( ~vector(true, true, true, true) == vector(false, false, false, false) );
- // ! for vector<bool>
- assert( (!vector(true, false, true, false)) == vector(false, true, false, true) );
- assert( (!vector(true, true, false, false)) == vector(false, false, true, true) );
- assert( (!vector(true, true, true, true)) == vector(false, false, false, false) );
- // ~ for vector<vector<bool>>
- assert( (~vector(vector(true, false), vector(true, false))) ==
- vector(vector(false, true), vector(false, true)) );
- assert( (~vector(vector(true, true), vector(false, false))) ==
- vector(vector(false, false), vector(true, true)) );
- assert( (~vector(vector(true, true), vector(true, true))) ==
- vector(vector(false, false), vector(false, false)) );
- // ! for vector<vector<bool>>
- assert( (!vector(vector(true, false), vector(true, false))) ==
- vector(vector(false, true), vector(false, true)) );
- assert( (!vector(vector(true, true), vector(false, false))) ==
- vector(vector(false, false), vector(true, true)) );
- assert( (!vector(vector(true, true), vector(true, true))) ==
- vector(vector(false, false), vector(false, false)) );
- }
- void ComparisonOperators()
- {
- int4 p(1, 2, 3, 4);
- int4 p2(1, -2, 0, 1);
- // some random masking logic
- assert(p * int4(p2 > int4::zero()) == int4(1, 0, 0, 4));
- assert(p * int4(p2 < int4::zero()) == int4(0, 2, 0, 0));
- assert(p * int4(p2 == int4::zero()) == int4(0, 0, 3, 0));
- assert(p * int4(p2 == int4::zero() | p2 == int4::one()) == int4(1, 0, 3, 4));
- assert(p * int4(p2 != int4::zero() | p2 == int4::one()) == int4(1, 2, 0, 4));
- assert(p * int4(p2 != int4::zero() & p2 != int4::one(-2)) == int4(1, 0, 0, 4));
- }
- int PotentiallyAmbigous(geom::vector<int, 2>){ return 2; }
- int PotentiallyAmbigous(geom::vector<int, 3>){ return 3; }
- void DisabiguateOnConstructorParameterCount()
- {
- assert( PotentiallyAmbigous({1,2,3}) == 3 );
- assert( PotentiallyAmbigous({1,2}) == 2 );
- }
- void NumericLimits()
- {
- using limits = std::numeric_limits<int4>;
- using coordLimits = std::numeric_limits<int4::coordinate_type>;
- static_assert(limits::is_specialized);
- static_assert(limits::max() == int4::one(coordLimits::max()));
- static_assert(limits::min() == int4::one(coordLimits::min()));
- }
- void CoordinateOrder()
- {
- geom::vector<int, 4, std::index_sequence<3,2,1,0>> p_wzyx(1,2,3,4);
- assert( p_wzyx.x() == 4 );
- assert( p_wzyx.y() == 3 );
- assert( p_wzyx.z() == 2 );
- assert( p_wzyx.w() == 1 );
- assert( p_wzyx.get<0>() == 4 );
- assert( p_wzyx.get<1>() == 3 );
- assert( p_wzyx.get<2>() == 2 );
- assert( p_wzyx.get<3>() == 1 );
- assert( p_wzyx[p_wzyx.x_index] == 4 );
- assert( p_wzyx[p_wzyx.y_index] == 3 );
- assert( p_wzyx[p_wzyx.z_index] == 2 );
- assert( p_wzyx[p_wzyx.w_index] == 1 );
- assert( p_wzyx[0] == 1 );
- assert( p_wzyx[1] == 2 );
- assert( p_wzyx[2] == 3 );
- assert( p_wzyx[3] == 4 );
- assert( int4(p_wzyx) == int4(4,3,2,1) );
- auto [x,y,z,w] = p_wzyx;
- assert( x == p_wzyx.x() );
- assert( y == p_wzyx.y() );
- assert( z == p_wzyx.z() );
- assert( w == p_wzyx.w() );
- }
- // not absolutely insane unsigned short
- struct naius
- {
- unsigned short val;
- };
- bool operator==(naius a, naius b) { return a.val == b.val; }
- bool operator!=(naius a, naius b) { return !(a == b); }
- naius operator-(naius a)
- {
- auto promoted = -unsigned(a.val);
- return naius{(unsigned short)promoted};
- }
- naius operator>>(naius a, int shift)
- {
- auto promoted = unsigned(a.val) << shift;
- return naius{(unsigned short)promoted};
- }
- unsigned operator*(naius a, naius b)
- {
- return unsigned(a.val) * unsigned(b.val);
- }
- void DefyPromotion()
- {
- using puny = unsigned short; // bad
- // NOTE: can no longer demonstrate buny of size 1, since it promotes and decays to element type when shifted and initializer list contructor catches the bad implicit cast
- using buny = vector<puny,2>; // used to be goodish but now bad
- using vuny = vector<naius,1>; // good
- if constexpr (sizeof(puny) < sizeof(decltype(-puny{})))
- {
- // TODO: this test also relies on 2's complement representation and sign extension -_-
- puny p{1};
- assert( puny( -p >> 1 ) == puny(-p) ); // this does not look equivalent at all!
- assert( puny( -p >> 1 ) != -p >> 1 ); // and this does!
- // same for vector
- buny b{p,p};
- assert( buny( -b >> 1 ) == buny(-b) );
- assert( buny( -b >> 1 ) != -b >> 1 );
- // all fixed by a sane element type
- vuny v{naius{1}};
- assert( vuny( -v >> 1 ) != vuny(-v) );
- assert( vuny( -v >> 1 ) == -v >> 1 );
- // bonus multiplication, old goodish vector couldn't do this properly
- if constexpr (sizeof(unsigned short)*2 == sizeof(unsigned) && sizeof(int) == sizeof(unsigned))
- {
- auto biggy = std::numeric_limits<puny>::max();
- // assert( biggy * biggy < std::numeric_limits<int>::max() ); // instaUB
- naius nicey{biggy};
- assert( nicey * nicey > std::numeric_limits<int>::max() ); // all fine and dandy
- vuny vicey{nicey};
- assert(( vicey * vicey > vector<unsigned, 1>{{std::numeric_limits<int>::max()}} )); // vector respec sanity
- [[maybe_unused]] buny buggy{biggy, biggy};
- // assert(( buggy * buggy < vector(std::numeric_limits<int>::max(),std::numeric_limits<int>::max()) )); // as well as insanity -_-
- }
- else
- std::puts("what a world we live in~");
- }
- else
- std::puts("Type not puny enough to test promotion defiance!");
- };
- constexpr bool Constexprness() // TODO: needs better coverage
- {
- constexpr int4 p = int4(1,2,3,4);
- constexpr std::array<int, p[2]> arr = {1,2,3};
- constexpr std::array<int, int4::zero()[0]> arr2 = {};
- constexpr std::array<int, int4::one()[1]> arr3 = {13};
- static_assert(arr[p[1]] == 3, "Some other test should have caught this error.");
- static_assert(arr2.size() == 0, "Some other test should have caught this error.");
- static_assert(arr3[0] == 13, "Some other test should have caught this error.");
- assert(arr[2] == 3); // redundant check;
- return true;
- }
- void ValueCategoryOfGet()
- {
- using std::get;
- vector a(1,2,3);
- static_assert(std::is_same_v<decltype(( get<0>(a) )), int&>);
- static_assert(std::is_same_v<decltype(( a[0] )), int&>);
- static_assert(std::is_same_v<decltype(( a.x() )), int&>);
- static_assert(std::is_same_v<decltype(( get<0>(vector(1,2,3)) )), int&&>);
- static_assert(std::is_same_v<decltype(( vector(1,2,3)[0] )), int&&>);
- // static_assert(std::is_same_v<decltype(( vector(1,2,3).x() )), int&&>); // TODO
- vector b(vector(1,2),vector(3,4));
- static_assert(std::is_same_v<decltype(( get<0>(b) )), vector<int,2>&>);
- static_assert(std::is_same_v<decltype(( get<1>(get<0>(b)) )), int&>);
- static_assert(std::is_same_v<decltype(( b[0] )), vector<int,2>&>);
- static_assert(std::is_same_v<decltype(( b[0][0] )), int&>);
- static_assert(std::is_same_v<decltype(( get<0>(
- vector(vector(1,2),vector(3,4))
- ) )), vector<int,2>&&>);
- static_assert(std::is_same_v<decltype(( get<1>(get<0>(
- vector(vector(1,2),vector(3,4))
- )) )), int&&>);
- static_assert(std::is_same_v<
- decltype(( vector(vector(1,2),vector(3,4))[0] )),
- vector<int,2>&&>);
- static_assert(std::is_same_v<
- decltype(( vector(vector(1,2),vector(3,4))[0][1] )),
- int&&>);
- }
- void EmbracePromotion()
- {
- using short3 = vector<short, 3>;
- short3 a {{1,2,3}}, b {{4,5,6}};
- auto c = a + b;
- assert((c == vector(5,7,9)));
- static_assert( std::is_same_v<decltype(c), vector<int,3>> );
- auto d = short3(a + b);
- assert((d == short3{{5,7,9}}));
- static_assert( std::is_same_v<decltype(d), short3> );
- auto e = a + a + b;
- assert((e == vector(6,9,12)));
- static_assert( std::is_same_v<decltype(e), vector<int,3>> );
- d += a;
- assert((d == short3{{6,9,12}}));
- e += d;
- assert((e == vector(12,18,24)));
- auto cc = a + 1;
- static_assert( std::is_same_v<decltype(cc), vector<int,3>> );
- }
- template <typename E>
- class expr
- {
- public:
- operator int() const
- {
- return static_cast<const E&>(*this);
- }
- };
- class expr_int : public expr<expr_int>
- {
- int value;
- public:
- operator int() const { return value; }
- expr_int(int value = int{}) : value(value) {}
- template <typename E>
- expr_int(expr<E> const& expr) : value{expr} {}
- };
- template <typename E1, typename E2>
- class expr_sum : public expr<expr_sum<E1, E2> > {
- E1 const* left;
- E2 const* right;
- public:
- expr_sum() : left(), right() {}
- expr_sum(E1 const& left, E2 const& right) : left(&left), right(&right) {}
- operator int() const { return static_cast<int>(*left) + static_cast<int>(*right); }
- };
- template <typename E1, typename E2>
- expr_sum<E1, E2>
- operator+(expr<E1> const& left, expr<E2> const& right) {
- return expr_sum<E1, E2>(*static_cast<const E1*>(&left), *static_cast<const E2*>(&right));
- }
- void ExpressionTemplates()
- {
- using expr_vec = vector<expr_int, 2>;
- expr_vec x{1,2};
- expr_vec y{3,4};
- vector<int,2> z (x + y + x);
- assert(z == vector(5,8));
- }
- void BoolBitwiseCorrections()
- {
- // insanity check
- static_assert(std::is_same_v<int, decltype(true & true)>);
- static_assert(std::is_same_v<int, decltype(true | true)>);
- static_assert(std::is_same_v<int, decltype(true ^ true)>);
- // static_assert(std::is_same_v<int, decltype(~true)>); // this is kind of sane, but compiler warns so cleary shouldn't be used
- // much saner vector -v-
- static_assert(std::is_same_v<vector<bool,1>, decltype(vector(true) & vector(true))>);
- static_assert(std::is_same_v<vector<bool,1>, decltype(vector(true) | vector(true))>);
- static_assert(std::is_same_v<vector<bool,1>, decltype(vector(true) ^ vector(true))>);
- static_assert(std::is_same_v<vector<bool,1>, decltype(~vector(true))>); // ok with vector, it's same as !
- // note: in conditional expressions ~ is elementwise negation, while ! causes a reduction to plain bool (see bool_algebra.cpp)
- // make sure we didn't break other things
- // bit operations involving other types still promotes
- static_assert(std::is_same_v<vector<int,1>, decltype(vector(true) & vector(1))>);
- static_assert(std::is_same_v<vector<int,1>, decltype(vector(1) & vector(1))>);
- static_assert(std::is_same_v<vector<int,1>, decltype(vector(true) | vector(1))>);
- static_assert(std::is_same_v<vector<int,1>, decltype(vector(1) | vector(true))>);
- static_assert(std::is_same_v<vector<int,1>, decltype(vector(true) ^ vector(1))>);
- static_assert(std::is_same_v<vector<int,1>, decltype(vector(1) ^ vector(true))>);
- // arithmetic still promotes
- static_assert(std::is_same_v<vector<int,1>, decltype(vector(true) + vector(true))>);
- static_assert(std::is_same_v<vector<int,1>, decltype(vector(true) - vector(true))>);
- // TODO: not sure about these... multiplication is basically conjunction so maybe should return bool,
- // division makes no sense, can only divide by 1, / is a no-op, % is constant 0, both still stay within bounds of bool though
- static_assert(std::is_same_v<vector<int,1>, decltype(vector(true) * vector(true))>);
- static_assert(std::is_same_v<vector<int,1>, decltype(vector(true) / vector(true))>);
- static_assert(std::is_same_v<vector<int,1>, decltype(vector(true) % vector(true))>);
- }
- void BoolReductionImplicitConversion()
- {
- vector x (1,2,3);
- assert( x + (x == vector(1,1,1)) == vector(2,2,3) );
- assert( (x == vector(1,1,1)) + x == vector(2,2,3) );
- x += x == vector(1,1,1);
- assert( x == vector(2,2,3) );
- x = x == vector(2,2,2);
- assert( x == vector(1,1,0) );
- }
- void OneDimentionalVectorDecays()
- {
- using puny = short;
- assert (vector(puny(1)) + puny(1) == 2);
- static_assert( std::is_same_v<decltype(vector(puny(1)) + puny(1)), int> );
- }
- template <int4 i, int4 j = i> constexpr auto template_plus() { return i + j; }
- void NonTypeTemplateParamater()
- {
- static_assert(template_plus<int4{1,2,3,4}>() == int4{2,4,6,8});
- static_assert(template_plus<int4{1,2,3,4}, int4{5,6,7,8}>() == int4{6,8,10,12});
- }
- int main()
- {
- ZeroConstruction();
- EqualityComparison();
- OtherConstruction();
- ImplicitConversion();
- Transformation();
- Mixing();
- MultidimensionalElementAccess();
- RangeBasedLooping();
- Arithmetic();
- DiscreteArithmetic();
- ComparisonOperators();
- DisabiguateOnConstructorParameterCount();
- NumericLimits();
- CoordinateOrder();
- DefyPromotion();
- static_assert(Constexprness());
- ValueCategoryOfGet();
- EmbracePromotion();
- ExpressionTemplates();
- BoolBitwiseCorrections();
- BoolReductionImplicitConversion();
- OneDimentionalVectorDecays();
- NonTypeTemplateParamater();
- return 0;
- }
|