#ifndef VEC_HXX
#define VEC_HXX
#include "vect.hxx"
#include <cctk.h>
#include <array>
#include <cassert>
#include <functional>
#include <initializer_list>
#include <iostream>
#include <utility>
#include <vector>
#ifdef CCTK_DEBUG
#define ARITH_INLINE
#else
#define ARITH_INLINE CCTK_ATTRIBUTE_ALWAYS_INLINE
#endif
namespace Arith {
using namespace std;
enum class dnup_t : bool { dn, up };
constexpr dnup_t DN = dnup_t::dn;
constexpr dnup_t UP = dnup_t::up;
constexpr dnup_t operator!(const dnup_t dnup) { return dnup_t(!bool(dnup)); }
inline ostream &operator<<(ostream &os, const dnup_t dnup) {
return os << (dnup == DN ? "d" : "u");
}
template <typename T, int D, dnup_t dnup> class vec {
template <typename, int, dnup_t> friend class vec;
vect<T, D> elts;
static constexpr ARITH_INLINE int ind(const int n) {
#ifdef CCTK_DEBUG
assert(n >= 0 && n < D);
#endif
return n;
}
public:
constexpr ARITH_INLINE vec() : elts() {}
constexpr ARITH_INLINE vec(const vec &) = default;
constexpr ARITH_INLINE vec(vec &&) = default;
constexpr ARITH_INLINE vec &operator=(const vec &) = default;
constexpr ARITH_INLINE vec &operator=(vec &&) = default;
template <typename U>
constexpr ARITH_INLINE vec(const vec<U, D, dnup> &x) : elts(x.elts) {}
template <typename U>
constexpr ARITH_INLINE vec(vec<U, D, dnup> &&x) : elts(move(x.elts)) {}
constexpr ARITH_INLINE vec(const vect<T, D> &elts) : elts(elts) {}
constexpr ARITH_INLINE vec(vect<T, D> &&elts) : elts(move(elts)) {}
constexpr ARITH_INLINE vec(initializer_list<T> v) : elts(v) {}
constexpr ARITH_INLINE vec(const array<T, D> &v) : elts(v) {}
constexpr ARITH_INLINE vec(array<T, D> &&v) : elts(move(v)) {}
constexpr ARITH_INLINE vec(const vector<T> &v) : elts(v) {}
constexpr ARITH_INLINE vec(vector<T> &&v) : elts(move(v)) {}
template <typename F, typename = result_of_t<F(int)> >
constexpr ARITH_INLINE vec(F f) : vec(iota().map(f)) {}
static constexpr ARITH_INLINE vec unit(int i) {
vec r;
r(i) = 1;
return r;
}
static constexpr ARITH_INLINE vec<int, D, dnup> iota() {
vec<int, D, dnup> r;
for (int i = 0; i < D; ++i)
r(i) = i;
return r;
}
template <typename F,
typename R = remove_cv_t<remove_reference_t<result_of_t<F(T)> > > >
constexpr ARITH_INLINE vec<R, D, dnup> map(F f) const {
return vec<R, D, dnup>(elts.map(f));
}
template <
typename F, typename U,
typename R = remove_cv_t<remove_reference_t<result_of_t<F(T, U)> > > >
constexpr ARITH_INLINE vec<R, D, dnup> map(F f,
const vec<U, D, dnup> &x) const {
return vec<R, D, dnup>(elts.map(f, x.elt));
}
constexpr ARITH_INLINE const T &operator()(int i) const {
return elts[ind(i)];
}
constexpr ARITH_INLINE T &operator()(int i) { return elts[ind(i)]; }
friend constexpr ARITH_INLINE vec<T, D, dnup>
operator+(const vec<T, D, dnup> &x) {
return {+x.elts};
}
friend constexpr ARITH_INLINE vec<T, D, dnup>
operator-(const vec<T, D, dnup> &x) {
return {-x.elts};
}
friend constexpr ARITH_INLINE vec<T, D, dnup>
operator+(const vec<T, D, dnup> &x, const vec<T, D, dnup> &y) {
return {x.elts + y.elts};
}
friend constexpr ARITH_INLINE vec<T, D, dnup>
operator-(const vec<T, D, dnup> &x, const vec<T, D, dnup> &y) {
return {x.elts - y.elts};
}
friend constexpr ARITH_INLINE vec<T, D, dnup>
operator*(const T &a, const vec<T, D, dnup> &x) {
return {a * x.elts};
}
friend constexpr ARITH_INLINE vec<T, D, dnup>
operator*(const vec<T, D, dnup> &x, const T &a) {
return {x.elts * a};
}
constexpr ARITH_INLINE vec operator+=(const vec &x) {
return *this = *this + x;
}
constexpr ARITH_INLINE vec operator-=(const vec &x) {
return *this = *this - x;
}
constexpr ARITH_INLINE vec operator*=(const T &a) {
return *this = *this * a;
}
constexpr ARITH_INLINE vec operator/=(const T &a) {
return *this = *this / a;
}
friend constexpr ARITH_INLINE bool operator==(const vec<T, D, dnup> &x,
const vec<T, D, dnup> &y) {
return equal_to<vect<T, D> >()(x.elts, y.elts);
}
friend constexpr ARITH_INLINE bool operator!=(const vec<T, D, dnup> &x,
const vec<T, D, dnup> &y) {
return !(x == y);
}
constexpr ARITH_INLINE T maxabs() const { return elts.maxabs(); }
friend ostream &operator<<(ostream &os, const vec<T, D, dnup> &v) {
os << "(" << dnup << ")[";
for (int i = 0; i < D; ++i) {
if (i > 0)
os << ",";
os << v(i);
}
os << "]";
return os;
}
};
}
#undef ARITH_INLINE
#endif