/* * Copyright 2015-2020 Michele "King_DuckZ" Santullo * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "vectorwrapper/vectorwrapper.hpp" #include "vectorwrapper/sequence_bt.hpp" #include "vectorwrapper/size_type.hpp" #include #include #include #include #if defined VWR_OUTER_NAMESPACE namespace VWR_OUTER_NAMESPACE { #endif namespace vwr { namespace implem { //sets value to the index of the first I >= MAX or to sizeof...(I) if //no such value is found template struct find_ge_than_max; template struct find_ge_than_max { static constexpr size_type value = IDX + (I >= MAX ? 0 : 1); }; template struct find_ge_than_max { static constexpr size_type value = (L >= MAX ? IDX : find_ge_than_max::value); }; //helper to identify the invalid index in the build error messages template struct is_invalid_index { static_assert(not INVALID, "Invalid index specified, indices must all be >= 0 and <= dimensions" ); enum { value = 0 }; }; } //namespace implem template class sequence_range; template class sequence_range_iterator : OP, CMP { static_assert(not implem::is_invalid_index< implem::find_ge_than_max::value, sizeof...(I) != implem::find_ge_than_max::value >::value, ""); static_assert(sizeof...(I) > 0, "At least one index must be specified"); typedef sequence_range sequence_range_type; public: explicit sequence_range_iterator (const sequence_range_type& parSeq); sequence_range_iterator (const V& parCurrent, const sequence_range_type& parSeq); ~sequence_range_iterator() = default; sequence_range_iterator& operator++ (); const V& operator*() const { return m_current; } bool operator!= (const sequence_range_iterator& parOther) const; bool operator== (const sequence_range_iterator& parOther) const; private: V m_current; const sequence_range_type& m_seq; size_type m_active_elem; }; template class sequence_range { public: typedef sequence_range_iterator const_iterator; sequence_range (const V& parFrom, const V& parUpper); sequence_range (const V& parFrom, const V& parUpper, const V& parStep); const_iterator cbegin() const; const_iterator cend() const; const_iterator begin() const { return cbegin(); } const_iterator end() const { return cend(); } [[gnu::always_inline]] const V& from() const { return m_from; } [[gnu::always_inline]] const V& upper() const { return m_upper; } [[gnu::always_inline]] const V& step() const { return m_step; } private: V m_from; V m_upper; V m_end; V m_step; }; template class stepping_sequence_range : public sequence_range { public: stepping_sequence_range (const V& parFrom, const V& parUpper, const V& parStep); private: V m_step; }; namespace implem { template struct get_at_index; template struct get_at_index { static constexpr size_type value = N; }; template struct get_at_index { static_assert(SEEK < IDX, "Index out of range"); static constexpr size_type value = 0; }; template struct get_at_index { static constexpr size_type value = (IDX == SEEK ? L : get_at_index::value); }; template struct make_sequence_helper; template struct make_sequence_helper> { typedef sequence_range, OP, CMP, I...> type; }; template inline V make_end_vector (V parFrom, const V& parUpper) { constexpr const size_type last_idx = get_at_index::value; auto& last = parFrom[last_idx]; const auto& upper_last = parUpper[last_idx]; last = upper_last; return parFrom; } } //namespace implem template sequence_range_iterator::sequence_range_iterator (const sequence_range_type& parSeq) : sequence_range_iterator(parSeq.from(), parSeq) { } template sequence_range_iterator::sequence_range_iterator (const V& parCurrent, const sequence_range_type& parSeq) : m_current(parCurrent), m_seq(parSeq), m_active_elem(implem::get_at_index<0, 0, I...>::value) { } template auto sequence_range_iterator::operator++ () -> sequence_range_iterator& { static_assert(sizeof...(I) > 0, "At least one index must be given"); const OP& advance_op = *static_cast(this); const CMP& cmp_op = *static_cast(this); std::array lst {I...}; size_type index = lst[0]; m_current[index] = advance_op(m_current[index], m_seq.step()[index]); if (1 < sizeof...(I) and not cmp_op(m_current[index], m_seq.upper()[index])) { size_type count = 1; do { m_current[index] = m_seq.from()[index]; index = lst[count++]; m_current[index] = advance_op(m_current[index], m_seq.step()[index]); m_active_elem = index; } while (count < sizeof...(I) and not cmp_op(m_current[index], m_seq.upper()[index])); } return *this; } template bool sequence_range_iterator::operator!= (const sequence_range_iterator& parOther) const { return not this->operator==(parOther); } template bool sequence_range_iterator::operator== (const sequence_range_iterator& parOther) const { assert(&m_seq.from() == &parOther.m_seq.from() and &m_seq.upper() == &parOther.m_seq.upper()); const CMP& cmp_op = *static_cast(this); return m_current == parOther.m_current or ( implem::get_at_index::value == m_active_elem and not cmp_op(m_current[m_active_elem], m_seq.upper()[m_active_elem]) ); } template sequence_range::sequence_range (const V& parFrom, const V& parUpper) : m_from(parFrom), m_upper(parUpper), m_end(implem::make_end_vector(parFrom, parUpper)), m_step(1) { } template sequence_range::sequence_range (const V& parFrom, const V& parUpper, const V& parStep) : m_from(parFrom), m_upper(parUpper), m_end(implem::make_end_vector(parFrom, parUpper)), m_step(parStep) { } template auto sequence_range::cbegin() const -> const_iterator { return sequence_range_iterator(*this); } template auto sequence_range::cend() const -> const_iterator { return sequence_range_iterator(m_end, *this); } template using increasing_sequence_range = typename implem::make_sequence_helper< typename V::vector_type, std::plus, std::less, bt::number_range >::type; } //namespace vwr #if defined VWR_OUTER_NAMESPACE } //namespace VWR_OUTER_NAMESPACE #endif