From 0e739c9582e4e6fcf67e909a33aa58f7125a8b08 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Wed, 26 Jul 2017 13:52:30 +0100 Subject: [PATCH 1/9] Broken implementation of vector_iterator. WiP --- .gitignore | 1 + include/vectorwrapper/vector_iterator.hpp | 126 ++++++++++++++++++++++ test/unit/CMakeLists.txt | 1 + test/unit/test_vector_iterator.cpp | 67 ++++++++++++ 4 files changed, 195 insertions(+) create mode 100644 .gitignore create mode 100644 include/vectorwrapper/vector_iterator.hpp create mode 100644 test/unit/test_vector_iterator.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6e92f57 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +tags diff --git a/include/vectorwrapper/vector_iterator.hpp b/include/vectorwrapper/vector_iterator.hpp new file mode 100644 index 0000000..0b92422 --- /dev/null +++ b/include/vectorwrapper/vector_iterator.hpp @@ -0,0 +1,126 @@ +/* + * Copyright 2015-2017 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.hpp" +#include "sequence_bt.hpp" +#include "size_type.hpp" +#include +#include +#include +#include + +#if defined VWR_OUTER_NAMESPACE +namespace VWR_OUTER_NAMESPACE { +#endif + +namespace vwr { + namespace op { + template + struct inc { + T operator() (T parVal) const { return parVal + Inc; } + }; + + template + struct dec { + T operator() (T parVal) const { return parVal - Inc; } + }; + } //namespace op + + template + class vector_iterator : OP, CMP { + //static_assert(VectorWrapperInfo::dimensions >= sizeof...(I), "Start index out of valid range"); + public: + vector_iterator (const V& parFrom, const V& parUpper); + ~vector_iterator() = default; + + vector_iterator& operator++ (); + const V& operator*() const { return m_current; } + bool operator!= (const vector_iterator& parOther) const; + bool operator== (const vector_iterator& parOther) const; + + private: + V m_current; + V m_from; + V m_upper; + }; + + template + vector_iterator::vector_iterator (const V& parFrom, const V& parUpper) : + m_current(parFrom), + m_from(parFrom), + m_upper(parUpper) + { + } + + template + auto vector_iterator::operator++ () -> vector_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]); + if (1 < sizeof...(I) and not cmp_op(m_current[index], m_upper[index])) { + size_type count = 1; + do { + m_current[index] = m_from[index]; + index = lst[count++]; + m_current[index] = advance_op(m_current[index]); + } while (count < sizeof...(I) and not cmp_op(m_current[index], m_upper[index])); + } + + return *this; + } + + template + bool vector_iterator::operator!= (const vector_iterator& parOther) const { + return m_current != parOther.m_current; + } + + template + bool vector_iterator::operator== (const vector_iterator& parOther) const { + return m_current == parOther.m_current; + } + + template + inline vector_iterator make_vector_iterator ( + const Vec& parFrom, + const Vec& parUpper, + bt::number_seq + ) { + return vector_iterator, OP, CMP, I...>(parFrom, parUpper); + } + + template + inline vector_iterator make_vector_iterator_end ( + Vec parFrom, + const Vec& parUpper, + bt::number_seq + ) { + OP advance_op; + auto& last = parFrom[sizeof...(I) - 1]; + const auto& upper_last = parUpper[sizeof...(I) - 1]; + last = advance_op(upper_last); + return vector_iterator, OP, CMP, I...>(parFrom, parUpper); + } +} //namespace vwr + +#if defined VWR_OUTER_NAMESPACE +} //namespace VWR_OUTER_NAMESPACE +#endif diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 52abae0..1ed2532 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -7,6 +7,7 @@ add_executable(${PROJECT_NAME} example.cpp test_get_at.cpp test_operators.cpp + test_vector_iterator.cpp ) target_link_libraries(${PROJECT_NAME} diff --git a/test/unit/test_vector_iterator.cpp b/test/unit/test_vector_iterator.cpp new file mode 100644 index 0000000..c4e818b --- /dev/null +++ b/test/unit/test_vector_iterator.cpp @@ -0,0 +1,67 @@ +/* + * Copyright 2015-2017 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. + */ + +#include "sample_vectors.hpp" +#include "vectorwrapper/vector_iterator.hpp" +#include +#include +#include +#include + +TEST(vwr, vector_iterator) { + using namespace vwr; + + ivec3 from(100, 200, 300); + ivec3 to(102, 203, 304); + auto it = make_vector_iterator, std::less>(from, to, bt::number_range()); + auto it_end = make_vector_iterator_end, std::less>(from, to, bt::number_range()); + + std::array expected{ + ivec3(100, 200, 300), + ivec3(101, 200, 300), + ivec3(100, 201, 300), + ivec3(101, 201, 300), + ivec3(100, 202, 300), + ivec3(101, 202, 300), + ivec3(100, 200, 301), + ivec3(101, 200, 301), + ivec3(100, 201, 301), + ivec3(101, 201, 301), + ivec3(100, 202, 301), + ivec3(101, 202, 301), + ivec3(100, 200, 302), + ivec3(101, 200, 302), + ivec3(100, 201, 302), + ivec3(101, 201, 302), + ivec3(100, 202, 302), + ivec3(101, 202, 302), + ivec3(100, 200, 303), + ivec3(101, 200, 303), + ivec3(100, 201, 303), + ivec3(101, 201, 303), + ivec3(100, 202, 303), + ivec3(101, 202, 303) + }; + std::vector results; + for (; it != it_end; ++it) { + results.push_back(*it); + } + + EXPECT_EQ(expected.size(), results.size()); + for (std::size_t z = 0; z < expected.size(); ++z) { + EXPECT_EQ(expected[z], results[z]); + } +} From 221f236f40f445d7790b1738ea03afb2919a2bd0 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Wed, 26 Jul 2017 21:16:19 +0100 Subject: [PATCH 2/9] Finish implementing the sequence_range feature. --- include/vectorwrapper/sequence_range.hpp | 176 ++++++++++++++++++ include/vectorwrapper/vector_iterator.hpp | 126 ------------- test/unit/CMakeLists.txt | 2 +- ...r_iterator.cpp => test_sequence_range.cpp} | 7 +- 4 files changed, 181 insertions(+), 130 deletions(-) create mode 100644 include/vectorwrapper/sequence_range.hpp delete mode 100644 include/vectorwrapper/vector_iterator.hpp rename test/unit/{test_vector_iterator.cpp => test_sequence_range.cpp} (85%) diff --git a/include/vectorwrapper/sequence_range.hpp b/include/vectorwrapper/sequence_range.hpp new file mode 100644 index 0000000..cfb0447 --- /dev/null +++ b/include/vectorwrapper/sequence_range.hpp @@ -0,0 +1,176 @@ +/* + * Copyright 2015-2017 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.hpp" +#include "sequence_bt.hpp" +#include "size_type.hpp" +#include +#include +#include +#include + +#if defined VWR_OUTER_NAMESPACE +namespace VWR_OUTER_NAMESPACE { +#endif + +namespace vwr { + namespace op { + template + struct inc { + T operator() (T parVal) const { return parVal + Inc; } + }; + + template + struct dec { + T operator() (T parVal) const { return parVal - Inc; } + }; + } //namespace op + + template + class sequence_range_iterator : OP, CMP { + //static_assert(VectorWrapperInfo::dimensions >= sizeof...(I), "Start index out of valid range"); + public: + sequence_range_iterator (const V& parFrom, const V& parUpper); + sequence_range_iterator (const V& parCurrent, const V& parFrom, const V& parUpper); + ~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 V& m_from; + const V& m_upper; + }; + + template + class sequence_range { + public: + typedef sequence_range_iterator const_iterator; + + sequence_range (const V& parFrom, const V& parUpper); + const_iterator cbegin() const; + const_iterator cend() const; + const_iterator begin() const { return cbegin(); } + const_iterator end() const { return cend(); } + + private: + V m_from; + V m_upper; + V m_end; + }; + + namespace implem { + 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) { + auto& last = parFrom[V::dimensions - 1]; + const auto& upper_last = parUpper[V::dimensions - 1]; + last = upper_last; + return parFrom; + } + } //namespace implem + + template + sequence_range_iterator::sequence_range_iterator (const V& parFrom, const V& parUpper) : + m_current(parFrom), + m_from(parFrom), + m_upper(parUpper) + { + } + + template + sequence_range_iterator::sequence_range_iterator (const V& parCurrent, const V& parFrom, const V& parUpper) : + m_current(parCurrent), + m_from(parFrom), + m_upper(parUpper) + { + } + + 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]); + if (1 < sizeof...(I) and not cmp_op(m_current[index], m_upper[index])) { + size_type count = 1; + do { + m_current[index] = m_from[index]; + index = lst[count++]; + m_current[index] = advance_op(m_current[index]); + } while (count < sizeof...(I) and not cmp_op(m_current[index], m_upper[index])); + } + + return *this; + } + + template + bool sequence_range_iterator::operator!= (const sequence_range_iterator& parOther) const { + assert(&m_from == &parOther.m_from and &m_upper == &parOther.m_upper); + return m_current != parOther.m_current; + } + + template + bool sequence_range_iterator::operator== (const sequence_range_iterator& parOther) const { + assert(&m_from == &parOther.m_from and &m_upper == &parOther.m_upper); + return m_current == parOther.m_current; + } + + 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)) + { + } + + template + auto sequence_range::cbegin() const -> const_iterator { + return sequence_range_iterator(m_from, m_upper); + } + + template + auto sequence_range::cend() const -> const_iterator { + return sequence_range_iterator(m_end, m_from, m_upper); + } + + template + using increasing_sequence_range = typename implem::make_sequence_helper< + typename V::vector_type, + op::inc, + std::less, + bt::number_range + >::type; +} //namespace vwr + +#if defined VWR_OUTER_NAMESPACE +} //namespace VWR_OUTER_NAMESPACE +#endif diff --git a/include/vectorwrapper/vector_iterator.hpp b/include/vectorwrapper/vector_iterator.hpp deleted file mode 100644 index 0b92422..0000000 --- a/include/vectorwrapper/vector_iterator.hpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2015-2017 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.hpp" -#include "sequence_bt.hpp" -#include "size_type.hpp" -#include -#include -#include -#include - -#if defined VWR_OUTER_NAMESPACE -namespace VWR_OUTER_NAMESPACE { -#endif - -namespace vwr { - namespace op { - template - struct inc { - T operator() (T parVal) const { return parVal + Inc; } - }; - - template - struct dec { - T operator() (T parVal) const { return parVal - Inc; } - }; - } //namespace op - - template - class vector_iterator : OP, CMP { - //static_assert(VectorWrapperInfo::dimensions >= sizeof...(I), "Start index out of valid range"); - public: - vector_iterator (const V& parFrom, const V& parUpper); - ~vector_iterator() = default; - - vector_iterator& operator++ (); - const V& operator*() const { return m_current; } - bool operator!= (const vector_iterator& parOther) const; - bool operator== (const vector_iterator& parOther) const; - - private: - V m_current; - V m_from; - V m_upper; - }; - - template - vector_iterator::vector_iterator (const V& parFrom, const V& parUpper) : - m_current(parFrom), - m_from(parFrom), - m_upper(parUpper) - { - } - - template - auto vector_iterator::operator++ () -> vector_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]); - if (1 < sizeof...(I) and not cmp_op(m_current[index], m_upper[index])) { - size_type count = 1; - do { - m_current[index] = m_from[index]; - index = lst[count++]; - m_current[index] = advance_op(m_current[index]); - } while (count < sizeof...(I) and not cmp_op(m_current[index], m_upper[index])); - } - - return *this; - } - - template - bool vector_iterator::operator!= (const vector_iterator& parOther) const { - return m_current != parOther.m_current; - } - - template - bool vector_iterator::operator== (const vector_iterator& parOther) const { - return m_current == parOther.m_current; - } - - template - inline vector_iterator make_vector_iterator ( - const Vec& parFrom, - const Vec& parUpper, - bt::number_seq - ) { - return vector_iterator, OP, CMP, I...>(parFrom, parUpper); - } - - template - inline vector_iterator make_vector_iterator_end ( - Vec parFrom, - const Vec& parUpper, - bt::number_seq - ) { - OP advance_op; - auto& last = parFrom[sizeof...(I) - 1]; - const auto& upper_last = parUpper[sizeof...(I) - 1]; - last = advance_op(upper_last); - return vector_iterator, OP, CMP, I...>(parFrom, parUpper); - } -} //namespace vwr - -#if defined VWR_OUTER_NAMESPACE -} //namespace VWR_OUTER_NAMESPACE -#endif diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 1ed2532..8672eeb 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -7,7 +7,7 @@ add_executable(${PROJECT_NAME} example.cpp test_get_at.cpp test_operators.cpp - test_vector_iterator.cpp + test_sequence_range.cpp ) target_link_libraries(${PROJECT_NAME} diff --git a/test/unit/test_vector_iterator.cpp b/test/unit/test_sequence_range.cpp similarity index 85% rename from test/unit/test_vector_iterator.cpp rename to test/unit/test_sequence_range.cpp index c4e818b..96bb7a0 100644 --- a/test/unit/test_vector_iterator.cpp +++ b/test/unit/test_sequence_range.cpp @@ -15,7 +15,7 @@ */ #include "sample_vectors.hpp" -#include "vectorwrapper/vector_iterator.hpp" +#include "vectorwrapper/sequence_range.hpp" #include #include #include @@ -26,8 +26,9 @@ TEST(vwr, vector_iterator) { ivec3 from(100, 200, 300); ivec3 to(102, 203, 304); - auto it = make_vector_iterator, std::less>(from, to, bt::number_range()); - auto it_end = make_vector_iterator_end, std::less>(from, to, bt::number_range()); + auto seq = increasing_sequence_range(from, to); + auto it = seq.begin(); + auto it_end = seq.end(); std::array expected{ ivec3(100, 200, 300), From c1b6bd0500c093864859a296c32d068148c84a4d Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Wed, 26 Jul 2017 22:48:39 +0100 Subject: [PATCH 3/9] Add unit test for backwards iteration. --- test/unit/test_sequence_range.cpp | 35 +++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/test/unit/test_sequence_range.cpp b/test/unit/test_sequence_range.cpp index 96bb7a0..8b6de4b 100644 --- a/test/unit/test_sequence_range.cpp +++ b/test/unit/test_sequence_range.cpp @@ -26,9 +26,6 @@ TEST(vwr, vector_iterator) { ivec3 from(100, 200, 300); ivec3 to(102, 203, 304); - auto seq = increasing_sequence_range(from, to); - auto it = seq.begin(); - auto it_end = seq.end(); std::array expected{ ivec3(100, 200, 300), @@ -56,13 +53,33 @@ TEST(vwr, vector_iterator) { ivec3(100, 202, 303), ivec3(101, 202, 303) }; - std::vector results; - for (; it != it_end; ++it) { - results.push_back(*it); + + { + auto seq = increasing_sequence_range(from, to); + auto it = seq.begin(); + auto it_end = seq.end(); + + std::vector results; + for (; it != it_end; ++it) { + results.push_back(*it); + } + + EXPECT_EQ(expected.size(), results.size()); + for (std::size_t z = 0; z < expected.size(); ++z) { + EXPECT_EQ(expected[z], results[z]); + } } - EXPECT_EQ(expected.size(), results.size()); - for (std::size_t z = 0; z < expected.size(); ++z) { - EXPECT_EQ(expected[z], results[z]); + { + using dec_sequence_range = sequence_range, std::greater, 0, 1, 2>; + std::vector results; + for (auto& itm : dec_sequence_range(to, from)) { + results.push_back(itm); + } + + EXPECT_EQ(expected.size(), results.size()); + for (std::size_t z = 0; z < expected.size(); ++z) { + EXPECT_EQ(expected[z] + 1, results[results.size() - 1 - z]); + } } } From 42f313364037c9ca38e1d279e2db45fc7be440f1 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Wed, 26 Jul 2017 23:31:11 +0100 Subject: [PATCH 4/9] Check that all indices are valid. The code tries to make the compiler spit out which one is the invalid index, if any. --- include/vectorwrapper/sequence_range.hpp | 35 +++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/include/vectorwrapper/sequence_range.hpp b/include/vectorwrapper/sequence_range.hpp index cfb0447..8b47084 100644 --- a/include/vectorwrapper/sequence_range.hpp +++ b/include/vectorwrapper/sequence_range.hpp @@ -41,9 +41,42 @@ namespace vwr { }; } //namespace op + 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_iterator : OP, CMP { - //static_assert(VectorWrapperInfo::dimensions >= sizeof...(I), "Start index out of valid range"); + 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"); public: sequence_range_iterator (const V& parFrom, const V& parUpper); sequence_range_iterator (const V& parCurrent, const V& parFrom, const V& parUpper); From 2ff4301471d8fe2dd5c7a120eb84baa048c117f5 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Wed, 26 Jul 2017 23:53:13 +0100 Subject: [PATCH 5/9] Use the last index, not just the last value in Vec. --- include/vectorwrapper/sequence_range.hpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/include/vectorwrapper/sequence_range.hpp b/include/vectorwrapper/sequence_range.hpp index 8b47084..6618ee0 100644 --- a/include/vectorwrapper/sequence_range.hpp +++ b/include/vectorwrapper/sequence_range.hpp @@ -111,6 +111,18 @@ namespace vwr { }; namespace implem { + template + struct get_at_index; + template + struct get_at_index { + static_assert(SEEK == IDX, "Index out of range"); + static constexpr size_type value = I; + }; + template + struct get_at_index { + static constexpr size_type value = (IDX == SEEK ? L : get_at_index::value); + }; + template struct make_sequence_helper; @@ -119,10 +131,11 @@ namespace vwr { typedef sequence_range, OP, CMP, I...> type; }; - template + template inline V make_end_vector (V parFrom, const V& parUpper) { - auto& last = parFrom[V::dimensions - 1]; - const auto& upper_last = parUpper[V::dimensions - 1]; + 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; } @@ -181,7 +194,7 @@ namespace vwr { 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_end(implem::make_end_vector(parFrom, parUpper)) { } From 9dfa2b0545fcbce7ffc1b5f3cee5da4e4825b41b Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Wed, 26 Jul 2017 23:54:04 +0100 Subject: [PATCH 6/9] Add a convenience operator<< overload for easy printing to std::cout. --- include/vectorwrapper/vector_ostream.hpp | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 include/vectorwrapper/vector_ostream.hpp diff --git a/include/vectorwrapper/vector_ostream.hpp b/include/vectorwrapper/vector_ostream.hpp new file mode 100644 index 0000000..f09d6d5 --- /dev/null +++ b/include/vectorwrapper/vector_ostream.hpp @@ -0,0 +1,36 @@ +/* + * Copyright 2015-2017 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.hpp" +#include "size_type.hpp" +#include + +namespace vwr { + template + inline + std::ostream& operator<< (std::ostream& parStream, const Vec& parVec) { + static_assert(S > 0, "Invalid size"); + + parStream << '<'; + for (size_type z = 0; z < S - 1; ++z) { + parStream << parVec[z] << ','; + } + parStream << parVec[S - 1] << '>'; + return parStream; + } +} //namespace vwr From e242f0b154c575dffdecee7fb6313958c1323b7b Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Thu, 27 Jul 2017 20:48:52 +0100 Subject: [PATCH 7/9] Allow an iteration step. --- include/vectorwrapper/sequence_range.hpp | 81 ++++++++++++++---------- test/unit/test_sequence_range.cpp | 2 +- 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/include/vectorwrapper/sequence_range.hpp b/include/vectorwrapper/sequence_range.hpp index 6618ee0..2c30b27 100644 --- a/include/vectorwrapper/sequence_range.hpp +++ b/include/vectorwrapper/sequence_range.hpp @@ -29,18 +29,6 @@ namespace VWR_OUTER_NAMESPACE { #endif namespace vwr { - namespace op { - template - struct inc { - T operator() (T parVal) const { return parVal + Inc; } - }; - - template - struct dec { - T operator() (T parVal) const { return parVal - Inc; } - }; - } //namespace op - namespace implem { //sets value to the index of the first I >= MAX or to sizeof...(I) if //no such value is found @@ -70,6 +58,9 @@ namespace vwr { }; } //namespace implem + template + class sequence_range; + template class sequence_range_iterator : OP, CMP { static_assert(not implem::is_invalid_index< @@ -77,9 +68,11 @@ namespace vwr { 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: - sequence_range_iterator (const V& parFrom, const V& parUpper); - sequence_range_iterator (const V& parCurrent, const V& parFrom, const V& parUpper); + 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++ (); @@ -89,8 +82,7 @@ namespace vwr { private: V m_current; - const V& m_from; - const V& m_upper; + const sequence_range_type& m_seq; }; template @@ -99,15 +91,28 @@ namespace vwr { 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 { @@ -142,18 +147,16 @@ namespace vwr { } //namespace implem template - sequence_range_iterator::sequence_range_iterator (const V& parFrom, const V& parUpper) : - m_current(parFrom), - m_from(parFrom), - m_upper(parUpper) + sequence_range_iterator::sequence_range_iterator (const sequence_range_type& parSeq) : + m_current(parSeq.from()), + m_seq(parSeq) { } template - sequence_range_iterator::sequence_range_iterator (const V& parCurrent, const V& parFrom, const V& parUpper) : + sequence_range_iterator::sequence_range_iterator (const V& parCurrent, const sequence_range_type& parSeq) : m_current(parCurrent), - m_from(parFrom), - m_upper(parUpper) + m_seq(parSeq) { } @@ -165,14 +168,14 @@ namespace vwr { std::array lst {I...}; size_type index = lst[0]; - m_current[index] = advance_op(m_current[index]); - if (1 < sizeof...(I) and not cmp_op(m_current[index], m_upper[index])) { + 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_from[index]; + m_current[index] = m_seq.from()[index]; index = lst[count++]; - m_current[index] = advance_op(m_current[index]); - } while (count < sizeof...(I) and not cmp_op(m_current[index], m_upper[index])); + m_current[index] = advance_op(m_current[index], m_seq.step()[index]); + } while (count < sizeof...(I) and not cmp_op(m_current[index], m_seq.upper()[index])); } return *this; @@ -180,13 +183,13 @@ namespace vwr { template bool sequence_range_iterator::operator!= (const sequence_range_iterator& parOther) const { - assert(&m_from == &parOther.m_from and &m_upper == &parOther.m_upper); + assert(&m_seq.from() == &parOther.m_seq.from() and &m_seq.upper() == &parOther.m_seq.upper()); return m_current != parOther.m_current; } template bool sequence_range_iterator::operator== (const sequence_range_iterator& parOther) const { - assert(&m_from == &parOther.m_from and &m_upper == &parOther.m_upper); + assert(&m_seq.from() == &parOther.m_seq.from() and &m_seq.upper() == &parOther.m_seq.upper()); return m_current == parOther.m_current; } @@ -194,24 +197,34 @@ namespace vwr { 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_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(m_from, m_upper); + return sequence_range_iterator(*this); } template auto sequence_range::cend() const -> const_iterator { - return sequence_range_iterator(m_end, m_from, m_upper); + return sequence_range_iterator(m_end, *this); } template using increasing_sequence_range = typename implem::make_sequence_helper< typename V::vector_type, - op::inc, + std::plus, std::less, bt::number_range >::type; diff --git a/test/unit/test_sequence_range.cpp b/test/unit/test_sequence_range.cpp index 8b6de4b..cede4f0 100644 --- a/test/unit/test_sequence_range.cpp +++ b/test/unit/test_sequence_range.cpp @@ -71,7 +71,7 @@ TEST(vwr, vector_iterator) { } { - using dec_sequence_range = sequence_range, std::greater, 0, 1, 2>; + using dec_sequence_range = sequence_range, std::greater, 0, 1, 2>; std::vector results; for (auto& itm : dec_sequence_range(to, from)) { results.push_back(itm); From 445d7b5e27bc239a251383d05c5b5977dfdc07cc Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Thu, 27 Jul 2017 20:54:49 +0100 Subject: [PATCH 8/9] Forward to the other ctor. --- include/vectorwrapper/sequence_range.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/vectorwrapper/sequence_range.hpp b/include/vectorwrapper/sequence_range.hpp index 2c30b27..5f5ec22 100644 --- a/include/vectorwrapper/sequence_range.hpp +++ b/include/vectorwrapper/sequence_range.hpp @@ -148,8 +148,7 @@ namespace vwr { template sequence_range_iterator::sequence_range_iterator (const sequence_range_type& parSeq) : - m_current(parSeq.from()), - m_seq(parSeq) + sequence_range_iterator(parSeq.from(), parSeq) { } From d9dacb739a14f9da2bd90f6c458c02ca279a24d3 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Wed, 2 Aug 2017 23:37:25 +0100 Subject: [PATCH 9/9] Properly stop looping when vec values go past the end. --- include/vectorwrapper/sequence_range.hpp | 26 ++++++++++++++++-------- test/unit/test_sequence_range.cpp | 12 +++++++++++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/include/vectorwrapper/sequence_range.hpp b/include/vectorwrapper/sequence_range.hpp index 5f5ec22..9260fee 100644 --- a/include/vectorwrapper/sequence_range.hpp +++ b/include/vectorwrapper/sequence_range.hpp @@ -83,6 +83,7 @@ namespace vwr { private: V m_current; const sequence_range_type& m_seq; + size_type m_active_elem; }; template @@ -118,10 +119,14 @@ namespace vwr { namespace implem { template struct get_at_index; - template - struct get_at_index { - static_assert(SEEK == IDX, "Index out of range"); - static constexpr size_type value = I; + 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 { @@ -155,7 +160,8 @@ namespace vwr { template sequence_range_iterator::sequence_range_iterator (const V& parCurrent, const sequence_range_type& parSeq) : m_current(parCurrent), - m_seq(parSeq) + m_seq(parSeq), + m_active_elem(implem::get_at_index<0, 0, I...>::value) { } @@ -174,6 +180,7 @@ namespace vwr { 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])); } @@ -182,14 +189,17 @@ namespace vwr { 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()); - return m_current != parOther.m_current; + 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()); - return m_current == parOther.m_current; + 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 diff --git a/test/unit/test_sequence_range.cpp b/test/unit/test_sequence_range.cpp index cede4f0..652f63d 100644 --- a/test/unit/test_sequence_range.cpp +++ b/test/unit/test_sequence_range.cpp @@ -82,4 +82,16 @@ TEST(vwr, vector_iterator) { EXPECT_EQ(expected[z] + 1, results[results.size() - 1 - z]); } } + + { + auto seq = increasing_sequence_range(from, to, ivec3(3)); + std::vector results; + for (auto& itm : seq) { + results.push_back(itm); + } + + ASSERT_EQ(2, results.size()); + EXPECT_EQ(ivec3(100, 200, 300), results[0]); + EXPECT_EQ(ivec3(100, 200, 303), results[1]); + } }