// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "tdm/Types.h" namespace tdm { template struct vec { using value_type = T; static constexpr dim_t dimensions() { return L; } value_type values[L]; vec() : values{} { } ~vec() = default; vec(const vec& rhs) = default; vec& operator=(const vec& rhs) = default; vec(vec&& rhs) = default; vec& operator=(vec&& rhs) = default; template vec(const vec& rhs) { std::copy(std::begin(rhs.values), std::end(rhs.values), std::begin(values)); } template vec& operator=(const vec& rhs) { std::copy(std::begin(rhs.values), std::end(rhs.values), std::begin(values)); return *this; } template::type* = nullptr> vec(Vs... vs) : values{vs ...} { } template::value && (L > 1)>::type * = nullptr> explicit vec(U v) { std::fill_n(values, dimensions(), v); } template::value>::type* = nullptr> explicit vec(U* pv) { std::copy_n(pv, dimensions(), std::begin(values)); } T& operator[](dim_t index) { assert(index < dimensions()); return values[index]; } const T& operator[](dim_t index) const { assert(index < dimensions()); return values[index]; } template vec& apply(F func) { for (dim_t i{}; i < dimensions(); ++i) { func(values[i], i); } return *this; } template const vec& apply(F func) const { for (dim_t i{}; i < dimensions(); ++i) { func(values[i], i); } return *this; } vec& operator++() { return apply([](T& v, dim_t /*unused*/) { ++v; }); } vec& operator--() { return apply([](T& v, dim_t /*unused*/) { --v; }); } template vec& operator+=(U rhs) { return apply([rhs](T& v, dim_t /*unused*/) { v += rhs; }); } template vec& operator+=(const vec& rhs) { return apply([&rhs](T& v, dim_t i) { v += rhs[i]; }); } vec& operator+=(const vec& rhs) { return operator+=(rhs); } template vec& operator-=(U rhs) { return apply([rhs](T& v, dim_t /*unused*/) { v -= rhs; }); } template vec& operator-=(const vec& rhs) { return apply([&rhs](T& v, dim_t i) { v -= rhs[i]; }); } vec& operator-=(const vec& rhs) { return operator-=(rhs); } template vec& operator*=(U rhs) { return apply([rhs](T& v, dim_t /*unused*/) { v *= rhs; }); } template vec& operator*=(const vec& rhs) { return apply([&rhs](T& v, dim_t i) { v *= rhs[i]; }); } vec& operator*=(const vec& rhs) { return operator*=(rhs); } template vec& operator/=(U rhs) { return apply([rhs](T& v, dim_t /*unused*/) { v /= rhs; }); } template vec& operator/=(const vec& rhs) { return apply([&rhs](T& v, dim_t i) { v /= rhs[i]; }); } vec& operator/=(const vec& rhs) { return operator/=(rhs); } template typename std::enable_if::value, V>::type length() const { const auto& v = *this; return std::sqrt((v * v).sum()); } template typename std::enable_if::value, vec&>::type normalize() { return operator/=(length()); } vec& negate() { return apply([](T& v, dim_t /*unused*/) { v = -v; }); } T sum() const { T retval{}; apply([&retval](const T& v, dim_t /*unused*/) { retval += v; }); return retval; } }; template inline bool operator==(const vec& lhs, const vec& rhs) { bool equal = true; lhs.apply([&equal, &rhs](const T& v, dim_t i) { equal = equal && (v == rhs[i]); }); return equal; } template inline bool operator!=(const vec& lhs, const vec& rhs) { return !(lhs == rhs); } template inline vec operator+(const vec& v) { return v; } template inline vec operator-(vec v) { return v.negate(); } template inline vec operator+(const vec& lhs, const vec& rhs) { return vec(lhs) += rhs; } template inline vec operator+(const vec& lhs, U rhs) { return vec(lhs) += rhs; } template inline vec operator+(T lhs, const vec& rhs) { return vec(lhs) += rhs; } template inline vec operator-(const vec& lhs, const vec& rhs) { return vec(lhs) -= rhs; } template inline vec operator-(const vec& lhs, U rhs) { return vec(lhs) -= rhs; } template inline vec operator-(T lhs, const vec& rhs) { return vec(lhs) -= rhs; } template inline vec operator*(const vec& lhs, const vec& rhs) { return vec(lhs) *= rhs; } template inline typename std::enable_if::value, vec >::type operator*(const vec& lhs, U rhs) { return vec(lhs) *= rhs; } template inline typename std::enable_if::value, vec >::type operator*(T lhs, const vec& rhs) { return vec(lhs) *= rhs; } template inline vec operator/(const vec& lhs, const vec& rhs) { return vec(lhs) /= rhs; } template inline typename std::enable_if::value, vec >::type operator/(const vec& lhs, U rhs) { return vec(lhs) /= rhs; } template inline typename std::enable_if::value, vec >::type operator/(T lhs, const vec& rhs) { return vec(lhs) /= rhs; } template vec applied(const vec& lhs, F func) { vec v{lhs}; v.apply(func); return v; } } // namespace tdm