// L============================================================================= // L This software is distributed under the MIT license. // L Copyright 2021 Péter Kardos // L============================================================================= #pragma once #include "VectorImpl.hpp" #include namespace mathter { //------------------------------------------------------------------------------ // Utility //------------------------------------------------------------------------------ template inline auto DoElementwiseOp(const Vector& lhs, const Vector& rhs, Fun&& fun, std::index_sequence) { return Vector{ fun(lhs[Indices], rhs[Indices])... }; } template inline auto DoBinaryOp(const Vector& lhs, const Vector& rhs, Fun&& fun) { if constexpr (IsBatched()) { using B = Batch; return Vector{ fun(B::load_unaligned(lhs.data()), B::load_unaligned(rhs.data())) }; } else { return DoElementwiseOp(lhs, rhs, fun, std::make_index_sequence{}); } } template ::value, int> = 0> inline auto DoElementwiseOp(const Vector& lhs, const S& rhs, Fun&& fun, std::index_sequence) { using R = std::common_type_t; return Vector{ fun(R(lhs[Indices]), R(rhs))... }; } template ::value, int> = 0> inline auto DoBinaryOp(const Vector& lhs, const S& rhs, Fun&& fun) { using R = std::common_type_t; if constexpr (IsBatched() && IsBatched() && std::is_convertible_v, Batch>) { using TB = Batch; using RB = Batch; return Vector{ fun(RB(TB::load_unaligned(lhs.data())), RB(R(rhs))) }; } else { return DoElementwiseOp(lhs, rhs, fun, std::make_index_sequence{}); } } //------------------------------------------------------------------------------ // Vector arithmetic //------------------------------------------------------------------------------ /// Elementwise (Hadamard) vector product. template inline auto operator*(const Vector& lhs, const Vector& rhs) { return DoBinaryOp(lhs, rhs, std::multiplies{}); } /// Elementwise vector division. template inline Vector operator/(const Vector& lhs, const Vector& rhs) { return DoBinaryOp(lhs, rhs, std::divides{}); } /// Elementwise vector addition. template inline Vector operator+(const Vector& lhs, const Vector& rhs) { return DoBinaryOp(lhs, rhs, std::plus{}); } /// Elementwise vector subtraction. template inline Vector operator-(const Vector& lhs, const Vector& rhs) { return DoBinaryOp(lhs, rhs, std::minus{}); } //------------------------------------------------------------------------------ // Vector assign arithmetic //------------------------------------------------------------------------------ /// Elementwise (Hadamard) vector product. template inline Vector& operator*=(Vector& lhs, const Vector& rhs) { return lhs = lhs * rhs; } /// Elementwise vector division. template inline Vector& operator/=(Vector& lhs, const Vector& rhs) { return lhs = lhs / rhs; } /// Elementwise vector addition. template inline Vector& operator+=(Vector& lhs, const Vector& rhs) { return lhs = lhs + rhs; } /// Elementwise vector subtraction. template inline Vector& operator-=(Vector& lhs, const Vector& rhs) { return lhs = lhs - rhs; } //------------------------------------------------------------------------------ // Scalar arithmetic //------------------------------------------------------------------------------ /// Scales the vector by . template >> inline auto operator*(const Vector& lhs, U rhs) { return DoBinaryOp(lhs, rhs, std::multiplies{}); } /// Scales the vector by 1/. template >> inline auto operator/(const Vector& lhs, U rhs) { return DoBinaryOp(lhs, rhs, std::divides{}); } /// Adds to each element of the vector. template >> inline auto operator+(const Vector& lhs, U rhs) { return DoBinaryOp(lhs, rhs, std::plus{}); } /// Subtracts from each element of the vector. template >> inline auto operator-(const Vector& lhs, U rhs) { return DoBinaryOp(lhs, rhs, std::minus{}); } /// Scales vector by . template >> inline Vector operator*(U lhs, const Vector& rhs) { return rhs * lhs; } /// Adds to all elements of the vector. template >> inline Vector operator+(U lhs, const Vector& rhs) { return rhs + lhs; } /// Makes a vector with as all elements, then subtracts from it. template >> inline Vector operator-(U lhs, const Vector& rhs) { return Vector(lhs) - rhs; } /// Makes a vector with as all elements, then divides it by . template >> inline Vector operator/(U lhs, const Vector& rhs) { Vector copy(lhs); copy /= rhs; return copy; } //------------------------------------------------------------------------------ // Scalar assign arithmetic //------------------------------------------------------------------------------ /// Scales the vector by . template >> inline Vector& operator*=(Vector& lhs, U rhs) { return lhs = lhs * rhs; } /// Scales the vector by 1/. template >> inline Vector& operator/=(Vector& lhs, U rhs) { return lhs = lhs / rhs; } /// Adds to each element of the vector. template >> inline Vector& operator+=(Vector& lhs, U rhs) { return lhs = lhs + rhs; } /// Subtracts from each element of the vector. template >> inline Vector& operator-=(Vector& lhs, U rhs) { return lhs = lhs - rhs; } //------------------------------------------------------------------------------ // Extra //------------------------------------------------------------------------------ /// Return (a*b)+c. Performs MAD or FMA if supported by target architecture. template inline Vector MultiplyAdd(const Vector& a, const Vector& b, const Vector& c) { return a * b + c; } /// Negates all elements of the vector. template inline Vector operator-(const Vector& arg) { return arg * T(-1); } /// Optional plus sign, leaves the vector as is. template inline Vector operator+(const Vector& arg) { return arg; } //------------------------------------------------------------------------------ // Swizzle-vector //------------------------------------------------------------------------------ template auto operator*(const Vector& v, const Swizzle& s) -> std::enable_if_t> { return v * Vector(s); } template auto operator/(const Vector& v, const Swizzle& s) -> std::enable_if_t> { return v / Vector(s); } template auto operator+(const Vector& v, const Swizzle& s) -> std::enable_if_t> { return v + Vector(s); } template auto operator-(const Vector& v, const Swizzle& s) -> std::enable_if_t> { return v - Vector(s); } template auto operator*(const Swizzle& s, const Vector& v) -> std::enable_if_t> { return Vector(s) * v; } template auto operator/(const Swizzle& s, const Vector& v) -> std::enable_if_t> { return Vector(s) / v; } template auto operator+(const Swizzle& s, const Vector& v) -> std::enable_if_t> { return Vector(s) + v; } template auto operator-(const Swizzle& s, const Vector& v) -> std::enable_if_t> { return Vector(s) - v; } template auto operator*=(Vector& v, const Swizzle& s) -> std::enable_if_t>& { return v *= Vector(s); } template auto operator/=(Vector& v, const Swizzle& s) -> std::enable_if_t>& { return v /= Vector(s); } template auto operator+=(Vector& v, const Swizzle& s) -> std::enable_if_t>& { return v += Vector(s); } template auto operator-=(Vector& v, const Swizzle& s) -> std::enable_if_t>& { return v -= Vector(s); } template auto operator*=(Swizzle& s, const Vector& v) -> std::enable_if_t>& { return s = Vector(s) * v; } template auto operator/=(Swizzle& s, const Vector& v) -> std::enable_if_t>& { return s = Vector(s) / v; } template auto operator+=(Swizzle& s, const Vector& v) -> std::enable_if_t>& { return s = Vector(s) + v; } template auto operator-=(Swizzle& s, const Vector& v) -> std::enable_if_t>& { return s = Vector(s) - v; } //------------------------------------------------------------------------------ // Swizzle-swizzle //------------------------------------------------------------------------------ template auto operator*(const Swizzle& s1, const Swizzle& s2) { static_assert(sizeof...(Indices1) == sizeof...(Indices2)); constexpr bool Packed = Packed1 && Packed2; using V1 = Vector; using V2 = Vector; return V1(s1) * V2(s2); } template auto operator/(const Swizzle& s1, const Swizzle& s2) { static_assert(sizeof...(Indices1) == sizeof...(Indices2)); constexpr bool Packed = Packed1 && Packed2; using V1 = Vector; using V2 = Vector; return V1(s1) / V2(s2); } template auto operator+(const Swizzle& s1, const Swizzle& s2) { static_assert(sizeof...(Indices1) == sizeof...(Indices2)); constexpr bool Packed = Packed1 && Packed2; using V1 = Vector; using V2 = Vector; return V1(s1) + V2(s2); } template auto operator-(const Swizzle& s1, const Swizzle& s2) { static_assert(sizeof...(Indices1) == sizeof...(Indices2)); constexpr bool Packed = Packed1 && Packed2; using V1 = Vector; using V2 = Vector; return V1(s1) - V2(s2); } template auto& operator*=(Swizzle& s1, const Swizzle& s2) { return s1 = s1 * s2; } template auto& operator/=(Swizzle& s1, const Swizzle& s2) { return s1 = s1 / s2; } template auto& operator+=(Swizzle& s1, const Swizzle& s2) { return s1 = s1 + s2; } template auto& operator-=(Swizzle& s1, const Swizzle& s2) { return s1 = s1 - s2; } //------------------------------------------------------------------------------ // Swizzle-scalar //------------------------------------------------------------------------------ template >> auto operator*(const Swizzle& lhs, U rhs) { using VectorT = Vector; return VectorT(lhs) * rhs; } template >> auto operator/(const Swizzle& lhs, U rhs) { using VectorT = Vector; return VectorT(lhs) / rhs; } template >> auto operator+(const Swizzle& lhs, U rhs) { using VectorT = Vector; return VectorT(lhs) + rhs; } template >> auto operator-(const Swizzle& lhs, U rhs) { using VectorT = Vector; return VectorT(lhs) - rhs; } template >> auto operator*(U lhs, const Swizzle& rhs) { return rhs * lhs; } template >> auto operator/(U lhs, const Swizzle& rhs) { using VectorT = Vector; return lhs / VectorT(rhs); } template >> auto operator+(U lhs, const Swizzle& rhs) { return rhs + lhs; } template >> auto operator-(U lhs, const Swizzle& rhs) { using VectorT = Vector; return lhs - VectorT(rhs); } template >> auto& operator*=(Swizzle& lhs, U rhs) { using VectorT = Vector; lhs = VectorT(lhs) * rhs; return lhs; } template >> auto& operator/=(Swizzle& lhs, U rhs) { using VectorT = Vector; lhs = VectorT(lhs) / rhs; return lhs; } template >> auto& operator+=(Swizzle& lhs, U rhs) { using VectorT = Vector; lhs = VectorT(lhs) + rhs; return lhs; } template >> auto& operator-=(Swizzle& lhs, U rhs) { using VectorT = Vector; lhs = VectorT(lhs) - rhs; return lhs; } } // namespace mathter