// SPDX-License-Identifier: LGPL-2.1-or-later
// SPDX-FileCopyrightText: 2016-2017 Erik Hofman <erik@ehofman.com>

//  sim4d，一个向量类，支持4个或更少元素的向量，主要是实现向量的运算优化
#pragma once

#include <cstdint>
#include <cstring>
#include <cassert>
#include <cmath>
#include <new>

#include <simgear/math/SGLimits.hxx>
#include <simgear/math/SGMisc.hxx>

template<typename T, int N> class simd4_t;

namespace simd4
{

//  min函数，返回两个向量中各分量的最小值
template<typename T, int N>
inline simd4_t<T,N> min(simd4_t<T,N> v1, const simd4_t<T,N>& v2) {
    for (int i=0; i<N; ++i) {
        v1[i] = SGMisc<T>::min(v1[i], v2[i]);
    }
    return v1;
}

//  max函数，返回两个向量中各分量的最大值
template<typename T, int N>
inline simd4_t<T,N> max(simd4_t<T,N> v1, const simd4_t<T,N>& v2) {
    for (int i=0; i<N; ++i) {
        v1[i] = SGMisc<T>::max(v1[i], v2[i]);
    }
    return v1;
}

//  abs函数，返回向量中各分量的绝对值
template<typename T, int N>
inline simd4_t<T,N> abs(simd4_t<T,N> v) {
    for (int i=0; i<N; ++i) {
        v[i] = std::abs(v[i]);
    }
    return v;
}

//  magnitude2函数，返回向量中各分量的平方和，即二范数的平方
template<typename T, int N>
inline T magnitude2(const simd4_t<T,N>& vi) {
    simd4_t<T,N> v(vi);
    T mag2 = 0;
    v = v*v;
    for (int i=0; i<N; ++i) {
        mag2 += v[i];
    }
    return mag2;
}

//  interpolate函数，返回两个向量之间的线性插值
template<typename T, int N>
inline simd4_t<T,N> interpolate(T tau, const simd4_t<T,N>& v1, const simd4_t<T,N>& v2) {
    return v1 + tau*(v2-v1);
}

//  magnitude函数，返回向量的二范数
template<typename T, int N>
inline T magnitude(const simd4_t<T,N>& v) {
    return std::sqrt(magnitude2(v));
}

//  normalize函数，归一化向量
template<typename T, int N>
inline T normalize(simd4_t<T,N>& v) {
    T mag = simd4::magnitude(v);
    if (mag) {
        v /= mag;
    } else {
        v = T(0);
    }
    return mag;
}

//  dot函数，返回两个向量的点积
template<typename T, int N>
inline T dot(const simd4_t<T,N>& v1, const simd4_t<T,N>& v2) {
    simd4_t<T,N> v(v1*v2);
    T dp = T(0);
    for (int i=0; i<N; ++i) {
       dp += v[i];
    }
    return dp;
}

//  cross函数，返回两个向量的叉积，仅三维向量有效
template<typename T>
inline simd4_t<T,3> cross(const simd4_t<T,3>& v1, const simd4_t<T,3>& v2)
{
    simd4_t<T,3> d;
    d[0] = v1[1]*v2[2] - v1[2]*v2[1];
    d[1] = v1[2]*v2[0] - v1[0]*v2[2];
    d[2] = v1[0]*v2[1] - v1[1]*v2[0];
    return d;
}

} /* namespace simd4 */

//  simd4_t类，支持4个或更少元素的向量，主要是实现向量的运算优化
template<typename T, int N>
class simd4_t final
{
private:
//  联合体，用于存储4个元素的向量或N个元素的向量（N<=4）
    union {
       T _v4[4];
       T vec[N];
    };

public:
//  构造函数，初始化为全0
    simd4_t(void) {
        for (int i=0; i<4; ++i) _v4[i] = 0;
    }
//  构造函数，初始化为一个标量
    simd4_t(T s) {
        for (int i=0; i<N; ++i) vec[i] = s;
        for (int i=N; i<4; ++i) _v4[i] = 0;
    }
//  构造函数，初始化为二维向量，其余维度为0
    simd4_t(T x, T y) : simd4_t(x,y,0,0) {}
//  构造函数，初始化为三维向量，其余维度为0
    simd4_t(T x, T y, T z) : simd4_t(x,y,z,0) {}
//  构造函数，初始化为四维向量
    simd4_t(T x, T y, T z, T w) {
        _v4[0] = x; _v4[1] = y; _v4[2] = z; _v4[3] = w;
        for (int i=N; i<4; ++i) _v4[i] = 0;
    }
//  构造函数，由一个数组初始化为N维向量
    explicit simd4_t(const T v[N]) {
        std::memcpy(vec, v, sizeof(T[N]));
        for (int i=N; i<4; ++i) _v4[i] = 0;
    }
//  构造函数，由一个M维向量初始化为N维向量，M与N均不大于4
    template<int M>
    simd4_t(const simd4_t<T,M>& v) {
        std::memcpy(_v4, v.ptr(), sizeof(T[M]));
        for (int i=(M<N)?M:N; i<4; ++i) _v4[i] = 0;
    }
//  析构函数
    ~simd4_t(void) {}   // non-virtual intentional // 非虚拟析构函数，故意的

//  返回一个N维数组的引用
    inline T (&v4(void))[N] {
        return vec;
    }
//  返回一个N维数组的常量引用
    inline const T (&v4(void) const)[N] {
        return vec;
    }

    inline const T (&ptr(void) const)[N] {
        return vec;
    }
//  返回一个N维数组的引用
    inline T (&ptr(void))[N] {
        return vec;
    }
//  []运算符重载，返回第n个元素的常量引用
    inline  const T& operator[](unsigned n) const {
        assert(n<N);
        return vec[n];
    }
//  []运算符重载，返回第n个元素的引用
    inline T& operator[](unsigned n) {
        assert(n<N);
        return vec[n];
    }
//  赋值运算符重载，将一个M维向量赋值给一个N维向量
    template<int M>
    inline simd4_t<T,N>& operator=(const simd4_t<T,M>& v) {
        *this = simd4_t<T,N>(v);
        return *this;
    }
//  +=运算符重载，将一个标量加到N维向量的每个元素上
    inline simd4_t<T,N>& operator+=(T s) {
        for (int i=0; i<N; ++i) {
            vec[i] += s;
        }
        return *this;
    }
//  +=运算符重载，将一个N维数组加到该N维向量上
    inline simd4_t<T,N>& operator+=(const T v[N]) {
        for (int i=0; i<N; ++i) {
           vec[i] += v[i];
        }
        return *this;
    }
//  +=运算符重载，将一个N维向量加到该N维向量上
    inline simd4_t<T,N>& operator+=(const simd4_t<T,N>& v) {
        for (int i=0; i<N; ++i) {
           vec[i] += v[i];
        }
        return *this;
    }
//  -=运算符重载，在该N维向量的每个元素上减去一个标量
    inline simd4_t<T,N>& operator-=(T s) {
        for (int i=0; i<N; ++i) {
           vec[i] -= s;
        }
        return *this;
    }
//  -=运算符重载，在该N维向量上减去一个N维数组
    inline simd4_t<T,N>& operator-=(const T v[N]) {
        for (int i=0; i<N; ++i) {
            vec[i] -= v[i];
        }
        return *this;
    }
//  -=运算符重载，在该N维向量上减去一个N维向量
    inline simd4_t<T,N>& operator-=(const simd4_t<T,N>& v) {
        for (int i=0; i<N; ++i) {
            vec[i] -= v[i];
        }
        return *this;
    }
//  *=运算符重载，将该N维向量的每个元素乘以一个标量
    inline simd4_t<T,N>& operator*=(T s) {
        for (int i=0; i<N; ++i) {
           vec[i] *= s;
        }
        return *this;
    }
//  *=运算符重载，将该N维向量的每个元素乘以一个N维数组每个元素
    inline simd4_t<T,N>& operator*=(const T v[N]) {
        for (int i=0; i<N; ++i) {
           vec[i] *= v[i];
        }
        return *this;
    }
//  *=运算符重载，将该N维向量的每个元素乘以一个N维向量的每个元素
    inline simd4_t<T,N>& operator*=(const simd4_t<T,N>& v) {
        for (int i=0; i<N; ++i) {
           vec[i] *= v[i];
        }
        return *this;
    }
//  /=运算符重载，将该N维向量的每个元素除以一个标量
    inline simd4_t<T,N>& operator/=(T s) {
        for (int i=0; i<N; ++i) {
           vec[i] /= s;
        }
        return *this;
    }
//  /=运算符重载，将该N维向量的每个元素除以一个N维数组每个元素
    inline simd4_t<T,N>& operator/=(const T v[N]) {
        for (int i=0; i<N; ++i) {
           vec[i] /= v[i];
        }
        return *this;
    }
//  /=运算符重载，将该N维向量的每个元素除以一个N维向量的每个元素
    inline simd4_t<T,N>& operator/=(const simd4_t<T,N>& v) {
        for (int i=0; i<N; ++i) {
           vec[i] /= v[i];
        }
        return *this;
    }
};

// 以下均为类外重载
//  -运算符重载，返回一个N维向量的负值
template<typename T, int N>
inline simd4_t<T,N> operator-(const simd4_t<T,N>& v) {
    simd4_t<T,N> r(T(0));
    r -= v;
    return r;
}

//  +运算符重载，返回两个N维向量的和
template<typename T, int N>
inline simd4_t<T,N> operator+(simd4_t<T,N> v1, const simd4_t<T,N>& v2) {
    v1 += v2;
    return v1;
}

//  -运算符重载，返回两个N维向量的差
template<typename T, int N>
inline simd4_t<T,N> operator-(simd4_t<T,N> v1, const simd4_t<T,N>& v2) {
    v1 -= v2;
    return v1;
}

//  *运算符重载，将一个N维向量乘以一个N维向量（对应元素相乘）
template<typename T, int N>
inline simd4_t<T,N> operator*(simd4_t<T,N> v1, const simd4_t<T,N>& v2) {
    v1 *= v2;
    return v1;
}

//  /运算符重载，将一个N维向量除以一个N维向量（对应元素相除）
template<typename T, int N>
inline simd4_t<T,N> operator/(simd4_t<T,N> v1, const simd4_t<T,N>& v2) {
    v1 /= v2;
    return v1;
}

//  *运算符重载，将一个标量乘以一个N维向量
template<typename T, int N>
inline simd4_t<T,N> operator*(T f, simd4_t<T,N> v) {
    v *= f;
    return v;
}

//  *运算符重载，将一个N维向量乘以一个标量
template<typename T, int N>
inline simd4_t<T,N> operator*(simd4_t<T,N> v, T f) {
    v *= f;
    return v;
}

