/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * * Martin Renou * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XSIMD_ITERATOR_HPP #define XSIMD_ITERATOR_HPP namespace xsimd { template class batch_proxy; template struct simd_batch_traits> : simd_batch_traits { }; template struct simd_batch_inner_types> { using batch_reference = X; using const_batch_reference = X; }; /** * Aligned proxy that iterators can dereference to */ template class batch_proxy : public simd_base> { public: using self_type = batch_proxy; using base_type = simd_type; using batch_reference = typename base_type::batch_reference; using const_batch_reference = typename base_type::const_batch_reference; using batch_type = B; using value_type = typename B::value_type; using pointer = value_type*; batch_proxy(pointer ptr); batch_reference get(); const_batch_reference get() const; self_type& set(const batch_type& rhs); self_type& set(const self_type& rhs); operator batch_type() const; batch_proxy& operator=(const batch_type& rhs); private: value_type* m_ptr; }; template struct is_proxy : std::false_type { }; template struct is_proxy> : std::true_type { }; template std::ostream& operator<<(std::ostream& os, const batch_proxy& bp) { return os << bp.get(); } template class aligned_iterator { public: using self_type = aligned_iterator; using batch_type = B; using value_type = typename B::value_type; static constexpr std::size_t batch_size = B::size; using proxy_type = batch_proxy; using pointer = value_type*; using reference = proxy_type; aligned_iterator(pointer memory); reference operator*(); void operator++(int); aligned_iterator& operator++(); bool equal(const aligned_iterator& rhs) const; private: pointer m_cur_pointer; }; /****************************** * batch proxy implementation * *****************************/ template inline batch_proxy::batch_proxy(pointer ptr) : m_ptr(ptr) { } template inline auto batch_proxy::get() -> batch_reference { return batch_type(*this); } template inline auto batch_proxy::get() const -> const_batch_reference { return batch_type(*this); } template inline auto batch_proxy::set(const batch_type& rhs) -> self_type& { xsimd::store_aligned(m_ptr, rhs); return *this; } template inline auto batch_proxy::set(const self_type& rhs) -> self_type& { xsimd::store_aligned(m_ptr, rhs.get()); return *this; } template inline batch_proxy::operator batch_type() const { batch_type m_reg; m_reg.load_aligned(m_ptr); return m_reg; } template inline auto batch_proxy::operator=(const batch_type& rhs) -> batch_proxy& { xsimd::store_aligned(m_ptr, rhs); return *this; } /*********************************** * aligned iterator implementation * ***********************************/ template inline aligned_iterator::aligned_iterator(pointer memory) : m_cur_pointer(memory) { } template inline auto aligned_iterator::operator*() -> reference { return m_cur_pointer; } template inline aligned_iterator& aligned_iterator::operator++() { m_cur_pointer += batch_size; return *this; } template inline void aligned_iterator::operator++(int) { m_cur_pointer += batch_size; } template inline bool aligned_iterator::equal(const aligned_iterator& rhs) const { return m_cur_pointer == rhs.m_cur_pointer; } template inline bool operator==(const aligned_iterator& lhs, const aligned_iterator& rhs) { return lhs.equal(rhs); } template inline bool operator!=(const aligned_iterator& lhs, const aligned_iterator& rhs) { return !lhs.equal(rhs); } #if defined(_WIN32) && defined(__clang__) // See comment at the end of simd_base.hpp template inline B fma(const batch_proxy& a, const batch_proxy& b, const batch_proxy& c) { using base_type = simd_base>; const base_type& sba = a; const base_type& sbb = b; const base_type& sbc = c; return fma(sba, sbb, sbc); } #endif } #endif