2025-05-25 22:36:59 -04:00

1087 lines
40 KiB
C++

// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file vector.h
/// \brief the \ref page_fennec_math_vector
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_MATH_VECTOR_H
#define FENNEC_MATH_VECTOR_H
///
///
///
/// \page page_fennec_math_vector Vectors
///
/// \brief The fennec Vector Math Module
///
///
/// \section vector_types Types
///
/// <table>
/// <caption id="table_fennec_math_vector_types"></caption>
/// <tr><th>Type <th>Brief
/// <tr><td colspan=2 style="text-align: center;">Floats
/// <tr><td>```vec2``` <td>\copybrief fennec::vec2
/// <tr><td>```vec3``` <td>\copybrief fennec::vec3
/// <tr><td>```vec4``` <td>\copybrief fennec::vec4
/// <tr><td colspan=2 style="text-align: center;">Doubles
/// <tr><td>```dvec2```<td>\copybrief fennec::dvec2
/// <tr><td>```dvec3```<td>\copybrief fennec::dvec3
/// <tr><td>```dvec4```<td>\copybrief fennec::dvec4
/// <tr><td colspan=2 style="text-align: center;">Booleans
/// <tr><td>```bvec2```<td>\copybrief fennec::bvec2
/// <tr><td>```bvec3```<td>\copybrief fennec::bvec3
/// <tr><td>```bvec4```<td>\copybrief fennec::bvec4
/// <tr><td colspan=2 style="text-align: center;">Integers
/// <tr><td>```ivec2```<td>\copybrief fennec::ivec2
/// <tr><td>```ivec3```<td>\copybrief fennec::ivec3
/// <tr><td>```ivec4```<td>\copybrief fennec::ivec4
/// <tr><td colspan=2 style="text-align: center;">Unsigned Integers
/// <tr><td>```uvec2```<td>\copybrief fennec::uvec2
/// <tr><td>```uvec3```<td>\copybrief fennec::uvec3
/// <tr><td>```uvec4```<td>\copybrief fennec::uvec4
/// </table>
///
///
///
/// \section vector_components Components
///
/// Vectors are usually made up of one to four components, named ```x```, ```y```, ```z```, and ```w```.
/// Each component also has aliases for usage in colors ```rgba```, and texture coordinates ```stpq```. Accessing a
/// component outside the vector will cause an error at compile time, for example:
///
/// \code{.cpp}
/// vec2 pos;
/// float height;
/// pos.x; // is legal
/// pos.z; // is illegal
/// height.x; // is legal in glsl, but illegal in c++
/// height.y; // is illegal
/// \endcode
///
/// Components can also be accessed with indices using the array access operator \ref fennec::vector::operator[] "vector::operator[](size_t)".
///
///
///
/// \section vector_swizzling Swizzling
///
/// The fennec \ref page_fennec_math_vector allows for the "swizzling" of vectors. Each component in the vector can be
/// used in any combination, with up to 4 components, to create another vector. For example, <br><br>
///
/// let \f$V = (0, 1, 2)\f$
/// then \f$V.xy = (0, 1)\f$
/// and \f$V.zy = (2, 1)\f$
///
///
///
#include <fennec/math/detail/__fwd.h>
#include <fennec/math/vector_base.h>
#include <fennec/math/vector_traits.h>
#include <fennec/lang/conditional_types.h>
#include <fennec/lang/type_traits.h>
#include <fennec/lang/utility.h>
namespace fennec
{
///
/// \typedef vec
/// \anchor vec
/// \brief Main \ref fennec::vector "vector" template
/// \tparam ScalarT The type of the Components
/// \tparam SizeV The number of Components
template<typename ScalarT, size_t SizeV> using vec = decltype(detail::__gen_vector<vector, ScalarT>(make_index_sequence<SizeV>{}));
///
/// \typedef tvec2
/// \anchor tvec2
/// \brief Shorthand for ```vec<ScalarT, 2>```
/// \tparam ScalarT The type of the Components
template<typename ScalarT> using tvec2 = vec<ScalarT, 2>;
///
/// \typedef tvec3
/// \anchor tvec3
/// \brief Shorthand for ```vec<ScalarT, 3>```
/// \tparam ScalarT The type of the Components
template<typename ScalarT> using tvec3 = vec<ScalarT, 3>;
///
/// \typedef tvec4
/// \anchor tvec4
/// \brief Shorthand for ```vec<ScalarT, 4>```
/// \tparam ScalarT The type of the Components
template<typename ScalarT> using tvec4 = vec<ScalarT, 4>;
///
/// \typedef bvec2
/// \anchor bvec2
/// \brief A two-component boolean \ref fennec::vector "vector"
using bvec2 = tvec2<bool_t>;
///
/// \typedef bvec3
/// \anchor bvec3
/// \brief A three-component boolean \ref fennec::vector "vector"
using bvec3 = tvec3<bool_t>;
///
/// \typedef bvec4
/// \anchor bvec4
/// \brief A four-component boolean \ref fennec::vector "vector"
using bvec4 = tvec4<bool_t>;
///
/// \typedef ivec2
/// \anchor ivec2
/// \brief A two-component signed integer \ref fennec::vector "vector"
using ivec2 = tvec2<int32_t>;
/// \typedef ivec3
/// \anchor ivec3
/// \brief A three-component signed integer \ref fennec::vector "vector"
using ivec3 = tvec3<int32_t>;
/// \typedef ivec4
/// \anchor ivec4
/// \brief A four-component signed integer \ref fennec::vector "vector"
using ivec4 = tvec4<int32_t>;
///
/// \typedef uvec2
/// \anchor uvec2
/// \brief A two-component unsigned integer \ref fennec::vector "vector"
using uvec2 = tvec2<uint32_t>;
///
/// \typedef uvec3
/// \anchor uvec3
/// \brief A three-component unsigned integer \ref fennec::vector "vector"
using uvec3 = tvec3<uint32_t>;
///
/// \typedef uvec4
/// \anchor uvec4
/// \brief A four-component unsigned integer \ref fennec::vector "vector"
using uvec4 = tvec4<uint32_t>;
///
/// \typedef vec2
/// \anchor vec2
/// \brief A two-component single-precision floating-point \ref fennec::vector "vector"
using vec2 = tvec2<float32_t>;
///
/// \typedef vec3
/// \anchor vec3
/// \brief A three-component single-precision floating-point \ref fennec::vector "vector"
using vec3 = tvec3<float32_t>;
///
/// \typedef vec4
/// \anchor vec4
/// \brief A four-component single-precision floating-point \ref fennec::vector "vector"
using vec4 = tvec4<float32_t>;
///
/// \typedef dvec2
/// \anchor dvec2
/// \brief A two-component double-precision floating-point \ref fennec::vector "vector"
using dvec2 = tvec2<float64_t>;
///
/// \typedef dvec3
/// \anchor dvec3
/// \brief A three-component double-precision floating-point \ref fennec::vector "vector"
using dvec3 = tvec3<float64_t>;
///
/// \typedef dvec4
/// \anchor dvec4
/// \brief A four-component double-precision floating-point \ref fennec::vector "vector"
using dvec4 = tvec4<float64_t>;
///
/// \struct fennec::vector
/// \brief Math Vector Type
/// \tparam ScalarT base \ref scalar type of each Component
/// \tparam IndicesV index of each Component
/// \nosubgrouping
template<typename ScalarT, size_t...IndicesV>
struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
{
// Assertions ==========================================================================================================
static_assert(is_arithmetic_v<ScalarT>);
// Forward Defs ========================================================================================================
/// \name Forward Definitions & Constants
/// @{
///
/// \typedef vector::base_type
/// \brief vector base type
using base_type = detail::vector_base_type<ScalarT, sizeof...(IndicesV)>;
///
/// \brief vector data array
using base_type::data;
///
/// \typedef scalar_t
/// \brief alias for ScalarT
using scalar_t = ScalarT;
///
/// \typedef vector::vector_t
/// \brief alias for this type
using vector_t = vector;
// Size Aliases
static constexpr size_t dimension = sizeof...(IndicesV); ///< \brief dimension of the swizzle
static constexpr size_t num_components = sizeof...(IndicesV); ///< \brief number of components
static constexpr size_t size = sizeof...(IndicesV); ///< \brief size of the swizzle
static constexpr size_t N = sizeof...(IndicesV); ///< \brief size of the swizzle
using decay_t = conditional_t<N == 1, scalar_t, vector_t>; ///< Type that the \ref fennec::vector "vector" should Decay into
/// @}
// Constructors ========================================================================================================
/// \name Constructors
/// @{
///
/// \brief default constructor, initializes components with 0
///
/// \details ** **
constexpr vector() { data = { 0 }; }
///
/// \brief copy constructor
///
/// \details
/// \param x object to copy
constexpr vector(const vector_t& x) { data = x.data; }
///
/// \brief move constructor
///
/// \details
/// \param x object to move
constexpr vector(vector_t&& x) noexcept { data = std::move(x.data); }
///
/// \brief scalar constructor
///
/// \details
/// \param s scalar value to initialize with
explicit constexpr vector(scalar_t s) { ((data[IndicesV] = s), ...); }
///
/// \brief int conversion scalar
///
/// \details
/// \param s scalar value to initialize with
explicit constexpr vector(int_t s) requires(not is_same_v<ScalarT, int_t>) {
if constexpr(N == 1) data[0] = ScalarT(s);
else ((data[IndicesV] = ScalarT(s)), ...);
}
///
/// \brief double conversion scalar
///
/// \details
/// \param s scalar value to initialize with
explicit constexpr vector(double_t s) requires(not is_same_v<ScalarT, double_t>) {
if constexpr(N == 1) data[0] = ScalarT(s);
else ((data[IndicesV] = ScalarT(s)), ...);
}
///
/// \brief vector scalar conversion constructor
///
/// \details
/// \tparam OScalarT scalar Type of the \ref fennec::vector "vector" to Convert
/// \param v \ref fennec::vector "vector" to Convert
template<typename OScalarT>
explicit constexpr vector(const vector<OScalarT, IndicesV...>& v)
{ ((data[IndicesV] = ScalarT(v[IndicesV])), ...); }
///
/// \brief vector conversion constructor
///
/// \details
/// \tparam OScalarT scalar Type of the \ref fennec::vector "vector" to Convert
/// \tparam MoreIndicesStartV
/// \tparam MoreIndicesV
/// \param v
template<typename OScalarT, size_t MoreIndicesStartV, size_t...MoreIndicesV>
explicit constexpr vector(const vector<OScalarT, IndicesV..., MoreIndicesStartV, MoreIndicesV...>& v)
{ ((data[IndicesV] = ScalarT(v[IndicesV])), ...); }
///
/// \brief swizzle conversion constructor
///
/// \details
/// \tparam SwizzleDataT swizzle Data Type
/// \tparam SwizzleScalarT swizzle scalar Type
/// \tparam SwizzleIndicesV swizzle Indices
/// \param swizzle swizzle object
template<typename SwizzleDataT, typename SwizzleScalarT, size_t...SwizzleIndicesV>
explicit constexpr vector(const detail::swizzle_storage<SwizzleDataT, SwizzleScalarT, SwizzleIndicesV...>& swizzle)
{ ((data[IndicesV] = ScalarT(swizzle[IndicesV])), ...); }
///
/// \brief piecewise constructor
///
/// \details constructs a vector from a series of scalars, swizzles, and vectors
/// \tparam ArgsT argument types
/// \param args arguments
template<typename...ArgsT> requires(total_component_count_v<ArgsT...> == N)
explicit constexpr vector(ArgsT&&...args)
{ vector::__construct<0>(args...); }
/// @}
// Public Member Functions =============================================================================================
/// \name Public Member Functions
/// @{
///
/// \brief decay implementation
///
/// \details
/// \returns scalar if \f$N==1\f$, otherwise, \ref fennec::vector "vector"
decay_t decay()
{ return static_cast<const decay_t&>(*this); }
/// @}
// Access operators ====================================================================================================
/// \name Access operators
/// @{
///
/// \copydetails vector::operator[](size_t) const
constexpr scalar_t& operator[](size_t i)
{ return data[i]; }
///
/// \brief indexed access operator
///
/// \details
/// \returns a copy of the component
/// \param i the index of the component
constexpr scalar_t operator[](size_t i) const
{ return data[i]; }
/// @}
// Assignment operators ================================================================================================
/// \name Assignment operators
/// @{
///
/// \brief copy assignment
///
/// \details
/// \returns A reference to \c this, after having set \p lhs, such that \f$lhs_i=rhs_i\f$
/// \param rhs vector to copy
constexpr vector_t& operator=(const vector_t& rhs)
{ return ((data[IndicesV] = rhs[IndicesV]), ..., *this); }
///
/// \brief move assignment
///
/// \details
/// \returns A reference to \c this, after having set \p lhs, such that \f$lhs_i=rhs_i\f$
/// \param rhs vector to move
constexpr vector_t& operator=(vector_t&& rhs) noexcept
{ return ((data[IndicesV] = fennec::move(rhs[IndicesV])), ..., *this); }
/// @}
// Comparison Operators ================================================================================================
/// \name Comparison Operators
/// @{
///
/// \brief vector equality operator
///
/// \details
/// \returns **true** if every respective component is equivalent, otherwise returns **false**
/// \param rhs vector to compare with
constexpr bool_t operator==(const vector_t& rhs) const
{ return ((data[IndicesV] == rhs.data[IndicesV]) && ...); }
///
/// \brief vector inequality operator
///
/// \details
/// \returns **false** if every respective component is equivalent, otherwise returns **true**
/// \param rhs vector to compare with
constexpr bool_t operator!=(const vector_t& rhs) const
{ return ((data[IndicesV] != rhs.data[IndicesV]) || ...); }
/// @}
// Scalar-Vector Arithmetic operators ==================================================================================
/// \name \ref page_fennec_math_scalar "scalar" - \ref fennec::vector "vector" Arithmetic operators
/// @{
///
/// \brief \ref page_fennec_math_scalar "scalar" - \ref fennec::vector "vector" addition operator
///
/// \details
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$
/// \param lhs left hand side
/// \param rhs right hand side
constexpr friend vector_t operator+(scalar_t lhs, const vector_t& rhs)
{ return vector_t((lhs[IndicesV] + rhs[IndicesV]) ...); }
///
/// \brief \ref page_fennec_math_scalar "scalar" - \ref fennec::vector "vector" subtraction operator
///
/// \details
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$
/// \param lhs left hand side
/// \param rhs right hand side
constexpr friend vector_t operator-(scalar_t lhs, const vector_t& rhs)
{ return vector_t((lhs[IndicesV] - rhs[IndicesV]) ...); }
///
/// \brief \ref page_fennec_math_scalar "scalar" - \ref fennec::vector "vector" multiplication operator
///
/// \details
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$
/// \param lhs left hand side
/// \param rhs right hand side
constexpr friend vector_t operator*(scalar_t lhs, const vector_t& rhs)
{ return vector_t((lhs * rhs[IndicesV]) ...); }
///
/// \brief \ref page_fennec_math_scalar "scalar" - \ref fennec::vector "vector" division operator
///
/// \details
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$
/// \param lhs left hand side
/// \param rhs right hand side
constexpr friend vector_t operator/(scalar_t lhs, const vector_t& rhs)
{ return vector_t((lhs / rhs[IndicesV]) ...); }
///
/// \brief \ref page_fennec_math_scalar "scalar" - \ref fennec::vector "vector" integer modulus operator
///
/// \details
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$
/// \param lhs left hand side
/// \param rhs right hand side
constexpr friend vector_t operator%(scalar_t lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>)
{ return vector_t((lhs % rhs[IndicesV]) ...); }
/// @}
// Vector-Scalar Arithmetic operators ==================================================================================
/// \name \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" Arithmetic operators
/// @{
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" addition operator
///
/// \details
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$
/// \param lhs left hand side
/// \param rhs right hand side
constexpr friend vector_t operator+(const vector_t& lhs, scalar_t rhs)
{ return vector_t((lhs[IndicesV] + rhs) ...); }
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" subtraction operator
///
/// \details
/// \param lhs left hand side
/// \param rhs right hand side
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$
constexpr friend vector_t operator-(const vector_t& lhs, scalar_t rhs)
{ return vector_t((lhs[IndicesV] - rhs) ...); }
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" multiplication operator
///
/// \details
/// \param lhs left hand side
/// \param rhs right hand side
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$
constexpr friend vector_t operator*(const vector_t& lhs, scalar_t rhs)
{ return vector_t((lhs[IndicesV] * rhs) ...); }
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" division operator
///
/// \details
/// \param lhs left hand side
/// \param rhs right hand side
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$
constexpr friend vector_t operator/(const vector_t& lhs, scalar_t rhs)
{ return vector((lhs[IndicesV] / rhs) ...); }
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" integer modulus operator
///
/// \details
/// \param lhs left hand side
/// \param rhs right hand side
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$
constexpr friend vector_t operator%(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>)
{ return vector((lhs[IndicesV] % rhs) ...); }
/// @}
// Vector-Scalar Arithmetic Assignment operators =======================================================================
/// \name \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" Arithmetic Assignment operators
/// @{
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" addition operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$
constexpr friend vector_t& operator+=(vector_t& lhs, scalar_t rhs)
{ return ((lhs[IndicesV] += rhs), ..., lhs); }
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" Subtraction operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$
constexpr friend vector_t& operator-=(vector_t& lhs, scalar_t rhs)
{ return ((lhs[IndicesV] -= rhs), ..., lhs); }
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" multiplication operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$
constexpr friend vector_t& operator*=(vector_t& lhs, scalar_t rhs)
{ return ((lhs[IndicesV] *= rhs), ..., lhs); }
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" division operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$
constexpr friend vector_t& operator/=(vector_t& lhs, scalar_t rhs)
{ return ((lhs[IndicesV] /= rhs), ..., lhs); }
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" integer modulus operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$
constexpr friend vector_t& operator%=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>)
{ return ((lhs[IndicesV] %= rhs), ..., lhs); }
/// @}
// Vector-Vector Arithmetic operators ==================================================================================
/// \name \ref fennec::vector "vector" - \ref fennec::vector "vector" Arithmetic operators
/// @{
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" addition operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$
constexpr friend vector_t operator+(const vector_t& lhs, const vector_t& rhs)
{ return vector((lhs[IndicesV] + rhs[IndicesV]) ...); }
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" subtraction operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$
constexpr friend vector_t operator-(const vector_t& lhs, const vector_t& rhs)
{ return vector((lhs[IndicesV] - rhs[IndicesV]) ...); }
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" multiplication operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$
constexpr friend vector_t operator*(const vector_t& lhs, const vector_t& rhs)
{ return vector((lhs[IndicesV] * rhs[IndicesV]) ...); }
///
/// \fn vector::operator/(const vector_t&, const vector_t&)
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" division operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$
constexpr friend vector_t operator/(const vector_t& lhs, const vector_t& rhs)
{ return vector((lhs[IndicesV] / rhs[IndicesV]) ...); }
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" integer modulus operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$
constexpr friend vector_t operator%(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>)
{ return vector((lhs[IndicesV] % rhs[IndicesV]) ...); }
/// @}
// Vector-Vector Arithmetic Assignment operators =======================================================================
/// \name \ref fennec::vector "vector" - \ref fennec::vector "vector" Arithmetic Assignment operators
/// @{
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" addition operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$
constexpr friend vector_t& operator+=(vector_t& lhs, const vector_t& rhs)
{ return ((lhs[IndicesV] += rhs[IndicesV]), ..., lhs); }
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" subtraction operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$
constexpr friend vector_t& operator-=(vector_t& lhs, const vector_t& rhs)
{ return ((lhs[IndicesV] -= rhs[IndicesV]), ..., lhs); }
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" multiplication operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$
constexpr friend vector_t& operator*=(vector_t& lhs, const vector_t& rhs)
{ return ((lhs[IndicesV] *= rhs[IndicesV]), ..., lhs); }
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" division operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$
constexpr friend vector_t& operator/=(vector_t& lhs, const vector_t& rhs)
{ return ((lhs[IndicesV] /= rhs[IndicesV]), ..., lhs); }
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" integer modulus operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$
constexpr friend vector_t& operator%=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>)
{ return ((lhs[IndicesV] %= rhs[IndicesV]), ..., lhs); }
/// @}
// Boolean Operators ===================================================================================================
/// \name Boolean Operators
/// @{
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" logical and operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\&\&rhs_i\f$
constexpr friend vector_t operator&&(const vector_t& lhs, scalar_t rhs) requires(is_bool_v<scalar_t>)
{ return vector_t((lhs[IndicesV] && rhs) ...); }
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" logical and operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\&\&rhs_i\f$
constexpr friend vector_t operator&&(const vector_t& lhs, const vector_t& rhs) requires(is_bool_v<scalar_t>)
{ return vector_t((lhs[IndicesV] && rhs[IndicesV]) ...); }
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" logical or operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\|\|rhs_i\f$
constexpr friend vector_t operator||(const vector_t& lhs, scalar_t rhs) requires(is_bool_v<scalar_t>)
{ return vector_t((lhs[IndicesV] || rhs) ...); }
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" logical or operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\|\|rhs_i\f$
constexpr friend vector_t operator||(const vector_t& lhs, const vector_t& rhs) requires(is_bool_v<scalar_t>)
{ return vector_t((lhs[IndicesV] || rhs[IndicesV]) ...); }
/// @}
// Bitwise Operators ===================================================================================================
/// \name Bitwise Operators
/// @{
///
/// \brief \ref page_fennec_math_scalar "scalar" - \ref fennec::vector "vector" bitwise and operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$
constexpr friend vector_t operator&(scalar_t rhs, const vector_t& lhs) requires(is_integral_v<scalar_t>)
{ return vector_t((lhs & rhs[IndicesV]) ...); }
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" bitwise and assignment operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$
constexpr friend vector_t operator&=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>)
{ return ((lhs[IndicesV] &= rhs), ..., lhs); }
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" bitwise and operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$
constexpr friend vector_t operator&(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>)
{ return vector_t((lhs[IndicesV] & rhs) ...); }
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" bitwise and assignment operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$
constexpr friend vector_t operator&=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>)
{ return ((lhs[IndicesV] &= rhs), ..., lhs); }
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" bitwise and operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$
constexpr friend vector_t operator&(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>)
{ return vector_t((lhs[IndicesV] & rhs[IndicesV]) ...); }
///
/// \brief \ref page_fennec_math_scalar "scalar" - \ref fennec::vector "vector" bitwise or operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$
constexpr friend vector_t operator|(scalar_t rhs, const vector_t& lhs) requires(is_integral_v<scalar_t>)
{ return vector_t((lhs & rhs[IndicesV]) ...); }
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" bitwise or assignment operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$
constexpr friend vector_t operator|=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>)
{ return ((lhs[IndicesV] |= rhs), ..., lhs); }
///
/// \brief \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" bitwise or operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$
constexpr friend vector_t operator|(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>)
{ return vector_t((lhs[IndicesV] | rhs) ...); }
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" bitwise or assignment operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$
constexpr friend vector_t operator|=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>)
{ return ((lhs[IndicesV] |= rhs), ..., lhs); }
///
/// \brief \ref fennec::vector "vector" - \ref fennec::vector "vector" bitwise or operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$
constexpr friend vector_t operator|(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>)
{ return vector_t((lhs[IndicesV] | rhs[IndicesV]) ...); }
///
/// \ref page_fennec_math_scalar "scalar" - \ref fennec::vector "vector" bitwise or operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$
constexpr friend vector_t operator^(scalar_t rhs, const vector_t& lhs) requires(is_integral_v<scalar_t>)
{ return vector_t((lhs ^ rhs[IndicesV]) ...); }
///
/// \fn vector::operator^=(vector_t&, scalar_t)
/// \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" bitwise or assignment operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$
constexpr friend vector_t operator^=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>)
{ return ((lhs[IndicesV] ^= rhs), ..., lhs); }
///
/// \fn vector::operator^(const vector_t&, scalar_t)
/// \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" bitwise or operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$
constexpr friend vector_t operator^(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>)
{ return vector_t((lhs[IndicesV] ^ rhs) ...); }
///
/// \fn vector::operator^=(vector_t&, const vector_t&)
/// \ref fennec::vector "vector" - \ref fennec::vector "vector" bitwise or assignment operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$
constexpr friend vector_t operator^=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>)
{ return ((lhs[IndicesV] ^= rhs), ..., lhs); }
///
/// \fn vector::operator^(const vector_t&, const vector_t&)
/// \ref fennec::vector "vector" - \ref fennec::vector "vector" bitwise or operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$
constexpr friend vector_t operator^(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>)
{ return vector_t((lhs[IndicesV] ^ rhs[IndicesV]) ...); }
///
/// \fn vector::operator<<=(vector_t&, scalar_t)
/// \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" bitwise left-shift assignment operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i<<=rhs_i\f$
constexpr friend vector_t operator<<=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>)
{ return ((lhs[IndicesV] <<= rhs), ..., lhs); }
///
/// \fn vector::operator<<(const vector_t&, scalar_t)
/// \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" bitwise or operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i<<rhs_i\f$
constexpr friend vector_t operator<<(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>)
{ return vector_t((lhs[IndicesV] << rhs) ...); }
///
/// \fn vector::operator<<=(vector_t&, const vector_t&)
/// \ref fennec::vector "vector" - \ref fennec::vector "vector" bitwise or assignment operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i<<=rhs_i\f$
constexpr friend vector_t operator<<=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>)
{ return ((lhs[IndicesV] <<= rhs), ..., lhs); }
///
/// \fn vector::operator<<(const vector_t&, const vector_t&)
/// \ref fennec::vector "vector" - \ref fennec::vector "vector" bitwise or operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i<<rhs_i\f$
constexpr friend vector_t operator<<(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>)
{ return vector_t((lhs[IndicesV] << rhs[IndicesV]) ...); }
///
/// \fn vector::operator>>=(vector_t&, scalar_t)
/// \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" bitwise left-shift assignment operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i>>=rhs_i\f$
constexpr friend vector_t operator>>=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>)
{ return ((lhs[IndicesV] >>= rhs), ..., lhs); }
///
/// \fn vector::operator>>(const vector_t&, scalar_t)
/// \ref fennec::vector "vector" - \ref page_fennec_math_scalar "scalar" bitwise or operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i>>rhs_i\f$
constexpr friend vector_t operator>>(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>)
{ return vector_t((lhs[IndicesV] >> rhs) ...); }
///
/// \fn vector::operator>>=(vector_t&, const vector_t&)
/// \ref fennec::vector "vector" - \ref fennec::vector "vector" bitwise or assignment operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i>>=rhs_i\f$
constexpr friend vector_t operator>>=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>)
{ return ((lhs[IndicesV] >>= rhs), ..., lhs); }
///
/// \fn vector::operator>>(const vector_t&, const vector_t&)
/// \ref fennec::vector "vector" - \ref fennec::vector "vector" bitwise or operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec::vector "vector" \a v such that, \f$v_i=lhs_i>>rhs_i\f$
constexpr friend vector_t operator>>(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>)
{ return vector_t((lhs[IndicesV] >> rhs[IndicesV]) ...); }
/// @}
// Helpers =============================================================================================================
private:
template<size_t IndexV = 0, typename HeadT, typename...TailT>
constexpr void __construct(HeadT&& head, TailT&&...rest)
{
vector::__insert<IndexV>(fennec::forward<HeadT>(head));
if constexpr(sizeof...(TailT) > 0)
vector::__construct<IndexV + component_count_v<HeadT>>(fennec::forward<TailT>(rest)...);
}
template<size_t OffsetV>
constexpr void __insert(ScalarT& x)
{ data[OffsetV] = x; }
template<size_t OffsetV, typename OScalarT>
constexpr void __insert(OScalarT& x)
{ data[OffsetV] = ScalarT(x); }
template<size_t OffsetV = 0, typename OScalarT, size_t...OIndicesV>
constexpr void __insert(vector<OScalarT, OIndicesV...>& vec)
{ ((data[OffsetV + OIndicesV] = fennec::forward<OScalarT>(vec[OIndicesV])), ...); }
template<size_t OffsetV = 0, typename OVectorT, typename ODataT, typename OScalarT, size_t...OIndicesV>
constexpr void __insert(swizzle<OVectorT, ODataT, OScalarT, OIndicesV...>& vec)
{ size_t i = 0; ((data[OffsetV + (i++)] = vec.data[OIndicesV]), ...); }
};
}
#endif // FENNEC_MATH_VECTOR_H