#ifndef CK_ARRAY_HPP #define CK_ARRAY_HPP #include "Sequence.hpp" #include "functional2.hpp" namespace ck { template struct Array { using type = Array; using data_type = TData; index_t mData[NSize]; __host__ __device__ explicit constexpr Array() {} template __host__ __device__ explicit constexpr Array(X x, Xs... xs) : mData{static_cast(x), static_cast(xs)...} { static_assert(sizeof...(Xs) + 1 == NSize, "wrong! size"); } #if 0 template __host__ __device__ explicit constexpr Array(const T& x) { static_assert(T::Size() == NSize, "wrong! size"); static_for<0, NSize, 1>{}([&](auto i){ mData[i] = x.At(i); }) } #endif __host__ __device__ static constexpr index_t Size() { return NSize; } __host__ __device__ static constexpr index_t GetSize() { return Size(); } template __host__ __device__ constexpr const TData& At(Number) const { static_assert(I < NSize, "wrong!"); return mData[I]; } template __host__ __device__ constexpr TData& At(Number) { static_assert(I < NSize, "wrong!"); return mData[I]; } __host__ __device__ constexpr const TData& At(index_t i) const { return mData[i]; } __host__ __device__ constexpr TData& At(index_t i) { return mData[i]; } template __host__ __device__ constexpr const TData& operator[](I i) const { return At(i); } template __host__ __device__ constexpr TData& operator()(I i) { return At(i); } template __host__ __device__ constexpr type& operator=(const T& x) { static_for<0, Size(), 1>{}([&](auto i) { operator()(i) = x[i]; }); return *this; } struct lambda_PushBack // emulate constexpr lambda { const Array& old_array; Array& new_array; __host__ __device__ constexpr lambda_PushBack(const Array& old_array_, Array& new_array_) : old_array(old_array_), new_array(new_array_) { } template __host__ __device__ constexpr void operator()(Number) const { new_array(Number{}) = old_array[I]; } }; __host__ __device__ constexpr auto PushBack(TData x) const { Array new_array; static_for<0, NSize, 1>{}(lambda_PushBack(*this, new_array)); new_array(Number{}) = x; return new_array; } }; // Arr: Array // Picks: Sequence<...> template struct ArrayElementPicker { using type = ArrayElementPicker; using data_type = typename Arr::data_type; __host__ __device__ constexpr ArrayElementPicker() = delete; __host__ __device__ explicit constexpr ArrayElementPicker(Arr& array) : mArray{array} { constexpr index_t imax = accumulate_on_sequence(Picks{}, math::maxer{}, Number<0>{}); static_assert(imax < Arr::Size(), "wrong! exceeding # array element"); } __host__ __device__ static constexpr auto Size() { return Picks::Size(); } template __host__ __device__ constexpr const data_type& At(Number) const { static_assert(I < Size(), "wrong!"); constexpr auto IP = Picks{}[I]; return mArray[IP]; } template __host__ __device__ constexpr data_type& At(Number) { static_assert(I < Size(), "wrong!"); constexpr auto IP = Picks{}[I]; return mArray(IP); } template __host__ __device__ constexpr const data_type& operator[](I i) const { return At(i); } template __host__ __device__ constexpr data_type& operator()(I i) { return At(i); } template __host__ __device__ constexpr type& operator=(const T& a) { static_for<0, Size(), 1>{}([&](auto i) { operator()(i) = a[i]; }); return *this; } Arr& mArray; }; template __host__ __device__ constexpr auto pick_array_element(Arr& a, Picks) { return ArrayElementPicker(a); } #if 1 template __host__ __device__ constexpr auto to_array(const T& x) { Array y; static_for<0, T::Size(), 1>{}([&](auto i) { y.At(i) = x.At(i); }); return y; } #endif template __host__ __device__ constexpr auto sequence2array(Sequence) { return Array{Is...}; } template __host__ __device__ constexpr auto make_zero_array() { constexpr auto zero_sequence = typename uniform_sequence_gen::type{}; constexpr auto zero_array = sequence2array(zero_sequence); return zero_array; } template __host__ __device__ constexpr auto reorder_array_given_new2old(const Array& old_array, Sequence /*new2old*/) { static_assert(NSize == sizeof...(IRs), "NSize not consistent"); static_assert(is_valid_sequence_map>{}, "wrong! invalid reorder map"); return Array{old_array[IRs]...}; } template struct lambda_reorder_array_given_old2new { const Array& old_array; Array& new_array; __host__ __device__ constexpr lambda_reorder_array_given_old2new( const Array& old_array_, Array& new_array_) : old_array(old_array_), new_array(new_array_) { } template __host__ __device__ constexpr void operator()(Number) const { TData old_data = old_array[IOldDim]; constexpr index_t INewDim = MapOld2New::At(Number{}); new_array(Number{}) = old_data; } }; template __host__ __device__ constexpr auto reorder_array_given_old2new(const Array& old_array, Sequence /*old2new*/) { Array new_array; static_assert(NSize == sizeof...(IRs), "NSize not consistent"); static_assert(is_valid_sequence_map>::value, "wrong! invalid reorder map"); static_for<0, NSize, 1>{}( lambda_reorder_array_given_old2new>(old_array, new_array)); return new_array; } template __host__ __device__ constexpr auto extract_array(const Array& old_array, ExtractSeq) { Array new_array; constexpr index_t new_size = ExtractSeq::GetSize(); static_assert(new_size <= NSize, "wrong! too many extract"); static_for<0, new_size, 1>{}([&](auto I) { new_array(I) = old_array[ExtractSeq::At(I)]; }); return new_array; } template // emulate constepxr lambda for array // math struct lambda_array_math { const F& f; const X& x; const Y& y; Z& z; __host__ __device__ constexpr lambda_array_math(const F& f_, const X& x_, const Y& y_, Z& z_) : f(f_), x(x_), y(y_), z(z_) { } template __host__ __device__ constexpr void operator()(Number) const { constexpr auto IDim = Number{}; z(IDim) = f(x[IDim], y[IDim]); } }; // Array = Array + Array template __host__ __device__ constexpr auto operator+(Array a, Array b) { Array result; auto f = math::plus{}; static_for<0, NSize, 1>{}( lambda_array_math( f, a, b, result)); return result; } // Array = Array - Array template __host__ __device__ constexpr auto operator-(Array a, Array b) { Array result; auto f = math::minus{}; static_for<0, NSize, 1>{}( lambda_array_math( f, a, b, result)); return result; } // Array += Array template __host__ __device__ constexpr auto operator+=(Array& a, Array b) { a = a + b; return a; } // Array -= Array template __host__ __device__ constexpr auto operator-=(Array& a, Array b) { a = a - b; return a; } // Array = Array + Sequence template __host__ __device__ constexpr auto operator+(Array a, Sequence b) { static_assert(sizeof...(Is) == NSize, "wrong! size not the same"); Array result; auto f = math::plus{}; static_for<0, NSize, 1>{}( lambda_array_math( f, a, b, result)); return result; } // Array = Array - Sequence template __host__ __device__ constexpr auto operator-(Array a, Sequence b) { static_assert(sizeof...(Is) == NSize, "wrong! size not the same"); Array result; auto f = math::minus{}; static_for<0, NSize, 1>{}( lambda_array_math( f, a, b, result)); return result; } // Array = Array * Sequence template __host__ __device__ constexpr auto operator*(Array a, Sequence b) { static_assert(sizeof...(Is) == NSize, "wrong! size not the same"); Array result; auto f = math::multiplies{}; static_for<0, NSize, 1>{}( lambda_array_math( f, a, b, result)); return result; } // Array = Sequence - Array template __host__ __device__ constexpr auto operator-(Sequence a, Array b) { static_assert(sizeof...(Is) == NSize, "wrong! size not the same"); Array result; auto f = math::minus{}; static_for<0, NSize, 1>{}( lambda_array_math( f, a, b, result)); return result; } template __host__ __device__ constexpr TData accumulate_on_array(const Array& a, Reduce f, TData init) { TData result = init; static_assert(NSize > 0, "wrong"); static_for<0, NSize, 1>{}([&](auto I) { result = f(result, a[I]); }); return result; } } // namespace ck #endif