// linalg.h - 2.2-beta - Single-header public domain linear algebra library
//
// The intent of this library is to provide the bulk of the functionality
// you need to write programs that frequently use small, fixed-size vectors
// and matrices, in domains such as computational geometry or computer
// graphics. It strives for terse, readable source code.
//
// The original author of this software is Sterling Orsten, and its permanent
// home is . If you find this software
// useful, an acknowledgement in your source text and/or product documentation
// is appreciated, but not required.
//
// The author acknowledges significant insights and contributions by:
// Stan Melax
// Dimitri Diakopoulos
//
// Some features are deprecated. Define LINALG_FORWARD_COMPATIBLE to remove them.
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to
#pragma once
#ifndef LINALG_H
#define LINALG_H
#include // For various unary math functions, such as std::sqrt
#include // To resolve std::abs ambiguity on clang
#include // For implementing namespace linalg::aliases
#include // For std::array
#include // For forward definitions of std::ostream
#include // For std::enable_if, std::is_same, std::declval
#include // For std::hash declaration
// In Visual Studio 2015, `constexpr` applied to a member function implies `const`, which causes ambiguous overload resolution
#if _MSC_VER <= 1900
#define LINALG_CONSTEXPR14
#else
#define LINALG_CONSTEXPR14 constexpr
#endif
namespace linalg
{
// Small, fixed-length vector type, consisting of exactly M elements of type T, and presumed to be a column-vector unless otherwise noted.
template struct vec;
// Small, fixed-size matrix type, consisting of exactly M rows and N columns of type T, stored in column-major order.
template struct mat;
// Specialize converter with a function application operator that converts type U to type T to enable implicit conversions
template struct converter {};
namespace detail
{
template using conv_t = typename std::enable_if::value, decltype(converter{}(std::declval()))>::type;
// Trait for retrieving scalar type of any linear algebra object
template struct scalar_type {};
template struct scalar_type> { using type = T; };
template struct scalar_type> { using type = T; };
// Type returned by the compare(...) function which supports all six comparison operators against 0
template struct ord { T a,b; };
template constexpr bool operator == (const ord & o, std::nullptr_t) { return o.a == o.b; }
template constexpr bool operator != (const ord & o, std::nullptr_t) { return !(o.a == o.b); }
template constexpr bool operator < (const ord & o, std::nullptr_t) { return o.a < o.b; }
template constexpr bool operator > (const ord & o, std::nullptr_t) { return o.b < o.a; }
template constexpr bool operator <= (const ord & o, std::nullptr_t) { return !(o.b < o.a); }
template constexpr bool operator >= (const ord & o, std::nullptr_t) { return !(o.a < o.b); }
// Patterns which can be used with the compare(...) function
template struct any_compare {};
template struct any_compare,vec> { using type=ord; constexpr ord operator() (const vec & a, const vec & b) const { return ord{a.x,b.x}; } };
template struct any_compare,vec> { using type=ord; constexpr ord operator() (const vec & a, const vec & b) const { return !(a.x==b.x) ? ord{a.x,b.x} : ord{a.y,b.y}; } };
template struct any_compare,vec> { using type=ord; constexpr ord operator() (const vec & a, const vec & b) const { return !(a.x==b.x) ? ord{a.x,b.x} : !(a.y==b.y) ? ord{a.y,b.y} : ord{a.z,b.z}; } };
template struct any_compare,vec> { using type=ord; constexpr ord operator() (const vec & a, const vec & b) const { return !(a.x==b.x) ? ord{a.x,b.x} : !(a.y==b.y) ? ord{a.y,b.y} : !(a.z==b.z) ? ord{a.z,b.z} : ord{a.w,b.w}; } };
template struct any_compare,mat> { using type=ord; constexpr ord operator() (const mat & a, const mat & b) const { return compare(a.x,b.x); } };
template struct any_compare,mat> { using type=ord; constexpr ord operator() (const mat & a, const mat & b) const { return a.x!=b.x ? compare(a.x,b.x) : compare(a.y,b.y); } };
template struct any_compare,mat> { using type=ord; constexpr ord operator() (const mat & a, const mat & b) const { return a.x!=b.x ? compare(a.x,b.x) : a.y!=b.y ? compare(a.y,b.y) : compare(a.z,b.z); } };
template struct any_compare,mat> { using type=ord; constexpr ord operator() (const mat & a, const mat & b) const { return a.x!=b.x ? compare(a.x,b.x) : a.y!=b.y ? compare(a.y,b.y) : a.z!=b.z ? compare(a.z,b.z) : compare(a.w,b.w); } };
// Helper for compile-time index-based access to members of vector and matrix types
template struct getter;
template<> struct getter<0> { template constexpr auto operator() (A & a) const -> decltype(a.x) { return a.x; } };
template<> struct getter<1> { template constexpr auto operator() (A & a) const -> decltype(a.y) { return a.y; } };
template<> struct getter<2> { template constexpr auto operator() (A & a) const -> decltype(a.z) { return a.z; } };
template<> struct getter<3> { template constexpr auto operator() (A & a) const -> decltype(a.w) { return a.w; } };
// Stand-in for std::integer_sequence/std::make_integer_sequence
template struct seq {};
template struct make_seq_impl;
template struct make_seq_impl { using type=seq<>; };
template struct make_seq_impl { using type=seq; };
template struct make_seq_impl { using type=seq; };
template struct make_seq_impl { using type=seq; };
template struct make_seq_impl { using type=seq; };
template using make_seq = typename make_seq_impl::type;
template vec constexpr swizzle(const vec & v, seq i) { return {getter{}(v)...}; }
template mat constexpr swizzle(const mat & m, seq i, seq j) { return {swizzle(getter{}(m),i)...}; }
// SFINAE helpers to determine result of function application
template using ret_t = decltype(std::declval()(std::declval()...));
// SFINAE helper which is defined if all provided types are scalars
struct empty {};
template struct scalars;
template<> struct scalars<> { using type=void; };
template struct scalars : std::conditional::value, scalars, empty>::type {};
template using scalars_t = typename scalars::type;
// Helpers which indicate how apply(F, ...) should be called for various arguments
template struct apply {}; // Patterns which contain only vectors or scalars
template struct apply, vec > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a ) { return {f(getter{}(a) )...}; } };
template struct apply, vec, vec > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, const vec & b ) { return {f(getter{}(a), getter{}(b) )...}; } };
template struct apply, vec, B > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, B b ) { return {f(getter{}(a), b )...}; } };
template struct apply, A, vec > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, A a, const vec & b ) { return {f(a, getter{}(b) )...}; } };
template struct apply, vec, vec, vec> { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, const vec & b, const vec & c) { return {f(getter{}(a), getter{}(b), getter{}(c))...}; } };
template struct apply, vec, vec, C > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, const vec & b, C c) { return {f(getter{}(a), getter{}(b), c )...}; } };
template struct apply, vec, B, vec> { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, B b, const vec & c) { return {f(getter{}(a), b, getter{}(c))...}; } };
template struct apply, vec, B, C > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, B b, C c) { return {f(getter{}(a), b, c )...}; } };
template struct apply, A, vec, vec> { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, A a, const vec & b, const vec & c) { return {f(a, getter{}(b), getter{}(c))...}; } };
template struct apply, A, vec, C > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, A a, const vec & b, C c) { return {f(a, getter{}(b), c )...}; } };
template struct apply, A, B, vec> { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, A a, B b, const vec & c) { return {f(a, b, getter{}(c))...}; } };
template struct apply, mat > { using type=mat,M,N>; enum {size=N, mm=0}; template static constexpr type impl(seq, F f, const mat & a ) { return {apply >::impl(make_seq<0,M>{}, f, getter