/* enoki/stl.h -- vectorization support for STL pairs, tuples, and arrays Enoki is a C++ template library that enables transparent vectorization of numerical kernels using SIMD instruction sets available on current processor architectures. Copyright (c) 2019 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #pragma once #include NAMESPACE_BEGIN(enoki) template struct struct_support> { static constexpr bool IsDynamic = enoki::is_dynamic_v || enoki::is_dynamic_v; using Dynamic = std::pair, enoki::make_dynamic_t>; using Value = std::pair; static ENOKI_INLINE size_t slices(const Value &value) { return enoki::slices(value.first); } static ENOKI_INLINE size_t packets(const Value &value) { return enoki::packets(value.first); } static ENOKI_INLINE void set_slices(Value &value, size_t size) { enoki::set_slices(value.first, size); enoki::set_slices(value.second, size); } template static ENOKI_INLINE auto packet(T2 &&value, size_t i) { return std::pair( enoki::packet(value.first, i), enoki::packet(value.second, i)); } template static ENOKI_INLINE auto slice(T2 &&value, size_t i) { return std::pair( enoki::slice(value.first, i), enoki::slice(value.second, i)); } template static ENOKI_INLINE auto slice_ptr(T2 &&value, size_t i) { return std::pair( enoki::slice_ptr(value.first, i), enoki::slice_ptr(value.second, i)); } template static ENOKI_INLINE auto ref_wrap(T2 &&value) { return std::pair( enoki::ref_wrap(value.first), enoki::ref_wrap(value.second)); } template static ENOKI_INLINE auto masked(T2 &&value, const Mask &mask) { return std::pair( enoki::masked(value.first, mask), enoki::masked(value.second, mask)); } template static ENOKI_INLINE void scatter(T2 &dst, const Value &value, const Index &index, const Mask &mask) { enoki::scatter(dst.first, value.first, index, mask); enoki::scatter(dst.second, value.second, index, mask); } template static ENOKI_INLINE Value gather(const T2 &src, const Index &index, const Mask &mask) { return Value( enoki::gather(src.first, index, mask), enoki::gather(src.second, index, mask) ); } static ENOKI_INLINE Value zero(size_t size) { return Value(enoki::zero(size), enoki::zero(size)); } static ENOKI_INLINE Value empty(size_t size) { return Value(enoki::empty(size), enoki::empty(size)); } }; template struct struct_support> { static constexpr bool IsDynamic = std::disjunction_v...>; using Dynamic = std::tuple...>; using Value = std::tuple; static ENOKI_INLINE size_t slices(const Value &value) { return enoki::slices(std::get<0>(value)); } static ENOKI_INLINE size_t packets(const Value &value) { return enoki::packets(std::get<0>(value)); } static ENOKI_INLINE void set_slices(Value &value, size_t size) { set_slices(value, size, std::make_index_sequence()); } template static ENOKI_INLINE auto packet(T2 &&value, size_t i) { return packet(std::forward(value), i, std::make_index_sequence()); } template static ENOKI_INLINE auto slice(T2 &&value, size_t i) { return slice(std::forward(value), i, std::make_index_sequence()); } template static ENOKI_INLINE auto slice_ptr(T2 &&value, size_t i) { return slice_ptr(std::forward(value), i, std::make_index_sequence()); } template static ENOKI_INLINE auto ref_wrap(T2 &&value) { return ref_wrap(std::forward(value), std::make_index_sequence()); } template static ENOKI_INLINE auto masked(T2 &&value, const Mask &mask) { return masked(value, mask, std::make_index_sequence()); } static ENOKI_INLINE Value zero(size_t size) { return Value(enoki::zero(size)...); } static ENOKI_INLINE Value empty(size_t size) { return Value(enoki::empty(size)...); } template static ENOKI_INLINE void scatter(T2 &dst, const Value &value, const Index &index, const Mask &mask) { scatter(dst, value, index, mask, std::make_index_sequence()); } template static ENOKI_INLINE Value gather(const T2 &src, const Index &index, const Mask &mask) { return gather(src, index, mask, std::make_index_sequence()); } private: template static ENOKI_INLINE void set_slices(Value &value, size_t i, std::index_sequence) { bool unused[] = { (enoki::set_slices(std::get(value), i), false)..., false }; (void) unused; } template static ENOKI_INLINE auto packet(T2 &&value, size_t i, std::index_sequence) { return std::tuple(value), i))...>( enoki::packet(std::get(value), i)...); } template static ENOKI_INLINE auto slice(T2 &&value, size_t i, std::index_sequence) { return std::tuple(value), i))...>( enoki::slice(std::get(value), i)...); } template static ENOKI_INLINE auto slice_ptr(T2 &&value, size_t i, std::index_sequence) { return std::tuple(value), i))...>( enoki::slice_ptr(std::get(value), i)...); } template static ENOKI_INLINE auto ref_wrap(T2 &&value, std::index_sequence) { return std::tuple(value)))...>( enoki::ref_wrap(std::get(value))...); } template static ENOKI_INLINE auto masked(T2 &&value, const Mask &mask, std::index_sequence) { return std::tuple(value), mask))...>( enoki::masked(std::get(value), mask)...); } template static ENOKI_INLINE void scatter(T2 &dst, const Value &value, const Index &index, const Mask &mask, std::index_sequence) { bool unused[] = { (enoki::scatter(std::get(dst), std::get(value), index, mask), false)..., false }; ENOKI_MARK_USED(unused); } template static ENOKI_INLINE Value gather(const T2 &src, const Index &index, const Mask &mask, std::index_sequence) { return Value( enoki::gather>(std::get(src), index, mask)... ); } }; template struct struct_support> { static constexpr bool IsDynamic = enoki::is_dynamic_v; using Dynamic = std::array, Size>; using Value = std::array; static ENOKI_INLINE size_t slices(const Value &value) { return enoki::slices(value[0]); } static ENOKI_INLINE size_t packets(const Value &value) { return enoki::packets(value[0]); } static ENOKI_INLINE void set_slices(Value &value, size_t size) { for (size_t i = 0; i < Size; ++i) enoki::set_slices(value[i], size); } template static ENOKI_INLINE auto packet(T2 &&value, size_t i) { return packet(std::forward(value), i, std::make_index_sequence()); } template static ENOKI_INLINE auto slice(T2 &&value, size_t i) { return slice(std::forward(value), i, std::make_index_sequence()); } template static ENOKI_INLINE auto slice_ptr(T2 &&value, size_t i) { return slice_ptr(std::forward(value), i, std::make_index_sequence()); } template static ENOKI_INLINE auto ref_wrap(T2 &&value) { return ref_wrap(std::forward(value), std::make_index_sequence()); } template static ENOKI_INLINE auto masked(T2 &value, const Mask &mask) { return masked(value, mask, std::make_index_sequence()); } template static ENOKI_INLINE void scatter(T2 &dst, const Value &value, const Index &index, const Mask &mask) { scatter(dst, value, index, mask, std::make_index_sequence()); } template static ENOKI_INLINE Value gather(const T2 &src, const Index &index, const Mask &mask) { return gather(src, index, mask, std::make_index_sequence()); } static ENOKI_INLINE auto zero(size_t size) { return zero(size, std::make_index_sequence()); } static ENOKI_INLINE auto empty(size_t size) { return empty(size, std::make_index_sequence()); } private: template static ENOKI_INLINE auto packet(T2 &&value, size_t i, std::index_sequence) { return std::array{{ enoki::packet(value[Index], i)...}}; } template static ENOKI_INLINE auto slice(T2 &&value, size_t i, std::index_sequence) { return std::array{{ enoki::slice(value[Index], i)...}}; } template static ENOKI_INLINE auto slice_ptr(T2 &&value, size_t i, std::index_sequence) { return std::array{{ enoki::slice_ptr(value[Index], i)...}}; } template static ENOKI_INLINE auto ref_wrap(T2 &&value, std::index_sequence) { return std::array{{ enoki::ref_wrap(value[Index])...}}; } template static ENOKI_INLINE auto masked(T2 &value, const Mask &mask, std::index_sequence) { return std::array{{ enoki::masked(value[Index], mask)...}}; } template static ENOKI_INLINE auto zero(size_t size, std::index_sequence) { return Value{{ zero(Index, size)... }}; } template static ENOKI_INLINE auto empty(size_t size, std::index_sequence) { return Value{{ empty(Index, size)... }}; } template static ENOKI_INLINE void scatter(T2 &dst, const Value &value, const Index &index, const Mask &mask, std::index_sequence) { bool unused[] = { (enoki::scatter(dst[Is], value[Is], index, mask), false)..., false }; ENOKI_MARK_USED(unused); } template static ENOKI_INLINE Value gather(const T2 &src, const Index &index, const Mask &mask, std::index_sequence) { return Value{ enoki::gather(src[Is], index, mask)... }; } }; NAMESPACE_END(enoki)