From c178704ad28e642dec9c0cf9f5837317923be252 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 27 Sep 2016 11:03:00 -0700 Subject: [PATCH 001/403] update readme for c++14 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0f7d2d0a..498da157 100644 --- a/README.md +++ b/README.md @@ -657,8 +657,8 @@ for (auto&& i : chain.from_iterable(matrix)) { reversed ------- -*Additional Requirements*: Input must have `.rbegin()` and `.rend()`, or be -a plain C array. +*Additional Requirements*: Input must be compatible with `std::rbegin()` and +`std::rend()` Iterates over elements of a sequence in reverse order. From d410f2f4053d763c7bc307bc2390360e85617b51 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 6 Oct 2016 10:14:10 -0700 Subject: [PATCH 002/403] Update README.md adds twitter handle that I will optimistically use. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 498da157..a02a9b50 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ evaluation wherever possible. *Note*: Everthing is inside the `iter` namespace. +[@cppitertools on twitter](https://twitter.com/cppitertools) + #### Table of Contents [range](#range)
[enumerate](#enumerate)
From 394cc4debcd037db199551546b6fbc3ea3066722 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 7 Oct 2016 10:50:41 -0700 Subject: [PATCH 003/403] follow me XD --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a02a9b50..a740372d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ evaluation wherever possible. *Note*: Everthing is inside the `iter` namespace. -[@cppitertools on twitter](https://twitter.com/cppitertools) +Follow [@cppitertools](https://twitter.com/cppitertools) for updates. #### Table of Contents [range](#range)
From 57b7fa038567a08c740b6997746080eea9c31025 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 29 Oct 2016 00:03:13 -0700 Subject: [PATCH 004/403] Adds test for "base_iterator" --- test/test_base_iterator.cpp | 190 ++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 test/test_base_iterator.cpp diff --git a/test/test_base_iterator.cpp b/test/test_base_iterator.cpp new file mode 100644 index 00000000..8f323392 --- /dev/null +++ b/test/test_base_iterator.cpp @@ -0,0 +1,190 @@ +// NOTE this header tests implementation details + +#include "internal/base_iterator.hpp" +#include "catch.hpp" + + +// I'm using a std::vector of 1 int instead of just an int in order to give +// the iterator types non-trivial constructors, destructors, and assignment. + +// same begin() and end() types +struct SameTypes { + struct iterator { + iterator(int) : value_(1) { } + + bool operator!=(const iterator& other) const { return value_ != other.value_; } + iterator& operator++() { ++value_.front(); return *this; } + const int& operator*() const { return value_.front(); } + std::vector value_; // non-trvial operations + }; + + iterator begin() const { return {0}; } + iterator end() const { return {0}; } +}; + + +// different begin() and end() types +struct DifferentTypes { + struct iterator; + struct end_iterator; + struct iterator { + iterator(int i) : value_(1, i) {} + + bool operator!=(const iterator& other) const { return value() != other.value(); } + bool operator!=(const end_iterator&) const { return value() != 3; } + iterator& operator++() { ++value_.front(); return *this; } + const int& operator*() const { return value(); } + + const int& value() const { return value_.front(); } + std::vector value_; + }; + + struct end_iterator { + end_iterator(int){} + + bool operator!=(const end_iterator&) const { return false; } + bool operator!=(const iterator& other) const { return other.value() != 3; } + end_iterator& operator++() { return *this; } + const int& operator*() const { assert(false); return value(); } + + const int& value() const { return value_.front(); } + std::vector value_{}; + }; + + iterator begin() const { return {0}; } + end_iterator end() const { return {0}; } +}; + +// Explicit instatiations, which could cause failures if the implementation +// details of the implementation details change. +template class iter::impl::BaseIteratorImpl; +template class iter::impl::BaseIteratorImpl; + +using iter::impl::BaseIterator; + + +TEST_CASE("ensure test type iterators are totally comparable", "[test_util") { + { + SameTypes s{}; + auto it = s.begin(); + (void)(it != it); + } + + { + DifferentTypes d{}; + auto b = d.begin(); + auto e = d.end(); + (void)(b != b); + (void)(e != e); + (void)(b != e); + (void)(e != b); + } +} + + +TEST_CASE("Same and different iterator types gets the correct BaseIterator", + "[base_iterator]") { + REQUIRE(( + std::is_same, + iter::impl::BaseIteratorImpl>{})); + REQUIRE(( + std::is_same, + iter::impl::BaseIteratorImpl>{})); +} + +TEST_CASE("Operations on BaseIterators with SameTypes work", + "[base_iterator]") { + SameTypes s; + BaseIterator it(s.begin()); + REQUIRE(it.same_iterator_types); + REQUIRE(it.deref() == 0); + it.inc(); + REQUIRE(it.deref() == 1); +} + +TEST_CASE("Operations on BaseIterators with DifferentTypes work", + "[base_iterator]") { + DifferentTypes d; + using BI = BaseIterator; + BI it(d.begin()); + REQUIRE(it.deref() == 0); + it.inc(); + REQUIRE(it.deref() == 1); + + BI it2(d.begin()); + + REQUIRE(it.not_equal(it2)); + REQUIRE(it2.not_equal(it)); + it2.inc(); + + REQUIRE_FALSE(it.not_equal(it2)); + REQUIRE_FALSE(it2.not_equal(it)); + + BI bend(d.end()); + REQUIRE(it.not_equal(bend)); + REQUIRE(bend.not_equal(it)); + + it.inc(); + it.inc(); + REQUIRE_FALSE(it.not_equal(bend)); + REQUIRE_FALSE(bend.not_equal(it)); +} + +TEST_CASE("Can copy construct a BaseIterator with SameTypes", + "[base_iterator]") { + SameTypes s; + using BI = BaseIterator; + BI it(s.begin()); + BI it2(it); + REQUIRE_FALSE(it.not_equal(it2)); + it2.inc(); + REQUIRE(it.not_equal(it2)); +} + + +TEST_CASE("Can copy assign a BaseIterator with SameTypes", "[base_iterator]") { + SameTypes s; + using BI = BaseIterator; + BI it(s.begin()); + BI it2(s.begin()); + REQUIRE_FALSE(it.not_equal(it2)); + it2.inc(); + REQUIRE(it.not_equal(it2)); + it = it2; + REQUIRE_FALSE(it.not_equal(it2)); +} + +TEST_CASE("Can copy construct a BaseIterator with DifferentTypes", + "[base_iterator]") { + using BI = BaseIterator; + DifferentTypes d; + BI it(d.begin()); + BI it2(it); + REQUIRE_FALSE(it.not_equal(it2)); + it.inc(); + REQUIRE(it.not_equal(it2)); +} + +TEST_CASE("Can copy construct a BaseIterator with DifferenTypes", + "[base_iterator]") { + using BI = BaseIterator; + DifferentTypes d; + BI it(d.begin()); + BI it2(it); + it = it2; + // break assignment into a different test + REQUIRE_FALSE(it.not_equal(it2)); + BI it_end(d.end()); + REQUIRE(it.not_equal(it_end)); + SECTION("normal = end") { + it = it_end; + REQUIRE_FALSE(it.not_equal(it_end)); + } + SECTION("end = normal") { + it_end = BI{d.begin()}; + REQUIRE_FALSE(it.not_equal(it_end)); + } +} + + +// TODO test move operations From 63c7273f9be1c8ce769c09dd2c34f01e22b341e1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 29 Oct 2016 00:03:27 -0700 Subject: [PATCH 005/403] Adds BaseIterator This is suppose to handle an iterable with different types for begin() and end(). In the case where they are the same, there should be little, if any, overhead generally. If they are different, there is some branching that needs to happen but it doesn't seem too bad. --- internal/base_iterator.hpp | 179 +++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100755 internal/base_iterator.hpp diff --git a/internal/base_iterator.hpp b/internal/base_iterator.hpp new file mode 100755 index 00000000..a8d9ce9f --- /dev/null +++ b/internal/base_iterator.hpp @@ -0,0 +1,179 @@ +#ifndef ITERTOOLS_BASE_ITERATOR_HPP_ +#define ITERTOOLS_BASE_ITERATOR_HPP_ + +#include "iterbase.hpp" +#include + +namespace iter { +namespace impl { +// iterator_end_type is the type of C's end iterator +template +using iterator_end_type = decltype(std::end(std::declval())); + +template +class BaseIteratorImpl; + +template +using BaseIterator = impl::BaseIteratorImpl, + impl::iterator_end_type>{}>; +} +} + + +// Container's begin() and end() are the same type. +template +class iter::impl::BaseIteratorImpl { + private: + static_assert( + std::is_same, iterator_end_type>{}, + ""); + using SubIter = iterator_type; + + SubIter sub_iter_; + public: + static constexpr bool same_iterator_types = true; + BaseIteratorImpl() = default; + BaseIteratorImpl(SubIter&& it) : sub_iter_(std::move(it)) { } + + // I'm choosing to use named functions so that they aren't accidentally + // used by subclasses + bool not_equal(const BaseIteratorImpl& other) const { + return sub_iter_ != other.sub_iter_; + } + + void inc() { + ++sub_iter_; + } + + // TODO implement const deref? + decltype(auto) deref() { + return *sub_iter_; + } +}; + +template +class iter::impl::BaseIteratorImpl { + private: + static_assert( + !std::is_same, iterator_end_type>{}, + ""); + + using SubIter = iterator_type; + using SubEnd = iterator_end_type; + + enum class IterState { Normal, End, Uninitialized}; + + void destroy_sub() { + if (state_ == IterState::Normal) { + sub_iter_.~SubIter(); + } else if (state_ == IterState::End) { + sub_end_.~SubEnd(); + } + state_ = IterState::Uninitialized; + } + + template + void copy_or_move_sub_from(T&& other) { + if (this == &other) { return; } + if (state_ == other.state_) { + if (state_ == IterState::Normal) { + sub_iter_ = std::forward(other).sub_iter_; + } else if (state_ == IterState::End) { + sub_end_ = std::forward(other).sub_end_; + } + } else { + // state_s are different, must destroy and reconstruct + destroy_sub(); + if (other.state_ == IterState::Normal) { + new (&sub_iter_) SubIter(std::forward(other).sub_iter_); + } else if (other.state_ == IterState::End) { + new (&sub_end_) SubEnd(std::forward(other).sub_end_); + } + state_ = other.state_; + } + } + + + void copy_sub_from(const BaseIteratorImpl& other) { + copy_or_move_sub_from(other); + } + + void move_sub_from(BaseIteratorImpl&& other) { + copy_or_move_sub_from(std::move(other)); + } + + // TODO replace with std::variant when C++17 is going strong + union { + SubIter sub_iter_; + SubEnd sub_end_; + }; + IterState state_{IterState::Uninitialized}; + + public: + BaseIteratorImpl() {} + + BaseIteratorImpl(const BaseIteratorImpl& other) { + copy_sub_from(other); + } + + BaseIteratorImpl& operator=(const BaseIteratorImpl& other) { + copy_sub_from(other); + return *this; + } + + BaseIteratorImpl(BaseIteratorImpl&& other) { + move_sub_from(std::move(other)); + } + + BaseIteratorImpl& operator=(BaseIteratorImpl&& other) { + move_sub_from(std::move(other)); + return *this; + } + + BaseIteratorImpl(SubIter&& it) + : sub_iter_{std::move(it)}, + state_{IterState::Normal} { } + + BaseIteratorImpl(SubEnd&& it) + : sub_end_(std::move(it)), + state_{IterState::End} { } + + void inc() { + assert(state_ == IterState::Normal); // because ++ing the end is UB + ++sub_iter_; + } + + // TODO implement const deref? + decltype(auto) deref() { + assert(state_ == IterState::Normal); //because *ing the end is UB + return *sub_iter_; + } + + bool not_equal(const BaseIteratorImpl& other) const { + assert(state_ != IterState::Uninitialized + && other.state_ != IterState::Uninitialized); + if (state_ == other.state_) { + if (state_ == IterState::End) { + return sub_end_ != other.sub_end_; + } else { + return sub_iter_ != other.sub_iter_; + } + } else { + if(state_ == IterState::Normal) { // other is End + return sub_iter_ != other.sub_end_; + } else { // other is Normal + return sub_end_ != other.sub_iter_; + } + } + } + + ~BaseIteratorImpl() { + this->destroy_sub(); + } + +}; + + + +#endif From 31959056bb14cb42126d100f7d5a1569d7bd2059 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 29 Oct 2016 00:11:46 -0700 Subject: [PATCH 006/403] Replaces inc/deref/not_equal with ++/*/!= I originally thought BaseIter would be a base class for the other iterators, now I'm thinking composition will be better. --- internal/base_iterator.hpp | 14 +++++---- test/test_base_iterator.cpp | 62 ++++++++++++++++++------------------- 2 files changed, 39 insertions(+), 37 deletions(-) diff --git a/internal/base_iterator.hpp b/internal/base_iterator.hpp index a8d9ce9f..daccaa1e 100755 --- a/internal/base_iterator.hpp +++ b/internal/base_iterator.hpp @@ -38,16 +38,17 @@ class iter::impl::BaseIteratorImpl { // I'm choosing to use named functions so that they aren't accidentally // used by subclasses - bool not_equal(const BaseIteratorImpl& other) const { + bool operator!=(const BaseIteratorImpl& other) const { return sub_iter_ != other.sub_iter_; } - void inc() { + BaseIteratorImpl& operator++() { ++sub_iter_; + return *this; } // TODO implement const deref? - decltype(auto) deref() { + decltype(auto) operator*() { return *sub_iter_; } }; @@ -139,18 +140,19 @@ class iter::impl::BaseIteratorImpl { : sub_end_(std::move(it)), state_{IterState::End} { } - void inc() { + BaseIteratorImpl& operator++() { assert(state_ == IterState::Normal); // because ++ing the end is UB ++sub_iter_; + return *this; } // TODO implement const deref? - decltype(auto) deref() { + decltype(auto) operator*() { assert(state_ == IterState::Normal); //because *ing the end is UB return *sub_iter_; } - bool not_equal(const BaseIteratorImpl& other) const { + bool operator!=(const BaseIteratorImpl& other) const { assert(state_ != IterState::Uninitialized && other.state_ != IterState::Uninitialized); if (state_ == other.state_) { diff --git a/test/test_base_iterator.cpp b/test/test_base_iterator.cpp index 8f323392..98981415 100644 --- a/test/test_base_iterator.cpp +++ b/test/test_base_iterator.cpp @@ -97,9 +97,9 @@ TEST_CASE("Operations on BaseIterators with SameTypes work", SameTypes s; BaseIterator it(s.begin()); REQUIRE(it.same_iterator_types); - REQUIRE(it.deref() == 0); - it.inc(); - REQUIRE(it.deref() == 1); + REQUIRE(*it == 0); + ++it; + REQUIRE(*it == 1); } TEST_CASE("Operations on BaseIterators with DifferentTypes work", @@ -107,27 +107,27 @@ TEST_CASE("Operations on BaseIterators with DifferentTypes work", DifferentTypes d; using BI = BaseIterator; BI it(d.begin()); - REQUIRE(it.deref() == 0); - it.inc(); - REQUIRE(it.deref() == 1); + REQUIRE(*it == 0); + ++it; + REQUIRE(*it == 1); BI it2(d.begin()); - REQUIRE(it.not_equal(it2)); - REQUIRE(it2.not_equal(it)); - it2.inc(); + REQUIRE(it != it2); + REQUIRE(it2 != it); + ++it2; - REQUIRE_FALSE(it.not_equal(it2)); - REQUIRE_FALSE(it2.not_equal(it)); + REQUIRE_FALSE(it != it2); + REQUIRE_FALSE(it2 != it); BI bend(d.end()); - REQUIRE(it.not_equal(bend)); - REQUIRE(bend.not_equal(it)); + REQUIRE(it != bend); + REQUIRE(bend != it); - it.inc(); - it.inc(); - REQUIRE_FALSE(it.not_equal(bend)); - REQUIRE_FALSE(bend.not_equal(it)); + ++it; + ++it; + REQUIRE_FALSE(it != bend); + REQUIRE_FALSE(bend != it); } TEST_CASE("Can copy construct a BaseIterator with SameTypes", @@ -136,9 +136,9 @@ TEST_CASE("Can copy construct a BaseIterator with SameTypes", using BI = BaseIterator; BI it(s.begin()); BI it2(it); - REQUIRE_FALSE(it.not_equal(it2)); - it2.inc(); - REQUIRE(it.not_equal(it2)); + REQUIRE_FALSE(it != it2); + ++it2; + REQUIRE(it != it2); } @@ -147,11 +147,11 @@ TEST_CASE("Can copy assign a BaseIterator with SameTypes", "[base_iterator]") { using BI = BaseIterator; BI it(s.begin()); BI it2(s.begin()); - REQUIRE_FALSE(it.not_equal(it2)); - it2.inc(); - REQUIRE(it.not_equal(it2)); + REQUIRE_FALSE(it != it2); + ++it2; + REQUIRE(it != it2); it = it2; - REQUIRE_FALSE(it.not_equal(it2)); + REQUIRE_FALSE(it != it2); } TEST_CASE("Can copy construct a BaseIterator with DifferentTypes", @@ -160,9 +160,9 @@ TEST_CASE("Can copy construct a BaseIterator with DifferentTypes", DifferentTypes d; BI it(d.begin()); BI it2(it); - REQUIRE_FALSE(it.not_equal(it2)); - it.inc(); - REQUIRE(it.not_equal(it2)); + REQUIRE_FALSE(it != it2); + ++it; + REQUIRE(it != it2); } TEST_CASE("Can copy construct a BaseIterator with DifferenTypes", @@ -173,16 +173,16 @@ TEST_CASE("Can copy construct a BaseIterator with DifferenTypes", BI it2(it); it = it2; // break assignment into a different test - REQUIRE_FALSE(it.not_equal(it2)); + REQUIRE_FALSE(it != it2); BI it_end(d.end()); - REQUIRE(it.not_equal(it_end)); + REQUIRE(it != it_end); SECTION("normal = end") { it = it_end; - REQUIRE_FALSE(it.not_equal(it_end)); + REQUIRE_FALSE(it != it_end); } SECTION("end = normal") { it_end = BI{d.begin()}; - REQUIRE_FALSE(it.not_equal(it_end)); + REQUIRE_FALSE(it != it_end); } } From a712dc6b1472e3c6ffea6c47e8778c117d03c653 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 29 Oct 2016 00:28:33 -0700 Subject: [PATCH 007/403] If begin() and end() are the same, no wrapping. Rather than a thin wrapper around whatever the iterator type is, an extra layer jammed in the middle can make it actually directly use that iterator type rather than wrapping it in a way that only really serves to limit it. --- internal/base_iterator.hpp | 54 +++++++++++++------------------------ test/test_base_iterator.cpp | 20 +++++--------- 2 files changed, 25 insertions(+), 49 deletions(-) diff --git a/internal/base_iterator.hpp b/internal/base_iterator.hpp index daccaa1e..b46b27ed 100755 --- a/internal/base_iterator.hpp +++ b/internal/base_iterator.hpp @@ -10,51 +10,33 @@ namespace impl { template using iterator_end_type = decltype(std::end(std::declval())); -template +template class BaseIteratorImpl; + +// If begin and end return the same type, type will be iterator_type +// If begin and end return different types, type will be BaseIteratorImpl +template +struct BaseIteratorImplType; + +template +struct BaseIteratorImplType +: type_is>{}; + template -using BaseIterator = impl::BaseIteratorImpl +: type_is>{}; + +template +using BaseIterator = typename BaseIteratorImplType, - impl::iterator_end_type>{}>; + impl::iterator_end_type>{}>::type; } } -// Container's begin() and end() are the same type. -template -class iter::impl::BaseIteratorImpl { - private: - static_assert( - std::is_same, iterator_end_type>{}, - ""); - using SubIter = iterator_type; - - SubIter sub_iter_; - public: - static constexpr bool same_iterator_types = true; - BaseIteratorImpl() = default; - BaseIteratorImpl(SubIter&& it) : sub_iter_(std::move(it)) { } - - // I'm choosing to use named functions so that they aren't accidentally - // used by subclasses - bool operator!=(const BaseIteratorImpl& other) const { - return sub_iter_ != other.sub_iter_; - } - - BaseIteratorImpl& operator++() { - ++sub_iter_; - return *this; - } - - // TODO implement const deref? - decltype(auto) operator*() { - return *sub_iter_; - } -}; - template -class iter::impl::BaseIteratorImpl { +class iter::impl::BaseIteratorImpl { private: static_assert( !std::is_same, iterator_end_type>{}, diff --git a/test/test_base_iterator.cpp b/test/test_base_iterator.cpp index 98981415..db2062f0 100644 --- a/test/test_base_iterator.cpp +++ b/test/test_base_iterator.cpp @@ -57,8 +57,7 @@ struct DifferentTypes { // Explicit instatiations, which could cause failures if the implementation // details of the implementation details change. -template class iter::impl::BaseIteratorImpl; -template class iter::impl::BaseIteratorImpl; +template class iter::impl::BaseIteratorImpl; using iter::impl::BaseIterator; @@ -82,21 +81,13 @@ TEST_CASE("ensure test type iterators are totally comparable", "[test_util") { } -TEST_CASE("Same and different iterator types gets the correct BaseIterator", - "[base_iterator]") { - REQUIRE(( - std::is_same, - iter::impl::BaseIteratorImpl>{})); - REQUIRE(( - std::is_same, - iter::impl::BaseIteratorImpl>{})); -} - TEST_CASE("Operations on BaseIterators with SameTypes work", "[base_iterator]") { SameTypes s; BaseIterator it(s.begin()); - REQUIRE(it.same_iterator_types); + REQUIRE((std::is_same< + std::decay_t, + std::decay_t>{})); REQUIRE(*it == 0); ++it; REQUIRE(*it == 1); @@ -107,6 +98,9 @@ TEST_CASE("Operations on BaseIterators with DifferentTypes work", DifferentTypes d; using BI = BaseIterator; BI it(d.begin()); + REQUIRE((!std::is_same< + std::decay_t, + std::decay_t>{})); REQUIRE(*it == 0); ++it; REQUIRE(*it == 1); From 508f44cce832a91e6cfcb8769b97c20120fe3059 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 19 Feb 2017 13:16:23 -0800 Subject: [PATCH 008/403] Renames BaseIterator to IteratorWrapper Originally wanted BaseIterator to be a base class. The new name is more honest about what it does. --- ...base_iterator.hpp => iterator_wrapper.hpp} | 45 +++++++++---------- test/SConstruct | 1 + ...iterator.cpp => test_iterator_wrapper.cpp} | 30 ++++++------- 3 files changed, 38 insertions(+), 38 deletions(-) rename internal/{base_iterator.hpp => iterator_wrapper.hpp} (76%) rename test/{test_base_iterator.cpp => test_iterator_wrapper.cpp} (81%) diff --git a/internal/base_iterator.hpp b/internal/iterator_wrapper.hpp similarity index 76% rename from internal/base_iterator.hpp rename to internal/iterator_wrapper.hpp index b46b27ed..6d241020 100755 --- a/internal/base_iterator.hpp +++ b/internal/iterator_wrapper.hpp @@ -1,5 +1,5 @@ -#ifndef ITERTOOLS_BASE_ITERATOR_HPP_ -#define ITERTOOLS_BASE_ITERATOR_HPP_ +#ifndef ITERTOOLS_ITERATOR_WRAPPER_HPP_ +#define ITERTOOLS_ITERATOR_WRAPPER_HPP_ #include "iterbase.hpp" #include @@ -11,24 +11,24 @@ template using iterator_end_type = decltype(std::end(std::declval())); template -class BaseIteratorImpl; +class IteratorWrapperImpl; // If begin and end return the same type, type will be iterator_type -// If begin and end return different types, type will be BaseIteratorImpl +// If begin and end return different types, type will be IteratorWrapperImpl template -struct BaseIteratorImplType; +struct IteratorWrapperImplType; template -struct BaseIteratorImplType +struct IteratorWrapperImplType : type_is>{}; template -struct BaseIteratorImplType -: type_is>{}; +struct IteratorWrapperImplType +: type_is>{}; template -using BaseIterator = typename BaseIteratorImplType, impl::iterator_end_type>{}>::type; } @@ -36,7 +36,7 @@ using BaseIterator = typename BaseIteratorImplType -class iter::impl::BaseIteratorImpl { +class iter::impl::IteratorWrapperImpl { private: static_assert( !std::is_same, iterator_end_type>{}, @@ -78,11 +78,11 @@ class iter::impl::BaseIteratorImpl { } - void copy_sub_from(const BaseIteratorImpl& other) { + void copy_sub_from(const IteratorWrapperImpl& other) { copy_or_move_sub_from(other); } - void move_sub_from(BaseIteratorImpl&& other) { + void move_sub_from(IteratorWrapperImpl&& other) { copy_or_move_sub_from(std::move(other)); } @@ -94,35 +94,35 @@ class iter::impl::BaseIteratorImpl { IterState state_{IterState::Uninitialized}; public: - BaseIteratorImpl() {} + IteratorWrapperImpl() {} - BaseIteratorImpl(const BaseIteratorImpl& other) { + IteratorWrapperImpl(const IteratorWrapperImpl& other) { copy_sub_from(other); } - BaseIteratorImpl& operator=(const BaseIteratorImpl& other) { + IteratorWrapperImpl& operator=(const IteratorWrapperImpl& other) { copy_sub_from(other); return *this; } - BaseIteratorImpl(BaseIteratorImpl&& other) { + IteratorWrapperImpl(IteratorWrapperImpl&& other) { move_sub_from(std::move(other)); } - BaseIteratorImpl& operator=(BaseIteratorImpl&& other) { + IteratorWrapperImpl& operator=(IteratorWrapperImpl&& other) { move_sub_from(std::move(other)); return *this; } - BaseIteratorImpl(SubIter&& it) + IteratorWrapperImpl(SubIter&& it) : sub_iter_{std::move(it)}, state_{IterState::Normal} { } - BaseIteratorImpl(SubEnd&& it) + IteratorWrapperImpl(SubEnd&& it) : sub_end_(std::move(it)), state_{IterState::End} { } - BaseIteratorImpl& operator++() { + IteratorWrapperImpl& operator++() { assert(state_ == IterState::Normal); // because ++ing the end is UB ++sub_iter_; return *this; @@ -134,7 +134,7 @@ class iter::impl::BaseIteratorImpl { return *sub_iter_; } - bool operator!=(const BaseIteratorImpl& other) const { + bool operator!=(const IteratorWrapperImpl& other) const { assert(state_ != IterState::Uninitialized && other.state_ != IterState::Uninitialized); if (state_ == other.state_) { @@ -152,12 +152,11 @@ class iter::impl::BaseIteratorImpl { } } - ~BaseIteratorImpl() { + ~IteratorWrapperImpl() { this->destroy_sub(); } }; - #endif diff --git a/test/SConstruct b/test/SConstruct index cbf3cd3c..d2198470 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -43,6 +43,7 @@ progs = Split( zip iteratoriterator + iterator_wrapper iterbase mixed helpers diff --git a/test/test_base_iterator.cpp b/test/test_iterator_wrapper.cpp similarity index 81% rename from test/test_base_iterator.cpp rename to test/test_iterator_wrapper.cpp index db2062f0..0f0a210b 100644 --- a/test/test_base_iterator.cpp +++ b/test/test_iterator_wrapper.cpp @@ -1,6 +1,6 @@ // NOTE this header tests implementation details -#include "internal/base_iterator.hpp" +#include "internal/iterator_wrapper.hpp" #include "catch.hpp" @@ -57,9 +57,9 @@ struct DifferentTypes { // Explicit instatiations, which could cause failures if the implementation // details of the implementation details change. -template class iter::impl::BaseIteratorImpl; +template class iter::impl::IteratorWrapperImpl; -using iter::impl::BaseIterator; +using iter::impl::IteratorWrapper; TEST_CASE("ensure test type iterators are totally comparable", "[test_util") { @@ -81,10 +81,10 @@ TEST_CASE("ensure test type iterators are totally comparable", "[test_util") { } -TEST_CASE("Operations on BaseIterators with SameTypes work", +TEST_CASE("Operations on IteratorWrappers with SameTypes work", "[base_iterator]") { SameTypes s; - BaseIterator it(s.begin()); + IteratorWrapper it(s.begin()); REQUIRE((std::is_same< std::decay_t, std::decay_t>{})); @@ -93,10 +93,10 @@ TEST_CASE("Operations on BaseIterators with SameTypes work", REQUIRE(*it == 1); } -TEST_CASE("Operations on BaseIterators with DifferentTypes work", +TEST_CASE("Operations on IteratorWrappers with DifferentTypes work", "[base_iterator]") { DifferentTypes d; - using BI = BaseIterator; + using BI = IteratorWrapper; BI it(d.begin()); REQUIRE((!std::is_same< std::decay_t, @@ -124,10 +124,10 @@ TEST_CASE("Operations on BaseIterators with DifferentTypes work", REQUIRE_FALSE(bend != it); } -TEST_CASE("Can copy construct a BaseIterator with SameTypes", +TEST_CASE("Can copy construct a IteratorWrapper with SameTypes", "[base_iterator]") { SameTypes s; - using BI = BaseIterator; + using BI = IteratorWrapper; BI it(s.begin()); BI it2(it); REQUIRE_FALSE(it != it2); @@ -136,9 +136,9 @@ TEST_CASE("Can copy construct a BaseIterator with SameTypes", } -TEST_CASE("Can copy assign a BaseIterator with SameTypes", "[base_iterator]") { +TEST_CASE("Can copy assign a IteratorWrapper with SameTypes", "[base_iterator]") { SameTypes s; - using BI = BaseIterator; + using BI = IteratorWrapper; BI it(s.begin()); BI it2(s.begin()); REQUIRE_FALSE(it != it2); @@ -148,9 +148,9 @@ TEST_CASE("Can copy assign a BaseIterator with SameTypes", "[base_iterator]") { REQUIRE_FALSE(it != it2); } -TEST_CASE("Can copy construct a BaseIterator with DifferentTypes", +TEST_CASE("Can copy construct a IteratorWrapper with DifferentTypes", "[base_iterator]") { - using BI = BaseIterator; + using BI = IteratorWrapper; DifferentTypes d; BI it(d.begin()); BI it2(it); @@ -159,9 +159,9 @@ TEST_CASE("Can copy construct a BaseIterator with DifferentTypes", REQUIRE(it != it2); } -TEST_CASE("Can copy construct a BaseIterator with DifferenTypes", +TEST_CASE("Can copy construct a IteratorWrapper with DifferenTypes", "[base_iterator]") { - using BI = BaseIterator; + using BI = IteratorWrapper; DifferentTypes d; BI it(d.begin()); BI it2(it); From 24bde75170a23ed046abc33e1363a2cbb6d71127 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 19 Feb 2017 18:45:47 -0800 Subject: [PATCH 009/403] Doesn't actually compare end iterators range-v3 sentinels can't be compared, but if both iterators are of "end" type, they must (or should?) be equal. --- internal/iterator_wrapper.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/iterator_wrapper.hpp b/internal/iterator_wrapper.hpp index 6d241020..8b9d050a 100755 --- a/internal/iterator_wrapper.hpp +++ b/internal/iterator_wrapper.hpp @@ -139,7 +139,10 @@ class iter::impl::IteratorWrapperImpl { && other.state_ != IterState::Uninitialized); if (state_ == other.state_) { if (state_ == IterState::End) { - return sub_end_ != other.sub_end_; + // NOTE this used to be return sub_end_ != other.sub_end_; + // but rangev3 sentinels aren't comparable + // https://github.com/ericniebler/range-v3/issues/564 + return false; } else { return sub_iter_ != other.sub_iter_; } From 310a01b8a5f19f2509e33ae485f61fcbde661a47 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 19 Feb 2017 19:05:37 -0800 Subject: [PATCH 010/403] IteratorWrapper default constructs SubIter Instead of leaving uninitialized. This seems more correct, and will make the eventual switch to std::variant more straight forward. --- internal/iterator_wrapper.hpp | 2 +- test/test_iterator_wrapper.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/iterator_wrapper.hpp b/internal/iterator_wrapper.hpp index 8b9d050a..a817323c 100755 --- a/internal/iterator_wrapper.hpp +++ b/internal/iterator_wrapper.hpp @@ -94,7 +94,7 @@ class iter::impl::IteratorWrapperImpl { IterState state_{IterState::Uninitialized}; public: - IteratorWrapperImpl() {} + IteratorWrapperImpl() : IteratorWrapperImpl(SubIter{}) {} IteratorWrapperImpl(const IteratorWrapperImpl& other) { copy_sub_from(other); diff --git a/test/test_iterator_wrapper.cpp b/test/test_iterator_wrapper.cpp index 0f0a210b..b3b99f2d 100644 --- a/test/test_iterator_wrapper.cpp +++ b/test/test_iterator_wrapper.cpp @@ -28,6 +28,7 @@ struct DifferentTypes { struct iterator; struct end_iterator; struct iterator { + iterator() : value_{} { REQUIRE(false); } iterator(int i) : value_(1, i) {} bool operator!=(const iterator& other) const { return value() != other.value(); } @@ -40,6 +41,7 @@ struct DifferentTypes { }; struct end_iterator { + end_iterator() { REQUIRE(false); } end_iterator(int){} bool operator!=(const end_iterator&) const { return false; } From 99b05d3fc87aa3f073bea8984b02b73805c30734 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 19 Feb 2017 19:45:54 -0800 Subject: [PATCH 011/403] Moves iterator tuple aliases into their own header I want these to use iterator_wrapper.hpp, which includes iterbase.hpp, gotta resolve the circular dependency. --- chain.hpp | 1 + internal/iter_tuples.hpp | 59 ++++++++++++++++++++++++++++++++++++++++ internal/iterbase.hpp | 49 --------------------------------- zip.hpp | 1 + zip_longest.hpp | 1 + 5 files changed, 62 insertions(+), 49 deletions(-) create mode 100644 internal/iter_tuples.hpp diff --git a/chain.hpp b/chain.hpp index 38e7eb69..bce306b6 100644 --- a/chain.hpp +++ b/chain.hpp @@ -2,6 +2,7 @@ #define ITER_CHAIN_HPP_ #include "internal/iterbase.hpp" +#include "internal/iter_tuples.hpp" #include #include diff --git a/internal/iter_tuples.hpp b/internal/iter_tuples.hpp new file mode 100644 index 00000000..a70c3fd2 --- /dev/null +++ b/internal/iter_tuples.hpp @@ -0,0 +1,59 @@ +#ifndef ITERTOOLS_ITER_TUPLES_HPP_ +#define ITERTOOLS_ITER_TUPLES_HPP_ + +#include "iterbase.hpp" + +namespace iter { + namespace impl { + namespace detail { + template + std::tuple...> iterator_tuple_deref_helper( + const std::tuple&); + } + + namespace detail { + template + std::tuple...> iterator_tuple_type_helper( + const std::tuple&); + } + // Given a tuple template argument, evaluates to a tuple of iterators + // for the template argument's contained types. + template + using iterator_tuple_type = + decltype(detail::iterator_tuple_type_helper(std::declval())); + + // Given a tuple template argument, evaluates to a tuple of + // what the iterators for the template argument's contained types + // dereference to + template + using iterator_deref_tuple = decltype( + detail::iterator_tuple_deref_helper(std::declval())); + + // ---- Tuple utilities ---- // + + // function absorbing all arguments passed to it. used when + // applying a function to a parameter pack but not passing the evaluated + // results anywhere + template + void absorb(Ts&&...) {} + + namespace detail { + template + decltype(auto) call_with_tuple_impl( + Func&& mf, TupleType&& tup, std::index_sequence) { + return mf(std::forward>>(std::get(tup))...); + } + } + + // expand a TupleType into individual arguments when calling a Func + template + decltype(auto) call_with_tuple(Func&& mf, TupleType&& tup) { + constexpr auto TUP_SIZE = std::tuple_size>::value; + return detail::call_with_tuple_impl(std::forward(mf), + std::forward(tup), std::make_index_sequence{}); + } + } +} + +#endif diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index aa6d6a2c..ad547d66 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -192,55 +192,6 @@ namespace iter { : std::integral_constant::value && are_same::value> {}; - namespace detail { - template - std::tuple...> iterator_tuple_deref_helper( - const std::tuple&); - } - - namespace detail { - template - std::tuple...> iterator_tuple_type_helper( - const std::tuple&); - } - // Given a tuple template argument, evaluates to a tuple of iterators - // for the template argument's contained types. - template - using iterator_tuple_type = - decltype(detail::iterator_tuple_type_helper(std::declval())); - - // Given a tuple template argument, evaluates to a tuple of - // what the iterators for the template argument's contained types - // dereference to - template - using iterator_deref_tuple = decltype( - detail::iterator_tuple_deref_helper(std::declval())); - - // ---- Tuple utilities ---- // - - // function absorbing all arguments passed to it. used when - // applying a function to a parameter pack but not passing the evaluated - // results anywhere - template - void absorb(Ts&&...) {} - - namespace detail { - template - decltype(auto) call_with_tuple_impl( - Func&& mf, TupleType&& tup, std::index_sequence) { - return mf(std::forward>>(std::get(tup))...); - } - } - - // expand a TupleType into individual arguments when calling a Func - template - decltype(auto) call_with_tuple(Func&& mf, TupleType&& tup) { - constexpr auto TUP_SIZE = std::tuple_size>::value; - return detail::call_with_tuple_impl(std::forward(mf), - std::forward(tup), std::make_index_sequence{}); - } - // DerefHolder holds the value gotten from an iterator dereference // if the iterate dereferences to an lvalue references, a pointer to the // element is stored diff --git a/zip.hpp b/zip.hpp index ede3514e..b02c71c5 100644 --- a/zip.hpp +++ b/zip.hpp @@ -1,6 +1,7 @@ #ifndef ITER_ZIP_HPP_ #define ITER_ZIP_HPP_ +#include "internal/iter_tuples.hpp" #include "internal/iterbase.hpp" #include diff --git a/zip_longest.hpp b/zip_longest.hpp index ad4cafab..dfbcf5c1 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -2,6 +2,7 @@ #define ITER_ZIP_LONGEST_HPP_ #include "internal/iterbase.hpp" +#include "internal/iter_tuples.hpp" #include #include From dbf3c7e0f6f290ed63b0e8cec5c4393e8981cfae Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 19 Feb 2017 20:38:50 -0800 Subject: [PATCH 012/403] Makes dumb_advance handle different end type --- internal/iterbase.hpp | 16 ++++++++-------- test/test_iterbase.cpp | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index ad547d66..9d955a52 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -131,23 +131,23 @@ namespace iter { // version that will work with most things template - void dumb_advance(InputIt& iter, Distance distance = 1) { + void dumb_advance_unsafe(InputIt& iter, Distance distance) { for (Distance i(0); i < distance; ++i) { ++iter; } } - template + template void dumb_advance_impl( - Iter& iter, const Iter& end, Distance distance, std::false_type) { + Iter& iter, const EndIter& end, Distance distance, std::false_type) { for (Distance i(0); i < distance && iter != end; ++i) { ++iter; } } - template + template void dumb_advance_impl( - Iter& iter, const Iter& end, Distance distance, std::true_type) { + Iter& iter, const EndIter& end, Distance distance, std::true_type) { if (static_cast(end - iter) < distance) { iter = end; } else { @@ -156,14 +156,14 @@ namespace iter { } // iter will not be incremented past end - template - void dumb_advance(Iter& iter, const Iter& end, Distance distance = 1) { + template + void dumb_advance(Iter& iter, const EndIter& end, Distance distance) { dumb_advance_impl(iter, end, distance, is_random_access_iter{}); } template ForwardIt dumb_next(ForwardIt it, Distance distance = 1) { - dumb_advance(it, distance); + dumb_advance_unsafe(it, distance); return it; } diff --git a/test/test_iterbase.cpp b/test/test_iterbase.cpp index 91671155..a19247da 100644 --- a/test/test_iterbase.cpp +++ b/test/test_iterbase.cpp @@ -49,7 +49,7 @@ TEST_CASE("advance, next, size", "[iterbase]") { auto itr = std::begin(v); REQUIRE(it::apply_arrow(itr) == &v[0]); - it::dumb_advance(itr, 3); + it::dumb_advance_unsafe(itr, 3); REQUIRE(itr == (std::begin(v) + 3)); REQUIRE(it::dumb_next(std::begin(v), 3) == std::begin(v) + 3); REQUIRE(it::dumb_size(v) == v.size()); From fa10ace4628a32e9da4ef55bee76a47f3596ee03 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:13:44 -0800 Subject: [PATCH 013/403] Makes dumb_size handle different end types --- internal/iterbase.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 9d955a52..8f73cb0d 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -177,8 +177,9 @@ namespace iter { template Distance dumb_size(Container&& container) { Distance d{0}; - for (auto it = std::begin(container), end = std::end(container); - it != end; ++it) { + auto end_it = std::end(container); + for (auto it = std::begin(container); + it != end_it; ++it) { ++d; } return d; From 4a231af2d0f57b8a30a5ff6943d7cad8dc0cfffb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:14:44 -0800 Subject: [PATCH 014/403] Adds operators, uses iterators for types templating the wrapper on iterator types instead of a container makes this work with reversed() --- internal/iterator_wrapper.hpp | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/internal/iterator_wrapper.hpp b/internal/iterator_wrapper.hpp index a817323c..1f5e5536 100755 --- a/internal/iterator_wrapper.hpp +++ b/internal/iterator_wrapper.hpp @@ -10,7 +10,7 @@ namespace impl { template using iterator_end_type = decltype(std::end(std::declval())); -template +template class IteratorWrapperImpl; @@ -25,7 +25,7 @@ struct IteratorWrapperImplType template struct IteratorWrapperImplType -: type_is>{}; +: type_is, iterator_end_type>>{}; template using IteratorWrapper = typename IteratorWrapperImplType +template class iter::impl::IteratorWrapperImpl { private: static_assert( - !std::is_same, iterator_end_type>{}, + !std::is_same{}, ""); - - using SubIter = iterator_type; - using SubEnd = iterator_end_type; - enum class IterState { Normal, End, Uninitialized}; void destroy_sub() { @@ -128,12 +123,26 @@ class iter::impl::IteratorWrapperImpl { return *this; } - // TODO implement const deref? decltype(auto) operator*() { assert(state_ == IterState::Normal); //because *ing the end is UB return *sub_iter_; } + decltype(auto) operator*() const { + assert(state_ == IterState::Normal); //because *ing the end is UB + return *sub_iter_; + } + + decltype(auto) operator->() { + assert(state_ == IterState::Normal); + return apply_arrow(sub_iter_); + } + + decltype(auto) operator->() const { + assert(state_ == IterState::Normal); + return apply_arrow(sub_iter_); + } + bool operator!=(const IteratorWrapperImpl& other) const { assert(state_ != IterState::Uninitialized && other.state_ != IterState::Uninitialized); From 3adcb327d081780df96ea80f2e8ce5448886a730 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:15:48 -0800 Subject: [PATCH 015/403] Changes iterator tuples to use wrappers --- internal/iter_tuples.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/iter_tuples.hpp b/internal/iter_tuples.hpp index a70c3fd2..8e68f16e 100644 --- a/internal/iter_tuples.hpp +++ b/internal/iter_tuples.hpp @@ -2,6 +2,7 @@ #define ITERTOOLS_ITER_TUPLES_HPP_ #include "iterbase.hpp" +#include "iterator_wrapper.hpp" namespace iter { namespace impl { @@ -13,7 +14,7 @@ namespace iter { namespace detail { template - std::tuple...> iterator_tuple_type_helper( + std::tuple...> iterator_tuple_type_helper( const std::tuple&); } // Given a tuple template argument, evaluates to a tuple of iterators @@ -29,8 +30,6 @@ namespace iter { using iterator_deref_tuple = decltype( detail::iterator_tuple_deref_helper(std::declval())); - // ---- Tuple utilities ---- // - // function absorbing all arguments passed to it. used when // applying a function to a parameter pack but not passing the evaluated // results anywhere From 3dff623ebd5a8476c53862f821873a5b65288cf3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:16:11 -0800 Subject: [PATCH 016/403] Adds range types with different begin and end --- test/helpers.hpp | 218 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 204 insertions(+), 14 deletions(-) diff --git a/test/helpers.hpp b/test/helpers.hpp index d16f3bd4..9cf67fd0 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace itertest { @@ -168,7 +169,7 @@ namespace itertest { #ifdef DECLARE_REVERSE_ITERATOR Iterator rbegin(); Iterator rend(); -#endif // ifdef DECLARE_REVERSE_ITERATOR +#endif // ifdef DECLARE_REVERSE_ITERATOR }; using iter::impl::void_t; @@ -178,19 +179,16 @@ namespace itertest { template struct IsIterator())), // copyctor - decltype(std::declval() = - std::declval()), // copy = - decltype(*std::declval()), // operator* - decltype( - std::declval().operator->()), // operator-> - decltype(++std::declval()), // prefix ++ - decltype(std::declval()++), // postfix ++ - decltype(std::declval() - != std::declval()), // != - decltype(std::declval() - == std::declval()) // == - >> : std::true_type {}; + void_t())), // copyctor + decltype(std::declval() = std::declval()), // copy = + decltype(*std::declval()), // operator* + decltype(std::declval().operator->()), // operator-> + decltype(++std::declval()), // prefix ++ + decltype(std::declval()++), // postfix ++ + decltype( + std::declval() != std::declval()), // != + decltype(std::declval() == std::declval()) // == + >> : std::true_type {}; template struct IsForwardIterator @@ -205,5 +203,197 @@ namespace itertest { && !std::is_move_assignable::value && std::is_move_constructible::value> {}; } +template +class DiffEndRange { + private: + T start_; + T stop_; + std::vector all_results_; + + public: + constexpr DiffEndRange(T start, T stop) : start_{start}, stop_{stop} { + while (start < stop_) { + all_results_.push_back(start); + Inc{}(start); + } + } + + class Iterator; + class EndIterator; + + class Iterator { + using SubIter = typename std::vector::iterator; + private: + SubIter it_; + SubIter end_; + + public: +#ifdef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE + Iterator() = default; +#endif + Iterator(SubIter it, SubIter end_it) : it_{it}, end_{end_it} {} + + T& operator*() const { + return *it_; + } + T* operator->() const { + return &*it_; + } + + Iterator& operator++() { + ++it_; + return *this; + } + + bool operator!=(const Iterator& other) const { + return it_ != other.it_; + } + + bool operator!=(const EndIterator&) const { + return it_ != end_; + } + + friend bool operator!=(const EndIterator& lhs, const Iterator& rhs) { + return rhs != lhs; + } + }; + + class ReverseIterator { + using SubIter = typename std::vector::reverse_iterator; + private: + SubIter it_; + SubIter end_; + + public: +#ifdef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE + ReverseIterator() = default; +#endif + ReverseIterator(SubIter it, SubIter end_it) : it_{it}, end_{end_it} {} + + T& operator*() const { + return *it_; + } + T* operator->() const { + return &*it_; + } + + Iterator& operator++() { + ++it_; + return *this; + } + + bool operator!=(const Iterator& other) const { + return it_ != other.it_; + } + + bool operator!=(const EndIterator&) const { + return it_ != end_; + } + + friend bool operator!=(const EndIterator& lhs, const Iterator& rhs) { + return rhs != lhs; + } + }; + + class EndIterator {}; + class ReverseEndIterator {}; + + Iterator begin() { + return {std::begin(all_results_), std::end(all_results_)}; + } + + EndIterator end() { + return {}; + } + + ReverseIterator rbegin() { + return {std::rbegin(all_results_), std::rend(all_results_)}; + } + + ReverseEndIterator rend() { + return {}; + } +}; + +struct CharInc { + void operator()(char& c) { + ++c; + } +}; + +// A range from 'a' to stop, begin() and end() are different +class CharRange : public DiffEndRange { + public: + constexpr CharRange(char stop) : DiffEndRange('a', stop) {} +}; + +struct IncIntCharPair { + void operator()(std::pair& p) { + ++p.first; + ++p.second; + } +}; + +class IntCharPairRange + : public DiffEndRange, IncIntCharPair> { + public: + IntCharPairRange(std::pair stop) + : DiffEndRange, IncIntCharPair>({0, 'a'}, stop) {} +}; + +#if 0 +class CharRange { + private: + char stop_{}; + + public: + constexpr CharRange(char stop) : stop_{stop} {} + + class Iterator; + class EndIterator; + + class Iterator { + private: + char stop_{}; + mutable char value_{'a'}; + public: +#ifdef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE + Iterator() = default; +#endif + Iterator(char stop) : stop_{stop} {} + + char& operator*() const { return value_; } + char* operator->() const { return &value_; } + + Iterator& operator++() { + ++value_; + return *this; + } + + bool operator!=(const Iterator& other) const { + return value_ != other.value_; + } + + bool operator!=(const EndIterator&) const { + return value_ < stop_; + } + + friend bool operator!=(const EndIterator& lhs, const Iterator& rhs) { + return rhs != lhs; + } + + }; + + class EndIterator { }; + + Iterator begin() { + return {stop_}; + } + + EndIterator end() { + return {}; + } +}; +#endif #endif From 43d6f4aed5743dd1e973dbac058ba4c0e0a9a36b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:17:23 -0800 Subject: [PATCH 017/403] tests accumulate with different begin and end --- test/test_accumulate.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/test_accumulate.cpp b/test/test_accumulate.cpp index 7df80628..fdab1913 100644 --- a/test/test_accumulate.cpp +++ b/test/test_accumulate.cpp @@ -102,6 +102,16 @@ TEST_CASE("accumulate: iterator meets requirements", "[accumulate]") { REQUIRE(itertest::IsIterator::value); } +TEST_CASE("accumulate: Works with different begin and end types", + "[accumulate]") { + CharRange cr{'d'}; + auto a = accumulate(cr); + Vec v(a.begin(), a.end()); + Vec vc{'a', 'a' + 'b', 'a' + 'b' + 'c'}; + REQUIRE(v == vc); +} + + template using ImpT = decltype(accumulate(std::declval())); TEST_CASE("accumulate: has correct ctor and assign ops", "[accumulate]") { From 02d4e8b0bd6e7ad67e495b9b384226ee83f5dc38 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:17:38 -0800 Subject: [PATCH 018/403] Supports different begin and end in accumulate --- accumulate.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 3df0fd29..cad5f29c 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -2,6 +2,7 @@ #define ITER_ACCUMULATE_H_ #include "internal/iterbase.hpp" +#include "internal/iterator_wrapper.hpp" #include #include @@ -39,13 +40,13 @@ class iter::impl::Accumulator { class Iterator : public std::iterator { private: - iterator_type sub_iter; - iterator_type sub_end; + IteratorWrapper sub_iter; + IteratorWrapper sub_end; AccumulateFunc* accumulate_func; std::unique_ptr acc_val; public: - Iterator(iterator_type&& iter, iterator_type&& end, + Iterator(IteratorWrapper&& iter, IteratorWrapper&& end, AccumulateFunc& in_accumulate_fun) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, From d39c02ca02bbe0423a9951550c7f14dce345c3dd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:18:02 -0800 Subject: [PATCH 019/403] Tests chain with different begin and end --- chain.hpp | 9 +++++---- test/test_chain.cpp | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/chain.hpp b/chain.hpp index bce306b6..44e6f94f 100644 --- a/chain.hpp +++ b/chain.hpp @@ -2,6 +2,7 @@ #define ITER_CHAIN_HPP_ #include "internal/iterbase.hpp" +#include "internal/iterator_wrapper.hpp" #include "internal/iter_tuples.hpp" #include @@ -183,10 +184,10 @@ class iter::impl::ChainedFromIterable { iterator_traits_deref>> { private: using SubContainer = iterator_deref; - using SubIter = iterator_type; + using SubIter = IteratorWrapper; - iterator_type top_level_iter; - iterator_type top_level_end; + IteratorWrapper top_level_iter; + IteratorWrapper top_level_end; std::unique_ptr sub_iter_p; std::unique_ptr sub_end_p; @@ -208,7 +209,7 @@ class iter::impl::ChainedFromIterable { public: Iterator( - iterator_type&& top_iter, iterator_type&& top_end) + IteratorWrapper&& top_iter, IteratorWrapper&& top_end) : top_level_iter{std::move(top_iter)}, top_level_end{std::move(top_end)}, sub_iter_p{!(top_iter != top_end) diff --git a/test/test_chain.cpp b/test/test_chain.cpp index f026bfe8..c0c6efb7 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -39,6 +39,19 @@ TEST_CASE("chain: with different container types", "[chain]") { REQUIRE(v == vc); } +TEST_CASE("chain: where one container has different begin and end types", + "[chain]") { + std::string s1{"abc"}; + std::list li{'m', 'n', 'o'}; + CharRange cr('e'); + auto ch = chain(s1, li, cr); + + Vec v(std::begin(ch), std::end(ch)); + Vec vc{'a', 'b', 'c', 'm', 'n', 'o', 'a', 'b', 'c', 'd'}; + + REQUIRE(v == vc); +} + TEST_CASE("chain: handles empty containers", "[chain]") { std::string emp; std::string a{"a"}; @@ -172,6 +185,15 @@ TEST_CASE("chain.from_iterable: basic test", "[chain.from_iterable]") { REQUIRE(v == vc); } +TEST_CASE("chain.fromm_iterable: Works with different begin and end types", + "[chain.from_iterable]") { + std::vector crv = {{'c'}, {'d'}}; + auto ch = chain.from_iterable(crv); + const std::vector v(std::begin(ch), std::end(ch)); + const std::vector vc = {'a', 'b', 'a', 'b', 'c'}; + REQUIRE(v == vc); +} + TEST_CASE( "chain.from_iterable: iterators cant be copy constructed " "and assigned", From 197706b415c2cec56897b485c3ea9e8752eb2c3a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:19:02 -0800 Subject: [PATCH 020/403] Tests chunked with different begin and end --- test/test_chunked.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/test_chunked.cpp b/test/test_chunked.cpp index 2bca55f4..2ecfc8c4 100644 --- a/test/test_chunked.cpp +++ b/test/test_chunked.cpp @@ -60,6 +60,17 @@ TEST_CASE("chunked: size 0 is empty", "[chunked]") { REQUIRE(std::begin(g) == std::end(g)); } +TEST_CASE("chunked: Works with different begin and end types", + "[chunked]") { + CharRange cr{'f'}; + std::vector> results; + for (auto&& g : chunked(cr, 3)) { + results.emplace_back(std::begin(g), std::end(g)); + } + std::vector> rc = {{'a', 'b', 'c'}, {'d', 'e'}}; + REQUIRE(results == rc); +} + TEST_CASE("chunked: empty iterable gives empty chunked", "[chunked]") { Vec ns{}; auto g = chunked(ns, 1); From 6064bec41aceea02b26cea8d40c4b28c081c575e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:19:15 -0800 Subject: [PATCH 021/403] Supports different begin and end in chunked --- chunked.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/chunked.hpp b/chunked.hpp index d5676568..a0009896 100644 --- a/chunked.hpp +++ b/chunked.hpp @@ -3,6 +3,7 @@ #include "internal/iterbase.hpp" #include "internal/iteratoriterator.hpp" +#include "internal/iterator_wrapper.hpp" #include #include @@ -32,15 +33,15 @@ class iter::impl::Chunker { friend ChunkedFn; - using IndexVector = std::vector>; + using IndexVector = std::vector>; using DerefVec = IterIterWrapper; public: Chunker(Chunker&&) = default; class Iterator : public std::iterator { private: - iterator_type sub_iter; - iterator_type sub_end; + IteratorWrapper sub_iter; + IteratorWrapper sub_end; DerefVec chunk; std::size_t chunk_size = 0; @@ -59,8 +60,8 @@ class iter::impl::Chunker { } public: - Iterator(iterator_type&& in_iter, - iterator_type&& in_end, std::size_t s) + Iterator(IteratorWrapper&& in_iter, + IteratorWrapper&& in_end, std::size_t s) : sub_iter{std::move(in_iter)}, sub_end{std::move(in_end)}, chunk_size{s} { From 113db4184dfbd7ba2e1a5f287fb9f5bf5ae920cb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:19:30 -0800 Subject: [PATCH 022/403] Tests combinations with different begin and end --- test/test_combinations.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/test_combinations.cpp b/test/test_combinations.cpp index 2b994a75..ef4e4653 100644 --- a/test/test_combinations.cpp +++ b/test/test_combinations.cpp @@ -1,5 +1,7 @@ #define DEFINE_DEFAULT_ITERATOR_CTOR +#define CHAR_RANGE_DEFAULT_CONSTRUCTIBLE #include "helpers.hpp" +#undef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE #undef DEFINE_DEFAULT_ITERATOR_CTOR #include @@ -35,6 +37,18 @@ TEST_CASE("combinations: Simple combination of 4", "[combinations]") { REQUIRE(ans == sc); } +TEST_CASE("combinations: Works with different begin and end types", + "[combinations]") { + CharRange cr{'e'}; + CharCombSet sc; + for (auto&& v : combinations(cr, 2)) { + sc.emplace_back(std::begin(v), std::end(v)); + } + CharCombSet ans = { + {'a', 'b'}, {'a', 'c'}, {'a', 'd'}, {'b', 'c'}, {'b', 'd'}, {'c', 'd'}}; + REQUIRE(ans == sc); +} + TEST_CASE("combinations: iterators can be compared", "[combinations]") { std::string s{"ABCD"}; auto c = combinations(s, 2); From d10d54e9a63066eb4d35e7569a721a6f1050fd88 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:20:09 -0800 Subject: [PATCH 023/403] Tests comb_w_repl with different begin and end --- test/test_combinations_with_replacement.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/test_combinations_with_replacement.cpp b/test/test_combinations_with_replacement.cpp index 9db79414..9540588d 100644 --- a/test/test_combinations_with_replacement.cpp +++ b/test/test_combinations_with_replacement.cpp @@ -5,7 +5,9 @@ #include #include +#define CHAR_RANGE_DEFAULT_CONSTRUCTIBLE #include "helpers.hpp" +#undef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE #include "catch.hpp" using iter::combinations_with_replacement; @@ -31,6 +33,18 @@ TEST_CASE("combinations_with_replacement: Simple combination", REQUIRE(ans == sc); } +TEST_CASE("combinations_with_replacement: Works with different begin and end types", + "[combinations_with_replacement]") { + CharRange cr{'d'}; + CharCombSet sc; + for (auto&& v : combinations_with_replacement(cr, 2)) { + sc.emplace_back(std::begin(v), std::end(v)); + } + CharCombSet ans = { + {'a', 'a'}, {'a', 'b'}, {'a', 'c'}, {'b', 'b'}, {'b', 'c'}, {'c', 'c'}}; + REQUIRE(ans == sc); +} + TEST_CASE("combinations_with_replacement: iterators can be compared", "[combinations_with_replacement]") { std::string s{"ABCD"}; From 4d5c3ee3e8112d7a5831aadeac40704e34f2c816 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:20:23 -0800 Subject: [PATCH 024/403] Tests compress with different begin and end --- test/test_compress.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_compress.cpp b/test/test_compress.cpp index 9a0c30b2..7938b23a 100644 --- a/test/test_compress.cpp +++ b/test/test_compress.cpp @@ -136,6 +136,15 @@ TEST_CASE("compress: iterator meets requirements", "[compress]") { REQUIRE(itertest::IsIterator::value); } +TEST_CASE("compress: Works with different begin and end types", + "[compress]") { + CharRange cr{'d'}; + auto c = compress(cr, std::vector{true, false, true}); + Vec v(c.begin(), c.end()); + Vec vc{'a', 'c'}; + REQUIRE(v == vc); +} + template using ImpT = decltype(compress(std::declval(), std::declval())); TEST_CASE("compress: has correct ctor and assign ops", "[compress]") { From 1dc483e5c8fb1655d9a0f437053c0c52a6683cce Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:20:34 -0800 Subject: [PATCH 025/403] Supports different begin and end in compress --- compress.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compress.hpp b/compress.hpp index 22d8cded..0482298d 100644 --- a/compress.hpp +++ b/compress.hpp @@ -2,6 +2,7 @@ #define ITER_COMPRESS_H_ #include "internal/iterbase.hpp" +#include "internal/iterator_wrapper.hpp" #include #include @@ -38,8 +39,8 @@ class iter::impl::Compressed { class Iterator : public std::iterator> { private: - iterator_type sub_iter; - iterator_type sub_end; + IteratorWrapper sub_iter; + IteratorWrapper sub_end; selector_iter_type selector_iter; selector_iter_type selector_end; @@ -58,8 +59,8 @@ class iter::impl::Compressed { } public: - Iterator(iterator_type&& cont_iter, - iterator_type&& cont_end, selector_iter_type&& sel_iter, + Iterator(IteratorWrapper&& cont_iter, + IteratorWrapper&& cont_end, selector_iter_type&& sel_iter, selector_iter_type&& sel_end) : sub_iter{std::move(cont_iter)}, sub_end{std::move(cont_end)}, From 48123d612175961736fa348a07ac7b15d351ec86 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:23:42 -0800 Subject: [PATCH 026/403] Tests cycle with different begin and end --- test/test_cycle.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/test/test_cycle.cpp b/test/test_cycle.cpp index 8d4ab37c..3066d00d 100644 --- a/test/test_cycle.cpp +++ b/test/test_cycle.cpp @@ -17,7 +17,7 @@ TEST_CASE("cycle: iterate twice", "[cycle]") { for (auto i : cycle(ns)) { v.push_back(i); ++count; - if (count == ns.size() * 2) break; + if (count == ns.size() * 2) { break; } } auto vc = ns; @@ -25,6 +25,24 @@ TEST_CASE("cycle: iterate twice", "[cycle]") { REQUIRE(v == vc); } +TEST_CASE("cycle: Works with different begin and end types", + "[cycle]") { + constexpr auto sz = 'd' - 'a'; + CharRange cr{'d'}; + const std::vector vc{'a', 'b', 'c', 'a', 'b', 'c'}; + std::vector v; + std::size_t count = 0; + for (auto i : cycle(cr)) { + v.push_back(i); + ++count; + if (count == sz * 2) { break; } + } + + REQUIRE(v == vc); +} + + + TEST_CASE("cycle: with pipe", "[cycle]") { std::vector ns{2, 4, 6}; std::vector v; @@ -32,7 +50,7 @@ TEST_CASE("cycle: with pipe", "[cycle]") { for (auto i : ns | cycle) { v.push_back(i); ++count; - if (count == ns.size() * 2) break; + if (count == ns.size() * 2) { break; } } auto vc = ns; From d2d5adc21fe2ad31d6f814e85e34a5b309c9fa4e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:24:31 -0800 Subject: [PATCH 027/403] Supports different begin and end in cycle --- cycle.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 64b3ee84..b416553f 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -2,6 +2,7 @@ #define ITER_CYCLE_H_ #include "internal/iterbase.hpp" +#include "internal/iterator_wrapper.hpp" #include #include @@ -32,13 +33,13 @@ class iter::impl::Cycler { class Iterator : public std::iterator> { private: - iterator_type sub_iter; - iterator_type begin; - iterator_type end; + IteratorWrapper sub_iter; + IteratorWrapper begin; + IteratorWrapper end; public: Iterator( - const iterator_type& iter, iterator_type&& in_end) + IteratorWrapper&& iter, IteratorWrapper&& in_end) : sub_iter{iter}, begin{iter}, end{std::move(in_end)} {} iterator_deref operator*() { From 95c503414e263c057833ab9c1f77cd8e6ac12465 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:24:41 -0800 Subject: [PATCH 028/403] Tests dropwhile with different begin and end --- test/test_dropwhile.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_dropwhile.cpp b/test/test_dropwhile.cpp index 599ab407..aba3ec09 100644 --- a/test/test_dropwhile.cpp +++ b/test/test_dropwhile.cpp @@ -27,6 +27,15 @@ TEST_CASE("dropwhile: skips initial elements", "[dropwhile]") { REQUIRE(v == vc); } +TEST_CASE("dropwhile: Works with different begin and end types", + "[dropwhile]") { + CharRange cr{'f'}; + auto d = dropwhile([](char c){return c < 'c';}, cr); + Vec v(d.begin(), d.end()); + Vec vc{'c', 'd', 'e'}; + REQUIRE(v == vc); +} + TEST_CASE("dropwhile: doesn't skip anything if it shouldn't", "[dropwhile]") { Vec ns{3, 4, 5, 6}; auto d = dropwhile([](int i) { return i < 3; }, ns); From 35d55c8847f5fdbbc078b3e7bc8f5ce97d03a014 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:24:49 -0800 Subject: [PATCH 029/403] Supports different begin and end in dropwhile --- dropwhile.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 869e0070..1f8c587d 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -2,6 +2,7 @@ #define ITER_DROPWHILE_H_ #include "internal/iterbase.hpp" +#include "internal/iterator_wrapper.hpp" #include "filter.hpp" #include @@ -35,8 +36,8 @@ class iter::impl::Dropper { iterator_traits_deref> { private: using Holder = DerefHolder>; - iterator_type sub_iter; - iterator_type sub_end; + IteratorWrapper sub_iter; + IteratorWrapper sub_end; Holder item; FilterFunc* filter_func; @@ -56,7 +57,7 @@ class iter::impl::Dropper { } public: - Iterator(iterator_type&& iter, iterator_type&& end, + Iterator(IteratorWrapper&& iter, IteratorWrapper&& end, FilterFunc& in_filter_func) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, From 9d012aa330356c5755fa20c255bc59353f48f0e8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:24:56 -0800 Subject: [PATCH 030/403] Tests takewhile with different begin and end --- test/test_takewhile.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_takewhile.cpp b/test/test_takewhile.cpp index af5f6091..202e99ab 100644 --- a/test/test_takewhile.cpp +++ b/test/test_takewhile.cpp @@ -57,6 +57,15 @@ TEST_CASE("takewhile: works with lambda, callable, and function pointer", } } +TEST_CASE("takewhile: Works with different begin and end types", + "[takewhile]") { + CharRange cr{'f'}; + auto t = takewhile([](char c){return c < 'd';}, cr); + Vec v(t.begin(), t.end()); + Vec vc{'a', 'b', 'c'}; + REQUIRE(v == vc); +} + TEST_CASE("takewhile: identity", "[takewhile]") { Vec ns{1, 2, 3, 0, 4, 5, 0}; std::vector v; From 473fded048f9ae55beef9435ce85d880afcb165d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:25:02 -0800 Subject: [PATCH 031/403] Supports different begin and end in takewhile --- takewhile.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 003e38a0..f05828dd 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -2,6 +2,7 @@ #define ITER_TAKEWHILE_H_ #include "internal/iterbase.hpp" +#include "internal/iterator_wrapper.hpp" #include "filter.hpp" #include @@ -36,8 +37,8 @@ class iter::impl::Taker { iterator_traits_deref> { private: using Holder = DerefHolder>; - iterator_type sub_iter; - iterator_type sub_end; + IteratorWrapper sub_iter; + IteratorWrapper sub_end; Holder item; FilterFunc* filter_func; @@ -56,7 +57,7 @@ class iter::impl::Taker { } public: - Iterator(iterator_type&& iter, iterator_type&& end, + Iterator(IteratorWrapper&& iter, IteratorWrapper&& end, FilterFunc& in_filter_func) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, From 1d59f3f2da1f2511ae00fb03baa26d658d41139d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:25:10 -0800 Subject: [PATCH 032/403] Tests enumerate with different begin and end --- test/test_enumerate.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index be5209ff..3b8f56ac 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -148,6 +148,15 @@ TEST_CASE("enumerate: works index and pipe", "[enumerate]") { REQUIRE(v == vc); } +TEST_CASE("enumerate: Works with different begin and end types", + "[enumerate]") { + CharRange cr{'d'}; + auto e = enumerate(cr); + Vec v(e.begin(), e.end()); + Vec vc{{0, 'a'}, {1, 'b'}, {2, 'c'}}; + REQUIRE(v == vc); +} + template using ImpT = decltype(enumerate(std::declval())); TEST_CASE("enumerate: has correct ctor and assign ops", "[enumerate]") { From f1ba8f6eb661ece762e2fb810ddf0b7ae3feaa03 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:25:15 -0800 Subject: [PATCH 033/403] Supports different begin and end in enumerate --- enumerate.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 6492c909..3f4ab47c 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -2,6 +2,7 @@ #define ITER_ENUMERATE_H_ #include "internal/iterbase.hpp" +#include "internal/iterator_wrapper.hpp" #include #include @@ -51,11 +52,11 @@ class iter::impl::Enumerable { // Each dereference returns an IterYield. class Iterator : public std::iterator { private: - iterator_type sub_iter; + IteratorWrapper sub_iter; Index index; public: - Iterator(iterator_type&& si, Index start) + Iterator(IteratorWrapper&& si, Index start) : sub_iter{std::move(si)}, index{start} {} IterYield operator*() { From d6d6a95afd7bf38a0255a576763fa9b861a244bc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:25:19 -0800 Subject: [PATCH 034/403] Tests filter with different begin and end --- test/test_filter.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_filter.cpp b/test/test_filter.cpp index 63b8e068..d5c1aed3 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -145,6 +145,15 @@ TEST_CASE("filter: using identity and pipe", "[filter]") { REQUIRE(v == vc); } +TEST_CASE("filter: Works with different begin and end types", + "[filter]") { + CharRange cr{'d'}; + auto f = filter([](char c){return c != 'b';}, cr); + Vec v(f.begin(), f.end()); + Vec vc{'a', 'c'}; + REQUIRE(v == vc); +} + TEST_CASE("filter: iterator meets requirements", "[filter]") { std::string s{}; auto c = filter([] { return true; }, s); From 6265e6606921dd3cc4df111532389b05ce291e71 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:25:56 -0800 Subject: [PATCH 035/403] Supports different begin and end in filter --- filter.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/filter.hpp b/filter.hpp index f7364f3a..42ad09bd 100644 --- a/filter.hpp +++ b/filter.hpp @@ -2,6 +2,7 @@ #define ITER_FILTER_H_ #include "internal/iterbase.hpp" +#include "internal/iterator_wrapper.hpp" #include #include @@ -46,8 +47,8 @@ class iter::impl::Filtered { iterator_traits_deref> { protected: using Holder = DerefHolder>; - iterator_type sub_iter; - iterator_type sub_end; + IteratorWrapper sub_iter; + IteratorWrapper sub_end; Holder item; FilterFunc* filter_func; @@ -68,9 +69,9 @@ class iter::impl::Filtered { } public: - Iterator(iterator_type iter, iterator_type end, + Iterator(IteratorWrapper&& iter, IteratorWrapper&& end, FilterFunc& in_filter_func) - : sub_iter{iter}, sub_end{end}, filter_func(&in_filter_func) { + : sub_iter{std::move(iter)}, sub_end{std::move(end)}, filter_func(&in_filter_func) { if (this->sub_iter != this->sub_end) { this->item.reset(*this->sub_iter); } From 4295c840b09864f818be80215d8a28ed621bca2e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:26:20 -0800 Subject: [PATCH 036/403] Tests groupby with different begin and end --- test/test_groupby.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/test_groupby.cpp b/test/test_groupby.cpp index a102692f..c353b491 100644 --- a/test/test_groupby.cpp +++ b/test/test_groupby.cpp @@ -69,6 +69,21 @@ TEST_CASE("groupby: works with lambda, callable, and function pointer") { REQUIRE(groups == gc); } +TEST_CASE("groupby: Works with different begin and end types", + "[groupby]") { + CharRange cr{'f'}; + std::vector keys; + std::vector> groups; + for (auto&& gb : groupby(cr, [](char c){return c == 'c';})) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + const std::vector kc = {false, true, false}; + const std::vector> gc = {{'a' ,'b'}, {'c'}, {'d', 'e'}}; + REQUIRE(keys == kc); + REQUIRE(groups == gc); +} + TEST_CASE("groupby: groups can be skipped completely", "[groupby]") { std::vector keys; std::vector> groups; From cfe0c367b144a0dce2c4335e394f5a3a88f7d0db Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:26:20 -0800 Subject: [PATCH 037/403] Supports different begin and end in groupby --- groupby.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index a0af1d4d..e0a5f53a 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -4,6 +4,7 @@ // this is easily the most functionally complex itertool #include "internal/iterbase.hpp" +#include "internal/iterator_wrapper.hpp" #include #include @@ -54,15 +55,15 @@ class iter::impl::GroupProducer { public: class Iterator : public std::iterator { private: - iterator_type sub_iter; - iterator_type sub_end; + IteratorWrapper sub_iter; + IteratorWrapper sub_end; Holder item; KeyFunc* key_func; std::unique_ptr current_key_group_pair; public: - Iterator(iterator_type&& si, iterator_type&& end, + Iterator(IteratorWrapper&& si, IteratorWrapper&& end, KeyFunc& in_key_func) : sub_iter{std::move(si)}, sub_end{std::move(end)}, From df05e374f016385906d0807507128a91e7a0730d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:26:45 -0800 Subject: [PATCH 038/403] Tests permutations with different begin and end --- test/test_permutations.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/test_permutations.cpp b/test/test_permutations.cpp index c184e651..a2ab49ee 100644 --- a/test/test_permutations.cpp +++ b/test/test_permutations.cpp @@ -31,6 +31,22 @@ TEST_CASE("permutations: basic test, 3 element sequence", "[permutations]") { REQUIRE(v == vc); } +TEST_CASE("permutations: Works with different begin and end types", + "[permutations]") { + CharRange cr{'d'}; + using CharPermSet = std::multiset>; + CharPermSet sc; + for (auto&& v : permutations(cr)) { + sc.emplace(std::begin(v), std::end(v)); + } + const CharPermSet ans = { + {'a', 'b', 'c'}, {'a', 'c', 'b'}, + {'b', 'a', 'c'}, {'b', 'c', 'a'}, + {'c', 'a', 'b'}, {'c', 'b', 'a'}}; + + REQUIRE(ans == sc); +} + TEST_CASE( "permutations: empty sequence has one empy permutation", "[permutations]") { const std::vector ns{}; From 53260484e7906580869ed33f55a1e736f6df4c73 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:26:45 -0800 Subject: [PATCH 039/403] Supports different begin and end in permutations --- permutations.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/permutations.hpp b/permutations.hpp index dea9fa8c..0e6c3aa5 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -3,6 +3,7 @@ #include "internal/iterbase.hpp" #include "internal/iteratoriterator.hpp" +#include "internal/iterator_wrapper.hpp" #include #include @@ -25,7 +26,7 @@ class iter::impl::Permuter { friend PermutationsFn; Container container; - using IndexVector = std::vector>; + using IndexVector = std::vector>; using Permutable = IterIterWrapper; Permuter(Container&& in_container) @@ -37,8 +38,8 @@ class iter::impl::Permuter { class Iterator : public std::iterator { private: static constexpr const int COMPLETE = -1; - static bool cmp_iters(const iterator_type& lhs, - const iterator_type& rhs) noexcept { + static bool cmp_iters(IteratorWrapper lhs, + IteratorWrapper rhs) noexcept { return *lhs < *rhs; } @@ -47,7 +48,8 @@ class iter::impl::Permuter { public: Iterator( - iterator_type&& sub_iter, iterator_type&& sub_end) + IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end) : steps{sub_iter != sub_end ? 0 : COMPLETE} { // done like this instead of using vector ctor with // two iterators because that causes a substitution From cd36279b1167228c40b21167faa61ff6dcf0f84b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:26:56 -0800 Subject: [PATCH 040/403] Tests product with different begin and end --- test/test_product.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/test_product.cpp b/test/test_product.cpp index d42cde31..4f9f1d2c 100644 --- a/test/test_product.cpp +++ b/test/test_product.cpp @@ -26,6 +26,21 @@ TEST_CASE("product: basic test, two sequences", "[product]") { REQUIRE(v == vc); } +TEST_CASE("product: two sequences where one has different begin and end", "[product]") { + using TP = std::tuple; + using ResType = std::vector; + + Vec n1 = {0, 1}; + CharRange cr('d'); + + auto p = product(n1, cr); + ResType v(std::begin(p), std::end(p)); + ResType vc = { + TP{0, 'a'}, TP{0, 'b'}, TP{0, 'c'}, TP{1, 'a'}, TP{1, 'b'}, TP{1, 'c'}}; + + REQUIRE(v == vc); +} + TEST_CASE("product: three sequences", "[product]") { using TP = std::tuple; using ResType = const std::vector; From 65d96d75fb256218bdf9496baa2f60cf1ed3a086 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:26:56 -0800 Subject: [PATCH 041/403] Supports different begin and end in product --- product.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/product.hpp b/product.hpp index 8939a28e..3b1b5572 100644 --- a/product.hpp +++ b/product.hpp @@ -2,6 +2,7 @@ #define ITER_PRODUCT_HPP_ #include "internal/iterbase.hpp" +#include "internal/iterator_wrapper.hpp" #include #include @@ -50,15 +51,15 @@ class iter::impl::Productor { private: using RestIter = typename Productor::Iterator; - iterator_type iter; - iterator_type begin; + IteratorWrapper iter; + IteratorWrapper begin; RestIter rest_iter; RestIter rest_end; public: constexpr static const bool is_base_iter = false; - Iterator(const iterator_type& it, RestIter&& rest, + Iterator(IteratorWrapper&& it, RestIter&& rest, RestIter&& in_rest_end) : iter{it}, begin{it}, rest_iter{rest}, rest_end{in_rest_end} {} From 089eee761a95753183be7452e6cdac94fdd770d3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:27:01 -0800 Subject: [PATCH 042/403] Tests reversed with different begin and end --- test/test_reversed.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/test_reversed.cpp b/test/test_reversed.cpp index 1cd6fcfa..2ccf5d2f 100644 --- a/test/test_reversed.cpp +++ b/test/test_reversed.cpp @@ -31,6 +31,17 @@ TEST_CASE("reversed: can reverse a vector", "[reversed]") { REQUIRE(v == vc); } +#if 0 +TEST_CASE("reversed: Works with different begin and end types", + "[reversed]") { + CharRange cr{'d'}; + auto r = reversed(cr); + Vec v(r.begin(), r.end()); + Vec vc{'c', 'b', 'a'}; + REQUIRE(v == vc); +} +#endif + TEST_CASE("reversed: can reverse an array", "[reversed]") { int ns[] = {10, 20, 30, 40}; auto r = reversed(ns); From b9840c30ecf895dffcfe703ebda806b4099a4adf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:27:01 -0800 Subject: [PATCH 043/403] Supports different begin and end in reversed --- reversed.hpp | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/reversed.hpp b/reversed.hpp index 82ae9b46..b17457c3 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -1,13 +1,43 @@ #ifndef ITER_REVERSE_HPP_ #define ITER_REVERSE_HPP_ +#include "internal/iterator_wrapper.hpp" #include "internal/iterbase.hpp" -#include #include +#include namespace iter { namespace impl { + template + using reverse_iterator_type = + decltype(std::rbegin(std::declval())); + template + using reverse_iterator_end_type = + decltype(std::rend(std::declval())); + + // If rbegin and rend return the same type, type will be + // reverse_iterator_type + // If rbegin and rend return different types, type will be + // IteratorWrapperImpl + template + struct ReverseIteratorWrapperImplType; + + template + struct ReverseIteratorWrapperImplType + : type_is> {}; + + template + struct ReverseIteratorWrapperImplType + : type_is, + reverse_iterator_end_type>> {}; + + template + using ReverseIteratorWrapper = + typename ReverseIteratorWrapperImplType, + impl::reverse_iterator_end_type>{}>::type; + template class Reverser; @@ -25,26 +55,25 @@ class iter::impl::Reverser { Reverser(Container&& in_container) : container(std::forward(in_container)) {} - using reverse_iterator_type = - decltype(std::rbegin(std::declval())); - using reverse_iterator_deref = - decltype(*std::declval()); + decltype(*std::declval&>()); using reverse_iterator_traits_deref = std::remove_reference_t; - using reverse_iterator_arrow = detail::arrow; + using reverse_iterator_arrow = + detail::arrow>; public: Reverser(Reverser&&) = default; class Iterator : public std::iterator { private: - reverse_iterator_type sub_iter; + ReverseIteratorWrapper sub_iter; public: - Iterator(reverse_iterator_type&& iter) : sub_iter{std::move(iter)} {} + Iterator(ReverseIteratorWrapper&& iter) + : sub_iter{std::move(iter)} {} reverse_iterator_deref operator*() { return *this->sub_iter; From 8ba3bd5ddb353a3c38c0094f24326bd0972068ef Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:27:09 -0800 Subject: [PATCH 044/403] Tests slice with different begin and end --- test/test_slice.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_slice.cpp b/test/test_slice.cpp index 1500da6e..8cb3ee66 100644 --- a/test/test_slice.cpp +++ b/test/test_slice.cpp @@ -44,6 +44,15 @@ TEST_CASE("slice: start and stop", "[slice]") { REQUIRE(v == vc); } +TEST_CASE("slice: Works with different begin and end types", + "[slice]") { + CharRange cr{'z'}; + auto sl = slice(cr, 2, 5); + std::vector v(std::begin(sl), std::end(sl)); + const std::vector vc = {'c', 'd', 'e'}; + REQUIRE(v == vc); +} + TEST_CASE("slice: start, stop, step", "[slice]") { Vec ns = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; std::vector v; From d9fc76d7cadef8299a7a5867f7819aad01b91ad2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:27:09 -0800 Subject: [PATCH 045/403] Supports different begin and end in slice --- slice.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/slice.hpp b/slice.hpp index 8ff5a6af..df2ce0a2 100644 --- a/slice.hpp +++ b/slice.hpp @@ -2,6 +2,7 @@ #define ITER_SLICE_HPP_ #include "internal/iterbase.hpp" +#include "internal/iterator_wrapper.hpp" #include #include @@ -37,14 +38,14 @@ class iter::impl::Sliced { class Iterator : public std::iterator> { private: - iterator_type sub_iter; - iterator_type sub_end; + IteratorWrapper sub_iter; + IteratorWrapper sub_end; DifferenceType current; DifferenceType stop; DifferenceType step; public: - Iterator(iterator_type&& si, iterator_type&& se, + Iterator(IteratorWrapper&& si, IteratorWrapper&& se, DifferenceType in_start, DifferenceType in_stop, DifferenceType in_step) : sub_iter{std::move(si)}, sub_end{std::move(se)}, From 2ad5f0f7132bc008aa476656c83d98c956be01f7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:27:15 -0800 Subject: [PATCH 046/403] Tests sliding_window with different begin and end --- test/test_sliding_window.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/test_sliding_window.cpp b/test/test_sliding_window.cpp index 0cd26a52..8400aedf 100644 --- a/test/test_sliding_window.cpp +++ b/test/test_sliding_window.cpp @@ -28,6 +28,20 @@ TEST_CASE("sliding_window: window of size 3", "[sliding_window]") { REQUIRE(v == vc); } +TEST_CASE("sliding_window: Works with different begin and end types", + "[sliding_window]") { + CharRange cr{'f'}; + std::vector> results; + for (auto&& g : sliding_window(cr, 3)) { + results.emplace_back(std::begin(g), std::end(g)); + } + std::vector> rc = { + {'a', 'b', 'c'}, + {'b', 'c', 'd'}, + {'c', 'd', 'e'}}; + REQUIRE(results == rc); +} + TEST_CASE("sliding window: oversized window is empty", "[sliding_window]") { Vec ns = {10, 20, 30}; auto sw = sliding_window(ns, 5); From c82f9c8dcda59260988f34e4a508bbce295d7920 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:27:15 -0800 Subject: [PATCH 047/403] Supports different begin and end in sliding_window --- sliding_window.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index 9f58334b..6a68faaa 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -2,6 +2,7 @@ #define ITER_SLIDING_WINDOW_HPP_ #include "internal/iterbase.hpp" +#include "internal/iterator_wrapper.hpp" #include "internal/iteratoriterator.hpp" #include @@ -28,19 +29,19 @@ class iter::impl::WindowSlider { WindowSlider(Container&& in_container, std::size_t win_sz) : container(std::forward(in_container)), window_size{win_sz} {} - using IndexVector = std::deque>; + using IndexVector = std::deque>; using DerefVec = IterIterWrapper; public: WindowSlider(WindowSlider&&) = default; class Iterator : public std::iterator { private: - iterator_type sub_iter; + IteratorWrapper sub_iter; DerefVec window; public: - Iterator(iterator_type&& in_iter, - const iterator_type& in_end, std::size_t window_sz) + Iterator(IteratorWrapper&& in_iter, + IteratorWrapper&& in_end, std::size_t window_sz) : sub_iter(std::move(in_iter)) { std::size_t i{0}; while (i < window_sz && this->sub_iter != in_end) { @@ -83,8 +84,8 @@ class iter::impl::WindowSlider { }; Iterator begin() { - return {(this->window_size != 0 ? std::begin(this->container) - : std::end(this->container)), + return {(this->window_size != 0 ? IteratorWrapper{std::begin(this->container)} + : IteratorWrapper{std::end(this->container)}), std::end(this->container), this->window_size}; } From edcf82a521fad4c61c2c707aa96195f52980a14b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:27:38 -0800 Subject: [PATCH 048/403] Tests starmap with different begin and end --- test/test_starmap.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/test_starmap.cpp b/test/test_starmap.cpp index 25451dcf..6f1e7d7b 100644 --- a/test/test_starmap.cpp +++ b/test/test_starmap.cpp @@ -57,6 +57,18 @@ TEST_CASE("starmap: works with function pointer and lambda", "[starmap]") { REQUIRE(v == vc); } +TEST_CASE("starmap: Works with different begin and end types", + "[starmap]") { + IntCharPairRange icr{{3, 'd'}}; + using Vec = std::vector; + auto sm = starmap([](int i, char c) { + return std::to_string(i) + c;}, + icr); + Vec v(sm.begin(), sm.end()); + Vec vc{"0a", "1b", "2c"}; + REQUIRE(v == vc); +} + TEST_CASE("starmap: list of tuples", "[starmap]") { using Vec = const std::vector; using T = std::tuple; From 24a69cd5684c5255653d15041d7de285ecff9740 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:27:38 -0800 Subject: [PATCH 049/403] Supports different begin and end in starmap --- starmap.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index e4658e50..7570e03e 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -2,6 +2,7 @@ #define ITER_STARMAP_H_ #include "internal/iterbase.hpp" +#include "internal/iterator_wrapper.hpp" #include #include @@ -45,10 +46,10 @@ class iter::impl::StarMapper { : public std::iterator { private: Func* func; - iterator_type sub_iter; + IteratorWrapper sub_iter; public: - Iterator(Func& f, iterator_type&& iter) + Iterator(Func& f, IteratorWrapper&& iter) : func(&f), sub_iter(std::move(iter)) {} bool operator!=(const Iterator& other) const { From 3e260982740e4371a9a0b15114019ce24cfff65b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:27:59 -0800 Subject: [PATCH 050/403] Tests filterfalse with different begin and end --- test/test_filterfalse.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_filterfalse.cpp b/test/test_filterfalse.cpp index b9de4bd2..dbf826fd 100644 --- a/test/test_filterfalse.cpp +++ b/test/test_filterfalse.cpp @@ -60,6 +60,15 @@ TEST_CASE("filterfalse: handles different functor types", "[filterfalse]") { } } +TEST_CASE("filterfalse: Works with different begin and end types", + "[filterfalse]") { + CharRange cr{'d'}; + auto f = filterfalse([](char c){return c == 'b';}, cr); + Vec v(f.begin(), f.end()); + Vec vc{'a', 'c'}; + REQUIRE(v == vc); +} + TEST_CASE("filterfalse: using identity", "[filterfalse]") { Vec ns{0, 1, 2, 0, 3, 0, 0, 0, 4, 5, 0}; std::vector v; From ac46acc3a32581c264f66c4351b8f083107efb1c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:28:04 -0800 Subject: [PATCH 051/403] Tests imap with different begin and end --- test/test_imap.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/test_imap.cpp b/test/test_imap.cpp index 4912b11f..2ab1f5a6 100644 --- a/test/test_imap.cpp +++ b/test/test_imap.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "catch.hpp" @@ -60,6 +61,15 @@ TEST_CASE("imap: works with lambda, callable, and function", "[imap]") { REQUIRE(v == vc); } +TEST_CASE("imap: Works with different begin and end types", + "[imap]") { + CharRange cr{'d'}; + auto m = imap([](char c) { return std::toupper(c);}, cr); + Vec v(m.begin(), m.end()); + Vec vc{'A', 'B', 'C'}; + REQUIRE(v == vc); +} + TEST_CASE("imap: works with multiple sequences", "[imap]") { Vec bases = {0, 1, 2, 3}; Vec exps = {1, 2, 3, 4}; From c6f7e5591a98d80d49fdedbb886cdc35326d7de7 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:28:15 -0800 Subject: [PATCH 052/403] Tests powerset with different begin and end --- test/test_powerset.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/test_powerset.cpp b/test/test_powerset.cpp index 923baa13..b8fb388e 100644 --- a/test/test_powerset.cpp +++ b/test/test_powerset.cpp @@ -1,6 +1,8 @@ #include +#define CHAR_RANGE_DEFAULT_CONSTRUCTIBLE #include "helpers.hpp" +#undef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE #include #include @@ -31,6 +33,23 @@ TEST_CASE("powerset: basic test, [1, 2, 3]", "[powerset]") { REQUIRE(v == vc); } +TEST_CASE("powerset: Works with different begin and end types", + "[powerset]") { + CharRange cr{'d'}; + using CharPermSet = std::multiset>; + CharPermSet sc; + for (auto&& v : powerset(cr)) { + sc.emplace(std::begin(v), std::end(v)); + } + const CharPermSet ans = { + {}, + {'a'}, {'b'}, {'c'}, + {'a', 'b'}, {'a', 'c'}, {'b', 'c'}, + {'a', 'b', 'c'}}; + + REQUIRE(ans == sc); +} + TEST_CASE("powerset: empty sequence gives only empty set", "[powerset]") { const std::vector ns = {}; auto ps = powerset(ns); From f7b94d7c6481df4a0aadb0b91327f6b64e7a8169 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:28:24 -0800 Subject: [PATCH 053/403] Tests sorted with different begin and end --- test/test_sorted.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/test_sorted.cpp b/test/test_sorted.cpp index d04f9364..55a0a11c 100644 --- a/test/test_sorted.cpp +++ b/test/test_sorted.cpp @@ -38,6 +38,20 @@ TEST_CASE("sorted: can modify elements through sorted", "[sorted]") { REQUIRE(ns == vc); } +char inc_vowels(char c) { + return c == 'a' || c == 'e' ? c + 10 : c; +} + +TEST_CASE("sorted: Works with different begin and end types", + "[sorted]") { + using Vec = std::vector; + CharRange cr{'g'}; + auto s = sorted(cr, [](char x, char y){return inc_vowels(x) < inc_vowels(y);}); + Vec v(s.begin(), s.end()); + Vec vc{'b', 'c', 'd', 'f', 'a', 'e'}; + REQUIRE(v == vc); +} + TEST_CASE("sorted: can iterate over unordered container", "[sorted]") { std::unordered_set ns = {1, 3, 2, 0, 4}; auto s = sorted(ns); From cfb0854c157d14c0378094c8f27b2425155cc177 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:28:31 -0800 Subject: [PATCH 054/403] Tests unique_everseen with different begin and end --- test/test_unique_everseen.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/test_unique_everseen.cpp b/test/test_unique_everseen.cpp index f83b358e..44380d27 100644 --- a/test/test_unique_everseen.cpp +++ b/test/test_unique_everseen.cpp @@ -46,6 +46,16 @@ TEST_CASE( REQUIRE(bi.was_moved_from()); } +TEST_CASE("unique everseen: Works with different begin and end types", + "[unique_everseen]") { + CharRange cr{'d'}; + using Vec = std::vector; + auto ue = unique_everseen(cr); + Vec v(ue.begin(), ue.end()); + Vec vc{'a', 'b', 'c'}; + REQUIRE(v == vc); +} + TEST_CASE("unique_everseen: iterator meets requirements", "[unique_everseen]") { std::string s{}; auto c = unique_everseen(s); From 844ac9d695f04af424ce04a3ccb629f72a54c519 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:28:37 -0800 Subject: [PATCH 055/403] Tests unique_justseen with different begin and end --- test/test_unique_justseen.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/test_unique_justseen.cpp b/test/test_unique_justseen.cpp index e66bdee6..bbfb6a5d 100644 --- a/test/test_unique_justseen.cpp +++ b/test/test_unique_justseen.cpp @@ -35,6 +35,16 @@ TEST_CASE("unique justseen: some repeating values", "[unique_justseen]") { REQUIRE(v == vc); } +TEST_CASE("unique justseen: Works with different begin and end types", + "[unique_justseen]") { + CharRange cr{'d'}; + using Vec = std::vector; + auto uj = unique_justseen(cr); + Vec v(uj.begin(), uj.end()); + Vec vc{'a', 'b', 'c'}; + REQUIRE(v == vc); +} + TEST_CASE("unique justseen: doesn't omit non-adjacent duplicates", "[unique_justseen]") { Vec ns = {1, 2, 3, 2, 1, 2, 3, 2, 1}; From 1134aa32808aa1e1ae4acbc9c9fba9d243375467 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:28:54 -0800 Subject: [PATCH 056/403] Tests zip with different begin and end --- test/test_zip.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/test_zip.cpp b/test/test_zip.cpp index d8cb80e5..a5e002d8 100644 --- a/test/test_zip.cpp +++ b/test/test_zip.cpp @@ -29,6 +29,19 @@ TEST_CASE("zip: Simple case, same length", "[zip]") { REQUIRE(v == vc); } +TEST_CASE("zip: three sequences, one sequence has different begin and end", "[zip]") { + using Tu = std::tuple; + using ResVec = const std::vector; + std::vector iv{10, 20, 30}; + CharRange cr('d'); + double arr[] = {1.0, 2.0, 4.0}; + + auto z = zip(iv, cr, arr); + ResVec v(std::begin(z), std::end(z)); + ResVec vc{Tu{10, 'a', 1.0}, Tu{20, 'b', 2.0}, Tu{30, 'c', 4.0}}; + REQUIRE(v == vc); +} + TEST_CASE("zip: One empty, all empty", "[zip]") { std::vector iv = {1, 2, 3}; std::string s{}; From f78b813cda21adf8c8504eed60ef138d248a9837 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:29:00 -0800 Subject: [PATCH 057/403] Tests zip_longest with different begin and end --- test/test_zip_longest.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/test_zip_longest.cpp b/test/test_zip_longest.cpp index c8694e9e..d7d28b61 100644 --- a/test/test_zip_longest.cpp +++ b/test/test_zip_longest.cpp @@ -80,6 +80,22 @@ TEST_CASE( } } +TEST_CASE("zip_longest: three sequences, one sequence has different begin and end", "[zip_longest]") { + //using TP = const_opt_tuple; + using TP = std::tuple; + using ResVec = std::vector; + + std::vector iv{10, 20}; + CharRange cr('c'); + + ResVec v; + for (auto&& p : zip_longest(iv, cr)) { + v.push_back(TP{*std::get<0>(p), *std::get<1>(p)}); + } + ResVec vc{TP{10, 'a'}, TP{20, 'b'}}; + REQUIRE(v == vc); +} + TEST_CASE( "zip longest: when all are empty, terminates right away", "[zip_longest]") { const std::vector ivec{}; From 2e9d815bb5d6ae1f87fb8a06570735c3d57fa5d9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:29:22 -0800 Subject: [PATCH 058/403] Updates iterator wrapper test For templating on begin and end types instead of container --- test/test_iterator_wrapper.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test_iterator_wrapper.cpp b/test/test_iterator_wrapper.cpp index b3b99f2d..c133d725 100644 --- a/test/test_iterator_wrapper.cpp +++ b/test/test_iterator_wrapper.cpp @@ -59,7 +59,9 @@ struct DifferentTypes { // Explicit instatiations, which could cause failures if the implementation // details of the implementation details change. -template class iter::impl::IteratorWrapperImpl; +template class iter::impl::IteratorWrapperImpl< +iter::impl::iterator_type, + iter::impl::iterator_end_type>; using iter::impl::IteratorWrapper; From cce0ce6fcbb70efa77b08043dc5cd80ddb34f9e8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:39:31 -0800 Subject: [PATCH 059/403] clang-formats tests --- test/test_accumulate.cpp | 7 +- test/test_chain.cpp | 11 +- test/test_chunked.cpp | 7 +- test/test_combinations.cpp | 4 +- test/test_combinations_with_replacement.cpp | 5 +- test/test_compress.cpp | 10 +- test/test_count.cpp | 4 +- test/test_cycle.cpp | 21 ++-- test/test_dropwhile.cpp | 12 +- test/test_enumerate.cpp | 10 +- test/test_filter.cpp | 9 +- test/test_filterfalse.cpp | 10 +- test/test_groupby.cpp | 11 +- test/test_imap.cpp | 11 +- test/test_iterator_wrapper.cpp | 128 +++++++++++++------- test/test_iteratoriterator.cpp | 2 +- test/test_iterbase.cpp | 8 +- test/test_mixed.cpp | 11 +- test/test_permutations.cpp | 12 +- test/test_powerset.cpp | 19 ++- test/test_product.cpp | 7 +- test/test_range.cpp | 6 +- test/test_repeat.cpp | 4 +- test/test_reversed.cpp | 2 +- test/test_slice.cpp | 7 +- test/test_sliding_window.cpp | 8 +- test/test_sorted.cpp | 16 +-- test/test_starmap.cpp | 11 +- test/test_takewhile.cpp | 12 +- test/test_unique_everseen.cpp | 4 +- test/test_unique_justseen.cpp | 4 +- test/test_zip.cpp | 12 +- test/test_zip_longest.cpp | 17 +-- 33 files changed, 221 insertions(+), 201 deletions(-) diff --git a/test/test_accumulate.cpp b/test/test_accumulate.cpp index fdab1913..7ba3ba22 100644 --- a/test/test_accumulate.cpp +++ b/test/test_accumulate.cpp @@ -1,9 +1,9 @@ #include #include "helpers.hpp" -#include #include #include +#include #include "catch.hpp" @@ -102,8 +102,8 @@ TEST_CASE("accumulate: iterator meets requirements", "[accumulate]") { REQUIRE(itertest::IsIterator::value); } -TEST_CASE("accumulate: Works with different begin and end types", - "[accumulate]") { +TEST_CASE( + "accumulate: Works with different begin and end types", "[accumulate]") { CharRange cr{'d'}; auto a = accumulate(cr); Vec v(a.begin(), a.end()); @@ -111,7 +111,6 @@ TEST_CASE("accumulate: Works with different begin and end types", REQUIRE(v == vc); } - template using ImpT = decltype(accumulate(std::declval())); TEST_CASE("accumulate: has correct ctor and assign ops", "[accumulate]") { diff --git a/test/test_chain.cpp b/test/test_chain.cpp index c0c6efb7..fbb28cc4 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -1,12 +1,11 @@ -#include "helpers.hpp" #include +#include "helpers.hpp" -#include +#include #include #include -#include -#include #include +#include #include "catch.hpp" @@ -39,8 +38,8 @@ TEST_CASE("chain: with different container types", "[chain]") { REQUIRE(v == vc); } -TEST_CASE("chain: where one container has different begin and end types", - "[chain]") { +TEST_CASE( + "chain: where one container has different begin and end types", "[chain]") { std::string s1{"abc"}; std::list li{'m', 'n', 'o'}; CharRange cr('e'); diff --git a/test/test_chunked.cpp b/test/test_chunked.cpp index 2ecfc8c4..533bec05 100644 --- a/test/test_chunked.cpp +++ b/test/test_chunked.cpp @@ -1,12 +1,12 @@ #include -#include #include #include #include +#include -#include "helpers.hpp" #include "catch.hpp" +#include "helpers.hpp" using iter::chunked; using Vec = std::vector; @@ -60,8 +60,7 @@ TEST_CASE("chunked: size 0 is empty", "[chunked]") { REQUIRE(std::begin(g) == std::end(g)); } -TEST_CASE("chunked: Works with different begin and end types", - "[chunked]") { +TEST_CASE("chunked: Works with different begin and end types", "[chunked]") { CharRange cr{'f'}; std::vector> results; for (auto&& g : chunked(cr, 3)) { diff --git a/test/test_combinations.cpp b/test/test_combinations.cpp index ef4e4653..974b0798 100644 --- a/test/test_combinations.cpp +++ b/test/test_combinations.cpp @@ -6,10 +6,10 @@ #include +#include #include -#include #include -#include +#include #include "catch.hpp" diff --git a/test/test_combinations_with_replacement.cpp b/test/test_combinations_with_replacement.cpp index 9540588d..905450f5 100644 --- a/test/test_combinations_with_replacement.cpp +++ b/test/test_combinations_with_replacement.cpp @@ -1,8 +1,8 @@ #include #include -#include #include +#include #include #define CHAR_RANGE_DEFAULT_CONSTRUCTIBLE @@ -33,7 +33,8 @@ TEST_CASE("combinations_with_replacement: Simple combination", REQUIRE(ans == sc); } -TEST_CASE("combinations_with_replacement: Works with different begin and end types", +TEST_CASE( + "combinations_with_replacement: Works with different begin and end types", "[combinations_with_replacement]") { CharRange cr{'d'}; CharCombSet sc; diff --git a/test/test_compress.cpp b/test/test_compress.cpp index 7938b23a..5b13b345 100644 --- a/test/test_compress.cpp +++ b/test/test_compress.cpp @@ -1,11 +1,10 @@ -#include "helpers.hpp" #include +#include "helpers.hpp" -#include -#include -#include #include +#include #include +#include #include "catch.hpp" @@ -136,8 +135,7 @@ TEST_CASE("compress: iterator meets requirements", "[compress]") { REQUIRE(itertest::IsIterator::value); } -TEST_CASE("compress: Works with different begin and end types", - "[compress]") { +TEST_CASE("compress: Works with different begin and end types", "[compress]") { CharRange cr{'d'}; auto c = compress(cr, std::vector{true, false, true}); Vec v(c.begin(), c.end()); diff --git a/test/test_count.cpp b/test/test_count.cpp index 643819ea..d1f0ff65 100644 --- a/test/test_count.cpp +++ b/test/test_count.cpp @@ -1,9 +1,9 @@ -#include "helpers.hpp" #include +#include "helpers.hpp" -#include #include #include +#include #include "catch.hpp" diff --git a/test/test_cycle.cpp b/test/test_cycle.cpp index 3066d00d..39e3bb19 100644 --- a/test/test_cycle.cpp +++ b/test/test_cycle.cpp @@ -2,9 +2,9 @@ #include "helpers.hpp" -#include -#include #include +#include +#include #include "catch.hpp" @@ -17,7 +17,9 @@ TEST_CASE("cycle: iterate twice", "[cycle]") { for (auto i : cycle(ns)) { v.push_back(i); ++count; - if (count == ns.size() * 2) { break; } + if (count == ns.size() * 2) { + break; + } } auto vc = ns; @@ -25,8 +27,7 @@ TEST_CASE("cycle: iterate twice", "[cycle]") { REQUIRE(v == vc); } -TEST_CASE("cycle: Works with different begin and end types", - "[cycle]") { +TEST_CASE("cycle: Works with different begin and end types", "[cycle]") { constexpr auto sz = 'd' - 'a'; CharRange cr{'d'}; const std::vector vc{'a', 'b', 'c', 'a', 'b', 'c'}; @@ -35,14 +36,14 @@ TEST_CASE("cycle: Works with different begin and end types", for (auto i : cycle(cr)) { v.push_back(i); ++count; - if (count == sz * 2) { break; } + if (count == sz * 2) { + break; + } } REQUIRE(v == vc); } - - TEST_CASE("cycle: with pipe", "[cycle]") { std::vector ns{2, 4, 6}; std::vector v; @@ -50,7 +51,9 @@ TEST_CASE("cycle: with pipe", "[cycle]") { for (auto i : ns | cycle) { v.push_back(i); ++count; - if (count == ns.size() * 2) { break; } + if (count == ns.size() * 2) { + break; + } } auto vc = ns; diff --git a/test/test_dropwhile.cpp b/test/test_dropwhile.cpp index aba3ec09..49b4e49a 100644 --- a/test/test_dropwhile.cpp +++ b/test/test_dropwhile.cpp @@ -2,9 +2,9 @@ #include "helpers.hpp" -#include -#include #include +#include +#include #include "catch.hpp" @@ -27,10 +27,10 @@ TEST_CASE("dropwhile: skips initial elements", "[dropwhile]") { REQUIRE(v == vc); } -TEST_CASE("dropwhile: Works with different begin and end types", - "[dropwhile]") { +TEST_CASE( + "dropwhile: Works with different begin and end types", "[dropwhile]") { CharRange cr{'f'}; - auto d = dropwhile([](char c){return c < 'c';}, cr); + auto d = dropwhile([](char c) { return c < 'c'; }, cr); Vec v(d.begin(), d.end()); Vec vc{'c', 'd', 'e'}; REQUIRE(v == vc); @@ -52,7 +52,7 @@ TEST_CASE("dropwhile: skips all elements when all are true under predicate", } TEST_CASE("dropwhile: identity", "[dropwhile]") { - Vec ns {1, 2, 0, 3, 1, 0}; + Vec ns{1, 2, 0, 3, 1, 0}; auto d = dropwhile(ns); Vec v(std::begin(d), std::end(d)); Vec vc = {0, 3, 1, 0}; diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index 3b8f56ac..33666dc6 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -2,11 +2,11 @@ #include "helpers.hpp" -#include -#include #include -#include #include +#include +#include +#include namespace Catch { template @@ -148,8 +148,8 @@ TEST_CASE("enumerate: works index and pipe", "[enumerate]") { REQUIRE(v == vc); } -TEST_CASE("enumerate: Works with different begin and end types", - "[enumerate]") { +TEST_CASE( + "enumerate: Works with different begin and end types", "[enumerate]") { CharRange cr{'d'}; auto e = enumerate(cr); Vec v(e.begin(), e.end()); diff --git a/test/test_filter.cpp b/test/test_filter.cpp index d5c1aed3..4badfaf1 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -2,9 +2,9 @@ #include "helpers.hpp" -#include -#include #include +#include +#include #include "catch.hpp" @@ -145,10 +145,9 @@ TEST_CASE("filter: using identity and pipe", "[filter]") { REQUIRE(v == vc); } -TEST_CASE("filter: Works with different begin and end types", - "[filter]") { +TEST_CASE("filter: Works with different begin and end types", "[filter]") { CharRange cr{'d'}; - auto f = filter([](char c){return c != 'b';}, cr); + auto f = filter([](char c) { return c != 'b'; }, cr); Vec v(f.begin(), f.end()); Vec vc{'a', 'c'}; REQUIRE(v == vc); diff --git a/test/test_filterfalse.cpp b/test/test_filterfalse.cpp index dbf826fd..dec5c2eb 100644 --- a/test/test_filterfalse.cpp +++ b/test/test_filterfalse.cpp @@ -2,9 +2,9 @@ #include "helpers.hpp" -#include -#include #include +#include +#include #include "catch.hpp" @@ -60,10 +60,10 @@ TEST_CASE("filterfalse: handles different functor types", "[filterfalse]") { } } -TEST_CASE("filterfalse: Works with different begin and end types", - "[filterfalse]") { +TEST_CASE( + "filterfalse: Works with different begin and end types", "[filterfalse]") { CharRange cr{'d'}; - auto f = filterfalse([](char c){return c == 'b';}, cr); + auto f = filterfalse([](char c) { return c == 'b'; }, cr); Vec v(f.begin(), f.end()); Vec vc{'a', 'c'}; REQUIRE(v == vc); diff --git a/test/test_groupby.cpp b/test/test_groupby.cpp index c353b491..cc1b824a 100644 --- a/test/test_groupby.cpp +++ b/test/test_groupby.cpp @@ -2,9 +2,9 @@ #include "helpers.hpp" -#include -#include #include +#include +#include #include "catch.hpp" @@ -69,17 +69,16 @@ TEST_CASE("groupby: works with lambda, callable, and function pointer") { REQUIRE(groups == gc); } -TEST_CASE("groupby: Works with different begin and end types", - "[groupby]") { +TEST_CASE("groupby: Works with different begin and end types", "[groupby]") { CharRange cr{'f'}; std::vector keys; std::vector> groups; - for (auto&& gb : groupby(cr, [](char c){return c == 'c';})) { + for (auto&& gb : groupby(cr, [](char c) { return c == 'c'; })) { keys.push_back(gb.first); groups.emplace_back(std::begin(gb.second), std::end(gb.second)); } const std::vector kc = {false, true, false}; - const std::vector> gc = {{'a' ,'b'}, {'c'}, {'d', 'e'}}; + const std::vector> gc = {{'a', 'b'}, {'c'}, {'d', 'e'}}; REQUIRE(keys == kc); REQUIRE(groups == gc); } diff --git a/test/test_imap.cpp b/test/test_imap.cpp index 2ab1f5a6..e7c2bcd2 100644 --- a/test/test_imap.cpp +++ b/test/test_imap.cpp @@ -2,10 +2,10 @@ #include "helpers.hpp" -#include -#include -#include #include +#include +#include +#include #include "catch.hpp" @@ -61,10 +61,9 @@ TEST_CASE("imap: works with lambda, callable, and function", "[imap]") { REQUIRE(v == vc); } -TEST_CASE("imap: Works with different begin and end types", - "[imap]") { +TEST_CASE("imap: Works with different begin and end types", "[imap]") { CharRange cr{'d'}; - auto m = imap([](char c) { return std::toupper(c);}, cr); + auto m = imap([](char c) { return std::toupper(c); }, cr); Vec v(m.begin(), m.end()); Vec vc{'A', 'B', 'C'}; REQUIRE(v == vc); diff --git a/test/test_iterator_wrapper.cpp b/test/test_iterator_wrapper.cpp index c133d725..6c79a278 100644 --- a/test/test_iterator_wrapper.cpp +++ b/test/test_iterator_wrapper.cpp @@ -1,8 +1,7 @@ // NOTE this header tests implementation details -#include "internal/iterator_wrapper.hpp" #include "catch.hpp" - +#include "internal/iterator_wrapper.hpp" // I'm using a std::vector of 1 int instead of just an int in order to give // the iterator types non-trivial constructors, destructors, and assignment. @@ -10,62 +9,101 @@ // same begin() and end() types struct SameTypes { struct iterator { - iterator(int) : value_(1) { } - - bool operator!=(const iterator& other) const { return value_ != other.value_; } - iterator& operator++() { ++value_.front(); return *this; } - const int& operator*() const { return value_.front(); } - std::vector value_; // non-trvial operations + iterator(int) : value_(1) {} + + bool operator!=(const iterator& other) const { + return value_ != other.value_; + } + iterator& operator++() { + ++value_.front(); + return *this; + } + const int& operator*() const { + return value_.front(); + } + std::vector value_; // non-trvial operations }; - iterator begin() const { return {0}; } - iterator end() const { return {0}; } + iterator begin() const { + return {0}; + } + iterator end() const { + return {0}; + } }; - // different begin() and end() types struct DifferentTypes { struct iterator; struct end_iterator; struct iterator { - iterator() : value_{} { REQUIRE(false); } + iterator() : value_{} { + REQUIRE(false); + } iterator(int i) : value_(1, i) {} - bool operator!=(const iterator& other) const { return value() != other.value(); } - bool operator!=(const end_iterator&) const { return value() != 3; } - iterator& operator++() { ++value_.front(); return *this; } - const int& operator*() const { return value(); } - - const int& value() const { return value_.front(); } + bool operator!=(const iterator& other) const { + return value() != other.value(); + } + bool operator!=(const end_iterator&) const { + return value() != 3; + } + iterator& operator++() { + ++value_.front(); + return *this; + } + const int& operator*() const { + return value(); + } + + const int& value() const { + return value_.front(); + } std::vector value_; }; struct end_iterator { - end_iterator() { REQUIRE(false); } - end_iterator(int){} - - bool operator!=(const end_iterator&) const { return false; } - bool operator!=(const iterator& other) const { return other.value() != 3; } - end_iterator& operator++() { return *this; } - const int& operator*() const { assert(false); return value(); } - - const int& value() const { return value_.front(); } + end_iterator() { + REQUIRE(false); + } + end_iterator(int) {} + + bool operator!=(const end_iterator&) const { + return false; + } + bool operator!=(const iterator& other) const { + return other.value() != 3; + } + end_iterator& operator++() { + return *this; + } + const int& operator*() const { + assert(false); + return value(); + } + + const int& value() const { + return value_.front(); + } std::vector value_{}; }; - iterator begin() const { return {0}; } - end_iterator end() const { return {0}; } + iterator begin() const { + return {0}; + } + end_iterator end() const { + return {0}; + } }; // Explicit instatiations, which could cause failures if the implementation // details of the implementation details change. -template class iter::impl::IteratorWrapperImpl< -iter::impl::iterator_type, - iter::impl::iterator_end_type>; +template class iter::impl:: + IteratorWrapperImpl, + iter::impl::iterator_end_type>; using iter::impl::IteratorWrapper; - TEST_CASE("ensure test type iterators are totally comparable", "[test_util") { { SameTypes s{}; @@ -84,14 +122,12 @@ TEST_CASE("ensure test type iterators are totally comparable", "[test_util") { } } - -TEST_CASE("Operations on IteratorWrappers with SameTypes work", - "[base_iterator]") { +TEST_CASE( + "Operations on IteratorWrappers with SameTypes work", "[base_iterator]") { SameTypes s; IteratorWrapper it(s.begin()); - REQUIRE((std::is_same< - std::decay_t, - std::decay_t>{})); + REQUIRE((std::is_same, + std::decay_t>{})); REQUIRE(*it == 0); ++it; REQUIRE(*it == 1); @@ -102,9 +138,8 @@ TEST_CASE("Operations on IteratorWrappers with DifferentTypes work", DifferentTypes d; using BI = IteratorWrapper; BI it(d.begin()); - REQUIRE((!std::is_same< - std::decay_t, - std::decay_t>{})); + REQUIRE((!std::is_same, + std::decay_t>{})); REQUIRE(*it == 0); ++it; REQUIRE(*it == 1); @@ -128,8 +163,8 @@ TEST_CASE("Operations on IteratorWrappers with DifferentTypes work", REQUIRE_FALSE(bend != it); } -TEST_CASE("Can copy construct a IteratorWrapper with SameTypes", - "[base_iterator]") { +TEST_CASE( + "Can copy construct a IteratorWrapper with SameTypes", "[base_iterator]") { SameTypes s; using BI = IteratorWrapper; BI it(s.begin()); @@ -139,8 +174,8 @@ TEST_CASE("Can copy construct a IteratorWrapper with SameTypes", REQUIRE(it != it2); } - -TEST_CASE("Can copy assign a IteratorWrapper with SameTypes", "[base_iterator]") { +TEST_CASE( + "Can copy assign a IteratorWrapper with SameTypes", "[base_iterator]") { SameTypes s; using BI = IteratorWrapper; BI it(s.begin()); @@ -183,6 +218,5 @@ TEST_CASE("Can copy construct a IteratorWrapper with DifferenTypes", REQUIRE_FALSE(it != it_end); } } - // TODO test move operations diff --git a/test/test_iteratoriterator.cpp b/test/test_iteratoriterator.cpp index c3abd95a..c4442f7a 100644 --- a/test/test_iteratoriterator.cpp +++ b/test/test_iteratoriterator.cpp @@ -1,7 +1,7 @@ #include -#include #include +#include #include "catch.hpp" diff --git a/test/test_iterbase.cpp b/test/test_iterbase.cpp index a19247da..59b80066 100644 --- a/test/test_iterbase.cpp +++ b/test/test_iterbase.cpp @@ -2,13 +2,13 @@ // on any of this. Users of the library must consider all of this undocumented // +#include #include -#include -#include #include -#include #include -#include +#include +#include +#include #include "catch.hpp" #include "helpers.hpp" diff --git a/test/test_mixed.cpp b/test/test_mixed.cpp index cc607e64..ecf65091 100644 --- a/test/test_mixed.cpp +++ b/test/test_mixed.cpp @@ -123,7 +123,7 @@ TEST_CASE("takewhile doesn't dereference multiple times", "[imap][takewhile]") { } TEST_CASE("sorted(chain.from_iterable)", "[sorted][chain.from_iterable]") { - std::vector> v = {{2,4,6}}; + std::vector> v = {{2, 4, 6}}; auto s = iter::sorted(iter::chain.from_iterable(v)); } @@ -133,10 +133,11 @@ TEST_CASE("filter into enumerate with pipe", "[filter][enumerate]") { using iter::enumerate; std::array arr = {{{41}, {42}, {43}, {44}}}; - auto seq = arr - | filter([](const MyUnMovable& mv) { return mv.get_val() % 2 == 0; }) - | enumerate - | imap([] (const auto& imv) { return std::make_pair(imv.first, imv.second.get_val());}); + auto seq = + arr | filter([](const MyUnMovable& mv) { return mv.get_val() % 2 == 0; }) + | enumerate | imap([](const auto& imv) { + return std::make_pair(imv.first, imv.second.get_val()); + }); using Vec = std::vector>; const Vec v(std::begin(seq), std::end(seq)); const Vec vc = {{0, 42}, {1, 44}}; diff --git a/test/test_permutations.cpp b/test/test_permutations.cpp index a2ab49ee..d07c6ffd 100644 --- a/test/test_permutations.cpp +++ b/test/test_permutations.cpp @@ -2,9 +2,9 @@ #include "helpers.hpp" -#include -#include #include +#include +#include #include "catch.hpp" @@ -39,11 +39,9 @@ TEST_CASE("permutations: Works with different begin and end types", for (auto&& v : permutations(cr)) { sc.emplace(std::begin(v), std::end(v)); } - const CharPermSet ans = { - {'a', 'b', 'c'}, {'a', 'c', 'b'}, - {'b', 'a', 'c'}, {'b', 'c', 'a'}, - {'c', 'a', 'b'}, {'c', 'b', 'a'}}; - + const CharPermSet ans = {{'a', 'b', 'c'}, {'a', 'c', 'b'}, {'b', 'a', 'c'}, + {'b', 'c', 'a'}, {'c', 'a', 'b'}, {'c', 'b', 'a'}}; + REQUIRE(ans == sc); } diff --git a/test/test_powerset.cpp b/test/test_powerset.cpp index b8fb388e..cfc8515d 100644 --- a/test/test_powerset.cpp +++ b/test/test_powerset.cpp @@ -4,9 +4,9 @@ #include "helpers.hpp" #undef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE -#include -#include #include +#include +#include #include "catch.hpp" @@ -28,25 +28,20 @@ TEST_CASE("powerset: basic test, [1, 2, 3]", "[powerset]") { } const IntPermSet vc = { - std::multiset{}, {1}, {2}, {3}, - {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}; + std::multiset{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}; REQUIRE(v == vc); } -TEST_CASE("powerset: Works with different begin and end types", - "[powerset]") { +TEST_CASE("powerset: Works with different begin and end types", "[powerset]") { CharRange cr{'d'}; using CharPermSet = std::multiset>; CharPermSet sc; for (auto&& v : powerset(cr)) { sc.emplace(std::begin(v), std::end(v)); } - const CharPermSet ans = { - {}, - {'a'}, {'b'}, {'c'}, - {'a', 'b'}, {'a', 'c'}, {'b', 'c'}, - {'a', 'b', 'c'}}; - + const CharPermSet ans = {{}, {'a'}, {'b'}, {'c'}, {'a', 'b'}, {'a', 'c'}, + {'b', 'c'}, {'a', 'b', 'c'}}; + REQUIRE(ans == sc); } diff --git a/test/test_product.cpp b/test/test_product.cpp index 4f9f1d2c..f5303e4f 100644 --- a/test/test_product.cpp +++ b/test/test_product.cpp @@ -2,9 +2,9 @@ #include "helpers.hpp" -#include -#include #include +#include +#include #include "catch.hpp" @@ -26,7 +26,8 @@ TEST_CASE("product: basic test, two sequences", "[product]") { REQUIRE(v == vc); } -TEST_CASE("product: two sequences where one has different begin and end", "[product]") { +TEST_CASE("product: two sequences where one has different begin and end", + "[product]") { using TP = std::tuple; using ResType = std::vector; diff --git a/test/test_range.cpp b/test/test_range.cpp index 52482df0..c7705d41 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -1,11 +1,11 @@ #include "range.hpp" -#include -#include #include +#include +#include -#include "helpers.hpp" #include "catch.hpp" +#include "helpers.hpp" using Vec = const std::vector; using iter::range; diff --git a/test/test_repeat.cpp b/test/test_repeat.cpp index 3cd928df..df42c99c 100644 --- a/test/test_repeat.cpp +++ b/test/test_repeat.cpp @@ -2,9 +2,9 @@ #include "helpers.hpp" -#include -#include #include +#include +#include #include "catch.hpp" diff --git a/test/test_reversed.cpp b/test/test_reversed.cpp index 2ccf5d2f..81ea1d4f 100644 --- a/test/test_reversed.cpp +++ b/test/test_reversed.cpp @@ -1,9 +1,9 @@ #include -#include #include #include #include +#include #include "catch.hpp" diff --git a/test/test_slice.cpp b/test/test_slice.cpp index 8cb3ee66..385e6c12 100644 --- a/test/test_slice.cpp +++ b/test/test_slice.cpp @@ -1,11 +1,11 @@ #include -#include #include #include +#include -#include "helpers.hpp" #include "catch.hpp" +#include "helpers.hpp" using iter::slice; using Vec = const std::vector; @@ -44,8 +44,7 @@ TEST_CASE("slice: start and stop", "[slice]") { REQUIRE(v == vc); } -TEST_CASE("slice: Works with different begin and end types", - "[slice]") { +TEST_CASE("slice: Works with different begin and end types", "[slice]") { CharRange cr{'z'}; auto sl = slice(cr, 2, 5); std::vector v(std::begin(sl), std::end(sl)); diff --git a/test/test_sliding_window.cpp b/test/test_sliding_window.cpp index 8400aedf..21d93679 100644 --- a/test/test_sliding_window.cpp +++ b/test/test_sliding_window.cpp @@ -1,12 +1,12 @@ #include -#include #include #include #include +#include -#include "helpers.hpp" #include "catch.hpp" +#include "helpers.hpp" using iter::sliding_window; using Vec = const std::vector; @@ -36,9 +36,7 @@ TEST_CASE("sliding_window: Works with different begin and end types", results.emplace_back(std::begin(g), std::end(g)); } std::vector> rc = { - {'a', 'b', 'c'}, - {'b', 'c', 'd'}, - {'c', 'd', 'e'}}; + {'a', 'b', 'c'}, {'b', 'c', 'd'}, {'c', 'd', 'e'}}; REQUIRE(results == rc); } diff --git a/test/test_sorted.cpp b/test/test_sorted.cpp index 55a0a11c..054b1eda 100644 --- a/test/test_sorted.cpp +++ b/test/test_sorted.cpp @@ -1,14 +1,14 @@ #include -#include -#include -#include #include +#include #include +#include #include +#include -#include "helpers.hpp" #include "catch.hpp" +#include "helpers.hpp" using iter::sorted; @@ -42,11 +42,11 @@ char inc_vowels(char c) { return c == 'a' || c == 'e' ? c + 10 : c; } -TEST_CASE("sorted: Works with different begin and end types", - "[sorted]") { +TEST_CASE("sorted: Works with different begin and end types", "[sorted]") { using Vec = std::vector; CharRange cr{'g'}; - auto s = sorted(cr, [](char x, char y){return inc_vowels(x) < inc_vowels(y);}); + auto s = + sorted(cr, [](char x, char y) { return inc_vowels(x) < inc_vowels(y); }); Vec v(s.begin(), s.end()); Vec vc{'b', 'c', 'd', 'f', 'a', 'e'}; REQUIRE(v == vc); @@ -193,7 +193,7 @@ TEST_CASE("sorted: moves rvalues and binds to lvalues", "[sorted]") { TEST_CASE("sorted: doesn't move or copy elements of iterable", "[sorted]") { using itertest::SolidInt; constexpr SolidInt arr[] = {{6}, {7}, {8}}; - for (auto &&i : sorted(arr, [](const SolidInt &lhs, const SolidInt &rhs) { + for (auto &&i : sorted(arr, [](const SolidInt&lhs, const SolidInt&rhs) { return lhs.getint() < rhs.getint(); })) { (void)i; diff --git a/test/test_starmap.cpp b/test/test_starmap.cpp index 6f1e7d7b..55e94503 100644 --- a/test/test_starmap.cpp +++ b/test/test_starmap.cpp @@ -2,10 +2,10 @@ #include "helpers.hpp" -#include +#include #include #include -#include +#include #include "catch.hpp" @@ -57,13 +57,10 @@ TEST_CASE("starmap: works with function pointer and lambda", "[starmap]") { REQUIRE(v == vc); } -TEST_CASE("starmap: Works with different begin and end types", - "[starmap]") { +TEST_CASE("starmap: Works with different begin and end types", "[starmap]") { IntCharPairRange icr{{3, 'd'}}; using Vec = std::vector; - auto sm = starmap([](int i, char c) { - return std::to_string(i) + c;}, - icr); + auto sm = starmap([](int i, char c) { return std::to_string(i) + c; }, icr); Vec v(sm.begin(), sm.end()); Vec vc{"0a", "1b", "2c"}; REQUIRE(v == vc); diff --git a/test/test_takewhile.cpp b/test/test_takewhile.cpp index 202e99ab..14a739c1 100644 --- a/test/test_takewhile.cpp +++ b/test/test_takewhile.cpp @@ -1,12 +1,12 @@ #include -#include #include #include #include +#include -#include "helpers.hpp" #include "catch.hpp" +#include "helpers.hpp" using iter::takewhile; using Vec = const std::vector; @@ -57,10 +57,10 @@ TEST_CASE("takewhile: works with lambda, callable, and function pointer", } } -TEST_CASE("takewhile: Works with different begin and end types", - "[takewhile]") { +TEST_CASE( + "takewhile: Works with different begin and end types", "[takewhile]") { CharRange cr{'f'}; - auto t = takewhile([](char c){return c < 'd';}, cr); + auto t = takewhile([](char c) { return c < 'd'; }, cr); Vec v(t.begin(), t.end()); Vec vc{'a', 'b', 'c'}; REQUIRE(v == vc); @@ -77,7 +77,7 @@ TEST_CASE("takewhile: identity", "[takewhile]") { auto tw = ns | takewhile; v.assign(std::begin(tw), std::end(tw)); } - Vec vc = {1,2,3}; + Vec vc = {1, 2, 3}; REQUIRE(v == vc); } diff --git a/test/test_unique_everseen.cpp b/test/test_unique_everseen.cpp index 44380d27..03bc6439 100644 --- a/test/test_unique_everseen.cpp +++ b/test/test_unique_everseen.cpp @@ -2,9 +2,9 @@ #include "helpers.hpp" -#include -#include #include +#include +#include #include "catch.hpp" diff --git a/test/test_unique_justseen.cpp b/test/test_unique_justseen.cpp index bbfb6a5d..3d7dabc7 100644 --- a/test/test_unique_justseen.cpp +++ b/test/test_unique_justseen.cpp @@ -2,9 +2,9 @@ #include "helpers.hpp" -#include -#include #include +#include +#include #include "catch.hpp" diff --git a/test/test_zip.cpp b/test/test_zip.cpp index a5e002d8..b0312e1e 100644 --- a/test/test_zip.cpp +++ b/test/test_zip.cpp @@ -2,13 +2,12 @@ #include "helpers.hpp" -#include -#include -#include #include -#include #include -#include +#include +#include +#include +#include #include "catch.hpp" @@ -29,7 +28,8 @@ TEST_CASE("zip: Simple case, same length", "[zip]") { REQUIRE(v == vc); } -TEST_CASE("zip: three sequences, one sequence has different begin and end", "[zip]") { +TEST_CASE( + "zip: three sequences, one sequence has different begin and end", "[zip]") { using Tu = std::tuple; using ResVec = const std::vector; std::vector iv{10, 20, 30}; diff --git a/test/test_zip_longest.cpp b/test/test_zip_longest.cpp index d7d28b61..85b8ee31 100644 --- a/test/test_zip_longest.cpp +++ b/test/test_zip_longest.cpp @@ -2,14 +2,13 @@ #include "helpers.hpp" -#include -#include -#include -#include -#include +#include #include #include -#include +#include +#include +#include +#include #include "catch.hpp" @@ -80,8 +79,10 @@ TEST_CASE( } } -TEST_CASE("zip_longest: three sequences, one sequence has different begin and end", "[zip_longest]") { - //using TP = const_opt_tuple; +TEST_CASE( + "zip_longest: three sequences, one sequence has different begin and end", + "[zip_longest]") { + // using TP = const_opt_tuple; using TP = std::tuple; using ResVec = std::vector; From 1330973210bab3eb11e8a15974b12f8ef9ccdabc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:40:01 -0800 Subject: [PATCH 060/403] clang-format --- accumulate.hpp | 12 +- chain.hpp | 20 +- chunked.hpp | 10 +- combinations.hpp | 6 +- combinations_with_replacement.hpp | 4 +- compress.hpp | 5 +- cycle.hpp | 6 +- dropwhile.hpp | 10 +- enumerate.hpp | 6 +- filter.hpp | 14 +- filterfalse.hpp | 2 +- groupby.hpp | 11 +- imap.hpp | 2 +- internal/iter_tuples.hpp | 2 +- internal/iterator_wrapper.hpp | 298 +++++++++++++++--------------- internal/iteratoriterator.hpp | 11 +- internal/iterbase.hpp | 13 +- itertools.hpp | 4 +- permutations.hpp | 11 +- powerset.hpp | 6 +- product.hpp | 4 +- range.hpp | 20 +- repeat.hpp | 2 +- slice.hpp | 7 +- sliding_window.hpp | 11 +- sorted.hpp | 7 +- starmap.hpp | 13 +- takewhile.hpp | 10 +- unique_everseen.hpp | 8 +- unique_justseen.hpp | 10 +- zip.hpp | 2 +- zip_longest.hpp | 2 +- 32 files changed, 272 insertions(+), 277 deletions(-) mode change 100755 => 100644 internal/iterator_wrapper.hpp diff --git a/accumulate.hpp b/accumulate.hpp index cad5f29c..875ab8c8 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -1,14 +1,14 @@ #ifndef ITER_ACCUMULATE_H_ #define ITER_ACCUMULATE_H_ -#include "internal/iterbase.hpp" #include "internal/iterator_wrapper.hpp" +#include "internal/iterbase.hpp" -#include -#include #include -#include +#include #include +#include +#include namespace iter { namespace impl { @@ -46,8 +46,8 @@ class iter::impl::Accumulator { std::unique_ptr acc_val; public: - Iterator(IteratorWrapper&& iter, IteratorWrapper&& end, - AccumulateFunc& in_accumulate_fun) + Iterator(IteratorWrapper&& iter, + IteratorWrapper&& end, AccumulateFunc& in_accumulate_fun) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, accumulate_func(&in_accumulate_fun), diff --git a/chain.hpp b/chain.hpp index 44e6f94f..99e57cac 100644 --- a/chain.hpp +++ b/chain.hpp @@ -1,9 +1,9 @@ #ifndef ITER_CHAIN_HPP_ #define ITER_CHAIN_HPP_ -#include "internal/iterbase.hpp" -#include "internal/iterator_wrapper.hpp" #include "internal/iter_tuples.hpp" +#include "internal/iterator_wrapper.hpp" +#include "internal/iterbase.hpp" #include #include @@ -156,19 +156,23 @@ class iter::impl::Chained { template constexpr std::array::DerefFunc, - sizeof...(Is)> iter::impl::Chained::derefers; + sizeof...(Is)> + iter::impl::Chained::derefers; template constexpr std::array::ArrowFunc, - sizeof...(Is)> iter::impl::Chained::arrowers; + sizeof...(Is)> + iter::impl::Chained::arrowers; template constexpr std::array::IncFunc, - sizeof...(Is)> iter::impl::Chained::incrementers; + sizeof...(Is)> + iter::impl::Chained::incrementers; template constexpr std::array::NeqFunc, - sizeof...(Is)> iter::impl::Chained::neq_comparers; + sizeof...(Is)> + iter::impl::Chained::neq_comparers; template class iter::impl::ChainedFromIterable { @@ -208,8 +212,8 @@ class iter::impl::ChainedFromIterable { } public: - Iterator( - IteratorWrapper&& top_iter, IteratorWrapper&& top_end) + Iterator(IteratorWrapper&& top_iter, + IteratorWrapper&& top_end) : top_level_iter{std::move(top_iter)}, top_level_end{std::move(top_end)}, sub_iter_p{!(top_iter != top_end) diff --git a/chunked.hpp b/chunked.hpp index a0009896..0b79a80c 100644 --- a/chunked.hpp +++ b/chunked.hpp @@ -1,16 +1,16 @@ #ifndef ITER_CHUNKED_HPP_ #define ITER_CHUNKED_HPP_ -#include "internal/iterbase.hpp" -#include "internal/iteratoriterator.hpp" #include "internal/iterator_wrapper.hpp" +#include "internal/iteratoriterator.hpp" +#include "internal/iterbase.hpp" -#include #include -#include #include -#include #include +#include +#include +#include namespace iter { namespace impl { diff --git a/combinations.hpp b/combinations.hpp index d90e21c6..e6de19c5 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -1,12 +1,12 @@ #ifndef ITER_COMBINATIONS_HPP_ #define ITER_COMBINATIONS_HPP_ -#include "internal/iterbase.hpp" #include "internal/iteratoriterator.hpp" +#include "internal/iterbase.hpp" -#include -#include #include +#include +#include namespace iter { namespace impl { diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index cfc04957..2257543a 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -1,12 +1,12 @@ #ifndef ITER_COMBINATIONS_WITH_REPLACEMENT_HPP_ #define ITER_COMBINATIONS_WITH_REPLACEMENT_HPP_ -#include "internal/iterbase.hpp" #include "internal/iteratoriterator.hpp" +#include "internal/iterbase.hpp" #include -#include #include +#include namespace iter { namespace impl { diff --git a/compress.hpp b/compress.hpp index 0482298d..b1d11f7c 100644 --- a/compress.hpp +++ b/compress.hpp @@ -1,11 +1,11 @@ #ifndef ITER_COMPRESS_H_ #define ITER_COMPRESS_H_ -#include "internal/iterbase.hpp" #include "internal/iterator_wrapper.hpp" +#include "internal/iterbase.hpp" -#include #include +#include namespace iter { namespace impl { @@ -15,7 +15,6 @@ namespace iter { template impl::Compressed compress(Container&&, Selector&&); - } template diff --git a/cycle.hpp b/cycle.hpp index b416553f..51bed25c 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -1,12 +1,12 @@ #ifndef ITER_CYCLE_H_ #define ITER_CYCLE_H_ -#include "internal/iterbase.hpp" #include "internal/iterator_wrapper.hpp" +#include "internal/iterbase.hpp" -#include -#include #include +#include +#include namespace iter { namespace impl { diff --git a/dropwhile.hpp b/dropwhile.hpp index 1f8c587d..4aceb371 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -1,12 +1,12 @@ #ifndef ITER_DROPWHILE_H_ #define ITER_DROPWHILE_H_ -#include "internal/iterbase.hpp" -#include "internal/iterator_wrapper.hpp" #include "filter.hpp" +#include "internal/iterator_wrapper.hpp" +#include "internal/iterbase.hpp" -#include #include +#include namespace iter { namespace impl { @@ -57,8 +57,8 @@ class iter::impl::Dropper { } public: - Iterator(IteratorWrapper&& iter, IteratorWrapper&& end, - FilterFunc& in_filter_func) + Iterator(IteratorWrapper&& iter, + IteratorWrapper&& end, FilterFunc& in_filter_func) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, filter_func(&in_filter_func) { diff --git a/enumerate.hpp b/enumerate.hpp index 3f4ab47c..02201b90 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -1,14 +1,14 @@ #ifndef ITER_ENUMERATE_H_ #define ITER_ENUMERATE_H_ -#include "internal/iterbase.hpp" #include "internal/iterator_wrapper.hpp" +#include "internal/iterbase.hpp" -#include -#include #include #include +#include #include +#include namespace iter { namespace impl { diff --git a/filter.hpp b/filter.hpp index 42ad09bd..69838cbf 100644 --- a/filter.hpp +++ b/filter.hpp @@ -1,12 +1,12 @@ #ifndef ITER_FILTER_H_ #define ITER_FILTER_H_ -#include "internal/iterbase.hpp" #include "internal/iterator_wrapper.hpp" +#include "internal/iterbase.hpp" -#include -#include #include +#include +#include namespace iter { namespace impl { @@ -69,9 +69,11 @@ class iter::impl::Filtered { } public: - Iterator(IteratorWrapper&& iter, IteratorWrapper&& end, - FilterFunc& in_filter_func) - : sub_iter{std::move(iter)}, sub_end{std::move(end)}, filter_func(&in_filter_func) { + Iterator(IteratorWrapper&& iter, + IteratorWrapper&& end, FilterFunc& in_filter_func) + : sub_iter{std::move(iter)}, + sub_end{std::move(end)}, + filter_func(&in_filter_func) { if (this->sub_iter != this->sub_end) { this->item.reset(*this->sub_iter); } diff --git a/filterfalse.hpp b/filterfalse.hpp index 513962f7..f46aba2a 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -1,8 +1,8 @@ #ifndef ITER_FILTER_FALSE_HPP_ #define ITER_FILTER_FALSE_HPP_ -#include "internal/iterbase.hpp" #include "filter.hpp" +#include "internal/iterbase.hpp" #include diff --git a/groupby.hpp b/groupby.hpp index e0a5f53a..24c8c048 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -3,13 +3,13 @@ // this is easily the most functionally complex itertool -#include "internal/iterbase.hpp" #include "internal/iterator_wrapper.hpp" +#include "internal/iterbase.hpp" -#include +#include #include +#include #include -#include namespace iter { namespace impl { @@ -193,9 +193,8 @@ class iter::impl::GroupProducer { } // move-constructible, non-copy-constructible, non-assignable - Group(Group&& other) noexcept : owner(other.owner), - key{other.key}, - completed{other.completed} { + Group(Group&& other) noexcept + : owner(other.owner), key{other.key}, completed{other.completed} { other.completed = true; } diff --git a/imap.hpp b/imap.hpp index 807a2826..f022e6d0 100644 --- a/imap.hpp +++ b/imap.hpp @@ -1,8 +1,8 @@ #ifndef ITER_IMAP_H_ #define ITER_IMAP_H_ -#include "zip.hpp" #include "starmap.hpp" +#include "zip.hpp" #include diff --git a/internal/iter_tuples.hpp b/internal/iter_tuples.hpp index 8e68f16e..cfba2cf3 100644 --- a/internal/iter_tuples.hpp +++ b/internal/iter_tuples.hpp @@ -1,8 +1,8 @@ #ifndef ITERTOOLS_ITER_TUPLES_HPP_ #define ITERTOOLS_ITER_TUPLES_HPP_ -#include "iterbase.hpp" #include "iterator_wrapper.hpp" +#include "iterbase.hpp" namespace iter { namespace impl { diff --git a/internal/iterator_wrapper.hpp b/internal/iterator_wrapper.hpp old mode 100755 new mode 100644 index 1f5e5536..a181539f --- a/internal/iterator_wrapper.hpp +++ b/internal/iterator_wrapper.hpp @@ -1,174 +1,170 @@ #ifndef ITERTOOLS_ITERATOR_WRAPPER_HPP_ #define ITERTOOLS_ITERATOR_WRAPPER_HPP_ -#include "iterbase.hpp" #include +#include "iterbase.hpp" namespace iter { -namespace impl { -// iterator_end_type is the type of C's end iterator -template -using iterator_end_type = decltype(std::end(std::declval())); - -template -class IteratorWrapperImpl; - - -// If begin and end return the same type, type will be iterator_type -// If begin and end return different types, type will be IteratorWrapperImpl -template -struct IteratorWrapperImplType; - -template -struct IteratorWrapperImplType -: type_is>{}; - -template -struct IteratorWrapperImplType -: type_is, iterator_end_type>>{}; - -template -using IteratorWrapper = typename IteratorWrapperImplType, - impl::iterator_end_type>{}>::type; -} + namespace impl { + // iterator_end_type is the type of C's end iterator + template + using iterator_end_type = decltype(std::end(std::declval())); + + template + class IteratorWrapperImpl; + + // If begin and end return the same type, type will be + // iterator_type + // If begin and end return different types, type will be IteratorWrapperImpl + template + struct IteratorWrapperImplType; + + template + struct IteratorWrapperImplType + : type_is> {}; + + template + struct IteratorWrapperImplType + : type_is, + iterator_end_type>> {}; + + template + using IteratorWrapper = typename IteratorWrapperImplType, + impl::iterator_end_type>{}>::type; + } } template class iter::impl::IteratorWrapperImpl { - private: - static_assert( - !std::is_same{}, - ""); - enum class IterState { Normal, End, Uninitialized}; + private: + static_assert(!std::is_same{}, ""); + enum class IterState { Normal, End, Uninitialized }; + + void destroy_sub() { + if (state_ == IterState::Normal) { + sub_iter_.~SubIter(); + } else if (state_ == IterState::End) { + sub_end_.~SubEnd(); + } + state_ = IterState::Uninitialized; + } - void destroy_sub() { + template + void copy_or_move_sub_from(T&& other) { + if (this == &other) { + return; + } + if (state_ == other.state_) { if (state_ == IterState::Normal) { - sub_iter_.~SubIter(); + sub_iter_ = std::forward(other).sub_iter_; } else if (state_ == IterState::End) { - sub_end_.~SubEnd(); + sub_end_ = std::forward(other).sub_end_; } - state_ = IterState::Uninitialized; - } - - template - void copy_or_move_sub_from(T&& other) { - if (this == &other) { return; } - if (state_ == other.state_) { - if (state_ == IterState::Normal) { - sub_iter_ = std::forward(other).sub_iter_; - } else if (state_ == IterState::End) { - sub_end_ = std::forward(other).sub_end_; - } - } else { - // state_s are different, must destroy and reconstruct - destroy_sub(); - if (other.state_ == IterState::Normal) { - new (&sub_iter_) SubIter(std::forward(other).sub_iter_); - } else if (other.state_ == IterState::End) { - new (&sub_end_) SubEnd(std::forward(other).sub_end_); - } - state_ = other.state_; + } else { + // state_s are different, must destroy and reconstruct + destroy_sub(); + if (other.state_ == IterState::Normal) { + new (&sub_iter_) SubIter(std::forward(other).sub_iter_); + } else if (other.state_ == IterState::End) { + new (&sub_end_) SubEnd(std::forward(other).sub_end_); } + state_ = other.state_; } - - - void copy_sub_from(const IteratorWrapperImpl& other) { - copy_or_move_sub_from(other); - } - - void move_sub_from(IteratorWrapperImpl&& other) { - copy_or_move_sub_from(std::move(other)); - } - - // TODO replace with std::variant when C++17 is going strong - union { - SubIter sub_iter_; - SubEnd sub_end_; - }; - IterState state_{IterState::Uninitialized}; - - public: - IteratorWrapperImpl() : IteratorWrapperImpl(SubIter{}) {} - - IteratorWrapperImpl(const IteratorWrapperImpl& other) { - copy_sub_from(other); - } - - IteratorWrapperImpl& operator=(const IteratorWrapperImpl& other) { - copy_sub_from(other); - return *this; - } - - IteratorWrapperImpl(IteratorWrapperImpl&& other) { - move_sub_from(std::move(other)); - } - - IteratorWrapperImpl& operator=(IteratorWrapperImpl&& other) { - move_sub_from(std::move(other)); - return *this; - } - - IteratorWrapperImpl(SubIter&& it) - : sub_iter_{std::move(it)}, - state_{IterState::Normal} { } - - IteratorWrapperImpl(SubEnd&& it) - : sub_end_(std::move(it)), - state_{IterState::End} { } - - IteratorWrapperImpl& operator++() { - assert(state_ == IterState::Normal); // because ++ing the end is UB - ++sub_iter_; - return *this; - } - - decltype(auto) operator*() { - assert(state_ == IterState::Normal); //because *ing the end is UB - return *sub_iter_; - } - - decltype(auto) operator*() const { - assert(state_ == IterState::Normal); //because *ing the end is UB - return *sub_iter_; - } - - decltype(auto) operator->() { - assert(state_ == IterState::Normal); - return apply_arrow(sub_iter_); - } - - decltype(auto) operator->() const { - assert(state_ == IterState::Normal); - return apply_arrow(sub_iter_); - } - - bool operator!=(const IteratorWrapperImpl& other) const { - assert(state_ != IterState::Uninitialized - && other.state_ != IterState::Uninitialized); - if (state_ == other.state_) { - if (state_ == IterState::End) { - // NOTE this used to be return sub_end_ != other.sub_end_; - // but rangev3 sentinels aren't comparable - // https://github.com/ericniebler/range-v3/issues/564 - return false; - } else { - return sub_iter_ != other.sub_iter_; - } + } + + void copy_sub_from(const IteratorWrapperImpl& other) { + copy_or_move_sub_from(other); + } + + void move_sub_from(IteratorWrapperImpl&& other) { + copy_or_move_sub_from(std::move(other)); + } + + // TODO replace with std::variant when C++17 is going strong + union { + SubIter sub_iter_; + SubEnd sub_end_; + }; + IterState state_{IterState::Uninitialized}; + + public: + IteratorWrapperImpl() : IteratorWrapperImpl(SubIter{}) {} + + IteratorWrapperImpl(const IteratorWrapperImpl& other) { + copy_sub_from(other); + } + + IteratorWrapperImpl& operator=(const IteratorWrapperImpl& other) { + copy_sub_from(other); + return *this; + } + + IteratorWrapperImpl(IteratorWrapperImpl&& other) { + move_sub_from(std::move(other)); + } + + IteratorWrapperImpl& operator=(IteratorWrapperImpl&& other) { + move_sub_from(std::move(other)); + return *this; + } + + IteratorWrapperImpl(SubIter&& it) + : sub_iter_{std::move(it)}, state_{IterState::Normal} {} + + IteratorWrapperImpl(SubEnd&& it) + : sub_end_(std::move(it)), state_{IterState::End} {} + + IteratorWrapperImpl& operator++() { + assert(state_ == IterState::Normal); // because ++ing the end is UB + ++sub_iter_; + return *this; + } + + decltype(auto) operator*() { + assert(state_ == IterState::Normal); // because *ing the end is UB + return *sub_iter_; + } + + decltype(auto) operator*() const { + assert(state_ == IterState::Normal); // because *ing the end is UB + return *sub_iter_; + } + + decltype(auto) operator-> () { + assert(state_ == IterState::Normal); + return apply_arrow(sub_iter_); + } + + decltype(auto) operator-> () const { + assert(state_ == IterState::Normal); + return apply_arrow(sub_iter_); + } + + bool operator!=(const IteratorWrapperImpl& other) const { + assert(state_ != IterState::Uninitialized + && other.state_ != IterState::Uninitialized); + if (state_ == other.state_) { + if (state_ == IterState::End) { + // NOTE this used to be return sub_end_ != other.sub_end_; + // but rangev3 sentinels aren't comparable + // https://github.com/ericniebler/range-v3/issues/564 + return false; } else { - if(state_ == IterState::Normal) { // other is End - return sub_iter_ != other.sub_end_; - } else { // other is Normal - return sub_end_ != other.sub_iter_; - } + return sub_iter_ != other.sub_iter_; + } + } else { + if (state_ == IterState::Normal) { // other is End + return sub_iter_ != other.sub_end_; + } else { // other is Normal + return sub_end_ != other.sub_iter_; } } + } - ~IteratorWrapperImpl() { - this->destroy_sub(); - } - + ~IteratorWrapperImpl() { + this->destroy_sub(); + } }; - #endif diff --git a/internal/iteratoriterator.hpp b/internal/iteratoriterator.hpp index a49b4b06..23bde9d5 100644 --- a/internal/iteratoriterator.hpp +++ b/internal/iteratoriterator.hpp @@ -1,10 +1,10 @@ #ifndef ITERATOR_ITERATOR_HPP_ #define ITERATOR_ITERATOR_HPP_ -#include "iterbase.hpp" #include #include #include +#include "iterbase.hpp" // IterIterWrapper and IteratorIterator provide a means to have a container // of iterators act like a container of the pointed to objects. This is useful @@ -25,11 +25,12 @@ namespace iter { template class IteratorIterator : public std::iterator())>::type> { + typename std::remove_reference())>::type> { using Diff = std::ptrdiff_t; static_assert( - std::is_same::iterator_category, + std::is_same< + typename std::iterator_traits::iterator_category, std::random_access_iterator_tag>::value, "IteratorIterator only works with random access iterators"); @@ -74,7 +75,7 @@ namespace iter { return **this->sub_iter; } - auto operator -> () -> decltype(*sub_iter) { + auto operator-> () -> decltype(*sub_iter) { return *this->sub_iter; } diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 8f73cb0d..032d8e00 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -7,13 +7,13 @@ // also applies to the name of the file. No user code should include // this file directly. -#include -#include -#include +#include #include +#include #include +#include #include -#include +#include namespace iter { namespace impl { @@ -178,8 +178,7 @@ namespace iter { Distance dumb_size(Container&& container) { Distance d{0}; auto end_it = std::end(container); - for (auto it = std::begin(container); - it != end_it; ++it) { + for (auto it = std::begin(container); it != end_it; ++it) { ++d; } return d; @@ -335,7 +334,7 @@ namespace iter { protected: template auto operator()(Container&& container, std::false_type) const { - return static_cast (*this)( + return static_cast(*this)( std::forward(container)); } diff --git a/itertools.hpp b/itertools.hpp index 939d6919..7dd9b9a8 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -3,6 +3,7 @@ #include "accumulate.hpp" #include "chain.hpp" +#include "chunked.hpp" #include "combinations.hpp" #include "combinations_with_replacement.hpp" #include "compress.hpp" @@ -13,9 +14,7 @@ #include "filter.hpp" #include "filterfalse.hpp" #include "groupby.hpp" -#include "chunked.hpp" #include "imap.hpp" -#include "sliding_window.hpp" #include "permutations.hpp" #include "powerset.hpp" #include "product.hpp" @@ -23,6 +22,7 @@ #include "repeat.hpp" #include "reversed.hpp" #include "slice.hpp" +#include "sliding_window.hpp" #include "sorted.hpp" #include "starmap.hpp" #include "takewhile.hpp" diff --git a/permutations.hpp b/permutations.hpp index 0e6c3aa5..4d895fa1 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -1,15 +1,15 @@ #ifndef ITER_PERMUTATIONS_HPP_ #define ITER_PERMUTATIONS_HPP_ -#include "internal/iterbase.hpp" -#include "internal/iteratoriterator.hpp" #include "internal/iterator_wrapper.hpp" +#include "internal/iteratoriterator.hpp" +#include "internal/iterbase.hpp" #include #include -#include -#include #include +#include +#include namespace iter { namespace impl { @@ -47,8 +47,7 @@ class iter::impl::Permuter { int steps{}; public: - Iterator( - IteratorWrapper&& sub_iter, + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end) : steps{sub_iter != sub_end ? 0 : COMPLETE} { // done like this instead of using vector ctor with diff --git a/powerset.hpp b/powerset.hpp index c0ea0ade..68aab5f8 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -1,15 +1,15 @@ #ifndef ITER_POWERSET_HPP_ #define ITER_POWERSET_HPP_ -#include "internal/iterbase.hpp" #include "combinations.hpp" +#include "internal/iterbase.hpp" #include -#include #include -#include #include +#include #include +#include namespace iter { namespace impl { diff --git a/product.hpp b/product.hpp index 3b1b5572..31eb9555 100644 --- a/product.hpp +++ b/product.hpp @@ -1,13 +1,13 @@ #ifndef ITER_PRODUCT_HPP_ #define ITER_PRODUCT_HPP_ -#include "internal/iterbase.hpp" #include "internal/iterator_wrapper.hpp" +#include "internal/iterbase.hpp" +#include #include #include #include -#include namespace iter { namespace impl { diff --git a/range.hpp b/range.hpp index 67a0c267..0aafa7de 100644 --- a/range.hpp +++ b/range.hpp @@ -3,10 +3,10 @@ #include "internal/iterbase.hpp" +#include #include -#include #include -#include +#include namespace iter { namespace impl { @@ -37,8 +37,7 @@ namespace iter { public: constexpr RangeIterData() noexcept = default; constexpr RangeIterData(T in_value, T in_step) noexcept - : value_{in_value}, - step_{in_step} {} + : value_{in_value}, step_{in_step} {} constexpr T value() const noexcept { return this->value_; @@ -73,9 +72,7 @@ namespace iter { public: constexpr RangeIterData() noexcept = default; constexpr RangeIterData(T in_start, T in_step) noexcept - : start_{in_start}, - value_{in_start}, - step_{in_step} {} + : start_{in_start}, value_{in_start}, step_{in_step} {} constexpr T value() const noexcept { return this->value_; @@ -124,9 +121,7 @@ class iter::impl::Range { constexpr Range(T in_stop) noexcept : start{0}, stop{in_stop}, step{1} {} constexpr Range(T in_start, T in_stop, T in_step = 1) noexcept - : start{in_start}, - stop{in_stop}, - step{in_step} {} + : start{in_start}, stop{in_stop}, step{in_step} {} public: // the reference type here is T, which doesn't strictly follow all @@ -170,8 +165,7 @@ class iter::impl::Range { constexpr Iterator() noexcept = default; constexpr Iterator(T in_value, T in_step, bool in_is_end) noexcept - : data(in_value, in_step), - is_end{in_is_end} {} + : data(in_value, in_step), is_end{in_is_end} {} constexpr T operator*() const noexcept { return this->data.value(); @@ -186,7 +180,7 @@ class iter::impl::Range { return *this; } - Iterator operator++(int) noexcept { + Iterator operator++(int)noexcept { auto ret = *this; ++*this; return ret; diff --git a/repeat.hpp b/repeat.hpp index c33d40c5..0dd8cf91 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -119,7 +119,7 @@ class iter::impl::Repeater { return *this; } - constexpr Iterator operator++(int) const { + constexpr Iterator operator++(int)const { return *this; } diff --git a/slice.hpp b/slice.hpp index df2ce0a2..c1d21e3a 100644 --- a/slice.hpp +++ b/slice.hpp @@ -1,8 +1,8 @@ #ifndef ITER_SLICE_HPP_ #define ITER_SLICE_HPP_ -#include "internal/iterbase.hpp" #include "internal/iterator_wrapper.hpp" +#include "internal/iterbase.hpp" #include #include @@ -111,9 +111,8 @@ struct iter::impl::SliceFn { private: friend SliceFn; constexpr FnPartial(DifferenceType in_start, DifferenceType in_stop, - DifferenceType in_step) noexcept : start{in_start}, - stop{in_stop}, - step{in_step} {} + DifferenceType in_step) noexcept + : start{in_start}, stop{in_stop}, step{in_step} {} DifferenceType start; DifferenceType stop; DifferenceType step; diff --git a/sliding_window.hpp b/sliding_window.hpp index 6a68faaa..2dc6e81d 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -1,13 +1,13 @@ #ifndef ITER_SLIDING_WINDOW_HPP_ #define ITER_SLIDING_WINDOW_HPP_ -#include "internal/iterbase.hpp" #include "internal/iterator_wrapper.hpp" #include "internal/iteratoriterator.hpp" +#include "internal/iterbase.hpp" #include -#include #include +#include namespace iter { namespace impl { @@ -41,7 +41,7 @@ class iter::impl::WindowSlider { public: Iterator(IteratorWrapper&& in_iter, - IteratorWrapper&& in_end, std::size_t window_sz) + IteratorWrapper&& in_end, std::size_t window_sz) : sub_iter(std::move(in_iter)) { std::size_t i{0}; while (i < window_sz && this->sub_iter != in_end) { @@ -84,8 +84,9 @@ class iter::impl::WindowSlider { }; Iterator begin() { - return {(this->window_size != 0 ? IteratorWrapper{std::begin(this->container)} - : IteratorWrapper{std::end(this->container)}), + return {(this->window_size != 0 + ? IteratorWrapper{std::begin(this->container)} + : IteratorWrapper{std::end(this->container)}), std::end(this->container), this->window_size}; } diff --git a/sorted.hpp b/sorted.hpp index 529b8dcc..5393d3a7 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -1,11 +1,11 @@ #ifndef ITER_SORTED_HPP_ #define ITER_SORTED_HPP_ -#include "internal/iterbase.hpp" #include "internal/iteratoriterator.hpp" +#include "internal/iterbase.hpp" -#include #include +#include #include namespace iter { @@ -38,8 +38,7 @@ class iter::impl::SortedView { } // sort by comparing the elements that the iterators point to - std::sort( - std::begin(sorted_iters.get()), std::end(sorted_iters.get()), + std::sort(std::begin(sorted_iters.get()), std::end(sorted_iters.get()), [compare_func](iterator_type it1, iterator_type it2) { return compare_func(*it1, *it2); }); } diff --git a/starmap.hpp b/starmap.hpp index 7570e03e..1521b5a4 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -1,15 +1,15 @@ #ifndef ITER_STARMAP_H_ #define ITER_STARMAP_H_ -#include "internal/iterbase.hpp" #include "internal/iterator_wrapper.hpp" +#include "internal/iterbase.hpp" -#include -#include -#include #include #include +#include #include +#include +#include namespace iter { namespace impl { @@ -169,7 +169,8 @@ class iter::impl::TupleStarMapper { template constexpr std::array< typename iter::impl::TupleStarMapper::CallerFunc, - sizeof...(Is)> iter::impl::TupleStarMapper::callers; + sizeof...(Is)> + iter::impl::TupleStarMapper::callers; struct iter::impl::StarMapFn : PipeableAndBindFirst { private: @@ -184,7 +185,7 @@ struct iter::impl::StarMapFn : PipeableAndBindFirst { auto helper(Func func, TupType&& tup, std::true_type) const { return helper_with_tuples(std::move(func), std::forward(tup), std::make_index_sequence>:: - value>{}); + value>{}); } // handles everything else diff --git a/takewhile.hpp b/takewhile.hpp index f05828dd..53df6a2a 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -1,12 +1,12 @@ #ifndef ITER_TAKEWHILE_H_ #define ITER_TAKEWHILE_H_ -#include "internal/iterbase.hpp" -#include "internal/iterator_wrapper.hpp" #include "filter.hpp" +#include "internal/iterator_wrapper.hpp" +#include "internal/iterbase.hpp" -#include #include +#include namespace iter { namespace impl { @@ -57,8 +57,8 @@ class iter::impl::Taker { } public: - Iterator(IteratorWrapper&& iter, IteratorWrapper&& end, - FilterFunc& in_filter_func) + Iterator(IteratorWrapper&& iter, + IteratorWrapper&& end, FilterFunc& in_filter_func) : sub_iter{std::move(iter)}, sub_end{std::move(end)}, filter_func(&in_filter_func) { diff --git a/unique_everseen.hpp b/unique_everseen.hpp index 21b15d21..3db10b99 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -1,14 +1,14 @@ #ifndef ITER_UNIQUE_EVERSEEN_HPP_ #define ITER_UNIQUE_EVERSEEN_HPP_ -#include "internal/iterbase.hpp" #include "filter.hpp" +#include "internal/iterbase.hpp" -#include #include -#include -#include #include +#include +#include +#include namespace iter { namespace impl { diff --git a/unique_justseen.hpp b/unique_justseen.hpp index caad5076..c7fd2462 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -4,8 +4,8 @@ #include "groupby.hpp" #include "imap.hpp" -#include #include +#include namespace iter { namespace impl { @@ -13,9 +13,11 @@ namespace iter { template auto operator()(Container&& container) const { // explicit return type in lambda so reference types are preserved - return imap([](auto&& group) -> impl::iterator_deref { - return *std::begin(group.second); - }, groupby(std::forward(container))); + return imap( + [](auto&& group) -> impl::iterator_deref { + return *std::begin(group.second); + }, + groupby(std::forward(container))); } }; } diff --git a/zip.hpp b/zip.hpp index b02c71c5..75bdba1d 100644 --- a/zip.hpp +++ b/zip.hpp @@ -4,10 +4,10 @@ #include "internal/iter_tuples.hpp" #include "internal/iterbase.hpp" +#include #include #include #include -#include namespace iter { namespace impl { diff --git a/zip_longest.hpp b/zip_longest.hpp index dfbcf5c1..f20ba869 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -1,8 +1,8 @@ #ifndef ITER_ZIP_LONGEST_HPP_ #define ITER_ZIP_LONGEST_HPP_ -#include "internal/iterbase.hpp" #include "internal/iter_tuples.hpp" +#include "internal/iterbase.hpp" #include #include From 3e2a51c559a2971b84ae0df71f718f6ea70a625a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 14:45:19 -0800 Subject: [PATCH 061/403] Adds missig include clang-format must have reordered things to expose this mistake. Cool --- starmap.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/starmap.hpp b/starmap.hpp index 1521b5a4..f71aaf6c 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -1,6 +1,7 @@ #ifndef ITER_STARMAP_H_ #define ITER_STARMAP_H_ +#include "internal/iter_tuples.hpp" #include "internal/iterator_wrapper.hpp" #include "internal/iterbase.hpp" From d7c54e35b1b4796e78c55dbe8806488650828b65 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:26:41 -0800 Subject: [PATCH 062/403] trailing _ on data members --- accumulate.hpp | 66 ++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 875ab8c8..64e3dd44 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -23,52 +23,52 @@ namespace iter { template class iter::impl::Accumulator { private: - Container container; - AccumulateFunc accumulate_func; + Container container_; + AccumulateFunc accumulate_func_; friend AccumulateFn; using AccumVal = std::remove_reference_t, iterator_deref)>>; - Accumulator(Container&& in_container, AccumulateFunc in_accumulate_func) - : container(std::forward(in_container)), - accumulate_func(in_accumulate_func) {} + Accumulator(Container&& container, AccumulateFunc accumulate_func) + : container_(std::forward(container)), + accumulate_func_(accumulate_func) {} public: Accumulator(Accumulator&&) = default; class Iterator : public std::iterator { private: - IteratorWrapper sub_iter; - IteratorWrapper sub_end; - AccumulateFunc* accumulate_func; - std::unique_ptr acc_val; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; + AccumulateFunc* accumulate_func_; + std::unique_ptr acc_val_; public: - Iterator(IteratorWrapper&& iter, - IteratorWrapper&& end, AccumulateFunc& in_accumulate_fun) - : sub_iter{std::move(iter)}, - sub_end{std::move(end)}, - accumulate_func(&in_accumulate_fun), + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, AccumulateFunc& accumulate_fun) + : sub_iter_{std::move(sub_iter)}, + sub_end_{std::move(sub_end)}, + accumulate_func_(&accumulate_fun), // only get first value if not an end iterator - acc_val{!(iter != end) ? nullptr : new AccumVal(*iter)} {} + acc_val_{ + !(sub_iter_ != sub_end_) ? nullptr : new AccumVal(*sub_iter_)} {} Iterator(const Iterator& other) - : sub_iter{other.sub_iter}, - sub_end{other.sub_end}, - accumulate_func{other.accumulate_func}, - acc_val{other.acc_val ? new AccumVal(*other.acc_val) : nullptr} {} + : sub_iter_{other.sub_iter_}, + sub_end_{other.sub_end_}, + accumulate_func_{other.accumulate_func_}, + acc_val_{other.acc_val_ ? new AccumVal(*other.acc_val_) : nullptr} {} Iterator& operator=(const Iterator& other) { if (this == &other) { return *this; } - this->sub_iter = other.sub_iter; - this->sub_end = other.sub_end; - this->accumulate_func = other.accumulate_func; - this->acc_val.reset( - other.acc_val ? new AccumVal(*other.acc_val) : nullptr); + sub_iter_ = other.sub_iter_; + sub_end_ = other.sub_end_; + accumulate_func_ = other.accumulate_func_; + acc_val_.reset(other.acc_val_ ? new AccumVal(*other.acc_val_) : nullptr); return *this; } @@ -76,17 +76,17 @@ class iter::impl::Accumulator { Iterator& operator=(Iterator&&) = default; const AccumVal& operator*() const { - return *this->acc_val; + return *acc_val_; } const AccumVal* operator->() const { - return this->acc_val.get(); + return acc_val_.get(); } Iterator& operator++() { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - *this->acc_val = (*accumulate_func)(*this->acc_val, *this->sub_iter); + ++sub_iter_; + if (sub_iter_ != sub_end_) { + *acc_val_ = (*accumulate_func_)(*acc_val_, *sub_iter_); } return *this; } @@ -98,7 +98,7 @@ class iter::impl::Accumulator { } bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; + return sub_iter_ != other.sub_iter_; } bool operator==(const Iterator& other) const { @@ -107,13 +107,11 @@ class iter::impl::Accumulator { }; Iterator begin() { - return {std::begin(this->container), std::end(this->container), - this->accumulate_func}; + return {std::begin(container_), std::end(container_), accumulate_func_}; } Iterator end() { - return {std::end(this->container), std::end(this->container), - this->accumulate_func}; + return {std::end(container_), std::end(container_), accumulate_func_}; } }; From 75958bbbab3c690a4589b8f2d1fc2ea020d3267c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:26:57 -0800 Subject: [PATCH 063/403] trailing _ on data members --- chain.hpp | 132 +++++++++++++++++++++++++++--------------------------- 1 file changed, 65 insertions(+), 67 deletions(-) diff --git a/chain.hpp b/chain.hpp index 99e57cac..7abb9f2a 100644 --- a/chain.hpp +++ b/chain.hpp @@ -87,42 +87,42 @@ class iter::impl::Chained { using TraitsValue = iterator_traits_deref>; private: - Chained(TupType&& t) : tup(std::move(t)) {} - TupType tup; + Chained(TupType&& t) : tup_(std::move(t)) {} + TupType tup_; public: Chained(Chained&&) = default; class Iterator : public std::iterator { private: - std::size_t index; - IterTupType iters; - IterTupType ends; + std::size_t index_; + IterTupType iters_; + IterTupType ends_; void check_for_end_and_adjust() { - while (this->index < sizeof...(Is) - && !(neq_comparers[this->index](this->iters, this->ends))) { - ++this->index; + while ( + index_ < sizeof...(Is) && !(neq_comparers[index_](iters_, ends_))) { + ++index_; } } public: - Iterator(std::size_t i, IterTupType&& in_iters, IterTupType&& in_ends) - : index{i}, iters(in_iters), ends(in_ends) { - this->check_for_end_and_adjust(); + Iterator(std::size_t i, IterTupType&& iters, IterTupType&& ends) + : index_{i}, iters_(std::move(iters)), ends_(std::move(ends)) { + check_for_end_and_adjust(); } decltype(auto) operator*() { - return derefers[this->index](this->iters); + return derefers[index_](iters_); } decltype(auto) operator-> () { - return arrowers[this->index](this->iters); + return arrowers[index_](iters_); } Iterator& operator++() { - incrementers[this->index](this->iters); - this->check_for_end_and_adjust(); + incrementers[index_](iters_); + check_for_end_and_adjust(); return *this; } @@ -133,9 +133,9 @@ class iter::impl::Chained { } bool operator!=(const Iterator& other) const { - return this->index != other.index - || (this->index != sizeof...(Is) - && neq_comparers[this->index](this->iters, other.iters)); + return index_ != other.index_ + || (index_ != sizeof...(Is) + && neq_comparers[index_](iters_, other.iters_)); } bool operator==(const Iterator& other) const { @@ -144,13 +144,13 @@ class iter::impl::Chained { }; Iterator begin() { - return {0, IterTupType{std::begin(std::get(this->tup))...}, - IterTupType{std::end(std::get(this->tup))...}}; + return {0, IterTupType{std::begin(std::get(tup_))...}, + IterTupType{std::end(std::get(tup_))...}}; } Iterator end() { - return {sizeof...(Is), IterTupType{std::end(std::get(this->tup))...}, - IterTupType{std::end(std::get(this->tup))...}}; + return {sizeof...(Is), IterTupType{std::end(std::get(tup_))...}, + IterTupType{std::end(std::get(tup_))...}}; } }; @@ -178,9 +178,9 @@ template class iter::impl::ChainedFromIterable { private: friend ChainFromIterableFn; - Container container; - ChainedFromIterable(Container&& in_container) - : container(std::forward(in_container)) {} + Container container_; + ChainedFromIterable(Container&& container) + : container_(std::forward(container)) {} public: ChainedFromIterable(ChainedFromIterable&&) = default; @@ -190,56 +190,56 @@ class iter::impl::ChainedFromIterable { using SubContainer = iterator_deref; using SubIter = IteratorWrapper; - IteratorWrapper top_level_iter; - IteratorWrapper top_level_end; - std::unique_ptr sub_iter_p; - std::unique_ptr sub_end_p; + IteratorWrapper top_level_iter_; + IteratorWrapper top_level_end_; + std::unique_ptr sub_iter_p_; + std::unique_ptr sub_end_p_; static std::unique_ptr clone_sub_pointer(const SubIter* sub_iter) { return sub_iter ? std::make_unique(*sub_iter) : nullptr; } bool sub_iters_differ(const Iterator& other) const { - if (this->sub_iter_p == other.sub_iter_p) { + if (sub_iter_p_ == other.sub_iter_p_) { return false; } - if (this->sub_iter_p == nullptr || other.sub_iter_p == nullptr) { + if (sub_iter_p_ == nullptr || other.sub_iter_p_ == nullptr) { // since the first check tests if they're the same, // this will return if only one is nullptr return true; } - return *this->sub_iter_p != *other.sub_iter_p; + return *sub_iter_p_ != *other.sub_iter_p_; } public: Iterator(IteratorWrapper&& top_iter, IteratorWrapper&& top_end) - : top_level_iter{std::move(top_iter)}, - top_level_end{std::move(top_end)}, - sub_iter_p{!(top_iter != top_end) + : top_level_iter_{std::move(top_iter)}, + top_level_end_{std::move(top_end)}, + sub_iter_p_{!(top_iter != top_end) + ? // iter == end ? + nullptr + : std::make_unique(std::begin(*top_iter))}, + sub_end_p_{!(top_iter != top_end) ? // iter == end ? nullptr - : std::make_unique(std::begin(*top_iter))}, - sub_end_p{!(top_iter != top_end) - ? // iter == end ? - nullptr - : std::make_unique(std::end(*top_iter))} {} + : std::make_unique(std::end(*top_iter))} {} Iterator(const Iterator& other) - : top_level_iter{other.top_level_iter}, - top_level_end{other.top_level_end}, - sub_iter_p{clone_sub_pointer(other.sub_iter_p.get())}, - sub_end_p{clone_sub_pointer(other.sub_end_p.get())} {} + : top_level_iter_{other.top_level_iter_}, + top_level_end_{other.top_level_end_}, + sub_iter_p_{clone_sub_pointer(other.sub_iter_p_.get())}, + sub_end_p_{clone_sub_pointer(other.sub_end_p_.get())} {} Iterator& operator=(const Iterator& other) { if (this == &other) { return *this; } - this->top_level_iter = other.top_level_iter; - this->top_level_end = other.top_level_end; - this->sub_iter_p = clone_sub_pointer(other.sub_iter_p.get()); - this->sub_end_p = clone_sub_pointer(other.sub_end_p.get()); + top_level_iter_ = other.top_level_iter_; + top_level_end_ = other.top_level_end_; + sub_iter_p_ = clone_sub_pointer(other.sub_iter_p_.get()); + sub_end_p_ = clone_sub_pointer(other.sub_end_p_.get()); return *this; } @@ -249,17 +249,15 @@ class iter::impl::ChainedFromIterable { ~Iterator() = default; Iterator& operator++() { - ++*this->sub_iter_p; - if (!(*this->sub_iter_p != *this->sub_end_p)) { - ++this->top_level_iter; - if (this->top_level_iter != this->top_level_end) { - sub_iter_p = - std::make_unique(std::begin(*this->top_level_iter)); - sub_end_p = - std::make_unique(std::end(*this->top_level_iter)); + ++*sub_iter_p_; + if (!(*sub_iter_p_ != *sub_end_p_)) { + ++top_level_iter_; + if (top_level_iter_ != top_level_end_) { + sub_iter_p_ = std::make_unique(std::begin(*top_level_iter_)); + sub_end_p_ = std::make_unique(std::end(*top_level_iter_)); } else { - sub_iter_p.reset(); - sub_end_p.reset(); + sub_iter_p_.reset(); + sub_end_p_.reset(); } } return *this; @@ -272,8 +270,8 @@ class iter::impl::ChainedFromIterable { } bool operator!=(const Iterator& other) const { - return this->top_level_iter != other.top_level_iter - || this->sub_iters_differ(other); + return top_level_iter_ != other.top_level_iter_ + || sub_iters_differ(other); } bool operator==(const Iterator& other) const { @@ -281,20 +279,20 @@ class iter::impl::ChainedFromIterable { } iterator_deref> operator*() { - return **this->sub_iter_p; + return **sub_iter_p_; } iterator_arrow> operator->() { - return apply_arrow(*this->sub_iter_p); + return apply_arrow(*sub_iter_p_); } }; Iterator begin() { - return {std::begin(this->container), std::end(this->container)}; + return {std::begin(container_), std::end(container_)}; } Iterator end() { - return {std::end(this->container), std::end(this->container)}; + return {std::end(container_), std::end(container_)}; } }; @@ -302,15 +300,15 @@ class iter::impl::ChainMaker { private: template Chained chain_impl( - TupleType&& in_containers, std::index_sequence) const { - return {std::move(in_containers)}; + TupleType&& containers, std::index_sequence) const { + return {std::move(containers)}; } public: // expose regular call operator to provide usual chain() template auto operator()(Containers&&... cs) const { - return this->chain_impl( + return chain_impl( std::tuple{std::forward(cs)...}, std::index_sequence_for{}); } From 685de0fb027289a86e38accb833818773bfbb0ec Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:27:04 -0800 Subject: [PATCH 064/403] trailing _ on data members --- chunked.hpp | 54 ++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/chunked.hpp b/chunked.hpp index 0b79a80c..6dcb8917 100644 --- a/chunked.hpp +++ b/chunked.hpp @@ -25,11 +25,11 @@ namespace iter { template class iter::impl::Chunker { private: - Container container; - std::size_t chunk_size; + Container container_; + std::size_t chunk_size_; - Chunker(Container&& c, std::size_t sz) - : container(std::forward(c)), chunk_size{sz} {} + Chunker(Container&& container, std::size_t sz) + : container_(std::forward(container)), chunk_size_{sz} {} friend ChunkedFn; @@ -40,37 +40,37 @@ class iter::impl::Chunker { Chunker(Chunker&&) = default; class Iterator : public std::iterator { private: - IteratorWrapper sub_iter; - IteratorWrapper sub_end; - DerefVec chunk; - std::size_t chunk_size = 0; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; + DerefVec chunk_; + std::size_t chunk_size_ = 0; bool done() const { - return this->chunk.empty(); + return chunk_.empty(); } void refill_chunk() { - this->chunk.get().clear(); + chunk_.get().clear(); std::size_t i{0}; - while (i < chunk_size && this->sub_iter != this->sub_end) { - chunk.get().push_back(this->sub_iter); - ++this->sub_iter; + while (i < chunk_size_ && sub_iter_ != sub_end_) { + chunk_.get().push_back(sub_iter_); + ++sub_iter_; ++i; } } public: - Iterator(IteratorWrapper&& in_iter, - IteratorWrapper&& in_end, std::size_t s) - : sub_iter{std::move(in_iter)}, - sub_end{std::move(in_end)}, - chunk_size{s} { - this->chunk.get().reserve(this->chunk_size); - this->refill_chunk(); + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, std::size_t s) + : sub_iter_{std::move(sub_iter)}, + sub_end_{std::move(sub_end)}, + chunk_size_{s} { + chunk_.get().reserve(chunk_size_); + refill_chunk(); } Iterator& operator++() { - this->refill_chunk(); + refill_chunk(); return *this; } @@ -85,25 +85,25 @@ class iter::impl::Chunker { } bool operator==(const Iterator& other) const { - return this->done() == other.done() - && (this->done() || !(this->sub_iter != other.sub_iter)); + return done() == other.done() + && (done() || !(sub_iter_ != other.sub_iter_)); } DerefVec& operator*() { - return this->chunk; + return chunk_; } DerefVec* operator->() { - return &this->chunk; + return &chunk_; } }; Iterator begin() { - return {std::begin(this->container), std::end(this->container), chunk_size}; + return {std::begin(container_), std::end(container_), chunk_size_}; } Iterator end() { - return {std::end(this->container), std::end(this->container), chunk_size}; + return {std::end(container_), std::end(container_), chunk_size_}; } }; From 717857a76d338f8ea98914d93a1c07f4ea80171e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:27:19 -0800 Subject: [PATCH 065/403] trailing _ on data members --- combinations.hpp | 59 ++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index e6de19c5..71660512 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -21,13 +21,13 @@ namespace iter { template class iter::impl::Combinator { private: - Container container; - std::size_t length; + Container container_; + std::size_t length_; friend CombinationsFn; - Combinator(Container&& in_container, std::size_t in_length) - : container(std::forward(in_container)), length{in_length} {} + Combinator(Container&& container, std::size_t length) + : container_(std::forward(container)), length_{length} {} using IndexVector = std::vector>; using CombIteratorDeref = IterIterWrapper; @@ -38,58 +38,59 @@ class iter::impl::Combinator { : public std::iterator { private: constexpr static const int COMPLETE = -1; - std::remove_reference_t* container_p; - CombIteratorDeref indices; - int steps{}; + std::remove_reference_t* container_p_; + CombIteratorDeref indices_; + int steps_{}; public: - Iterator(Container& in_container, std::size_t n) - : container_p{&in_container}, indices{n} { + Iterator(Container& container, std::size_t n) + : container_p_{&container}, indices_{n} { if (n == 0) { - this->steps = COMPLETE; + steps_ = COMPLETE; return; } size_t inc = 0; - for (auto& iter : this->indices.get()) { - auto it = std::begin(*this->container_p); - dumb_advance(it, std::end(*this->container_p), inc); - if (it != std::end(*this->container_p)) { + for (auto& iter : indices_.get()) { + auto it = std::begin(*container_p_); + dumb_advance(it, std::end(*container_p_), inc); + if (it != std::end(*container_p_)) { iter = it; ++inc; } else { - this->steps = COMPLETE; + steps_ = COMPLETE; break; } } } CombIteratorDeref& operator*() { - return this->indices; + return indices_; } CombIteratorDeref* operator->() { - return &this->indices; + return &indices_; } Iterator& operator++() { - for (auto iter = indices.get().rbegin(); iter != indices.get().rend(); + for (auto iter = indices_.get().rbegin(); iter != indices_.get().rend(); ++iter) { ++(*iter); // what we have to check here is if the distance between - // the index and the end of indices is >= the distance + // the index and the end of indices_ is >= the distance // between the item and end of item - auto dist = std::distance(this->indices.get().rbegin(), iter); + auto dist = std::distance(indices_.get().rbegin(), iter); - if (!(dumb_next(*iter, dist) != std::end(*this->container_p))) { - if ((iter + 1) != indices.get().rend()) { + if (!(dumb_next(*iter, dist) != std::end(*container_p_))) { + if ((iter + 1) != indices_.get().rend()) { size_t inc = 1; - for (auto down = iter; down != indices.get().rbegin() - 1; --down) { + for (auto down = iter; down != indices_.get().rbegin() - 1; + --down) { (*down) = dumb_next(*(iter + 1), 1 + inc); ++inc; } } else { - this->steps = COMPLETE; + steps_ = COMPLETE; break; } } else { @@ -98,8 +99,8 @@ class iter::impl::Combinator { // we break because none of the rest of the items need // to be incremented } - if (this->steps != COMPLETE) { - ++this->steps; + if (steps_ != COMPLETE) { + ++steps_; } return *this; } @@ -115,16 +116,16 @@ class iter::impl::Combinator { } bool operator==(const Iterator& other) const { - return this->steps == other.steps; + return steps_ == other.steps_; } }; Iterator begin() { - return {this->container, this->length}; + return {container_, length_}; } Iterator end() { - return {this->container, 0}; + return {container_, 0}; } }; From c5d4b2427019ce0cb179457d33962b52fc1c72b5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:27:25 -0800 Subject: [PATCH 066/403] trailing _ on data members --- combinations_with_replacement.hpp | 49 ++++++++++++++++--------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 2257543a..2fa33bd8 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -21,13 +21,13 @@ namespace iter { template class iter::impl::CombinatorWithReplacement { private: - Container container; - std::size_t length; + Container container_; + std::size_t length_; friend CombinationsWithReplacementFn; - CombinatorWithReplacement(Container&& in_container, std::size_t n) - : container(std::forward(in_container)), length{n} {} + CombinatorWithReplacement(Container&& container, std::size_t n) + : container_(std::forward(container)), length_{n} {} using IndexVector = std::vector>; using CombIteratorDeref = IterIterWrapper; @@ -38,37 +38,38 @@ class iter::impl::CombinatorWithReplacement { : public std::iterator { private: constexpr static const int COMPLETE = -1; - std::remove_reference_t* container_p; - CombIteratorDeref indices; - int steps; + std::remove_reference_t* container_p_; + CombIteratorDeref indices_; + int steps_; public: Iterator(Container& in_container, std::size_t n) - : container_p{&in_container}, - indices(n, std::begin(in_container)), - steps{(std::begin(in_container) != std::end(in_container) && n) - ? 0 - : COMPLETE} {} + : container_p_{&in_container}, + indices_(n, std::begin(in_container)), + steps_{(std::begin(in_container) != std::end(in_container) && n) + ? 0 + : COMPLETE} {} CombIteratorDeref& operator*() { - return this->indices; + return indices_; } CombIteratorDeref* operator->() { - return &this->indices; + return &indices_; } Iterator& operator++() { - for (auto iter = indices.get().rbegin(); iter != indices.get().rend(); + for (auto iter = indices_.get().rbegin(); iter != indices_.get().rend(); ++iter) { ++(*iter); - if (!(*iter != std::end(*this->container_p))) { - if ((iter + 1) != indices.get().rend()) { - for (auto down = iter; down != indices.get().rbegin() - 1; --down) { + if (!(*iter != std::end(*container_p_))) { + if ((iter + 1) != indices_.get().rend()) { + for (auto down = iter; down != indices_.get().rbegin() - 1; + --down) { (*down) = dumb_next(*(iter + 1)); } } else { - this->steps = COMPLETE; + steps_ = COMPLETE; break; } } else { @@ -77,8 +78,8 @@ class iter::impl::CombinatorWithReplacement { break; } } - if (this->steps != COMPLETE) { - ++this->steps; + if (steps_ != COMPLETE) { + ++steps_; } return *this; } @@ -94,16 +95,16 @@ class iter::impl::CombinatorWithReplacement { } bool operator==(const Iterator& other) const { - return this->steps == other.steps; + return steps_ == other.steps_; } }; Iterator begin() { - return {this->container, this->length}; + return {container_, length_}; } Iterator end() { - return {this->container, 0}; + return {container_, 0}; } }; From 3fa07d1441f871d668ddb442d332a5a25abbcbc2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:27:42 -0800 Subject: [PATCH 067/403] trailing _ on data members --- compress.hpp | 63 ++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/compress.hpp b/compress.hpp index b1d11f7c..ede8e934 100644 --- a/compress.hpp +++ b/compress.hpp @@ -20,40 +20,39 @@ namespace iter { template class iter::impl::Compressed { private: - Container container; - Selector selectors; + Container container_; + Selector selectors_; friend Compressed iter::compress( Container&&, Selector&&); // Selector::Iterator type - using selector_iter_type = decltype(std::begin(selectors)); + using selector_iter_type = decltype(std::begin(selectors_)); Compressed(Container&& in_container, Selector&& in_selectors) - : container(std::forward(in_container)), - selectors(std::forward(in_selectors)) {} + : container_(std::forward(in_container)), + selectors_(std::forward(in_selectors)) {} public: Compressed(Compressed&&) = default; class Iterator : public std::iterator> { private: - IteratorWrapper sub_iter; - IteratorWrapper sub_end; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; - selector_iter_type selector_iter; - selector_iter_type selector_end; + selector_iter_type selector_iter_; + selector_iter_type selector_end_; void increment_iterators() { - ++this->sub_iter; - ++this->selector_iter; + ++sub_iter_; + ++selector_iter_; } void skip_failures() { - while (this->sub_iter != this->sub_end - && this->selector_iter != this->selector_end - && !*this->selector_iter) { - this->increment_iterators(); + while (sub_iter_ != sub_end_ && selector_iter_ != selector_end_ + && !*selector_iter_) { + increment_iterators(); } } @@ -61,24 +60,24 @@ class iter::impl::Compressed { Iterator(IteratorWrapper&& cont_iter, IteratorWrapper&& cont_end, selector_iter_type&& sel_iter, selector_iter_type&& sel_end) - : sub_iter{std::move(cont_iter)}, - sub_end{std::move(cont_end)}, - selector_iter{std::move(sel_iter)}, - selector_end{std::move(sel_end)} { - this->skip_failures(); + : sub_iter_{std::move(cont_iter)}, + sub_end_{std::move(cont_end)}, + selector_iter_{std::move(sel_iter)}, + selector_end_{std::move(sel_end)} { + skip_failures(); } iterator_deref operator*() { - return *this->sub_iter; + return *sub_iter_; } iterator_arrow operator->() { - return apply_arrow(this->sub_iter); + return apply_arrow(sub_iter_); } Iterator& operator++() { - this->increment_iterators(); - this->skip_failures(); + increment_iterators(); + skip_failures(); return *this; } @@ -89,8 +88,8 @@ class iter::impl::Compressed { } bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter - && this->selector_iter != other.selector_iter; + return sub_iter_ != other.sub_iter_ + && selector_iter_ != other.selector_iter_; } bool operator==(const Iterator& other) const { @@ -99,21 +98,21 @@ class iter::impl::Compressed { }; Iterator begin() { - return {std::begin(this->container), std::end(this->container), - std::begin(this->selectors), std::end(this->selectors)}; + return {std::begin(container_), std::end(container_), + std::begin(selectors_), std::end(selectors_)}; } Iterator end() { - return {std::end(this->container), std::end(this->container), - std::end(this->selectors), std::end(this->selectors)}; + return {std::end(container_), std::end(container_), std::end(selectors_), + std::end(selectors_)}; } }; template iter::impl::Compressed iter::compress( - Container&& container, Selector&& selectors) { + Container&& container_, Selector&& selectors_) { return { - std::forward(container), std::forward(selectors)}; + std::forward(container_), std::forward(selectors_)}; } #endif From 200302984b576c1bb309399b1377dd2c2af1c87e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:27:47 -0800 Subject: [PATCH 068/403] trailing _ on data members --- cycle.hpp | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index 51bed25c..24396e7e 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -23,38 +23,40 @@ class iter::impl::Cycler { private: friend CycleFn; - Container container; + Container container_; - Cycler(Container&& in_container) - : container(std::forward(in_container)) {} + Cycler(Container&& container) + : container_(std::forward(container)) {} public: Cycler(Cycler&&) = default; class Iterator : public std::iterator> { private: - IteratorWrapper sub_iter; - IteratorWrapper begin; - IteratorWrapper end; + IteratorWrapper sub_iter_; + IteratorWrapper sub_begin_; + IteratorWrapper sub_end_; public: - Iterator( - IteratorWrapper&& iter, IteratorWrapper&& in_end) - : sub_iter{iter}, begin{iter}, end{std::move(in_end)} {} + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end) + : sub_iter_{sub_iter}, + sub_begin_{sub_iter}, + sub_end_{std::move(sub_end)} {} iterator_deref operator*() { - return *this->sub_iter; + return *sub_iter_; } iterator_arrow operator->() { - return apply_arrow(this->sub_iter); + return apply_arrow(sub_iter_); } Iterator& operator++() { - ++this->sub_iter; - // reset to beginning upon reaching the end - if (!(this->sub_iter != this->end)) { - this->sub_iter = this->begin; + ++sub_iter_; + // reset to beginning upon reaching the sub_end_ + if (!(sub_iter_ != sub_end_)) { + sub_iter_ = sub_begin_; } return *this; } @@ -66,7 +68,7 @@ class iter::impl::Cycler { } bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; + return sub_iter_ != other.sub_iter_; } bool operator==(const Iterator& other) const { @@ -75,11 +77,11 @@ class iter::impl::Cycler { }; Iterator begin() { - return {std::begin(this->container), std::end(this->container)}; + return {std::begin(container_), std::end(container_)}; } Iterator end() { - return {std::end(this->container), std::end(this->container)}; + return {std::end(container_), std::end(container_)}; } }; From 8dcad3aa4ca7c6bff8b542b542e42693eba8b442 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:27:54 -0800 Subject: [PATCH 069/403] trailing _ on data members --- dropwhile.hpp | 59 ++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 4aceb371..1f544137 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -21,14 +21,14 @@ namespace iter { template class iter::impl::Dropper { private: - Container container; - FilterFunc filter_func; + Container container_; + FilterFunc filter_func_; friend DropWhileFn; - Dropper(FilterFunc in_filter_func, Container&& in_container) - : container(std::forward(in_container)), - filter_func(in_filter_func) {} + Dropper(FilterFunc filter_func, Container&& container) + : container_(std::forward(container)), + filter_func_(filter_func) {} public: Dropper(Dropper&&) = default; @@ -36,48 +36,47 @@ class iter::impl::Dropper { iterator_traits_deref> { private: using Holder = DerefHolder>; - IteratorWrapper sub_iter; - IteratorWrapper sub_end; - Holder item; - FilterFunc* filter_func; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; + Holder item_; + FilterFunc* filter_func_; void inc_sub_iter() { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); + ++sub_iter_; + if (sub_iter_ != sub_end_) { + item_.reset(*sub_iter_); } } // skip all values for which the predicate is true void skip_passes() { - while (this->sub_iter != this->sub_end - && (*this->filter_func)(this->item.get())) { - this->inc_sub_iter(); + while (sub_iter_ != sub_end_ && (*filter_func_)(item_.get())) { + inc_sub_iter(); } } public: - Iterator(IteratorWrapper&& iter, - IteratorWrapper&& end, FilterFunc& in_filter_func) - : sub_iter{std::move(iter)}, - sub_end{std::move(end)}, - filter_func(&in_filter_func) { - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, FilterFunc& filter_func) + : sub_iter_{std::move(sub_iter)}, + sub_end_{std::move(sub_end)}, + filter_func_(&filter_func) { + if (sub_iter_ != sub_end_) { + item_.reset(*sub_iter_); } - this->skip_passes(); + skip_passes(); } typename Holder::reference operator*() { - return this->item.get(); + return item_.get(); } typename Holder::pointer operator->() { - return this->item.get_ptr(); + return item_.get_ptr(); } Iterator& operator++() { - this->inc_sub_iter(); + inc_sub_iter(); return *this; } @@ -88,7 +87,7 @@ class iter::impl::Dropper { } bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; + return sub_iter_ != other.sub_iter_; } bool operator==(const Iterator& other) const { @@ -97,13 +96,11 @@ class iter::impl::Dropper { }; Iterator begin() { - return {std::begin(this->container), std::end(this->container), - this->filter_func}; + return {std::begin(container_), std::end(container_), filter_func_}; } Iterator end() { - return {std::end(this->container), std::end(this->container), - this->filter_func}; + return {std::end(container_), std::end(container_), filter_func_}; } }; From 2efe1da2382f60bc0aa064c240affcbfa5ad2fec Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:28:17 -0800 Subject: [PATCH 070/403] trailing _ on data members --- enumerate.hpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 02201b90..9331b139 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -23,8 +23,8 @@ namespace iter { template class iter::impl::Enumerable { private: - Container container; - const Index start; + Container container_; + const Index start_; friend EnumerateFn; @@ -32,8 +32,8 @@ class iter::impl::Enumerable { using BasePair = std::pair>; // Value constructor for use only in the enumerate function - Enumerable(Container&& in_container, Index in_start) - : container(std::forward(in_container)), start{in_start} {} + Enumerable(Container&& container, Index start) + : container_(std::forward(container)), start_{start} {} public: Enumerable(Enumerable&&) = default; @@ -48,19 +48,19 @@ class iter::impl::Enumerable { }; // Holds an iterator of the contained type and an Index for the - // index. Each call to ++ increments both of these data members. + // index_. Each call to ++ increments both of these data members. // Each dereference returns an IterYield. class Iterator : public std::iterator { private: - IteratorWrapper sub_iter; - Index index; + IteratorWrapper sub_iter_; + Index index_; public: - Iterator(IteratorWrapper&& si, Index start) - : sub_iter{std::move(si)}, index{start} {} + Iterator(IteratorWrapper&& sub_iter, Index start) + : sub_iter_{std::move(sub_iter)}, index_{start} {} IterYield operator*() { - return {this->index, *this->sub_iter}; + return {index_, *sub_iter_}; } ArrowProxy operator->() { @@ -68,8 +68,8 @@ class iter::impl::Enumerable { } Iterator& operator++() { - ++this->sub_iter; - ++this->index; + ++sub_iter_; + ++index_; return *this; } @@ -80,7 +80,7 @@ class iter::impl::Enumerable { } bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; + return sub_iter_ != other.sub_iter_; } bool operator==(const Iterator& other) const { @@ -89,11 +89,11 @@ class iter::impl::Enumerable { }; Iterator begin() { - return {std::begin(this->container), start}; + return {std::begin(container_), start_}; } Iterator end() { - return {std::end(this->container), start}; + return {std::end(container_), start_}; } }; From 5e99c34e85d220d28495955bac6078a3c24248f4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:28:22 -0800 Subject: [PATCH 071/403] trailing _ on data members --- filter.hpp | 65 ++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/filter.hpp b/filter.hpp index 69838cbf..1c118407 100644 --- a/filter.hpp +++ b/filter.hpp @@ -15,8 +15,8 @@ namespace iter { struct BoolTester { template - constexpr bool operator()(const T& item) const { - return bool(item); + constexpr bool operator()(const T& item_) const { + return bool(item_); } }; @@ -29,16 +29,16 @@ namespace iter { template class iter::impl::Filtered { private: - Container container; - FilterFunc filter_func; + Container container_; + FilterFunc filter_func_; friend FilterFn; protected: // Value constructor for use only in the filter function - Filtered(FilterFunc in_filter_func, Container&& in_container) - : container(std::forward(in_container)), - filter_func(in_filter_func) {} + Filtered(FilterFunc filter_func, Container&& container) + : container_(std::forward(container)), + filter_func_(filter_func) {} public: Filtered(Filtered&&) = default; @@ -47,50 +47,49 @@ class iter::impl::Filtered { iterator_traits_deref> { protected: using Holder = DerefHolder>; - IteratorWrapper sub_iter; - IteratorWrapper sub_end; - Holder item; - FilterFunc* filter_func; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; + Holder item_; + FilterFunc* filter_func_; void inc_sub_iter() { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); + ++sub_iter_; + if (sub_iter_ != sub_end_) { + item_.reset(*sub_iter_); } } // increment until the iterator points to is true on the // predicate. Called by constructor and operator++ void skip_failures() { - while (this->sub_iter != this->sub_end - && !(*this->filter_func)(this->item.get())) { - this->inc_sub_iter(); + while (sub_iter_ != sub_end_ && !(*filter_func_)(item_.get())) { + inc_sub_iter(); } } public: - Iterator(IteratorWrapper&& iter, - IteratorWrapper&& end, FilterFunc& in_filter_func) - : sub_iter{std::move(iter)}, - sub_end{std::move(end)}, - filter_func(&in_filter_func) { - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, FilterFunc& filter_func) + : sub_iter_{std::move(sub_iter)}, + sub_end_{std::move(sub_end)}, + filter_func_(&filter_func) { + if (sub_iter_ != sub_end_) { + item_.reset(*sub_iter_); } - this->skip_failures(); + skip_failures(); } typename Holder::reference operator*() { - return this->item.get(); + return item_.get(); } typename Holder::pointer operator->() { - return this->item.get_ptr(); + return item_.get_ptr(); } Iterator& operator++() { - this->inc_sub_iter(); - this->skip_failures(); + inc_sub_iter(); + skip_failures(); return *this; } @@ -101,7 +100,7 @@ class iter::impl::Filtered { } bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; + return sub_iter_ != other.sub_iter_; } bool operator==(const Iterator& other) const { @@ -110,13 +109,11 @@ class iter::impl::Filtered { }; Iterator begin() { - return {std::begin(this->container), std::end(this->container), - this->filter_func}; + return {std::begin(container_), std::end(container_), filter_func_}; } Iterator end() { - return {std::end(this->container), std::end(this->container), - this->filter_func}; + return {std::end(container_), std::end(container_), filter_func_}; } }; From 5d81d3ced3d58d1d252c4c06a6a1117737e49432 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:28:28 -0800 Subject: [PATCH 072/403] trailing _ on data members --- filterfalse.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/filterfalse.hpp b/filterfalse.hpp index f46aba2a..9de7a3df 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -13,22 +13,22 @@ namespace iter { template class PredicateFlipper { private: - FilterFunc filter_func; + FilterFunc filter_func_; public: - PredicateFlipper(FilterFunc in_filter_func) - : filter_func(std::move(in_filter_func)) {} + PredicateFlipper(FilterFunc filter_func) + : filter_func_(std::move(filter_func)) {} - // Calls the filter_func + // Calls the filter_func_ template bool operator()(const T& item) const { - return !bool(filter_func(item)); + return !bool(filter_func_(item)); } // with non-const incase FilterFunc::operator() is non-const template bool operator()(const T& item) { - return !bool(filter_func(item)); + return !bool(filter_func_(item)); } }; From 780e64d08345653bd87a18754240b68ff85b6980 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:28:35 -0800 Subject: [PATCH 073/403] trailing _ on data members --- groupby.hpp | 137 +++++++++++++++++++++++++--------------------------- 1 file changed, 65 insertions(+), 72 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 24c8c048..a4074b5b 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -31,16 +31,15 @@ namespace iter { template class iter::impl::GroupProducer { private: - Container container; - KeyFunc key_func; + Container container_; + KeyFunc key_func_; friend GroupByFn; using key_func_ret = std::result_of_t)>; - GroupProducer(Container&& in_container, KeyFunc in_key_func) - : container(std::forward(in_container)), - key_func(in_key_func) {} + GroupProducer(Container&& container, KeyFunc key_func) + : container_(std::forward(container)), key_func_(key_func) {} public: GroupProducer(GroupProducer&&) = default; @@ -55,39 +54,38 @@ class iter::impl::GroupProducer { public: class Iterator : public std::iterator { private: - IteratorWrapper sub_iter; - IteratorWrapper sub_end; - Holder item; - KeyFunc* key_func; - - std::unique_ptr current_key_group_pair; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; + Holder item_; + KeyFunc* key_func_; + std::unique_ptr current_key_group_pair_; public: - Iterator(IteratorWrapper&& si, IteratorWrapper&& end, - KeyFunc& in_key_func) - : sub_iter{std::move(si)}, - sub_end{std::move(end)}, - key_func(&in_key_func) { - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, KeyFunc& key_func) + : sub_iter_{std::move(sub_iter)}, + sub_end_{std::move(sub_end)}, + key_func_(&key_func) { + if (sub_iter_ != sub_end_) { + item_.reset(*sub_iter_); } } Iterator(const Iterator& other) - : sub_iter{other.sub_iter}, - sub_end{other.sub_end}, - item{other.item}, - key_func{other.key_func} {} + : sub_iter_{other.sub_iter_}, + sub_end_{other.sub_end_}, + item_{other.item_}, + key_func_{other.key_func_} {} Iterator& operator=(const Iterator& other) { if (this == &other) { return *this; } - this->sub_iter = other.sub_iter; - this->sub_end = other.sub_end; - this->item = other.item; - this->key_func = other.key_func; - this->current_key_group_pair.reset(); + sub_iter_ = other.sub_iter_; + sub_end_ = other.sub_end_; + item_ = other.item_; + key_func_ = other.key_func_; + current_key_group_pair_.reset(); return *this; } @@ -98,19 +96,19 @@ class iter::impl::GroupProducer { KeyGroupPair& operator*() { set_key_group_pair(); - return *this->current_key_group_pair; + return *current_key_group_pair_; } KeyGroupPair* operator->() { set_key_group_pair(); - return this->current_key_group_pair.get(); + return current_key_group_pair_.get(); } Iterator& operator++() { - if (!this->current_key_group_pair) { - this->set_key_group_pair(); + if (!current_key_group_pair_) { + set_key_group_pair(); } - this->current_key_group_pair.reset(); + current_key_group_pair_.reset(); return *this; } @@ -121,7 +119,7 @@ class iter::impl::GroupProducer { } bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; + return sub_iter_ != other.sub_iter_; } bool operator==(const Iterator& other) const { @@ -129,35 +127,34 @@ class iter::impl::GroupProducer { } void increment_iterator() { - if (this->sub_iter != this->sub_end) { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); + if (sub_iter_ != sub_end_) { + ++sub_iter_; + if (sub_iter_ != sub_end_) { + item_.reset(*sub_iter_); } } } bool exhausted() const { - return !(this->sub_iter != this->sub_end); + return !(sub_iter_ != sub_end_); } typename Holder::reference get() { - return this->item.get(); + return item_.get(); } typename Holder::pointer get_ptr() { - return this->item.get_ptr(); + return item_.get_ptr(); } key_func_ret next_key() { - return (*this->key_func)(this->item.get()); + return (*key_func_)(item_.get()); } void set_key_group_pair() { - if (!this->current_key_group_pair) { - this->current_key_group_pair = - std::make_unique((*this->key_func)(this->item.get()), - Group{*this, this->next_key()}); + if (!current_key_group_pair_) { + current_key_group_pair_ = std::make_unique( + (*key_func_)(item_.get()), Group{*this, next_key()}); } } }; @@ -166,8 +163,8 @@ class iter::impl::GroupProducer { private: friend Iterator; friend class GroupIterator; - Iterator& owner; - key_func_ret key; + Iterator& owner_; + key_func_ret key_; // completed is set if a Group is iterated through // completely. It is checked in the destructor, and @@ -180,52 +177,50 @@ class iter::impl::GroupProducer { // when called. bool completed = false; - Group(Iterator& in_owner, key_func_ret in_key) - : owner(in_owner), key(in_key) {} + Group(Iterator& owner, key_func_ret key) : owner_(owner), key_(key) {} public: ~Group() { - if (!this->completed) { - for (auto iter = this->begin(), end = this->end(); iter != end; - ++iter) { + if (!completed) { + for (auto iter = begin(), end_it = end(); iter != end_it; ++iter) { } } } // move-constructible, non-copy-constructible, non-assignable Group(Group&& other) noexcept - : owner(other.owner), key{other.key}, completed{other.completed} { + : owner_(other.owner_), key_{other.key_}, completed{other.completed} { other.completed = true; } class GroupIterator : public std::iterator> { private: - std::remove_reference_t* key; - Group* group_p; + std::remove_reference_t* key_; + Group* group_p_; bool not_at_end() { - return !this->group_p->owner.exhausted() - && this->group_p->owner.next_key() == *this->key; + return !group_p_->owner_.exhausted() + && group_p_->owner_.next_key() == *key_; } public: - GroupIterator(Group* in_group_p, key_func_ret& in_key) - : key{&in_key}, group_p{in_group_p} {} + GroupIterator(Group* group_p, key_func_ret& key) + : key_{&key}, group_p_{group_p} {} bool operator!=(const GroupIterator& other) const { return !(*this == other); } bool operator==(const GroupIterator& other) const { - return this->group_p == other.group_p; + return group_p_ == other.group_p_; } GroupIterator& operator++() { - this->group_p->owner.increment_iterator(); - if (!this->not_at_end()) { - this->group_p->completed = true; - this->group_p = nullptr; + group_p_->owner_.increment_iterator(); + if (!not_at_end()) { + group_p_->completed = true; + group_p_ = nullptr; } return *this; } @@ -237,31 +232,29 @@ class iter::impl::GroupProducer { } iterator_deref operator*() { - return this->group_p->owner.get(); + return group_p_->owner_.get(); } typename Holder::pointer operator->() { - return this->group_p->owner.get_ptr(); + return group_p_->owner_.get_ptr(); } }; GroupIterator begin() { - return {this, key}; + return {this, key_}; } GroupIterator end() { - return {nullptr, key}; + return {nullptr, key_}; } }; Iterator begin() { - return { - std::begin(this->container), std::end(this->container), this->key_func}; + return {std::begin(container_), std::end(container_), key_func_}; } Iterator end() { - return { - std::end(this->container), std::end(this->container), this->key_func}; + return {std::end(container_), std::end(container_), key_func_}; } }; From 1d248dc8fb8a473f9db1970a05f835d6f9794e0e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:28:40 -0800 Subject: [PATCH 074/403] trailing _ on data members --- permutations.hpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/permutations.hpp b/permutations.hpp index 4d895fa1..a522a980 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -24,13 +24,13 @@ template class iter::impl::Permuter { private: friend PermutationsFn; - Container container; + Container container_; using IndexVector = std::vector>; using Permutable = IterIterWrapper; - Permuter(Container&& in_container) - : container(std::forward(in_container)) {} + Permuter(Container&& container) + : container_(std::forward(container)) {} public: Permuter(Permuter&&) = default; @@ -43,37 +43,37 @@ class iter::impl::Permuter { return *lhs < *rhs; } - Permutable working_set; - int steps{}; + Permutable working_set_; + int steps_{}; public: Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end) - : steps{sub_iter != sub_end ? 0 : COMPLETE} { + : steps_{sub_iter != sub_end ? 0 : COMPLETE} { // done like this instead of using vector ctor with // two iterators because that causes a substitution // failure when the iterator is minimal while (sub_iter != sub_end) { - this->working_set.get().push_back(sub_iter); + working_set_.get().push_back(sub_iter); ++sub_iter; } - std::sort(std::begin(working_set.get()), std::end(working_set.get()), + std::sort(std::begin(working_set_.get()), std::end(working_set_.get()), cmp_iters); } Permutable& operator*() { - return this->working_set; + return working_set_; } Permutable* operator->() { - return &this->working_set; + return &working_set_; } Iterator& operator++() { - ++this->steps; - if (!std::next_permutation(std::begin(working_set.get()), - std::end(working_set.get()), cmp_iters)) { - this->steps = COMPLETE; + ++steps_; + if (!std::next_permutation(std::begin(working_set_.get()), + std::end(working_set_.get()), cmp_iters)) { + steps_ = COMPLETE; } return *this; } @@ -89,16 +89,16 @@ class iter::impl::Permuter { } bool operator==(const Iterator& other) const { - return this->steps == other.steps; + return steps_ == other.steps_; } }; Iterator begin() { - return {std::begin(this->container), std::end(this->container)}; + return {std::begin(container_), std::end(container_)}; } Iterator end() { - return {std::end(this->container), std::end(this->container)}; + return {std::end(container_), std::end(container_)}; } }; From 50fe35e841d3e8fdff87773e9cd8d7a196666454 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:28:52 -0800 Subject: [PATCH 075/403] trailing _ on data members --- powerset.hpp | 56 +++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/powerset.hpp b/powerset.hpp index 68aab5f8..2cbad540 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -24,13 +24,13 @@ namespace iter { template class iter::impl::Powersetter { private: - Container container; + Container container_; using CombinatorType = decltype(combinations(std::declval(), 0)); friend PowersetFn; - Powersetter(Container&& in_container) - : container(std::forward(in_container)) {} + Powersetter(Container&& container) + : container_(std::forward(container)) {} public: Powersetter(Powersetter&&) = default; @@ -38,30 +38,29 @@ class iter::impl::Powersetter { class Iterator : public std::iterator { private: - std::remove_reference_t* container_p; - std::size_t set_size; - std::shared_ptr comb; - iterator_type comb_iter; - iterator_type comb_end; + std::remove_reference_t* container_p_; + std::size_t set_size_{}; + std::shared_ptr comb_; + iterator_type comb_iter_; + iterator_type comb_end_; public: - Iterator(Container& in_container, std::size_t sz) - : container_p{&in_container}, - set_size{sz}, - comb{ - std::make_shared(combinations(in_container, sz))}, - comb_iter{std::begin(*comb)}, - comb_end{std::end(*comb)} {} + Iterator(Container& container, std::size_t sz) + : container_p_{&container}, + set_size_{sz}, + comb_{std::make_shared(combinations(container, sz))}, + comb_iter_{std::begin(*comb_)}, + comb_end_{std::end(*comb_)} {} Iterator& operator++() { - ++this->comb_iter; - if (this->comb_iter == this->comb_end) { - ++this->set_size; - this->comb = std::make_shared( - combinations(*this->container_p, this->set_size)); - - this->comb_iter = std::begin(*this->comb); - this->comb_end = std::end(*this->comb); + ++comb_iter_; + if (comb_iter_ == comb_end_) { + ++set_size_; + comb_ = std::make_shared( + combinations(*container_p_, set_size_)); + + comb_iter_ = std::begin(*comb_); + comb_end_ = std::end(*comb_); } return *this; } @@ -73,11 +72,11 @@ class iter::impl::Powersetter { } iterator_deref operator*() { - return *this->comb_iter; + return *comb_iter_; } iterator_arrow operator->() { - apply_arrow(this->comb_iter); + apply_arrow(comb_iter_); } bool operator!=(const Iterator& other) const { @@ -85,17 +84,16 @@ class iter::impl::Powersetter { } bool operator==(const Iterator& other) const { - return this->set_size == other.set_size - && this->comb_iter == other.comb_iter; + return set_size_ == other.set_size_ && comb_iter_ == other.comb_iter_; } }; Iterator begin() { - return {this->container, 0}; + return {container_, 0}; } Iterator end() { - return {this->container, dumb_size(this->container) + 1}; + return {container_, dumb_size(container_) + 1}; } }; From 751db3a85deb544f03587a601af90336744550b9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:29:00 -0800 Subject: [PATCH 076/403] trailing _ on data members --- product.hpp | 51 +++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/product.hpp b/product.hpp index 31eb9555..e7e06f26 100644 --- a/product.hpp +++ b/product.hpp @@ -38,11 +38,11 @@ class iter::impl::Productor { std::tuple, iterator_deref...>; private: - Container container; - Productor rest_products; - Productor(Container&& in_container, RestContainers&&... rest) - : container(std::forward(in_container)), - rest_products{std::forward(rest)...} {} + Container container_; + Productor rest_products_; + Productor(Container&& container, RestContainers&&... rest) + : container_(std::forward(container)), + rest_products_{std::forward(rest)...} {} public: Productor(Productor&&) = default; @@ -51,27 +51,30 @@ class iter::impl::Productor { private: using RestIter = typename Productor::Iterator; - IteratorWrapper iter; - IteratorWrapper begin; + IteratorWrapper sub_iter_; + IteratorWrapper sub_begin_; - RestIter rest_iter; - RestIter rest_end; + RestIter rest_iter_; + RestIter rest_end_; public: constexpr static const bool is_base_iter = false; - Iterator(IteratorWrapper&& it, RestIter&& rest, - RestIter&& in_rest_end) - : iter{it}, begin{it}, rest_iter{rest}, rest_end{in_rest_end} {} + Iterator(IteratorWrapper&& sub_iter, RestIter&& rest_iter, + RestIter&& rest_end) + : sub_iter_{sub_iter}, + sub_begin_{sub_iter}, + rest_iter_{rest_iter}, + rest_end_{rest_end} {} void reset() { - this->iter = this->begin; + sub_iter_ = sub_begin_; } Iterator& operator++() { - ++this->rest_iter; - if (!(this->rest_iter != this->rest_end)) { - this->rest_iter.reset(); - ++this->iter; + ++rest_iter_; + if (!(rest_iter_ != rest_end_)) { + rest_iter_.reset(); + ++sub_iter_; } return *this; } @@ -83,8 +86,8 @@ class iter::impl::Productor { } bool operator!=(const Iterator& other) const { - return this->iter != other.iter - && (RestIter::is_base_iter || this->rest_iter != other.rest_iter); + return sub_iter_ != other.sub_iter_ + && (RestIter::is_base_iter || rest_iter_ != other.rest_iter_); } bool operator==(const Iterator& other) const { @@ -93,7 +96,7 @@ class iter::impl::Productor { ProdIterDeref operator*() { return std::tuple_cat( - std::tuple>{*this->iter}, *this->rest_iter); + std::tuple>{*sub_iter_}, *rest_iter_); } ArrowProxy operator->() { @@ -102,13 +105,13 @@ class iter::impl::Productor { }; Iterator begin() { - return {std::begin(this->container), std::begin(this->rest_products), - std::end(this->rest_products)}; + return {std::begin(container_), std::begin(rest_products_), + std::end(rest_products_)}; } Iterator end() { - return {std::end(this->container), std::end(this->rest_products), - std::end(this->rest_products)}; + return {std::end(container_), std::end(rest_products_), + std::end(rest_products_)}; } }; From 9e00b9428701780731fdde7ba482611940a5fc30 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:29:06 -0800 Subject: [PATCH 077/403] trailing _ on data members --- range.hpp | 70 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/range.hpp b/range.hpp index 0aafa7de..3d2df9b8 100644 --- a/range.hpp +++ b/range.hpp @@ -40,19 +40,19 @@ namespace iter { : value_{in_value}, step_{in_step} {} constexpr T value() const noexcept { - return this->value_; + return value_; } constexpr T step() const noexcept { - return this->step_; + return step_; } void inc() noexcept { - this->value_ += step_; + value_ += step_; } constexpr bool operator==(const RangeIterData& other) const noexcept { - return this->value_ == other.value_; + return value_ == other.value_; } constexpr bool operator!=(const RangeIterData& other) const noexcept { @@ -67,7 +67,7 @@ namespace iter { T start_{}; T value_{}; T step_{}; - std::size_t steps_taken{}; + std::size_t steps_taken_{}; public: constexpr RangeIterData() noexcept = default; @@ -75,24 +75,24 @@ namespace iter { : start_{in_start}, value_{in_start}, step_{in_step} {} constexpr T value() const noexcept { - return this->value_; + return value_; } constexpr T step() const noexcept { - return this->step_; + return step_; } void inc() noexcept { - ++this->steps_taken; - value_ = this->start_ + (this->step_ * this->steps_taken); + ++steps_taken_; + value_ = start_ + (step_ * steps_taken_); } constexpr bool operator==(const RangeIterData& other) const noexcept { // if the difference between the two values is less than the - // step size, they are considered equal - return (this->value_ < other.value_ ? other.value_ - this->value_ - : this->value_ - other.value_) - < this->step_; + // step_ size, they are considered equal + return (value_ < other.value_ ? other.value_ - value_ + : value_ - other.value_) + < step_; } constexpr bool operator!=(const RangeIterData& other) const noexcept { @@ -114,14 +114,14 @@ class iter::impl::Range { friend constexpr Range iter::range(U, U, U) noexcept; private: - const T start; - const T stop; - const T step; + const T start_; + const T stop_; + const T step_; - constexpr Range(T in_stop) noexcept : start{0}, stop{in_stop}, step{1} {} + constexpr Range(T stop) noexcept : start_{0}, stop_{stop}, step_{1} {} - constexpr Range(T in_start, T in_stop, T in_step = 1) noexcept - : start{in_start}, stop{in_stop}, step{in_step} {} + constexpr Range(T start, T stop, T step = 1) noexcept + : start_{start}, stop_{stop}, step_{step} {} public: // the reference type here is T, which doesn't strictly follow all @@ -168,7 +168,7 @@ class iter::impl::Range { : data(in_value, in_step), is_end{in_is_end} {} constexpr T operator*() const noexcept { - return this->data.value(); + return data.value(); } constexpr ArrowProxy operator->() const noexcept { @@ -176,7 +176,7 @@ class iter::impl::Range { } Iterator& operator++() noexcept { - this->data.inc(); + data.inc(); return *this; } @@ -196,9 +196,9 @@ class iter::impl::Range { // infinitely (theoretically). If this occurs, the Range // will instead effectively be empty // - // 2) (stop - start) % step != 0. For + // 2) (stop_ - start_) % step_ != 0. For // example Range(1, 10, 2). The iterator will never be - // exactly equal to the stop value. + // exactly equal to the stop_ value. // // Another way to think about it is that the "end" // iterator represents the range of values that are invalid @@ -208,12 +208,12 @@ class iter::impl::Range { // // Two non-end iterators will compare by their stored values bool operator!=(const Iterator& other) const noexcept { - if (this->is_end && other.is_end) { + if (is_end && other.is_end) { return false; } - if (!this->is_end && !other.is_end) { - return this->data != other.data; + if (!is_end && !other.is_end) { + return data != other.data; } return not_equal_to_end(*this, other); } @@ -224,27 +224,29 @@ class iter::impl::Range { }; constexpr Iterator begin() const noexcept { - return {start, step, false}; + return {start_, step_, false}; } constexpr Iterator end() const noexcept { - return {stop, step, true}; + return {stop_, step_, true}; } }; template -constexpr iter::impl::Range iter::range(T stop) noexcept { - return {stop}; +constexpr iter::impl::Range iter::range(T stop_) noexcept { + return {stop_}; } template -constexpr iter::impl::Range iter::range(T start, T stop) noexcept { - return {start, stop}; +constexpr iter::impl::Range iter::range(T start_, T stop_) noexcept { + return {start_, stop_}; } template -constexpr iter::impl::Range iter::range(T start, T stop, T step) noexcept { - return step == T(0) ? impl::Range{0} : impl::Range{start, stop, step}; +constexpr iter::impl::Range iter::range( + T start_, T stop_, T step_) noexcept { + return step_ == T(0) ? impl::Range{0} + : impl::Range{start_, stop_, step_}; } #endif From f547dfa85d0273d8fae21fa82917c5333c584a8f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:29:12 -0800 Subject: [PATCH 078/403] trailing _ on data members --- repeat.hpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/repeat.hpp b/repeat.hpp index 0dd8cf91..1073d750 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -23,11 +23,11 @@ class iter::impl::RepeaterWithCount { friend constexpr RepeaterWithCount iter::repeat(U&&, int); private: - T elem; - int count; + T elem_; + int count_; constexpr RepeaterWithCount(T e, int c) - : elem(std::forward(e)), count{c} {} + : elem_(std::forward(e)), count_{c} {} using TPlain = typename std::remove_reference::type; @@ -36,14 +36,14 @@ class iter::impl::RepeaterWithCount { class Iterator : public std::iterator { private: - const TPlain* elem; - int count; + const TPlain* elem_; + int count_; public: - constexpr Iterator(const TPlain* e, int c) : elem{e}, count{c} {} + constexpr Iterator(const TPlain* e, int c) : elem_{e}, count_{c} {} Iterator& operator++() { - --this->count; + --this->count_; return *this; } @@ -58,30 +58,30 @@ class iter::impl::RepeaterWithCount { } constexpr bool operator==(const Iterator& other) const { - return this->count == other.count; + return this->count_ == other.count_; } constexpr const TPlain& operator*() const { - return *this->elem; + return *this->elem_; } constexpr const TPlain* operator->() const { - return this->elem; + return this->elem_; } }; constexpr Iterator begin() const { - return {&this->elem, this->count}; + return {&this->elem_, this->count_}; } constexpr Iterator end() const { - return {&this->elem, 0}; + return {&this->elem_, 0}; } }; template -constexpr iter::impl::RepeaterWithCount iter::repeat(T&& e, int count) { - return {std::forward(e), count < 0 ? 0 : count}; +constexpr iter::impl::RepeaterWithCount iter::repeat(T&& e, int count_) { + return {std::forward(e), count_ < 0 ? 0 : count_}; } namespace iter { @@ -101,19 +101,19 @@ class iter::impl::Repeater { private: using TPlain = typename std::remove_reference::type; - T elem; + T elem_; - constexpr Repeater(T e) : elem(std::forward(e)) {} + constexpr Repeater(T e) : elem_(std::forward(e)) {} public: Repeater(Repeater&&) = default; class Iterator : public std::iterator { private: - const TPlain* elem; + const TPlain* elem_; public: - constexpr Iterator(const TPlain* e) : elem{e} {} + constexpr Iterator(const TPlain* e) : elem_{e} {} constexpr const Iterator& operator++() const { return *this; @@ -132,16 +132,16 @@ class iter::impl::Repeater { } constexpr const TPlain& operator*() const { - return *this->elem; + return *this->elem_; } constexpr const TPlain* operator->() const { - return this->elem; + return this->elem_; } }; constexpr Iterator begin() const { - return {&this->elem}; + return {&this->elem_}; } constexpr Iterator end() const { From 0382c985126d2018f931925632c715f88f72ec8c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:29:18 -0800 Subject: [PATCH 079/403] trailing _ on data members --- reversed.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/reversed.hpp b/reversed.hpp index b17457c3..987b0cd5 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -49,11 +49,11 @@ namespace iter { template class iter::impl::Reverser { private: - Container container; + Container container_; friend ReversedFn; - Reverser(Container&& in_container) - : container(std::forward(in_container)) {} + Reverser(Container&& container) + : container_(std::forward(container)) {} using reverse_iterator_deref = decltype(*std::declval&>()); @@ -69,22 +69,22 @@ class iter::impl::Reverser { class Iterator : public std::iterator { private: - ReverseIteratorWrapper sub_iter; + ReverseIteratorWrapper sub_iter_; public: - Iterator(ReverseIteratorWrapper&& iter) - : sub_iter{std::move(iter)} {} + Iterator(ReverseIteratorWrapper&& sub_iter) + : sub_iter_{std::move(sub_iter)} {} reverse_iterator_deref operator*() { - return *this->sub_iter; + return *sub_iter_; } reverse_iterator_arrow operator->() { - return apply_arrow(this->sub_iter); + return apply_arrow(sub_iter_); } Iterator& operator++() { - ++this->sub_iter; + ++sub_iter_; return *this; } @@ -95,7 +95,7 @@ class iter::impl::Reverser { } bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; + return sub_iter_ != other.sub_iter_; } bool operator==(const Iterator& other) const { @@ -104,11 +104,11 @@ class iter::impl::Reverser { }; Iterator begin() { - return {std::rbegin(this->container)}; + return {std::rbegin(container_)}; } Iterator end() { - return {std::rend(this->container)}; + return {std::rend(container_)}; } }; From 36e7ac929ed9bedba3561ed9ca849b01a554ef92 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:29:25 -0800 Subject: [PATCH 080/403] trailing _ on data members --- slice.hpp | 85 +++++++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/slice.hpp b/slice.hpp index c1d21e3a..ff4979a5 100644 --- a/slice.hpp +++ b/slice.hpp @@ -19,53 +19,54 @@ namespace iter { template class iter::impl::Sliced { private: - Container container; - DifferenceType start; - DifferenceType stop; - DifferenceType step; + Container container_; + DifferenceType start_; + DifferenceType stop_; + DifferenceType step_; friend SliceFn; - Sliced(Container&& in_container, DifferenceType in_start, - DifferenceType in_stop, DifferenceType in_step) - : container(std::forward(in_container)), - start{in_start < in_stop && in_step > 0 ? in_start : in_stop}, - stop{in_stop}, - step{in_step} {} + Sliced(Container&& container, DifferenceType start, DifferenceType stop, + DifferenceType step) + : container_(std::forward(container)), + start_{start < stop && step > 0 ? start : stop}, + stop_{stop}, + step_{step} {} public: Sliced(Sliced&&) = default; class Iterator : public std::iterator> { private: - IteratorWrapper sub_iter; - IteratorWrapper sub_end; - DifferenceType current; - DifferenceType stop; - DifferenceType step; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; + DifferenceType current_; + DifferenceType stop_; + DifferenceType step_; public: - Iterator(IteratorWrapper&& si, IteratorWrapper&& se, - DifferenceType in_start, DifferenceType in_stop, DifferenceType in_step) - : sub_iter{std::move(si)}, - sub_end{std::move(se)}, - current{in_start}, - stop{in_stop}, - step{in_step} {} + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, DifferenceType start, + DifferenceType stop, DifferenceType step) + : sub_iter_{std::move(sub_iter)}, + sub_end_{std::move(sub_end)}, + current_{start}, + stop_{stop}, + step_{step} {} iterator_deref operator*() { - return *this->sub_iter; + return *sub_iter_; } iterator_arrow operator->() { - return apply_arrow(this->sub_iter); + return apply_arrow(sub_iter_); } Iterator& operator++() { - dumb_advance(this->sub_iter, this->sub_end, this->step); - this->current += this->step; - if (this->stop < this->current) { - this->current = this->stop; + dumb_advance(sub_iter_, sub_end_, step_); + current_ += step_; + if (stop_ < current_) { + current_ = stop_; } return *this; } @@ -77,7 +78,7 @@ class iter::impl::Sliced { } bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter && this->current != other.current; + return sub_iter_ != other.sub_iter_ && current_ != other.current_; } bool operator==(const Iterator& other) const { @@ -86,15 +87,13 @@ class iter::impl::Sliced { }; Iterator begin() { - auto it = std::begin(this->container); - dumb_advance(it, std::end(this->container), this->start); - return {std::move(it), std::end(this->container), this->start, this->stop, - this->step}; + auto it = std::begin(container_); + dumb_advance(it, std::end(container_), start_); + return {std::move(it), std::end(container_), start_, stop_, step_}; } Iterator end() { - return {std::end(this->container), std::end(this->container), this->stop, - this->stop, this->step}; + return {std::end(container_), std::end(container_), stop_, stop_, step_}; } }; @@ -105,17 +104,17 @@ struct iter::impl::SliceFn { public: template Sliced operator()(Container&& container) const { - return {std::forward(container), start, stop, step}; + return {std::forward(container), start_, stop_, step_}; } private: friend SliceFn; - constexpr FnPartial(DifferenceType in_start, DifferenceType in_stop, - DifferenceType in_step) noexcept - : start{in_start}, stop{in_stop}, step{in_step} {} - DifferenceType start; - DifferenceType stop; - DifferenceType step; + constexpr FnPartial( + DifferenceType start, DifferenceType stop, DifferenceType step) noexcept + : start_{start}, stop_{stop}, step_{step} {} + DifferenceType start_; + DifferenceType stop_; + DifferenceType step_; }; public: @@ -127,7 +126,7 @@ struct iter::impl::SliceFn { return {std::forward(container), start, stop, step}; } - // only given the end, assume step is 1 and begin is 0 + // only given the end, assume step_ is 1 and begin is 0 template >> iter::impl::Sliced operator()( From 29c669c9462cdc268d999ec28385f6b5bfa1d605 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:29:32 -0800 Subject: [PATCH 081/403] trailing _ on data members --- sliding_window.hpp | 47 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index 2dc6e81d..27539c87 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -21,13 +21,13 @@ namespace iter { template class iter::impl::WindowSlider { private: - Container container; - std::size_t window_size; + Container container_; + std::size_t window_size_; friend SlidingWindowFn; - WindowSlider(Container&& in_container, std::size_t win_sz) - : container(std::forward(in_container)), window_size{win_sz} {} + WindowSlider(Container&& container, std::size_t win_sz) + : container_(std::forward(container)), window_size_{win_sz} {} using IndexVector = std::deque>; using DerefVec = IterIterWrapper; @@ -36,25 +36,25 @@ class iter::impl::WindowSlider { WindowSlider(WindowSlider&&) = default; class Iterator : public std::iterator { private: - IteratorWrapper sub_iter; - DerefVec window; + IteratorWrapper sub_iter_; + DerefVec window_; public: - Iterator(IteratorWrapper&& in_iter, - IteratorWrapper&& in_end, std::size_t window_sz) - : sub_iter(std::move(in_iter)) { + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, std::size_t window_sz) + : sub_iter_(std::move(sub_iter)) { std::size_t i{0}; - while (i < window_sz && this->sub_iter != in_end) { - this->window.get().push_back(this->sub_iter); + while (i < window_sz && sub_iter_ != sub_end) { + window_.get().push_back(sub_iter_); ++i; if (i != window_sz) { - ++this->sub_iter; + ++sub_iter_; } } } bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; + return sub_iter_ != other.sub_iter_; } bool operator==(const Iterator& other) const { @@ -62,17 +62,17 @@ class iter::impl::WindowSlider { } DerefVec& operator*() { - return this->window; + return window_; } DerefVec* operator->() { - return this->window; + return window_; } Iterator& operator++() { - ++this->sub_iter; - this->window.get().pop_front(); - this->window.get().push_back(this->sub_iter); + ++sub_iter_; + window_.get().pop_front(); + window_.get().push_back(sub_iter_); return *this; } @@ -84,15 +84,14 @@ class iter::impl::WindowSlider { }; Iterator begin() { - return {(this->window_size != 0 - ? IteratorWrapper{std::begin(this->container)} - : IteratorWrapper{std::end(this->container)}), - std::end(this->container), this->window_size}; + return { + (window_size_ != 0 ? IteratorWrapper{std::begin(container_)} + : IteratorWrapper{std::end(container_)}), + std::end(container_), window_size_}; } Iterator end() { - return {std::end(this->container), std::end(this->container), - this->window_size}; + return {std::end(container_), std::end(container_), window_size_}; } }; From cdcf2aeb58b55b1d25239d00565cd083c6d56a82 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:29:37 -0800 Subject: [PATCH 082/403] trailing _ on data members --- sorted.hpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index 5393d3a7..4caf35e0 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -25,20 +25,20 @@ class iter::impl::SortedView { friend SortedFn; - Container container; - IterIterWrap sorted_iters; - - SortedView(Container&& in_container, CompareFunc compare_func) - : container(std::forward(in_container)) { - // Fill the sorted_iters vector with an iterator to each - // element in the container - for (auto iter = std::begin(this->container); - iter != std::end(this->container); ++iter) { - this->sorted_iters.get().push_back(iter); + Container container_; + IterIterWrap sorted_iters_; + + SortedView(Container&& container, CompareFunc compare_func) + : container_(std::forward(container)) { + // Fill the sorted_iters_ vector with an iterator to each + // element in the container_ + for (auto iter = std::begin(container_); iter != std::end(container_); + ++iter) { + sorted_iters_.get().push_back(iter); } // sort by comparing the elements that the iterators point to - std::sort(std::begin(sorted_iters.get()), std::end(sorted_iters.get()), + std::sort(std::begin(sorted_iters_.get()), std::end(sorted_iters_.get()), [compare_func](iterator_type it1, iterator_type it2) { return compare_func(*it1, *it2); }); } @@ -47,11 +47,11 @@ class iter::impl::SortedView { SortedView(SortedView&&) = default; ItIt begin() { - return std::begin(sorted_iters); + return std::begin(sorted_iters_); } ItIt end() { - return std::end(sorted_iters); + return std::end(sorted_iters_); } }; From d36b6b13687a9149bafe6994406c67b89773e079 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:29:42 -0800 Subject: [PATCH 083/403] trailing _ on data members --- starmap.hpp | 56 ++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index f71aaf6c..84cb2da9 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -24,21 +24,21 @@ namespace iter { } } -// NOTE I don't know why, but clang gets very confused by having this-> in the +// NOTE I don't know why, but clang gets very confused by having in the // Iterators' member functions for these classes -// starmap with a container where T is one of tuple, pair, array +// starmap with a container_ where T is one of tuple, pair, array template class iter::impl::StarMapper { private: - Func func; - Container container; + Func func_; + Container container_; using StarIterDeref = std::remove_reference_t>()))>; + call_with_tuple(func_, std::declval>()))>; StarMapper(Func f, Container&& c) - : func(std::move(f)), container(std::forward(c)) {} + : func_(std::move(f)), container_(std::forward(c)) {} friend StarMapFn; @@ -46,15 +46,15 @@ class iter::impl::StarMapper { class Iterator : public std::iterator { private: - Func* func; - IteratorWrapper sub_iter; + Func* func_; + IteratorWrapper sub_iter_; public: - Iterator(Func& f, IteratorWrapper&& iter) - : func(&f), sub_iter(std::move(iter)) {} + Iterator(Func& f, IteratorWrapper&& sub_iter) + : func_(&f), sub_iter_(std::move(sub_iter)) {} bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; + return sub_iter_ != other.sub_iter_; } bool operator==(const Iterator& other) const { @@ -62,7 +62,7 @@ class iter::impl::StarMapper { } Iterator& operator++() { - ++this->sub_iter; + ++sub_iter_; return *this; } @@ -73,7 +73,7 @@ class iter::impl::StarMapper { } decltype(auto) operator*() { - return call_with_tuple(*func, *sub_iter); + return call_with_tuple(*func_, *sub_iter_); } auto operator-> () -> ArrowProxy { @@ -82,11 +82,11 @@ class iter::impl::StarMapper { }; Iterator begin() { - return {this->func, std::begin(this->container)}; + return {func_, std::begin(container_)}; } Iterator end() { - return {this->func, std::end(this->container)}; + return {func_, std::end(container_)}; } }; @@ -94,8 +94,8 @@ class iter::impl::StarMapper { template class iter::impl::TupleStarMapper { private: - Func func; - TupType tup; + Func func_; + TupType tup_; private: static_assert(sizeof...(Is) == std::tuple_size>::value, @@ -108,7 +108,7 @@ class iter::impl::TupleStarMapper { return call_with_tuple(f, std::get(t)); } - using ResultType = decltype(get_and_call_with_tuple<0>(func, tup)); + using ResultType = decltype(get_and_call_with_tuple<0>(func_, tup_)); using CallerFunc = ResultType (*)(Func&, TupType&); constexpr static std::array callers{ @@ -117,21 +117,21 @@ class iter::impl::TupleStarMapper { using TraitsValue = std::remove_reference_t; TupleStarMapper(Func f, TupType t) - : func(std::move(f)), tup(std::forward(t)) {} + : func_(std::move(f)), tup_(std::forward(t)) {} public: class Iterator : public std::iterator { private: - Func* func; - std::remove_reference_t* tup; - std::size_t index; + Func* func_; + std::remove_reference_t* tup_; + std::size_t index_; public: Iterator(Func& f, TupType& t, std::size_t i) - : func{&f}, tup{&t}, index{i} {} + : func_{&f}, tup_{&t}, index_{i} {} decltype(auto) operator*() { - return callers[index](*func, *tup); + return callers[index_](*func_, *tup_); } auto operator-> () -> ArrowProxy { @@ -139,7 +139,7 @@ class iter::impl::TupleStarMapper { } Iterator& operator++() { - ++index; + ++index_; return *this; } @@ -150,7 +150,7 @@ class iter::impl::TupleStarMapper { } bool operator!=(const Iterator& other) const { - return index != other.index; + return index_ != other.index_; } bool operator==(const Iterator& other) const { @@ -159,11 +159,11 @@ class iter::impl::TupleStarMapper { }; Iterator begin() { - return {this->func, this->tup, 0}; + return {func_, tup_, 0}; } Iterator end() { - return {this->func, this->tup, sizeof...(Is)}; + return {func_, tup_, sizeof...(Is)}; } }; From 3f4a694980d340dc06ba9903247cd1715516b2fc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:29:49 -0800 Subject: [PATCH 084/403] trailing _ on data members --- takewhile.hpp | 61 ++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 53df6a2a..e180acd1 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -21,14 +21,14 @@ namespace iter { template class iter::impl::Taker { private: - Container container; - FilterFunc filter_func; + Container container_; + FilterFunc filter_func_; friend TakeWhileFn; - Taker(FilterFunc in_filter_func, Container&& in_container) - : container(std::forward(in_container)), - filter_func(in_filter_func) {} + Taker(FilterFunc filter_func, Container&& container) + : container_(std::forward(container)), + filter_func_(filter_func) {} public: Taker(Taker&&) = default; @@ -37,48 +37,47 @@ class iter::impl::Taker { iterator_traits_deref> { private: using Holder = DerefHolder>; - IteratorWrapper sub_iter; - IteratorWrapper sub_end; - Holder item; - FilterFunc* filter_func; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; + Holder item_; + FilterFunc* filter_func_; void inc_sub_iter() { - ++this->sub_iter; - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); + ++sub_iter_; + if (sub_iter_ != sub_end_) { + item_.reset(*sub_iter_); } } void check_current() { - if (this->sub_iter != this->sub_end - && !(*this->filter_func)(this->item.get())) { - this->sub_iter = this->sub_end; + if (sub_iter_ != sub_end_ && !(*filter_func_)(item_.get())) { + sub_iter_ = sub_end_; } } public: - Iterator(IteratorWrapper&& iter, - IteratorWrapper&& end, FilterFunc& in_filter_func) - : sub_iter{std::move(iter)}, - sub_end{std::move(end)}, - filter_func(&in_filter_func) { - if (this->sub_iter != this->sub_end) { - this->item.reset(*this->sub_iter); + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, FilterFunc& filter_func) + : sub_iter_{std::move(sub_iter)}, + sub_end_{std::move(sub_end)}, + filter_func_(&filter_func) { + if (sub_iter_ != sub_end_) { + item_.reset(*sub_iter_); } - this->check_current(); + check_current(); } typename Holder::reference operator*() { - return this->item.get(); + return item_.get(); } typename Holder::pointer operator->() { - return this->item.get_ptr(); + return item_.get_ptr(); } Iterator& operator++() { - this->inc_sub_iter(); - this->check_current(); + inc_sub_iter(); + check_current(); return *this; } @@ -89,7 +88,7 @@ class iter::impl::Taker { } bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; + return sub_iter_ != other.sub_iter_; } bool operator==(const Iterator& other) const { @@ -98,13 +97,11 @@ class iter::impl::Taker { }; Iterator begin() { - return {std::begin(this->container), std::end(this->container), - this->filter_func}; + return {std::begin(container_), std::end(container_), filter_func_}; } Iterator end() { - return {std::end(this->container), std::end(this->container), - this->filter_func}; + return {std::end(container_), std::end(container_), filter_func_}; } }; From ca3ae7a9755969401859c9f17d9d660478343dd4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:29:53 -0800 Subject: [PATCH 085/403] trailing _ on data members --- zip.hpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/zip.hpp b/zip.hpp index 75bdba1d..89182fe6 100644 --- a/zip.hpp +++ b/zip.hpp @@ -25,25 +25,26 @@ namespace iter { template class iter::impl::Zipped { private: - TupleType containers; + TupleType containers_; friend Zipped iter::impl::zip_impl( TupleType&&, std::index_sequence); using ZipIterDeref = iterator_deref_tuple; - Zipped(TupleType&& in_containers) : containers(std::move(in_containers)) {} + Zipped(TupleType&& containers) : containers_(std::move(containers)) {} public: Zipped(Zipped&&) = default; class Iterator : public std::iterator { private: - iterator_tuple_type iters; + iterator_tuple_type iters_; public: - Iterator(iterator_tuple_type&& its) : iters(std::move(its)) {} + Iterator(iterator_tuple_type&& iters) + : iters_(std::move(iters)) {} Iterator& operator++() { - absorb(++std::get(this->iters)...); + absorb(++std::get(iters_)...); return *this; } @@ -57,7 +58,7 @@ class iter::impl::Zipped { if (sizeof...(Is) == 0) return false; bool results[] = { - true, (std::get(this->iters) != std::get(other.iters))...}; + true, (std::get(iters_) != std::get(other.iters_))...}; return std::all_of( std::begin(results), std::end(results), [](bool b) { return b; }); } @@ -67,7 +68,7 @@ class iter::impl::Zipped { } ZipIterDeref operator*() { - return ZipIterDeref{(*std::get(this->iters))...}; + return ZipIterDeref{(*std::get(iters_))...}; } auto operator-> () -> ArrowProxy { @@ -77,19 +78,19 @@ class iter::impl::Zipped { Iterator begin() { return {iterator_tuple_type{ - std::begin(std::get(this->containers))...}}; + std::begin(std::get(containers_))...}}; } Iterator end() { - return {iterator_tuple_type{ - std::end(std::get(this->containers))...}}; + return { + iterator_tuple_type{std::end(std::get(containers_))...}}; } }; template iter::impl::Zipped iter::impl::zip_impl( - TupleType&& in_containers, std::index_sequence) { - return {std::move(in_containers)}; + TupleType&& containers, std::index_sequence) { + return {std::move(containers)}; } template From a7ada5d14f259a7426292535ef1df444363cca37 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:30:00 -0800 Subject: [PATCH 086/403] trailing _ on data members --- zip_longest.hpp | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index f20ba869..b72aa5c7 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -26,7 +26,7 @@ namespace iter { template class iter::impl::ZippedLongest { private: - TupleType containers; + TupleType containers_; friend ZippedLongest zip_longest_impl( TupleType&&, std::index_sequence); @@ -36,26 +36,25 @@ class iter::impl::ZippedLongest { using ZipIterDeref = std::tuple...>; - ZippedLongest(TupleType&& in_containers) - : containers(std::move(in_containers)) {} + ZippedLongest(TupleType&& containers) : containers_(std::move(containers)) {} public: ZippedLongest(ZippedLongest&&) = default; class Iterator : public std::iterator { private: - iterator_tuple_type iters; - iterator_tuple_type ends; + iterator_tuple_type iters_; + iterator_tuple_type ends_; public: - Iterator(iterator_tuple_type&& in_iters, - iterator_tuple_type&& in_ends) - : iters(std::move(in_iters)), ends(std::move(in_ends)) {} + Iterator(iterator_tuple_type&& iters, + iterator_tuple_type&& ends) + : iters_(std::move(iters)), ends_(std::move(ends)) {} Iterator& operator++() { // increment every iterator that's not already at // the end - absorb(((std::get(this->iters) != std::get(this->ends)) - ? (++std::get(this->iters), 0) + absorb(((std::get(iters_) != std::get(ends_)) + ? (++std::get(iters_), 0) : 0)...); return *this; } @@ -70,7 +69,7 @@ class iter::impl::ZippedLongest { if (sizeof...(Is) == 0) return false; bool results[] = { - false, (std::get(this->iters) != std::get(other.iters))...}; + false, (std::get(iters_) != std::get(other.iters_))...}; return std::any_of( std::begin(results), std::end(results), [](bool b) { return b; }); } @@ -80,10 +79,9 @@ class iter::impl::ZippedLongest { } ZipIterDeref operator*() { - return ZipIterDeref{ - ((std::get(this->iters) != std::get(this->ends)) - ? OptType{*std::get(this->iters)} - : OptType{})...}; + return ZipIterDeref{((std::get(iters_) != std::get(ends_)) + ? OptType{*std::get(iters_)} + : OptType{})...}; } auto operator-> () -> ArrowProxy { @@ -93,23 +91,21 @@ class iter::impl::ZippedLongest { Iterator begin() { return {iterator_tuple_type{ - std::begin(std::get(this->containers))...}, - iterator_tuple_type{ - std::end(std::get(this->containers))...}}; + std::begin(std::get(containers_))...}, + iterator_tuple_type{std::end(std::get(containers_))...}}; } Iterator end() { - return {iterator_tuple_type{ - std::end(std::get(this->containers))...}, - iterator_tuple_type{ - std::end(std::get(this->containers))...}}; + return { + iterator_tuple_type{std::end(std::get(containers_))...}, + iterator_tuple_type{std::end(std::get(containers_))...}}; } }; template iter::impl::ZippedLongest iter::impl::zip_longest_impl( - TupleType&& in_containers, std::index_sequence) { - return {std::move(in_containers)}; + TupleType&& containers, std::index_sequence) { + return {std::move(containers)}; } template From c5c53ea6580bbb3f1add09046f3620e422cc9afa Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:31:55 -0800 Subject: [PATCH 087/403] s/functor/callable --- test/test_filter.cpp | 2 +- test/test_filterfalse.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_filter.cpp b/test/test_filter.cpp index 4badfaf1..bb29ee90 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -30,7 +30,7 @@ namespace { }; } -TEST_CASE("filter: handles different functor types", "[filter]") { +TEST_CASE("filter: handles different callable types", "[filter]") { Vec ns = {1, 2, 5, 6, 3, 1, 7, -1, 5}; Vec vc = {1, 2, 3, 1, -1}; SECTION("with function pointer") { diff --git a/test/test_filterfalse.cpp b/test/test_filterfalse.cpp index dec5c2eb..07726cf8 100644 --- a/test/test_filterfalse.cpp +++ b/test/test_filterfalse.cpp @@ -30,7 +30,7 @@ namespace { }; } -TEST_CASE("filterfalse: handles different functor types", "[filterfalse]") { +TEST_CASE("filterfalse: handles different callable types", "[filterfalse]") { Vec ns = {1, 2, 5, 6, 3, 1, 7, -1, 5}; Vec vc = {5, 6, 7, 5}; SECTION("with function pointer") { From bdd8a054cd304bbeb69ac8e181a71c5897d4a1ae Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:33:07 -0800 Subject: [PATCH 088/403] Fixes init list example Dropped support for that a while ago. --- examples/sliding_window_examples.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/sliding_window_examples.cpp b/examples/sliding_window_examples.cpp index 3c0d39dd..ff286202 100644 --- a/examples/sliding_window_examples.cpp +++ b/examples/sliding_window_examples.cpp @@ -13,7 +13,7 @@ int main() { } std::cout << "Empty when window size is > length\n"; - for (auto&& sec : iter::sliding_window({1,2,3}, 10)) { + for (auto&& sec : iter::sliding_window(std::vector{1,2,3}, 10)) { for (auto&& i : sec) { std::cout << i << ' '; } From c1ac1d743d4b67d1cdcb9e37f80efab21dcf6cab Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 17:48:18 -0800 Subject: [PATCH 089/403] Switches to C++17! --- test/SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SConstruct b/test/SConstruct index d2198470..5c4bc272 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -3,7 +3,7 @@ import os env = Environment( ENV = os.environ, CXXFLAGS= ['-g', '-Wall', '-Wextra', - '-pedantic', '-std=c++14', + '-pedantic', '-std=c++17', '-I/usr/local/include', '-I.'], CPPPATH='..', LINKFLAGS=['-L/usr/local/lib']) From 965b8b6e8e54f6af399326fa799dbfba576dbfef Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Feb 2017 23:53:22 -0800 Subject: [PATCH 090/403] Rewrite of iterator_wrapper with std::variant So much code deleted. So much nicer now. The future looks bright. --- internal/iterator_wrapper.hpp | 123 +++++++--------------------------- 1 file changed, 26 insertions(+), 97 deletions(-) diff --git a/internal/iterator_wrapper.hpp b/internal/iterator_wrapper.hpp index a181539f..9a94e89a 100644 --- a/internal/iterator_wrapper.hpp +++ b/internal/iterator_wrapper.hpp @@ -2,6 +2,8 @@ #define ITERTOOLS_ITERATOR_WRAPPER_HPP_ #include +#include +#include #include "iterbase.hpp" namespace iter { @@ -38,132 +40,59 @@ namespace iter { template class iter::impl::IteratorWrapperImpl { private: - static_assert(!std::is_same{}, ""); - enum class IterState { Normal, End, Uninitialized }; - - void destroy_sub() { - if (state_ == IterState::Normal) { - sub_iter_.~SubIter(); - } else if (state_ == IterState::End) { - sub_end_.~SubEnd(); - } - state_ = IterState::Uninitialized; + static_assert(!std::is_same{}); + SubIter& sub_iter() { + auto* sub = std::get_if(&sub_iter_or_end_); + assert(sub); + return *sub; } - template - void copy_or_move_sub_from(T&& other) { - if (this == &other) { - return; - } - if (state_ == other.state_) { - if (state_ == IterState::Normal) { - sub_iter_ = std::forward(other).sub_iter_; - } else if (state_ == IterState::End) { - sub_end_ = std::forward(other).sub_end_; - } - } else { - // state_s are different, must destroy and reconstruct - destroy_sub(); - if (other.state_ == IterState::Normal) { - new (&sub_iter_) SubIter(std::forward(other).sub_iter_); - } else if (other.state_ == IterState::End) { - new (&sub_end_) SubEnd(std::forward(other).sub_end_); - } - state_ = other.state_; - } - } - - void copy_sub_from(const IteratorWrapperImpl& other) { - copy_or_move_sub_from(other); - } - - void move_sub_from(IteratorWrapperImpl&& other) { - copy_or_move_sub_from(std::move(other)); + const SubIter& sub_iter() const { + auto* sub = std::get_if(&sub_iter_or_end_); + assert(sub); + return *sub; } - // TODO replace with std::variant when C++17 is going strong - union { - SubIter sub_iter_; - SubEnd sub_end_; - }; - IterState state_{IterState::Uninitialized}; + std::variant sub_iter_or_end_; public: IteratorWrapperImpl() : IteratorWrapperImpl(SubIter{}) {} - IteratorWrapperImpl(const IteratorWrapperImpl& other) { - copy_sub_from(other); - } + IteratorWrapperImpl(SubIter&& it) : sub_iter_or_end_{std::move(it)} {} - IteratorWrapperImpl& operator=(const IteratorWrapperImpl& other) { - copy_sub_from(other); - return *this; - } - - IteratorWrapperImpl(IteratorWrapperImpl&& other) { - move_sub_from(std::move(other)); - } - - IteratorWrapperImpl& operator=(IteratorWrapperImpl&& other) { - move_sub_from(std::move(other)); - return *this; - } - - IteratorWrapperImpl(SubIter&& it) - : sub_iter_{std::move(it)}, state_{IterState::Normal} {} - - IteratorWrapperImpl(SubEnd&& it) - : sub_end_(std::move(it)), state_{IterState::End} {} + IteratorWrapperImpl(SubEnd&& it) : sub_iter_or_end_(std::move(it)) {} IteratorWrapperImpl& operator++() { - assert(state_ == IterState::Normal); // because ++ing the end is UB - ++sub_iter_; + ++sub_iter(); return *this; } decltype(auto) operator*() { - assert(state_ == IterState::Normal); // because *ing the end is UB - return *sub_iter_; + return *sub_iter(); } decltype(auto) operator*() const { - assert(state_ == IterState::Normal); // because *ing the end is UB - return *sub_iter_; + return *sub_iter(); } decltype(auto) operator-> () { - assert(state_ == IterState::Normal); - return apply_arrow(sub_iter_); + return apply_arrow(sub_iter()); } decltype(auto) operator-> () const { - assert(state_ == IterState::Normal); - return apply_arrow(sub_iter_); + return apply_arrow(sub_iter()); } bool operator!=(const IteratorWrapperImpl& other) const { - assert(state_ != IterState::Uninitialized - && other.state_ != IterState::Uninitialized); - if (state_ == other.state_) { - if (state_ == IterState::End) { - // NOTE this used to be return sub_end_ != other.sub_end_; - // but rangev3 sentinels aren't comparable - // https://github.com/ericniebler/range-v3/issues/564 + constexpr static struct : std::not_equal_to { + // specially compare Ends because rangev3 sentinels are not equality + // comparable + bool operator()(const SubEnd&, const SubEnd&) const { return false; - } else { - return sub_iter_ != other.sub_iter_; - } - } else { - if (state_ == IterState::Normal) { // other is End - return sub_iter_ != other.sub_end_; - } else { // other is Normal - return sub_end_ != other.sub_iter_; } - } - } - - ~IteratorWrapperImpl() { - this->destroy_sub(); + using std::not_equal_to::operator(); + } not_equal; + return std::visit(not_equal, sub_iter_or_end_, other.sub_iter_or_end_); } }; From ccb84810169ce699e9060c613b690a9526189044 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 23 Feb 2017 12:03:24 -0800 Subject: [PATCH 091/403] uses structured bindings in zip_examples --- examples/zip_examples.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/zip_examples.cpp b/examples/zip_examples.cpp index 0b7f347a..d35dd0cf 100644 --- a/examples/zip_examples.cpp +++ b/examples/zip_examples.cpp @@ -10,8 +10,8 @@ int main() { // zip terminates on the shortest sequence, and is variadic std::cout << "zipping a vector of ints and a vector of strings\n"; - for (auto&& e : iter::zip(ivec, svec)) { - std::cout << '(' << std::get<0>(e) << ", " << std::get<1>(e) << ")\n"; + for (auto&& [i, s] : iter::zip(ivec, svec)) { + std::cout << '(' << i << ", " << s << ")\n"; } } From 49a9a85522ed1b8c62291a87bd4e4a11619c6d6b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 23 Feb 2017 12:04:15 -0800 Subject: [PATCH 092/403] uses structured bindings in zip_longest_examples --- examples/zip_longest_examples.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/zip_longest_examples.cpp b/examples/zip_longest_examples.cpp index 1bbffbf8..5f8dc9e7 100644 --- a/examples/zip_longest_examples.cpp +++ b/examples/zip_longest_examples.cpp @@ -22,8 +22,7 @@ int main() { std::vector svec = {"hello", "good day", "goodbye"}; std::cout << "zipping a vector of strings with a vector of ints:\n"; - for (auto&& e : iter::zip_longest(ivec, svec)) { - std::cout << '(' << std::get<0>(e) << ", " - << std::get<1>(e) << ")\n"; + for (auto&& [i, s] : iter::zip_longest(ivec, svec)) { + std::cout << '(' << i << ", " << s << ")\n"; } } From f42a27d912c7e04d7139991d7737feb500adecf6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 23 Feb 2017 12:05:27 -0800 Subject: [PATCH 093/403] uses structured bindings in product example --- examples/combinatoric_examples.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/combinatoric_examples.cpp b/examples/combinatoric_examples.cpp index d7111a56..653d428c 100644 --- a/examples/combinatoric_examples.cpp +++ b/examples/combinatoric_examples.cpp @@ -45,11 +45,8 @@ int main() { std::vector v3 = {"abc", "def"}; std::cout << "product of three vectors (int, int, string):\n"; - for (auto&& t : iter::product(v1,v2,v3)) { - std::cout << "{ " - << std::get<0>(t) << ' ' - << std::get<1>(t) << ' ' - << std::get<2>(t) << " }\n"; + for (auto&& [a, b, c] : iter::product(v1,v2,v3)) { + std::cout << "{ " << a << ' ' << b << ' ' << c << " }\n"; } std::cout << "powerset({1,2,3,4,5}):\n"; From 9f0d349dfcf6cdcaf0e3b411f44f3c79015cdf11 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 23 Feb 2017 12:09:09 -0800 Subject: [PATCH 094/403] uses structured bindings in README zip example --- README.md | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index a740372d..4af5b982 100644 --- a/README.md +++ b/README.md @@ -500,17 +500,14 @@ tuple of the elements the iterators were holding. Example usage: ```c++ -array i{{1,2,3,4}}; -vector f{1.2,1.4,12.3,4.5,9.9}; -vector s{"i","like","apples","alot","dude"}; -array d{{1.2,1.2,1.2,1.2,1.2}}; - -for (auto&& e : zip(i,f,s,d)) { - cout << std::get<0>(e) << ' ' - << std::get<1>(e) << ' ' - << std::get<2>(e) << ' ' - << std::get<3>(e) << '\n'; - std::get<1>(e)=2.2f; // modifies the underlying 'f' array +array iseq{{1,2,3,4}}; +vector fseq{1.2,1.4,12.3,4.5,9.9}; +vector sseq{"i","like","apples","a lot","dude"}; +array dseq{{1.2,1.2,1.2,1.2,1.2}}; + +for (auto&& [i, f, s, d] : zip(iseq, fseq, sseq, dseq)) { + cout << i << ' ' << f << ' ' << s << ' ' << d << '\n'; + f = 2.2f; // modifies the underlying 'fseq' sequence } ``` From a3592d9dac066507ddeb2913867daaf733cf388b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 23 Feb 2017 12:10:25 -0800 Subject: [PATCH 095/403] uses structured bindings in README zip_longest ex --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4af5b982..587a8118 100644 --- a/README.md +++ b/README.md @@ -524,16 +524,16 @@ element in each tuple yielded. ```c++ vector v1 = {0, 1, 2, 3}; vector v2 = {10, 11}; -for (auto&& t : zip_longest(v1, v2)) { +for (auto&& [x, y] : zip_longest(v1, v2)) { cout << '{'; - if (std::get<0>(t)) { - cout << "Just " << *std::get<0>(t); + if (x) { + cout << "Just " << *x; } else { cout << "Nothing"; } cout << ", "; - if (std::get<1>(t)) { - cout << "Just " << *std::get<1>(t); + if (y) { + cout << "Just " << *y; } else { cout << "Nothing"; } From cc06e7a5ae2c96013eb08a2c4b8b941f741420f0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 23 Feb 2017 12:18:37 -0800 Subject: [PATCH 096/403] uses structured bindings in README product example --- README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 587a8118..e7bcd27e 100644 --- a/README.md +++ b/README.md @@ -749,12 +749,9 @@ Example usage: vector v1{1,2,3}; vector v2{7,8}; vector v3{"the","cat"}; -vector v4{"hi","what","up","dude"}; -for (auto&& t : product(v1,v2,v3,v4)) { - cout << std::get<0>(t) << ", " - << std::get<1>(t) << ", " - << std::get<2>(t) << ", " - << std::get<3>(t) << '\n'; +vector v4{"hi","what's","up","dude"}; +for (auto&& [a, b, c, d] : product(v1,v2,v3,v4)) { + cout << a << ", " << b << ", " << c << ", " << d << '\n'; } ``` From 72164712b7dd7ae6e94b56280792b20d3a479046 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 23 Feb 2017 22:01:52 -0800 Subject: [PATCH 097/403] uses structured bindings in test_zip --- test/test_zip.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_zip.cpp b/test/test_zip.cpp index b0312e1e..0fc3b8fc 100644 --- a/test/test_zip.cpp +++ b/test/test_zip.cpp @@ -67,9 +67,9 @@ TEST_CASE("zip: Empty", "[zip]") { TEST_CASE("zip: Modify sequence through zip", "[zip]") { std::vector iv{1, 2, 3}; std::vector iv2{1, 2, 3, 4}; - for (auto&& t : zip(iv, iv2)) { - std::get<0>(t) = -1; - std::get<1>(t) = -1; + for (auto&& [a, b] : zip(iv, iv2)) { + a = -1; + b = -1; } const std::vector vc{-1, -1, -1}; From 606bd1f5415a2c9e793433f16c97420cdeceac71 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 23 Feb 2017 22:02:07 -0800 Subject: [PATCH 098/403] uses structured bindings in test_zip_longest --- test/test_zip_longest.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test_zip_longest.cpp b/test/test_zip_longest.cpp index 85b8ee31..fd421097 100644 --- a/test/test_zip_longest.cpp +++ b/test/test_zip_longest.cpp @@ -90,8 +90,8 @@ TEST_CASE( CharRange cr('c'); ResVec v; - for (auto&& p : zip_longest(iv, cr)) { - v.push_back(TP{*std::get<0>(p), *std::get<1>(p)}); + for (auto&& [i, c] : zip_longest(iv, cr)) { + v.push_back(TP{*i, *c}); } ResVec vc{TP{10, 'a'}, TP{20, 'b'}}; REQUIRE(v == vc); @@ -110,9 +110,9 @@ TEST_CASE( TEST_CASE("zip longest: can modify zipped sequences", "[zip_longest]") { std::vector ns1 = {1, 2, 3}; std::vector ns2 = {10, 11, 12}; - for (auto&& t : zip_longest(ns1, ns2)) { - *std::get<0>(t) = -1; - *std::get<1>(t) = -1; + for (auto&& [a, b] : zip_longest(ns1, ns2)) { + *a = -1; + *b = -1; } std::vector vc = {-1, -1, -1}; From 150792dd39b4cd65f4876bba445080e3baff07f2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Feb 2017 23:41:21 -0800 Subject: [PATCH 099/403] Adds get_begin() and get_end() for non-members These should delegate to std::begin or non-member begin (or end). Whatever works. --- examples/SConstruct | 12 ++++++++---- internal/iterbase.hpp | 39 ++++++++++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/examples/SConstruct b/examples/SConstruct index 947064f9..8a6b6f40 100644 --- a/examples/SConstruct +++ b/examples/SConstruct @@ -2,12 +2,16 @@ import os env = Environment( ENV=os.environ, - CXX='c++', + CXX='clang++', CXXFLAGS= ['-g', '-Wall', '-Wextra', - '-pedantic', '-std=c++14', - '-I/usr/local/include'], + '-stdlib=libc++', + '-pedantic', '-std=c++1z', + '-I/usr/local/include' + ], CPPPATH='..', - LINKFLAGS='-L/usr/local/lib') + LINKFLAGS=['-L/usr/local/lib', + '-lc++', '-lc++abi', + ]) # allows highighting to print to terminal from compiler output env['ENV']['TERM'] = os.environ['TERM'] diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 032d8e00..9970610c 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -17,6 +17,31 @@ namespace iter { namespace impl { + namespace get_iters { + // This has to be set up in a really weird way. + // This looks at first as if it could be + // decltype(auto) get_begin(T& t) { + // using std::begin; + // return begin(t); + // } + // However, without return types in the declaration, SFINAE gets + // messed up everywhere. + using std::begin; + // TODO add constexpr for c++17 + template + auto get_begin(T& t) -> decltype(begin(t)) { + return begin(t); + } + using std::end; + // TODO add constexpr for c++17 + template + auto get_end(T& t) -> decltype(end(t)) { + return end(t); + } + } + using get_iters::get_begin; + using get_iters::get_end; + template struct type_is { using type = T; @@ -32,7 +57,7 @@ namespace iter { // iterator_type is the type of C's iterator template - using iterator_type = decltype(std::begin(std::declval())); + using iterator_type = decltype(get_begin(std::declval())); // iterator_deref is the type obtained by dereferencing an iterator // to an object of type C @@ -53,7 +78,7 @@ namespace iter { template struct IsIterable : std::false_type {}; - // Assuming that if a type works with std::begin, it is an iterable. + // Assuming that if a type works with begin, it is an iterable. template struct IsIterable>> : std::true_type {}; @@ -121,9 +146,9 @@ namespace iter { template struct is_random_access_iter::iterator_category, - std::random_access_iterator_tag>::value>> : std::true_type {}; + std::enable_if_t< + std::is_same::iterator_category, + std::random_access_iterator_tag>::value>> : std::true_type {}; template using has_random_access_iter = is_random_access_iter>; @@ -177,8 +202,8 @@ namespace iter { template Distance dumb_size(Container&& container) { Distance d{0}; - auto end_it = std::end(container); - for (auto it = std::begin(container); it != end_it; ++it) { + auto end_it = get_end(container); + for (auto it = get_begin(container); it != end_it; ++it) { ++d; } return d; From 263bca384b662b8f97d304292da593f734018430 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Feb 2017 23:43:26 -0800 Subject: [PATCH 100/403] Switches BasicIterable to non-member begin and end --- test/helpers.hpp | 65 ++++-------------------------------------------- 1 file changed, 5 insertions(+), 60 deletions(-) diff --git a/test/helpers.hpp b/test/helpers.hpp index 9cf67fd0..1ab8adfe 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -158,20 +158,20 @@ namespace itertest { } }; - Iterator begin() { - return {this->data}; + friend BasicIterable::Iterator begin(BasicIterable& b) { + return {b.data}; } - Iterator end() { - return {this->data + this->size}; + friend BasicIterable::Iterator end(BasicIterable& b) { + return {b.data + b.size}; } + #ifdef DECLARE_REVERSE_ITERATOR Iterator rbegin(); Iterator rend(); #endif // ifdef DECLARE_REVERSE_ITERATOR }; - using iter::impl::void_t; template @@ -341,59 +341,4 @@ class IntCharPairRange : DiffEndRange, IncIntCharPair>({0, 'a'}, stop) {} }; -#if 0 -class CharRange { - private: - char stop_{}; - - public: - constexpr CharRange(char stop) : stop_{stop} {} - - class Iterator; - class EndIterator; - - class Iterator { - private: - char stop_{}; - mutable char value_{'a'}; - public: -#ifdef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE - Iterator() = default; -#endif - Iterator(char stop) : stop_{stop} {} - - char& operator*() const { return value_; } - char* operator->() const { return &value_; } - - Iterator& operator++() { - ++value_; - return *this; - } - - bool operator!=(const Iterator& other) const { - return value_ != other.value_; - } - - bool operator!=(const EndIterator&) const { - return value_ < stop_; - } - - friend bool operator!=(const EndIterator& lhs, const Iterator& rhs) { - return rhs != lhs; - } - - }; - - class EndIterator { }; - - Iterator begin() { - return {stop_}; - } - - EndIterator end() { - return {}; - } -}; -#endif - #endif From 3a6db8349c298b0e685ca7938791b6aa01d83598 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Feb 2017 23:43:55 -0800 Subject: [PATCH 101/403] Tests get_begin() returns correct type --- test/test_iterbase.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/test_iterbase.cpp b/test/test_iterbase.cpp index 59b80066..fecfb9a4 100644 --- a/test/test_iterbase.cpp +++ b/test/test_iterbase.cpp @@ -89,3 +89,8 @@ TEST_CASE("DerefHolder non-reference", "[iterbase]") { dh.reset(std::move(b)); REQUIRE(dh.get() == 5); } + +TEST_CASE("get_begin returns correct type", "[iterbase]") { + std::vector v; + REQUIRE((std::is_same{})); +} From d1d7e6ad71ff4e7e86c731eed01aaf4afeb4921b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Feb 2017 23:44:48 -0800 Subject: [PATCH 102/403] Uses get_begin and get_end throughout itertools Now everything should work with non-member begin and end iterables. Not that anyone cared enough to ask for it. Gotta stay ahead of the game. --- accumulate.hpp | 4 ++-- chain.hpp | 20 ++++++++++---------- chunked.hpp | 4 ++-- combinations.hpp | 8 ++++---- combinations_with_replacement.hpp | 6 +++--- compress.hpp | 10 +++++----- cycle.hpp | 4 ++-- dropwhile.hpp | 4 ++-- enumerate.hpp | 4 ++-- filter.hpp | 4 ++-- groupby.hpp | 4 ++-- internal/iterator_wrapper.hpp | 2 +- permutations.hpp | 10 +++++----- powerset.hpp | 8 ++++---- product.hpp | 8 ++++---- slice.hpp | 8 ++++---- sliding_window.hpp | 8 ++++---- sorted.hpp | 8 ++++---- starmap.hpp | 8 ++++---- takewhile.hpp | 4 ++-- unique_justseen.hpp | 2 +- zip.hpp | 6 +++--- zip_longest.hpp | 12 ++++++------ 23 files changed, 78 insertions(+), 78 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 64e3dd44..aec33626 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -107,11 +107,11 @@ class iter::impl::Accumulator { }; Iterator begin() { - return {std::begin(container_), std::end(container_), accumulate_func_}; + return {get_begin(container_), get_end(container_), accumulate_func_}; } Iterator end() { - return {std::end(container_), std::end(container_), accumulate_func_}; + return {get_end(container_), get_end(container_), accumulate_func_}; } }; diff --git a/chain.hpp b/chain.hpp index 7abb9f2a..90f553e1 100644 --- a/chain.hpp +++ b/chain.hpp @@ -144,13 +144,13 @@ class iter::impl::Chained { }; Iterator begin() { - return {0, IterTupType{std::begin(std::get(tup_))...}, - IterTupType{std::end(std::get(tup_))...}}; + return {0, IterTupType{get_begin(std::get(tup_))...}, + IterTupType{get_end(std::get(tup_))...}}; } Iterator end() { - return {sizeof...(Is), IterTupType{std::end(std::get(tup_))...}, - IterTupType{std::end(std::get(tup_))...}}; + return {sizeof...(Is), IterTupType{get_end(std::get(tup_))...}, + IterTupType{get_end(std::get(tup_))...}}; } }; @@ -219,11 +219,11 @@ class iter::impl::ChainedFromIterable { sub_iter_p_{!(top_iter != top_end) ? // iter == end ? nullptr - : std::make_unique(std::begin(*top_iter))}, + : std::make_unique(get_begin(*top_iter))}, sub_end_p_{!(top_iter != top_end) ? // iter == end ? nullptr - : std::make_unique(std::end(*top_iter))} {} + : std::make_unique(get_end(*top_iter))} {} Iterator(const Iterator& other) : top_level_iter_{other.top_level_iter_}, @@ -253,8 +253,8 @@ class iter::impl::ChainedFromIterable { if (!(*sub_iter_p_ != *sub_end_p_)) { ++top_level_iter_; if (top_level_iter_ != top_level_end_) { - sub_iter_p_ = std::make_unique(std::begin(*top_level_iter_)); - sub_end_p_ = std::make_unique(std::end(*top_level_iter_)); + sub_iter_p_ = std::make_unique(get_begin(*top_level_iter_)); + sub_end_p_ = std::make_unique(get_end(*top_level_iter_)); } else { sub_iter_p_.reset(); sub_end_p_.reset(); @@ -288,11 +288,11 @@ class iter::impl::ChainedFromIterable { }; Iterator begin() { - return {std::begin(container_), std::end(container_)}; + return {get_begin(container_), get_end(container_)}; } Iterator end() { - return {std::end(container_), std::end(container_)}; + return {get_end(container_), get_end(container_)}; } }; diff --git a/chunked.hpp b/chunked.hpp index 6dcb8917..90f578ca 100644 --- a/chunked.hpp +++ b/chunked.hpp @@ -99,11 +99,11 @@ class iter::impl::Chunker { }; Iterator begin() { - return {std::begin(container_), std::end(container_), chunk_size_}; + return {get_begin(container_), get_end(container_), chunk_size_}; } Iterator end() { - return {std::end(container_), std::end(container_), chunk_size_}; + return {get_end(container_), get_end(container_), chunk_size_}; } }; diff --git a/combinations.hpp b/combinations.hpp index 71660512..fe6c31ac 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -51,9 +51,9 @@ class iter::impl::Combinator { } size_t inc = 0; for (auto& iter : indices_.get()) { - auto it = std::begin(*container_p_); - dumb_advance(it, std::end(*container_p_), inc); - if (it != std::end(*container_p_)) { + auto it = get_begin(*container_p_); + dumb_advance(it, get_end(*container_p_), inc); + if (it != get_end(*container_p_)) { iter = it; ++inc; } else { @@ -81,7 +81,7 @@ class iter::impl::Combinator { // between the item and end of item auto dist = std::distance(indices_.get().rbegin(), iter); - if (!(dumb_next(*iter, dist) != std::end(*container_p_))) { + if (!(dumb_next(*iter, dist) != get_end(*container_p_))) { if ((iter + 1) != indices_.get().rend()) { size_t inc = 1; for (auto down = iter; down != indices_.get().rbegin() - 1; diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 2fa33bd8..0467147c 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -45,8 +45,8 @@ class iter::impl::CombinatorWithReplacement { public: Iterator(Container& in_container, std::size_t n) : container_p_{&in_container}, - indices_(n, std::begin(in_container)), - steps_{(std::begin(in_container) != std::end(in_container) && n) + indices_(n, get_begin(in_container)), + steps_{(get_begin(in_container) != get_end(in_container) && n) ? 0 : COMPLETE} {} @@ -62,7 +62,7 @@ class iter::impl::CombinatorWithReplacement { for (auto iter = indices_.get().rbegin(); iter != indices_.get().rend(); ++iter) { ++(*iter); - if (!(*iter != std::end(*container_p_))) { + if (!(*iter != get_end(*container_p_))) { if ((iter + 1) != indices_.get().rend()) { for (auto down = iter; down != indices_.get().rbegin() - 1; --down) { diff --git a/compress.hpp b/compress.hpp index ede8e934..ca0da7d2 100644 --- a/compress.hpp +++ b/compress.hpp @@ -27,7 +27,7 @@ class iter::impl::Compressed { Container&&, Selector&&); // Selector::Iterator type - using selector_iter_type = decltype(std::begin(selectors_)); + using selector_iter_type = decltype(get_begin(selectors_)); Compressed(Container&& in_container, Selector&& in_selectors) : container_(std::forward(in_container)), @@ -98,13 +98,13 @@ class iter::impl::Compressed { }; Iterator begin() { - return {std::begin(container_), std::end(container_), - std::begin(selectors_), std::end(selectors_)}; + return {get_begin(container_), get_end(container_), get_begin(selectors_), + get_end(selectors_)}; } Iterator end() { - return {std::end(container_), std::end(container_), std::end(selectors_), - std::end(selectors_)}; + return {get_end(container_), get_end(container_), get_end(selectors_), + get_end(selectors_)}; } }; diff --git a/cycle.hpp b/cycle.hpp index 24396e7e..cd058335 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -77,11 +77,11 @@ class iter::impl::Cycler { }; Iterator begin() { - return {std::begin(container_), std::end(container_)}; + return {get_begin(container_), get_end(container_)}; } Iterator end() { - return {std::end(container_), std::end(container_)}; + return {get_end(container_), get_end(container_)}; } }; diff --git a/dropwhile.hpp b/dropwhile.hpp index 1f544137..6e781baf 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -96,11 +96,11 @@ class iter::impl::Dropper { }; Iterator begin() { - return {std::begin(container_), std::end(container_), filter_func_}; + return {get_begin(container_), get_end(container_), filter_func_}; } Iterator end() { - return {std::end(container_), std::end(container_), filter_func_}; + return {get_end(container_), get_end(container_), filter_func_}; } }; diff --git a/enumerate.hpp b/enumerate.hpp index 9331b139..25fbceb6 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -89,11 +89,11 @@ class iter::impl::Enumerable { }; Iterator begin() { - return {std::begin(container_), start_}; + return {get_begin(container_), start_}; } Iterator end() { - return {std::end(container_), start_}; + return {get_end(container_), start_}; } }; diff --git a/filter.hpp b/filter.hpp index 1c118407..aa0de753 100644 --- a/filter.hpp +++ b/filter.hpp @@ -109,11 +109,11 @@ class iter::impl::Filtered { }; Iterator begin() { - return {std::begin(container_), std::end(container_), filter_func_}; + return {get_begin(container_), get_end(container_), filter_func_}; } Iterator end() { - return {std::end(container_), std::end(container_), filter_func_}; + return {get_end(container_), get_end(container_), filter_func_}; } }; diff --git a/groupby.hpp b/groupby.hpp index a4074b5b..1a06e60f 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -250,11 +250,11 @@ class iter::impl::GroupProducer { }; Iterator begin() { - return {std::begin(container_), std::end(container_), key_func_}; + return {get_begin(container_), get_end(container_), key_func_}; } Iterator end() { - return {std::end(container_), std::end(container_), key_func_}; + return {get_end(container_), get_end(container_), key_func_}; } }; diff --git a/internal/iterator_wrapper.hpp b/internal/iterator_wrapper.hpp index a181539f..272266cf 100644 --- a/internal/iterator_wrapper.hpp +++ b/internal/iterator_wrapper.hpp @@ -8,7 +8,7 @@ namespace iter { namespace impl { // iterator_end_type is the type of C's end iterator template - using iterator_end_type = decltype(std::end(std::declval())); + using iterator_end_type = decltype(get_end(std::declval())); template class IteratorWrapperImpl; diff --git a/permutations.hpp b/permutations.hpp index a522a980..540ae62b 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -57,7 +57,7 @@ class iter::impl::Permuter { working_set_.get().push_back(sub_iter); ++sub_iter; } - std::sort(std::begin(working_set_.get()), std::end(working_set_.get()), + std::sort(get_begin(working_set_.get()), get_end(working_set_.get()), cmp_iters); } @@ -71,8 +71,8 @@ class iter::impl::Permuter { Iterator& operator++() { ++steps_; - if (!std::next_permutation(std::begin(working_set_.get()), - std::end(working_set_.get()), cmp_iters)) { + if (!std::next_permutation(get_begin(working_set_.get()), + get_end(working_set_.get()), cmp_iters)) { steps_ = COMPLETE; } return *this; @@ -94,11 +94,11 @@ class iter::impl::Permuter { }; Iterator begin() { - return {std::begin(container_), std::end(container_)}; + return {get_begin(container_), get_end(container_)}; } Iterator end() { - return {std::end(container_), std::end(container_)}; + return {get_end(container_), get_end(container_)}; } }; diff --git a/powerset.hpp b/powerset.hpp index 2cbad540..9c369e98 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -49,8 +49,8 @@ class iter::impl::Powersetter { : container_p_{&container}, set_size_{sz}, comb_{std::make_shared(combinations(container, sz))}, - comb_iter_{std::begin(*comb_)}, - comb_end_{std::end(*comb_)} {} + comb_iter_{get_begin(*comb_)}, + comb_end_{get_end(*comb_)} {} Iterator& operator++() { ++comb_iter_; @@ -59,8 +59,8 @@ class iter::impl::Powersetter { comb_ = std::make_shared( combinations(*container_p_, set_size_)); - comb_iter_ = std::begin(*comb_); - comb_end_ = std::end(*comb_); + comb_iter_ = get_begin(*comb_); + comb_end_ = get_end(*comb_); } return *this; } diff --git a/product.hpp b/product.hpp index e7e06f26..db9d31f7 100644 --- a/product.hpp +++ b/product.hpp @@ -105,13 +105,13 @@ class iter::impl::Productor { }; Iterator begin() { - return {std::begin(container_), std::begin(rest_products_), - std::end(rest_products_)}; + return {get_begin(container_), get_begin(rest_products_), + get_end(rest_products_)}; } Iterator end() { - return {std::end(container_), std::end(rest_products_), - std::end(rest_products_)}; + return { + get_end(container_), get_end(rest_products_), get_end(rest_products_)}; } }; diff --git a/slice.hpp b/slice.hpp index ff4979a5..1ee4252a 100644 --- a/slice.hpp +++ b/slice.hpp @@ -87,13 +87,13 @@ class iter::impl::Sliced { }; Iterator begin() { - auto it = std::begin(container_); - dumb_advance(it, std::end(container_), start_); - return {std::move(it), std::end(container_), start_, stop_, step_}; + auto it = get_begin(container_); + dumb_advance(it, get_end(container_), start_); + return {std::move(it), get_end(container_), start_, stop_, step_}; } Iterator end() { - return {std::end(container_), std::end(container_), stop_, stop_, step_}; + return {get_end(container_), get_end(container_), stop_, stop_, step_}; } }; diff --git a/sliding_window.hpp b/sliding_window.hpp index 27539c87..84c0e4b1 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -85,13 +85,13 @@ class iter::impl::WindowSlider { Iterator begin() { return { - (window_size_ != 0 ? IteratorWrapper{std::begin(container_)} - : IteratorWrapper{std::end(container_)}), - std::end(container_), window_size_}; + (window_size_ != 0 ? IteratorWrapper{get_begin(container_)} + : IteratorWrapper{get_end(container_)}), + get_end(container_), window_size_}; } Iterator end() { - return {std::end(container_), std::end(container_), window_size_}; + return {get_end(container_), get_end(container_), window_size_}; } }; diff --git a/sorted.hpp b/sorted.hpp index 4caf35e0..d5fdf050 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -32,13 +32,13 @@ class iter::impl::SortedView { : container_(std::forward(container)) { // Fill the sorted_iters_ vector with an iterator to each // element in the container_ - for (auto iter = std::begin(container_); iter != std::end(container_); + for (auto iter = get_begin(container_); iter != get_end(container_); ++iter) { sorted_iters_.get().push_back(iter); } // sort by comparing the elements that the iterators point to - std::sort(std::begin(sorted_iters_.get()), std::end(sorted_iters_.get()), + std::sort(get_begin(sorted_iters_.get()), get_end(sorted_iters_.get()), [compare_func](iterator_type it1, iterator_type it2) { return compare_func(*it1, *it2); }); } @@ -47,11 +47,11 @@ class iter::impl::SortedView { SortedView(SortedView&&) = default; ItIt begin() { - return std::begin(sorted_iters_); + return get_begin(sorted_iters_); } ItIt end() { - return std::end(sorted_iters_); + return get_end(sorted_iters_); } }; diff --git a/starmap.hpp b/starmap.hpp index 84cb2da9..3748f244 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -82,11 +82,11 @@ class iter::impl::StarMapper { }; Iterator begin() { - return {func_, std::begin(container_)}; + return {func_, get_begin(container_)}; } Iterator end() { - return {func_, std::end(container_)}; + return {func_, get_end(container_)}; } }; @@ -185,8 +185,8 @@ struct iter::impl::StarMapFn : PipeableAndBindFirst { template auto helper(Func func, TupType&& tup, std::true_type) const { return helper_with_tuples(std::move(func), std::forward(tup), - std::make_index_sequence>:: - value>{}); + std::make_index_sequence< + std::tuple_size>::value>{}); } // handles everything else diff --git a/takewhile.hpp b/takewhile.hpp index e180acd1..af3eeeb9 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -97,11 +97,11 @@ class iter::impl::Taker { }; Iterator begin() { - return {std::begin(container_), std::end(container_), filter_func_}; + return {get_begin(container_), get_end(container_), filter_func_}; } Iterator end() { - return {std::end(container_), std::end(container_), filter_func_}; + return {get_end(container_), get_end(container_), filter_func_}; } }; diff --git a/unique_justseen.hpp b/unique_justseen.hpp index c7fd2462..5e5e3170 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -15,7 +15,7 @@ namespace iter { // explicit return type in lambda so reference types are preserved return imap( [](auto&& group) -> impl::iterator_deref { - return *std::begin(group.second); + return *get_begin(group.second); }, groupby(std::forward(container))); } diff --git a/zip.hpp b/zip.hpp index 89182fe6..c5142cc4 100644 --- a/zip.hpp +++ b/zip.hpp @@ -60,7 +60,7 @@ class iter::impl::Zipped { bool results[] = { true, (std::get(iters_) != std::get(other.iters_))...}; return std::all_of( - std::begin(results), std::end(results), [](bool b) { return b; }); + get_begin(results), get_end(results), [](bool b) { return b; }); } bool operator==(const Iterator& other) const { @@ -78,12 +78,12 @@ class iter::impl::Zipped { Iterator begin() { return {iterator_tuple_type{ - std::begin(std::get(containers_))...}}; + get_begin(std::get(containers_))...}}; } Iterator end() { return { - iterator_tuple_type{std::end(std::get(containers_))...}}; + iterator_tuple_type{get_end(std::get(containers_))...}}; } }; diff --git a/zip_longest.hpp b/zip_longest.hpp index b72aa5c7..00c15cbd 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -71,7 +71,7 @@ class iter::impl::ZippedLongest { bool results[] = { false, (std::get(iters_) != std::get(other.iters_))...}; return std::any_of( - std::begin(results), std::end(results), [](bool b) { return b; }); + get_begin(results), get_end(results), [](bool b) { return b; }); } bool operator==(const Iterator& other) const { @@ -90,15 +90,15 @@ class iter::impl::ZippedLongest { }; Iterator begin() { - return {iterator_tuple_type{ - std::begin(std::get(containers_))...}, - iterator_tuple_type{std::end(std::get(containers_))...}}; + return { + iterator_tuple_type{get_begin(std::get(containers_))...}, + iterator_tuple_type{get_end(std::get(containers_))...}}; } Iterator end() { return { - iterator_tuple_type{std::end(std::get(containers_))...}, - iterator_tuple_type{std::end(std::get(containers_))...}}; + iterator_tuple_type{get_end(std::get(containers_))...}, + iterator_tuple_type{get_end(std::get(containers_))...}}; } }; From 635d8d09507bd89faea725adfb85b7ff70606bd2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 25 Feb 2017 17:34:02 -0800 Subject: [PATCH 103/403] Replaces iter::impl::void_t with std::void_t --- internal/iteratoriterator.hpp | 6 +++--- internal/iterbase.hpp | 13 +++---------- starmap.hpp | 2 +- test/helpers.hpp | 6 +++--- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/internal/iteratoriterator.hpp b/internal/iteratoriterator.hpp index 23bde9d5..e29d740a 100644 --- a/internal/iteratoriterator.hpp +++ b/internal/iteratoriterator.hpp @@ -19,7 +19,7 @@ namespace iter { struct HasConstDeref : std::false_type {}; template - struct HasConstDeref())>> + struct HasConstDeref())>> : std::true_type {}; template @@ -156,7 +156,7 @@ namespace iter { template struct ConstAtTypeOrVoid().at(0))>> + std::void_t().at(0))>> : type_is().at(0))> {}; using const_at_type_or_void_t = typename ConstAtTypeOrVoid<>::type; @@ -166,7 +166,7 @@ namespace iter { template struct ConstIndexTypeOrVoid()[0])>> + std::void_t()[0])>> : type_is()[0])> {}; using const_index_type_or_void_t = typename ConstIndexTypeOrVoid<>::type; diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 9970610c..7e133c3a 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -47,14 +47,6 @@ namespace iter { using type = T; }; - // gcc CWG 1558 - template - struct void_t_help { - using type = void; - }; - template - using void_t = typename void_t_help::type; - // iterator_type is the type of C's iterator template using iterator_type = decltype(get_begin(std::declval())); @@ -80,7 +72,7 @@ namespace iter { // Assuming that if a type works with begin, it is an iterable. template - struct IsIterable>> : std::true_type {}; + struct IsIterable>> : std::true_type {}; template constexpr bool is_iterable = IsIterable::value; @@ -101,7 +93,8 @@ namespace iter { }; template - struct ArrowHelper().operator->())>> { + struct ArrowHelper().operator->())>> { using type = decltype(std::declval().operator->()); type operator()(T& t) const { return t.operator->(); diff --git a/starmap.hpp b/starmap.hpp index 3748f244..1f259437 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -201,7 +201,7 @@ struct iter::impl::StarMapFn : PipeableAndBindFirst { template struct is_tuple_like>::value)>> + std::void_t>::value)>> : public std::true_type {}; public: diff --git a/test/helpers.hpp b/test/helpers.hpp index 1ab8adfe..cc2180b2 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -166,20 +166,18 @@ namespace itertest { return {b.data + b.size}; } - #ifdef DECLARE_REVERSE_ITERATOR Iterator rbegin(); Iterator rend(); #endif // ifdef DECLARE_REVERSE_ITERATOR }; - using iter::impl::void_t; template struct IsIterator : std::false_type {}; template struct IsIterator())), // copyctor + std::void_t())), // copyctor decltype(std::declval() = std::declval()), // copy = decltype(*std::declval()), // operator* decltype(std::declval().operator->()), // operator-> @@ -223,6 +221,7 @@ class DiffEndRange { class Iterator { using SubIter = typename std::vector::iterator; + private: SubIter it_; SubIter end_; @@ -260,6 +259,7 @@ class DiffEndRange { class ReverseIterator { using SubIter = typename std::vector::reverse_iterator; + private: SubIter it_; SubIter end_; From b49e4822050ac4d088c8731fa33432aa14bdb08e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 8 Apr 2017 10:20:22 -0700 Subject: [PATCH 104/403] Moves IterYield out of Enumerable class Preparing for structured bindings. --- enumerate.hpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 25fbceb6..36738121 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -9,9 +9,23 @@ #include #include #include +#include namespace iter { namespace impl { + template + using EnumBasePair = std::pair; + + // "yielded" by the Enumerable::Iterator. Has a .index, and a + // .element referencing the value yielded by the subiterator + template + class EnumIterYield : public EnumBasePair { + using BasePair = EnumBasePair; + using BasePair::BasePair; + typename BasePair::first_type& index = BasePair::first; + typename BasePair::second_type& element = BasePair::second; + }; + template class Enumerable; @@ -28,9 +42,6 @@ class iter::impl::Enumerable { friend EnumerateFn; - // for IterYield - using BasePair = std::pair>; - // Value constructor for use only in the enumerate function Enumerable(Container&& container, Index start) : container_(std::forward(container)), start_{start} {} @@ -38,14 +49,7 @@ class iter::impl::Enumerable { public: Enumerable(Enumerable&&) = default; - // "yielded" by the Enumerable::Iterator. Has a .index, and a - // .element referencing the value yielded by the subiterator - class IterYield : public BasePair { - public: - using BasePair::BasePair; - typename BasePair::first_type& index = BasePair::first; - typename BasePair::second_type& element = BasePair::second; - }; + using IterYield = EnumIterYield>; // Holds an iterator of the contained type and an Index for the // index_. Each call to ++ increments both of these data members. @@ -96,5 +100,4 @@ class iter::impl::Enumerable { return {get_end(container_), start_}; } }; - #endif From 34717e6920fa43714907dba2d66c054c526fb343 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 8 Apr 2017 10:29:26 -0700 Subject: [PATCH 105/403] Tests enumerate IterYield has tuple_size --- test/test_enumerate.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index 33666dc6..e854c081 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -48,6 +48,13 @@ TEST_CASE("Postfix ++ enumerate", "[enumerate]") { REQUIRE((*it).first == 1); } +TEST_CASE("enumerate: structured bindings", "[enumerate]") { + std::string s{"amz"}; + auto e = enumerate(s); + auto it = std::begin(e); + REQUIRE(std::tuple_size>{} == 2); +} + TEST_CASE("enumerate: with starting value", "[enumerate]") { std::string str = "hey"; auto e = enumerate(str, 5u); From 1defa207c3fc337da5717b4eb59ed1f850f75856 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 8 Apr 2017 10:33:13 -0700 Subject: [PATCH 106/403] Supports tuple_size for IterYield --- enumerate.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/enumerate.hpp b/enumerate.hpp index 36738121..5e76703e 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -34,6 +34,12 @@ namespace iter { constexpr impl::EnumerateFn enumerate{}; } +namespace std { + template + class tuple_size> + : public tuple_size> { }; +} + template class iter::impl::Enumerable { private: From 3e612405b8023fd7ebc65dfd6a1317c1f84b10d0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 8 Apr 2017 11:02:44 -0700 Subject: [PATCH 107/403] Tests structured bindings with enumerate() --- test/test_enumerate.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index e854c081..e70f168c 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -49,10 +49,20 @@ TEST_CASE("Postfix ++ enumerate", "[enumerate]") { } TEST_CASE("enumerate: structured bindings", "[enumerate]") { - std::string s{"amz"}; - auto e = enumerate(s); - auto it = std::begin(e); - REQUIRE(std::tuple_size>{} == 2); + { + std::string s{"amz"}; + auto e = enumerate(s); + auto it = std::begin(e); + REQUIRE(std::tuple_size>{} == 2); + REQUIRE(std::get<0>(*it) == it->first); + } + + Vec v; + for (auto && [ i, c ] : enumerate(std::string{"xyz"})) { + v.emplace_back(i, c); + } + const Vec vc{{0, 'x'}, {1, 'y'}, {2, 'z'}}; + REQUIRE(v == vc); } TEST_CASE("enumerate: with starting value", "[enumerate]") { From 3ef2107c26709214821f086e44b9c91fa4506ef4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 8 Apr 2017 11:04:44 -0700 Subject: [PATCH 108/403] Supports structured bindings in enumerate. It turns out I didn't need to implement get<>, having tuple_element and tuple_size is enough. get<> for std::pair is actually called and we're all set! --- enumerate.hpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 5e76703e..22c7e33b 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -7,9 +7,9 @@ #include #include #include +#include #include #include -#include namespace iter { namespace impl { @@ -20,7 +20,7 @@ namespace iter { // .element referencing the value yielded by the subiterator template class EnumIterYield : public EnumBasePair { - using BasePair = EnumBasePair; + using BasePair = EnumBasePair; using BasePair::BasePair; typename BasePair::first_type& index = BasePair::first; typename BasePair::second_type& element = BasePair::second; @@ -35,9 +35,13 @@ namespace iter { } namespace std { - template - class tuple_size> - : public tuple_size> { }; + template + class tuple_size> + : public tuple_size> {}; + + template + class tuple_element> + : public tuple_element> {}; } template From 321cdb53af3aea33e21113f43bf4cc5aff4441ff Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 8 Apr 2017 10:29:26 -0700 Subject: [PATCH 109/403] Tests enumerate IterYield has tuple_size --- test/test_enumerate.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index 33666dc6..e854c081 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -48,6 +48,13 @@ TEST_CASE("Postfix ++ enumerate", "[enumerate]") { REQUIRE((*it).first == 1); } +TEST_CASE("enumerate: structured bindings", "[enumerate]") { + std::string s{"amz"}; + auto e = enumerate(s); + auto it = std::begin(e); + REQUIRE(std::tuple_size>{} == 2); +} + TEST_CASE("enumerate: with starting value", "[enumerate]") { std::string str = "hey"; auto e = enumerate(str, 5u); From 33b68783988efdb306678185c68f2ce53f71b464 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 8 Apr 2017 10:20:22 -0700 Subject: [PATCH 110/403] Moves IterYield out of Enumerable class Preparing for structured bindings. --- enumerate.hpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 25fbceb6..36738121 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -9,9 +9,23 @@ #include #include #include +#include namespace iter { namespace impl { + template + using EnumBasePair = std::pair; + + // "yielded" by the Enumerable::Iterator. Has a .index, and a + // .element referencing the value yielded by the subiterator + template + class EnumIterYield : public EnumBasePair { + using BasePair = EnumBasePair; + using BasePair::BasePair; + typename BasePair::first_type& index = BasePair::first; + typename BasePair::second_type& element = BasePair::second; + }; + template class Enumerable; @@ -28,9 +42,6 @@ class iter::impl::Enumerable { friend EnumerateFn; - // for IterYield - using BasePair = std::pair>; - // Value constructor for use only in the enumerate function Enumerable(Container&& container, Index start) : container_(std::forward(container)), start_{start} {} @@ -38,14 +49,7 @@ class iter::impl::Enumerable { public: Enumerable(Enumerable&&) = default; - // "yielded" by the Enumerable::Iterator. Has a .index, and a - // .element referencing the value yielded by the subiterator - class IterYield : public BasePair { - public: - using BasePair::BasePair; - typename BasePair::first_type& index = BasePair::first; - typename BasePair::second_type& element = BasePair::second; - }; + using IterYield = EnumIterYield>; // Holds an iterator of the contained type and an Index for the // index_. Each call to ++ increments both of these data members. @@ -96,5 +100,4 @@ class iter::impl::Enumerable { return {get_end(container_), start_}; } }; - #endif From f049edd585cdd38e04f53daa9f09029ecd863830 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 8 Apr 2017 10:33:13 -0700 Subject: [PATCH 111/403] Supports tuple_size for IterYield --- enumerate.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/enumerate.hpp b/enumerate.hpp index 36738121..5e76703e 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -34,6 +34,12 @@ namespace iter { constexpr impl::EnumerateFn enumerate{}; } +namespace std { + template + class tuple_size> + : public tuple_size> { }; +} + template class iter::impl::Enumerable { private: From df4c68628cfb9d623484fbded6c9b19b71e6ba77 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 8 Apr 2017 11:04:44 -0700 Subject: [PATCH 112/403] Supports structured bindings in enumerate. It turns out I didn't need to implement get<>, having tuple_element and tuple_size is enough. get<> for std::pair is actually called and we're all set! --- enumerate.hpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 5e76703e..22c7e33b 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -7,9 +7,9 @@ #include #include #include +#include #include #include -#include namespace iter { namespace impl { @@ -20,7 +20,7 @@ namespace iter { // .element referencing the value yielded by the subiterator template class EnumIterYield : public EnumBasePair { - using BasePair = EnumBasePair; + using BasePair = EnumBasePair; using BasePair::BasePair; typename BasePair::first_type& index = BasePair::first; typename BasePair::second_type& element = BasePair::second; @@ -35,9 +35,13 @@ namespace iter { } namespace std { - template - class tuple_size> - : public tuple_size> { }; + template + class tuple_size> + : public tuple_size> {}; + + template + class tuple_element> + : public tuple_element> {}; } template From 686a1e16204ab4de65d761f275d15260417b4b2e Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Sun, 23 Apr 2017 06:47:53 -0700 Subject: [PATCH 113/403] tests enumerate index and element --- test/test_enumerate.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index e854c081..a56f07d1 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -116,6 +116,21 @@ TEST_CASE("enumerate: operator->", "[enumerate]") { REQUIRE(it->second == 50); } +TEST_CASE("enumerate: index and element", "[enumerate]") { + std::string s{"ace"}; + auto e = enumerate(s); + auto it = std::begin(e); + REQUIRE((*it).index == 0); + REQUIRE((*it).element == 'a'); + + Vec v; + for (auto&& p : enumerate(s)) { + v.emplace_back(p.index, p.element); + } + Vec vc{{0, 'a'}, {1, 'c'}, {2, 'e'}}; + REQUIRE(v == vc); +} + TEST_CASE("Works with const iterable", "[enumerate]") { const std::string s{"ace"}; auto e = enumerate(s); From 278500cf77bca7d76ca7b4f014c3adef746a00cb Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Sun, 23 Apr 2017 06:48:07 -0700 Subject: [PATCH 114/403] Fixes EnumIterYield, index & element were private --- enumerate.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/enumerate.hpp b/enumerate.hpp index 22c7e33b..0780facb 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -22,6 +22,7 @@ namespace iter { class EnumIterYield : public EnumBasePair { using BasePair = EnumBasePair; using BasePair::BasePair; + public: typename BasePair::first_type& index = BasePair::first; typename BasePair::second_type& element = BasePair::second; }; From 6d98d621716281cf83f2d5448017c6b399702803 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Sun, 23 Apr 2017 08:12:26 -0700 Subject: [PATCH 115/403] Tests enum ->index --- test/test_enumerate.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index a56f07d1..5633e00c 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -131,6 +131,25 @@ TEST_CASE("enumerate: index and element", "[enumerate]") { REQUIRE(v == vc); } +TEST_CASE("enumerate: index and element through arrow", "[enumerate]") { + std::string s{"ace"}; + auto e = enumerate(s); + SECTION("One inspection") { + auto it = std::begin(e); + REQUIRE(it->index == 0); + REQUIRE(it->element == 'a'); + } + + SECTION("full loop") { + Vec v; + for (auto it = std::begin(e), end_it = std::end(e); it != end_it; ++it) { + v.emplace_back(it->index, it->element); + } + Vec vc{{0, 'a'}, {1, 'c'}, {2, 'e'}}; + REQUIRE(v == vc); + } +} + TEST_CASE("Works with const iterable", "[enumerate]") { const std::string s{"ace"}; auto e = enumerate(s); From 89c6752a7e2832a98277a58e834bbc99fa911cc4 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Sun, 23 Apr 2017 08:12:43 -0700 Subject: [PATCH 116/403] Makes IterYield index not a reference. There are problems with lifetime extension; binding a reference to index won't extend the lifetime of the IterYield object (or whatever it's called now). element isn't an obvious issue because the object it references should live inside of Enumerable, unless the underlying iterable's operator* returns a non-reference type in which case we're kind of screwed. --- enumerate.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/enumerate.hpp b/enumerate.hpp index 0780facb..7e0a8196 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -22,8 +22,9 @@ namespace iter { class EnumIterYield : public EnumBasePair { using BasePair = EnumBasePair; using BasePair::BasePair; + public: - typename BasePair::first_type& index = BasePair::first; + typename BasePair::first_type index = BasePair::first; typename BasePair::second_type& element = BasePair::second; }; From 79a233be0750261bad78efcbe6945a1707419e59 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Sun, 23 Apr 2017 08:17:34 -0700 Subject: [PATCH 117/403] Undoes accidental SConstruct changes --- examples/SConstruct | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/examples/SConstruct b/examples/SConstruct index 8a6b6f40..119b2026 100644 --- a/examples/SConstruct +++ b/examples/SConstruct @@ -2,16 +2,12 @@ import os env = Environment( ENV=os.environ, - CXX='clang++', CXXFLAGS= ['-g', '-Wall', '-Wextra', - '-stdlib=libc++', - '-pedantic', '-std=c++1z', + '-pedantic', '-std=c++14', '-I/usr/local/include' ], CPPPATH='..', - LINKFLAGS=['-L/usr/local/lib', - '-lc++', '-lc++abi', - ]) + LINKFLAGS=['-L/usr/local/lib']) # allows highighting to print to terminal from compiler output env['ENV']['TERM'] = os.environ['TERM'] From 222abfeb3da381038cc02f110255b076e1bd7338 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 9 Jul 2017 19:55:03 -0700 Subject: [PATCH 118/403] Supports const iteration on enumerate --- enumerate.hpp | 27 +++++++++++++++++++-------- internal/iterbase.hpp | 21 ++++++++++++++++++--- test/test_enumerate.cpp | 23 +++++++++++++++++++++++ 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 22c7e33b..cfedbf79 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -59,25 +59,28 @@ class iter::impl::Enumerable { public: Enumerable(Enumerable&&) = default; - using IterYield = EnumIterYield>; + template + using IterYield = EnumIterYield>; // Holds an iterator of the contained type and an Index for the // index_. Each call to ++ increments both of these data members. // Each dereference returns an IterYield. - class Iterator : public std::iterator { + template + class Iterator + : public std::iterator> { private: - IteratorWrapper sub_iter_; + IteratorWrapper sub_iter_; Index index_; public: - Iterator(IteratorWrapper&& sub_iter, Index start) + Iterator(IteratorWrapper&& sub_iter, Index start) : sub_iter_{std::move(sub_iter)}, index_{start} {} - IterYield operator*() { + IterYield operator*() { return {index_, *sub_iter_}; } - ArrowProxy operator->() { + ArrowProxy> operator->() { return {**this}; } @@ -102,12 +105,20 @@ class iter::impl::Enumerable { } }; - Iterator begin() { + Iterator begin() { return {get_begin(container_), start_}; } - Iterator end() { + Iterator end() { return {get_end(container_), start_}; } + + Iterator> begin() const { + return {get_begin(as_const(container_)), start_}; + } + + Iterator> end() const { + return {get_end(as_const(container_)), start_}; + } }; #endif diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 9970610c..3ac7409f 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -47,6 +47,21 @@ namespace iter { using type = T; }; + // TODO use std::as_const for c++17 + template + const T& as_const(T& t) { + return t; + } + template + const T& as_const(const T& t) { + return t; + } + template + void as_const(T&&) = delete; + + template + using AsConst = decltype(as_const(std::declval())); + // gcc CWG 1558 template struct void_t_help { @@ -146,9 +161,9 @@ namespace iter { template struct is_random_access_iter::iterator_category, - std::random_access_iterator_tag>::value>> : std::true_type {}; + std::enable_if_t::iterator_category, + std::random_access_iterator_tag>::value>> : std::true_type {}; template using has_random_access_iter = is_random_access_iter>; diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index e854c081..bf5a7a7d 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -34,6 +34,29 @@ TEST_CASE("Basic Functioning enumerate", "[enumerate]") { REQUIRE(v == vc); } +TEST_CASE("const enumerate", "[enumerate][const]") { + Vec v; + SECTION("lvalue") { + std::string str = "abc"; + const auto e = enumerate(str); + v.assign(std::begin(e), std::end(e)); + } + SECTION("rvalue") { + const auto e = enumerate(std::string("abc")); + v.assign(std::begin(e), std::end(e)); + } + SECTION("const lvalue") { + const std::string str = "abc"; + const auto e = enumerate(str); + v.assign(std::begin(e), std::end(e)); + } + + + Vec vc{{0, 'a'}, {1, 'b'}, {2, 'c'}}; + + REQUIRE(v == vc); +} + TEST_CASE("Empty enumerate", "[enumerate]") { std::string emp{}; auto e = enumerate(emp); From 92043563da3f3bbe62838526cffca2add1bbf03f Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Fri, 28 Jul 2017 11:21:11 -0700 Subject: [PATCH 119/403] Adds product test with repeat argument. --- test/test_product.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/test_product.cpp b/test/test_product.cpp index f5303e4f..d4a2cfbd 100644 --- a/test/test_product.cpp +++ b/test/test_product.cpp @@ -58,6 +58,27 @@ TEST_CASE("product: three sequences", "[product]") { REQUIRE(v == vc); } +TEST_CASE("product: with repeat", "[product]") { + using TP = std::tuple; + using ResType = const std::vector; + const std::string s = "hop"; + auto p = product<3>(s); + ResType v(std::begin(p), std::end(p)); + + ResType vc = { + TP{'h', 'h', 'h'}, TP{'h', 'h', 'o'}, TP{'h', 'h', 'p'}, + TP{'h', 'o', 'h'}, TP{'h', 'o', 'o'}, TP{'h', 'o', 'p'}, + TP{'h', 'p', 'h'}, TP{'h', 'p', 'o'}, TP{'h', 'p', 'p'}, + TP{'o', 'h', 'h'}, TP{'o', 'h', 'o'}, TP{'o', 'h', 'p'}, + TP{'o', 'o', 'h'}, TP{'o', 'o', 'o'}, TP{'o', 'o', 'p'}, + TP{'o', 'p', 'h'}, TP{'o', 'p', 'o'}, TP{'o', 'p', 'p'}, + TP{'p', 'h', 'h'}, TP{'p', 'h', 'o'}, TP{'p', 'h', 'p'}, + TP{'p', 'o', 'h'}, TP{'p', 'o', 'o'}, TP{'p', 'o', 'p'}, + TP{'p', 'p', 'h'}, TP{'p', 'p', 'o'}, TP{'p', 'p', 'p'}, + }; + REQUIRE(v == vc); +} + TEST_CASE("product: empty when any iterable is empty", "[product]") { Vec n1 = {0, 1}; Vec n2 = {0, 1, 2}; From c1462d1452943dde2185eee75a01d0a3f2617eb6 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Fri, 28 Jul 2017 11:21:28 -0700 Subject: [PATCH 120/403] Adds repeat arg to product --- product.hpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/product.hpp b/product.hpp index db9d31f7..6a8c9bbe 100644 --- a/product.hpp +++ b/product.hpp @@ -164,6 +164,32 @@ iter::impl::Productor iter::product(Containers&&... containers) { } namespace iter { + namespace impl { + // rvalue must be copied, lvalue and const lvalue references can be bound + template + decltype(auto) product_repeat( + std::index_sequence, Container&& container) { + return product(((void)Is, Container(container))...); + } + + template + decltype(auto) product_repeat( + std::index_sequence, Container& container) { + return product(((void)Is, container)...); + } + + template + decltype(auto) product_repeat( + std::index_sequence, const Container& container) { + return product(((void)Is, container)...); + } + } + template + decltype(auto) product(Container&& container) { + return impl::product_repeat( + std::make_index_sequence{}, std::forward(container)); + } + constexpr std::array, 1> product() { return {{}}; } From 9818303b210a88f17df2b7d545afc944ab7886cd Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Fri, 28 Jul 2017 12:02:29 -0700 Subject: [PATCH 121/403] Some harder testing on the inputs to product --- test/helpers.hpp | 50 +++++++++++++++++++++++++++---------------- test/test_product.cpp | 25 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/test/helpers.hpp b/test/helpers.hpp index 1ab8adfe..76b4c359 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -87,7 +87,7 @@ namespace itertest { T* data; std::size_t size; bool was_moved_from_ = false; - bool was_copied_from_ = false; + mutable bool was_copied_from_ = false; public: BasicIterable(std::initializer_list il) @@ -104,18 +104,17 @@ namespace itertest { BasicIterable& operator=(BasicIterable&&) = delete; BasicIterable& operator=(const BasicIterable&) = delete; +#ifndef DEFINE_BASIC_ITERABLE_COPY_CTOR BasicIterable(const BasicIterable&) = delete; -#if 0 - BasicIterable(const BasicIterable& other) - : data{new T[other.size()]}, - size{other.size} - { - for (auto it = this->begin(), o_it = other.begin(); - o_it != other.end(); - ++it, ++o_it) { - *it = *o_it; - } - } +#else + BasicIterable(const BasicIterable& other) + : data{new T[other.size]}, size{other.size} { + other.was_copied_from_ = true; + for (auto it = begin(*this), o_it = begin(other); o_it != end(other); + ++it, ++o_it) { + *it = *o_it; + } + } #endif BasicIterable(BasicIterable&& other) : data{other.data}, size{other.size} { @@ -135,15 +134,16 @@ namespace itertest { delete[] this->data; } + template class Iterator { private: - T* p; + U* p; public: #ifdef DEFINE_DEFAULT_ITERATOR_CTOR Iterator() = default; #endif - Iterator(T* b) : p{b} {} + Iterator(U* b) : p{b} {} bool operator!=(const Iterator& other) const { return this->p != other.p; } @@ -153,25 +153,35 @@ namespace itertest { return *this; } - T& operator*() { + U& operator*() { return *this->p; } }; - friend BasicIterable::Iterator begin(BasicIterable& b) { + friend BasicIterable::Iterator begin(BasicIterable& b) { return {b.data}; } - friend BasicIterable::Iterator end(BasicIterable& b) { + friend BasicIterable::Iterator end(BasicIterable& b) { return {b.data + b.size}; } +#ifdef DEFINE_BASIC_ITERABLE_CONST_BEGIN_AND_END + friend BasicIterable::Iterator begin(const BasicIterable& b) { + return {b.data}; + } + + friend BasicIterable::Iterator end(const BasicIterable& b) { + return {b.data + b.size}; + } +#endif #ifdef DECLARE_REVERSE_ITERATOR - Iterator rbegin(); - Iterator rend(); + Iterator rbegin(); + Iterator rend(); #endif // ifdef DECLARE_REVERSE_ITERATOR }; + using iter::impl::void_t; template @@ -223,6 +233,7 @@ class DiffEndRange { class Iterator { using SubIter = typename std::vector::iterator; + private: SubIter it_; SubIter end_; @@ -260,6 +271,7 @@ class DiffEndRange { class ReverseIterator { using SubIter = typename std::vector::reverse_iterator; + private: SubIter it_; SubIter end_; diff --git a/test/test_product.cpp b/test/test_product.cpp index d4a2cfbd..5f7e701d 100644 --- a/test/test_product.cpp +++ b/test/test_product.cpp @@ -1,6 +1,10 @@ #include +#define DEFINE_BASIC_ITERABLE_COPY_CTOR +#define DEFINE_BASIC_ITERABLE_CONST_BEGIN_AND_END #include "helpers.hpp" +#undef DEFINE_BASIC_ITERABLE_CONST_BEGIN_AND_END +#undef DEFINE_BASIC_ITERABLE_COPY_CTOR #include #include @@ -128,14 +132,35 @@ TEST_CASE("product: binds to lvalues and moves rvalues", "[product]") { SECTION("First ref'd, second moved") { product(bi, std::move(bi2)); REQUIRE_FALSE(bi.was_moved_from()); + REQUIRE_FALSE(bi.was_copied_from()); REQUIRE(bi2.was_moved_from()); } SECTION("First moved, second ref'd") { product(std::move(bi), bi2); REQUIRE(bi.was_moved_from()); + REQUIRE_FALSE(bi2.was_copied_from()); REQUIRE_FALSE(bi2.was_moved_from()); } + + SECTION("repeat, lvalue not moved or copied") { + product<2>(bi); + REQUIRE_FALSE(bi.was_moved_from()); + REQUIRE_FALSE(bi.was_copied_from()); + } + + SECTION("repeat, const lvalue not moved or copied") { + const auto& r = bi; + product<2>(r); + REQUIRE_FALSE(bi.was_moved_from()); + REQUIRE_FALSE(bi.was_copied_from()); + } + + SECTION("repeat, rvalue copied") { + product<2>(std::move(bi)); + REQUIRE_FALSE(bi.was_moved_from()); + REQUIRE(bi.was_copied_from()); + } } TEST_CASE("product: doesn't move or copy elements of iterable", "[product]") { From d990df92820c3493eb1dbdd92fd23463a7089b6b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 28 Jul 2017 12:10:06 -0700 Subject: [PATCH 122/403] Adds description of product() with repeat --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index a740372d..cd2d7c6e 100644 --- a/README.md +++ b/README.md @@ -761,6 +761,17 @@ for (auto&& t : product(v1,v2,v3,v4)) { } ``` +Product also accepts a "repeat" as a template argument. Currently this is the only way to do repeats. **If you are reading this and need `product(seq, 3)` instead of `product<3>(seq)` please open an issue**. + +Example usage: +```c++ +std::string s = "abc"; +// equivalent of product(s, s, s); +for (auto&& t : product<3>(s)) { + // ... +} +``` + combinations ----------- *Additional Requirements*: Input must have a ForwardIterator From 7fdad8d8b02ef32325dce939b0eb2abc98a39968 Mon Sep 17 00:00:00 2001 From: Mislav Bradac Date: Thu, 10 Aug 2017 01:08:37 +0200 Subject: [PATCH 123/403] Migrate unique_ptr to optional --- accumulate.hpp | 15 ++++++++------- chain.hpp | 44 ++++++++++++++----------------------------- groupby.hpp | 7 ++++--- internal/iterbase.hpp | 13 +++++-------- 4 files changed, 31 insertions(+), 48 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index aec33626..75b357ee 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include @@ -43,7 +43,7 @@ class iter::impl::Accumulator { IteratorWrapper sub_iter_; IteratorWrapper sub_end_; AccumulateFunc* accumulate_func_; - std::unique_ptr acc_val_; + std::optional acc_val_; public: Iterator(IteratorWrapper&& sub_iter, @@ -52,14 +52,15 @@ class iter::impl::Accumulator { sub_end_{std::move(sub_end)}, accumulate_func_(&accumulate_fun), // only get first value if not an end iterator - acc_val_{ - !(sub_iter_ != sub_end_) ? nullptr : new AccumVal(*sub_iter_)} {} + acc_val_{!(sub_iter_ != sub_end_) + ? std::nullopt + : std::make_optional(*sub_iter_)} {} Iterator(const Iterator& other) : sub_iter_{other.sub_iter_}, sub_end_{other.sub_end_}, accumulate_func_{other.accumulate_func_}, - acc_val_{other.acc_val_ ? new AccumVal(*other.acc_val_) : nullptr} {} + acc_val_{other.acc_val_} {} Iterator& operator=(const Iterator& other) { if (this == &other) { @@ -68,7 +69,7 @@ class iter::impl::Accumulator { sub_iter_ = other.sub_iter_; sub_end_ = other.sub_end_; accumulate_func_ = other.accumulate_func_; - acc_val_.reset(other.acc_val_ ? new AccumVal(*other.acc_val_) : nullptr); + acc_val_ = other.acc_val_; return *this; } @@ -80,7 +81,7 @@ class iter::impl::Accumulator { } const AccumVal* operator->() const { - return acc_val_.get(); + return acc_val_.operator->(); } Iterator& operator++() { diff --git a/chain.hpp b/chain.hpp index 90f553e1..c122e509 100644 --- a/chain.hpp +++ b/chain.hpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include @@ -192,24 +192,8 @@ class iter::impl::ChainedFromIterable { IteratorWrapper top_level_iter_; IteratorWrapper top_level_end_; - std::unique_ptr sub_iter_p_; - std::unique_ptr sub_end_p_; - - static std::unique_ptr clone_sub_pointer(const SubIter* sub_iter) { - return sub_iter ? std::make_unique(*sub_iter) : nullptr; - } - - bool sub_iters_differ(const Iterator& other) const { - if (sub_iter_p_ == other.sub_iter_p_) { - return false; - } - if (sub_iter_p_ == nullptr || other.sub_iter_p_ == nullptr) { - // since the first check tests if they're the same, - // this will return if only one is nullptr - return true; - } - return *sub_iter_p_ != *other.sub_iter_p_; - } + std::optional sub_iter_p_; + std::optional sub_end_p_; public: Iterator(IteratorWrapper&& top_iter, @@ -218,18 +202,18 @@ class iter::impl::ChainedFromIterable { top_level_end_{std::move(top_end)}, sub_iter_p_{!(top_iter != top_end) ? // iter == end ? - nullptr - : std::make_unique(get_begin(*top_iter))}, + std::nullopt + : std::make_optional(get_begin(*top_iter))}, sub_end_p_{!(top_iter != top_end) ? // iter == end ? - nullptr - : std::make_unique(get_end(*top_iter))} {} + std::nullopt + : std::make_optional(get_end(*top_iter))} {} Iterator(const Iterator& other) : top_level_iter_{other.top_level_iter_}, top_level_end_{other.top_level_end_}, - sub_iter_p_{clone_sub_pointer(other.sub_iter_p_.get())}, - sub_end_p_{clone_sub_pointer(other.sub_end_p_.get())} {} + sub_iter_p_{other.sub_iter_p_}, + sub_end_p_{other.sub_end_p_} {} Iterator& operator=(const Iterator& other) { if (this == &other) { @@ -238,8 +222,8 @@ class iter::impl::ChainedFromIterable { top_level_iter_ = other.top_level_iter_; top_level_end_ = other.top_level_end_; - sub_iter_p_ = clone_sub_pointer(other.sub_iter_p_.get()); - sub_end_p_ = clone_sub_pointer(other.sub_end_p_.get()); + sub_iter_p_ = other.sub_iter_p_; + sub_end_p_ = other.sub_end_p_; return *this; } @@ -253,8 +237,8 @@ class iter::impl::ChainedFromIterable { if (!(*sub_iter_p_ != *sub_end_p_)) { ++top_level_iter_; if (top_level_iter_ != top_level_end_) { - sub_iter_p_ = std::make_unique(get_begin(*top_level_iter_)); - sub_end_p_ = std::make_unique(get_end(*top_level_iter_)); + sub_iter_p_ = get_begin(*top_level_iter_); + sub_end_p_ = get_end(*top_level_iter_); } else { sub_iter_p_.reset(); sub_end_p_.reset(); @@ -271,7 +255,7 @@ class iter::impl::ChainedFromIterable { bool operator!=(const Iterator& other) const { return top_level_iter_ != other.top_level_iter_ - || sub_iters_differ(other); + || sub_iter_p_ != other.sub_iter_p_; } bool operator==(const Iterator& other) const { diff --git a/groupby.hpp b/groupby.hpp index 1a06e60f..68c5e515 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -58,7 +59,7 @@ class iter::impl::GroupProducer { IteratorWrapper sub_end_; Holder item_; KeyFunc* key_func_; - std::unique_ptr current_key_group_pair_; + std::optional current_key_group_pair_; public: Iterator(IteratorWrapper&& sub_iter, @@ -101,7 +102,7 @@ class iter::impl::GroupProducer { KeyGroupPair* operator->() { set_key_group_pair(); - return current_key_group_pair_.get(); + return current_key_group_pair_.operator->(); } Iterator& operator++() { @@ -153,7 +154,7 @@ class iter::impl::GroupProducer { void set_key_group_pair() { if (!current_key_group_pair_) { - current_key_group_pair_ = std::make_unique( + current_key_group_pair_.emplace( (*key_func_)(item_.get()), Group{*this, next_key()}); } } diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 7e133c3a..db9d9183 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -225,7 +225,7 @@ namespace iter { // it could still be an rvalue reference using TPlain = std::remove_reference_t; - std::unique_ptr item_p; + std::optional item_p; public: using reference = TPlain&; @@ -233,13 +233,10 @@ namespace iter { DerefHolder() = default; - DerefHolder(const DerefHolder& other) - : item_p{other.item_p ? std::make_unique(*other.item_p) - : nullptr} {} + DerefHolder(const DerefHolder& other) : item_p{other.item_p} {} DerefHolder& operator=(const DerefHolder& other) { - this->item_p = - other.item_p ? std::make_unique(*other.item_p) : nullptr; + this->item_p = other.item_p; return *this; } @@ -256,7 +253,7 @@ namespace iter { } void reset(T&& item) { - item_p = std::make_unique(std::move(item)); + item_p = std::move(item); } explicit operator bool() const { From ed73f31eee07075478e07444d0fd9ecf8a43d439 Mon Sep 17 00:00:00 2001 From: Mislav Bradac Date: Thu, 10 Aug 2017 02:50:27 +0200 Subject: [PATCH 124/403] Make copy operators default --- accumulate.hpp | 19 ++----------------- chain.hpp | 21 ++------------------- 2 files changed, 4 insertions(+), 36 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 75b357ee..a8e20a8f 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -56,23 +56,8 @@ class iter::impl::Accumulator { ? std::nullopt : std::make_optional(*sub_iter_)} {} - Iterator(const Iterator& other) - : sub_iter_{other.sub_iter_}, - sub_end_{other.sub_end_}, - accumulate_func_{other.accumulate_func_}, - acc_val_{other.acc_val_} {} - - Iterator& operator=(const Iterator& other) { - if (this == &other) { - return *this; - } - sub_iter_ = other.sub_iter_; - sub_end_ = other.sub_end_; - accumulate_func_ = other.accumulate_func_; - acc_val_ = other.acc_val_; - return *this; - } - + Iterator(const Iterator& other) = default; + Iterator& operator=(const Iterator& other) = default; Iterator(Iterator&&) = default; Iterator& operator=(Iterator&&) = default; diff --git a/chain.hpp b/chain.hpp index c122e509..d73a9d13 100644 --- a/chain.hpp +++ b/chain.hpp @@ -209,25 +209,8 @@ class iter::impl::ChainedFromIterable { std::nullopt : std::make_optional(get_end(*top_iter))} {} - Iterator(const Iterator& other) - : top_level_iter_{other.top_level_iter_}, - top_level_end_{other.top_level_end_}, - sub_iter_p_{other.sub_iter_p_}, - sub_end_p_{other.sub_end_p_} {} - - Iterator& operator=(const Iterator& other) { - if (this == &other) { - return *this; - } - - top_level_iter_ = other.top_level_iter_; - top_level_end_ = other.top_level_end_; - sub_iter_p_ = other.sub_iter_p_; - sub_end_p_ = other.sub_end_p_; - - return *this; - } - + Iterator(const Iterator& other) = default; + Iterator& operator=(const Iterator& other) = default; Iterator(Iterator&&) = default; Iterator& operator=(Iterator&&) = default; ~Iterator() = default; From 206216ac0c26a5357f2b7144c36fab59c9dbf7df Mon Sep 17 00:00:00 2001 From: Mislav Bradac Date: Thu, 10 Aug 2017 17:13:43 +0200 Subject: [PATCH 125/403] Change operator-> to &*, default copy functions --- accumulate.hpp | 2 +- groupby.hpp | 2 +- internal/iterbase.hpp | 9 ++------- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index a8e20a8f..c7c3a6c2 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -66,7 +66,7 @@ class iter::impl::Accumulator { } const AccumVal* operator->() const { - return acc_val_.operator->(); + return &*acc_val_; } Iterator& operator++() { diff --git a/groupby.hpp b/groupby.hpp index 68c5e515..9642c734 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -102,7 +102,7 @@ class iter::impl::GroupProducer { KeyGroupPair* operator->() { set_key_group_pair(); - return current_key_group_pair_.operator->(); + return &*current_key_group_pair_; } Iterator& operator++() { diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index db9d9183..deb01cf0 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -233,13 +233,8 @@ namespace iter { DerefHolder() = default; - DerefHolder(const DerefHolder& other) : item_p{other.item_p} {} - - DerefHolder& operator=(const DerefHolder& other) { - this->item_p = other.item_p; - return *this; - } - + DerefHolder(const DerefHolder& other) = default; + DerefHolder& operator=(const DerefHolder& other) = default; DerefHolder(DerefHolder&&) = default; DerefHolder& operator=(DerefHolder&&) = default; ~DerefHolder() = default; From 42c2dd6e470bd2b8dfc8e01b49eb42ef83369f3b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 10 Aug 2017 11:13:16 -0500 Subject: [PATCH 126/403] Fixes unused variable warning in test_accumulate --- test/test_accumulate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_accumulate.cpp b/test/test_accumulate.cpp index 7ba3ba22..0eb7c360 100644 --- a/test/test_accumulate.cpp +++ b/test/test_accumulate.cpp @@ -57,7 +57,7 @@ TEST_CASE("accumulate: intermidate type need not be default constructible", "[accumulate]") { std::vector v = {{2}, {3}, {10}}; auto a = accumulate(v, std::plus{}); - auto it = std::begin(a); + std::begin(a); } TEST_CASE("accumulate: binds reference when it should", "[accumulate]") { From 09c3bbe8d2bc010df40de37000df181e62a8b460 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 10 Aug 2017 11:15:03 -0500 Subject: [PATCH 127/403] Removes unnecessary declarations in DerefHolder --- internal/iterbase.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index deb01cf0..ed63c786 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -233,12 +233,6 @@ namespace iter { DerefHolder() = default; - DerefHolder(const DerefHolder& other) = default; - DerefHolder& operator=(const DerefHolder& other) = default; - DerefHolder(DerefHolder&&) = default; - DerefHolder& operator=(DerefHolder&&) = default; - ~DerefHolder() = default; - reference get() { return *this->item_p; } From eaef737da1bf8cb5bf1034ccf4c3f3b7a5090a57 Mon Sep 17 00:00:00 2001 From: Mislav Bradac Date: Fri, 11 Aug 2017 12:18:49 +0200 Subject: [PATCH 128/403] Make index and element public in enumerate --- enumerate.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/enumerate.hpp b/enumerate.hpp index 22c7e33b..f1a18bbe 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -22,6 +22,8 @@ namespace iter { class EnumIterYield : public EnumBasePair { using BasePair = EnumBasePair; using BasePair::BasePair; + + public: typename BasePair::first_type& index = BasePair::first; typename BasePair::second_type& element = BasePair::second; }; From f48355e819ffec8cca0798f91443916e91b9c656 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 11 Aug 2017 07:20:40 -0500 Subject: [PATCH 129/403] Tests that enumerate .index and .element. --- test/test_enumerate.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index 5633e00c..39afd090 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -34,6 +34,14 @@ TEST_CASE("Basic Functioning enumerate", "[enumerate]") { REQUIRE(v == vc); } +TEST_CASE("enumerate: has .index, .element, .first, and .second") { + std::string s = "abc"; + auto e = enumerate(s); + auto it = std::begin(e); + REQUIRE(it->index == it->first); + REQUIRE(&it->element == &it->second); +} + TEST_CASE("Empty enumerate", "[enumerate]") { std::string emp{}; auto e = enumerate(emp); From 67b2101ae8f0f246f90986273f804181798cc4c8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 11 Aug 2017 07:26:21 -0500 Subject: [PATCH 130/403] Switches to c++1z --- examples/SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/SConstruct b/examples/SConstruct index 119b2026..c1ed4d10 100644 --- a/examples/SConstruct +++ b/examples/SConstruct @@ -3,7 +3,7 @@ import os env = Environment( ENV=os.environ, CXXFLAGS= ['-g', '-Wall', '-Wextra', - '-pedantic', '-std=c++14', + '-pedantic', '-std=c++1z', '-I/usr/local/include' ], CPPPATH='..', From e26e338e60e62ae00f851dd2a918626dae03c224 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 11 Aug 2017 07:26:40 -0500 Subject: [PATCH 131/403] Uses structured bindings for enumerate --- examples/enumerate_examples.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/enumerate_examples.cpp b/examples/enumerate_examples.cpp index 39786696..899c3b39 100644 --- a/examples/enumerate_examples.cpp +++ b/examples/enumerate_examples.cpp @@ -9,16 +9,16 @@ int main() { std::cout << "enumerating the characters of a string \"hello\":\n"; const std::string const_string("hello"); - for (auto&& e : iter::enumerate(const_string)) { - std::cout << '(' << e.index << ", " << e.element << ") "; + for (auto&& [i, c] : iter::enumerate(const_string)) { + std::cout << '(' << i << ", " << c << ") "; } std::cout << '\n'; std::vector vec = {20, 30, 50}; std::cout << "enumerating a vector of {20, 30, 50}:\n"; - for (auto&& e : iter::enumerate(vec)) { - std::cout << '(' << e.index << ", " << e.element << ") "; - e.element = 0; + for (auto&& [i, n] : iter::enumerate(vec)) { + std::cout << '(' << i << ", " << n << ") "; + n = 0; } std::cout << '\n'; assert(vec[0] == 0); @@ -28,15 +28,15 @@ int main() { // itertools supports raw arrays std::cout << "statically sized arrays can be enumerated\n"; int array[] = {1, 9, 8, 11}; - for (auto&& e : iter::enumerate(array)) { - std::cout << '(' << e.index << ", " << e.element << ") "; + for (auto&& [i, n] : iter::enumerate(array)) { + std::cout << '(' << i << ", " << n << ") "; } std::cout << '\n'; // itertools supports temporaries std::cout << "vector temporary of {5, 2}\n"; - for (auto&& e : iter::enumerate(std::vector(5,2))) { - std::cout << '(' << e.index << ", " << e.element << ") "; + for (auto&& [i, n] : iter::enumerate(std::vector(5,2))) { + std::cout << '(' << i << ", " << n << ") "; } std::cout << '\n'; } From b4369bd4faada70af0a03b253337f155d4284b23 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 11 Aug 2017 07:39:21 -0500 Subject: [PATCH 132/403] removes unnecessary declarations of copy/= --- accumulate.hpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index c7c3a6c2..02fd9a6d 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -56,11 +56,6 @@ class iter::impl::Accumulator { ? std::nullopt : std::make_optional(*sub_iter_)} {} - Iterator(const Iterator& other) = default; - Iterator& operator=(const Iterator& other) = default; - Iterator(Iterator&&) = default; - Iterator& operator=(Iterator&&) = default; - const AccumVal& operator*() const { return *acc_val_; } From 28a2eb61533410a435b240c5bf1443233ba6593e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 11 Aug 2017 07:41:18 -0500 Subject: [PATCH 133/403] removes unnecessary declarations of copy/= --- chain.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/chain.hpp b/chain.hpp index d73a9d13..f6b247ea 100644 --- a/chain.hpp +++ b/chain.hpp @@ -209,12 +209,6 @@ class iter::impl::ChainedFromIterable { std::nullopt : std::make_optional(get_end(*top_iter))} {} - Iterator(const Iterator& other) = default; - Iterator& operator=(const Iterator& other) = default; - Iterator(Iterator&&) = default; - Iterator& operator=(Iterator&&) = default; - ~Iterator() = default; - Iterator& operator++() { ++*sub_iter_p_; if (!(*sub_iter_p_ != *sub_end_p_)) { From f2f85a6fa3212d89ac4d2698a45d12352b708e58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Dubouchet?= Date: Mon, 28 Aug 2017 16:34:01 +0200 Subject: [PATCH 134/403] Typo You probably wanted to say product and not project. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cd2d7c6e..0d138f3d 100644 --- a/README.md +++ b/README.md @@ -745,7 +745,7 @@ product ------ *Additional Requirements*: Input must have a ForwardIterator -Generates the cartesian project of the given ranges put together +Generates the cartesian product of the given ranges put together. Example usage: ```c++ From 5a16b0db6165a6e63f90b954f5cd8ac43abce16c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 4 Oct 2017 10:20:23 -0500 Subject: [PATCH 135/403] Tests comparison of const and non-const iterators --- test/test_enumerate.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index bf5a7a7d..75272c2f 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -51,12 +51,17 @@ TEST_CASE("const enumerate", "[enumerate][const]") { v.assign(std::begin(e), std::end(e)); } - Vec vc{{0, 'a'}, {1, 'b'}, {2, 'c'}}; REQUIRE(v == vc); } +TEST_CASE("enumerate: const iterators can be compared", "[enumerate][const]") { + auto e = enumerate(std::string("hello")); + const auto& ce = e; + std::begin(e) == std::end(ce); +} + TEST_CASE("Empty enumerate", "[enumerate]") { std::string emp{}; auto e = enumerate(emp); From 764310bd561cfa28710cf67b34c492a7dd18dcf8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 4 Oct 2017 10:33:17 -0500 Subject: [PATCH 136/403] Allows comparison of const and non-const iterators --- enumerate.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index cfedbf79..23cfe3cd 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -69,6 +69,8 @@ class iter::impl::Enumerable { class Iterator : public std::iterator> { private: + template + friend class Iterator; IteratorWrapper sub_iter_; Index index_; @@ -96,11 +98,13 @@ class iter::impl::Enumerable { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return sub_iter_ != other.sub_iter_; } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } }; From 238673886c294055ef180022a2c2170f907e7e16 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 4 Oct 2017 10:39:45 -0500 Subject: [PATCH 137/403] tests accumulate for const iterators --- test/test_accumulate.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/test_accumulate.cpp b/test/test_accumulate.cpp index 7ba3ba22..4774dece 100644 --- a/test/test_accumulate.cpp +++ b/test/test_accumulate.cpp @@ -45,6 +45,32 @@ TEST_CASE("accumulate: With subtraction lambda", "[accumulate]") { REQUIRE(v == vc); } +TEST_CASE("accumulate: const iterators", "[accumulate][const]") { + std::vector v; + SECTION("lvalue") { + Vec ns{1, 2, 3, 4, 5}; + const auto a = accumulate(ns); + v.assign(std::begin(a), std::end(a)); + } + SECTION("rvalue") { + const auto a = accumulate(Vec{1, 2, 3, 4, 5}); + v.assign(std::begin(a), std::end(a)); + } + SECTION("const lvalue") { + const Vec ns{1, 2, 3, 4, 5}; + const auto a = accumulate(ns); + v.assign(std::begin(a), std::end(a)); + } + Vec vc{1, 3, 6, 10, 15}; + REQUIRE(v == vc); +} + +TEST_CASE("accumulate: const iterators can be compared", "[accumulate][const]") { + auto e = accumulate(std::string("hello")); + const auto& ce = e; + std::begin(e) == std::end(ce); +} + struct Integer { const int value; constexpr Integer(int i) : value{i} {} From e73892f1dbcd963d3125e0ad90e6d9cb80a34e73 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 4 Oct 2017 10:39:58 -0500 Subject: [PATCH 138/403] Adds support for const iteration to accumulate --- accumulate.hpp | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index aec33626..d533a8d7 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -24,7 +24,7 @@ template class iter::impl::Accumulator { private: Container container_; - AccumulateFunc accumulate_func_; + mutable AccumulateFunc accumulate_func_; friend AccumulateFn; @@ -38,16 +38,19 @@ class iter::impl::Accumulator { public: Accumulator(Accumulator&&) = default; + template class Iterator : public std::iterator { private: - IteratorWrapper sub_iter_; - IteratorWrapper sub_end_; + template + friend class Iterator; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; AccumulateFunc* accumulate_func_; std::unique_ptr acc_val_; public: - Iterator(IteratorWrapper&& sub_iter, - IteratorWrapper&& sub_end, AccumulateFunc& accumulate_fun) + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, AccumulateFunc& accumulate_fun) : sub_iter_{std::move(sub_iter)}, sub_end_{std::move(sub_end)}, accumulate_func_(&accumulate_fun), @@ -97,22 +100,33 @@ class iter::impl::Accumulator { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return sub_iter_ != other.sub_iter_; } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } }; - Iterator begin() { + Iterator begin() { return {get_begin(container_), get_end(container_), accumulate_func_}; } - Iterator end() { + Iterator end() { return {get_end(container_), get_end(container_), accumulate_func_}; } + Iterator> begin() const { + return {get_begin(as_const(container_)), get_end(as_const(container_)), + accumulate_func_}; + } + + Iterator> end() const { + return {get_end(as_const(container_)), get_end(as_const(container_)), + accumulate_func_}; + } }; #endif From 829213e1fa0c280e9103b76e6aaea73cc291ec33 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 4 Oct 2017 11:06:14 -0500 Subject: [PATCH 139/403] Tests chunked with const iterators --- test/test_chunked.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/test_chunked.cpp b/test/test_chunked.cpp index 533bec05..f8c12f69 100644 --- a/test/test_chunked.cpp +++ b/test/test_chunked.cpp @@ -31,6 +31,27 @@ TEST_CASE("chunked: basic test", "[chunked]") { REQUIRE(results == rc); } +TEST_CASE("chunked: const chunked", "[chunked][const]") { + Vec ns = {1, 2, 3, 4, 5, 6}; + ResVec results; + SECTION("Normal call") { + const auto& ch = chunked(ns, 2); + for (auto&& g : ch) { + results.emplace_back(std::begin(g), std::end(g)); + } + } + ResVec rc = {{1, 2}, {3, 4}, {5, 6}}; + + REQUIRE(results == rc); +} + +TEST_CASE("chunked: const iterators can be compared to non-const iterators", + "[chunked][const]") { + auto c = chunked(Vec{}, 1); + const auto& cc = c; + std::begin(c) == std::end(cc); +} + TEST_CASE("chunked: len(iterable) % groupsize != 0", "[chunked]") { Vec ns = {1, 2, 3, 4, 5, 6, 7}; ResVec results; From bd12264e5e3fa5ecd5b9939a8490e77ff737d27a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 4 Oct 2017 11:16:45 -0500 Subject: [PATCH 140/403] Adds support for const iteration in chunked --- chunked.hpp | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/chunked.hpp b/chunked.hpp index 90f578ca..bf152a3f 100644 --- a/chunked.hpp +++ b/chunked.hpp @@ -33,16 +33,22 @@ class iter::impl::Chunker { friend ChunkedFn; - using IndexVector = std::vector>; - using DerefVec = IterIterWrapper; + template + using IndexVector = std::vector>; + template + using DerefVec = IterIterWrapper>; public: Chunker(Chunker&&) = default; - class Iterator : public std::iterator { + template + class Iterator + : public std::iterator> { private: - IteratorWrapper sub_iter_; - IteratorWrapper sub_end_; - DerefVec chunk_; + template + friend class Iterator; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; + DerefVec chunk_; std::size_t chunk_size_ = 0; bool done() const { @@ -60,8 +66,8 @@ class iter::impl::Chunker { } public: - Iterator(IteratorWrapper&& sub_iter, - IteratorWrapper&& sub_end, std::size_t s) + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, std::size_t s) : sub_iter_{std::move(sub_iter)}, sub_end_{std::move(sub_end)}, chunk_size_{s} { @@ -80,31 +86,43 @@ class iter::impl::Chunker { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return !(*this == other); } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return done() == other.done() && (done() || !(sub_iter_ != other.sub_iter_)); } - DerefVec& operator*() { + DerefVec& operator*() { return chunk_; } - DerefVec* operator->() { + DerefVec* operator->() { return &chunk_; } }; - Iterator begin() { + Iterator begin() { return {get_begin(container_), get_end(container_), chunk_size_}; } - Iterator end() { + Iterator end() { return {get_end(container_), get_end(container_), chunk_size_}; } + + Iterator> begin() const { + return {get_begin(as_const(container_)), get_end(as_const(container_)), + chunk_size_}; + } + + Iterator> end() const { + return {get_end(as_const(container_)), get_end(as_const(container_)), + chunk_size_}; + } }; #endif From 2bbb2ac0464f1994070d453530d2f72da656dd57 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 4 Oct 2017 11:40:40 -0500 Subject: [PATCH 141/403] Tests const iterators for filter --- test/test_filter.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/test_filter.cpp b/test/test_filter.cpp index bb29ee90..f6950eb7 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -53,6 +53,21 @@ TEST_CASE("filter: handles different callable types", "[filter]") { } } +TEST_CASE("filter: const iteration", "[filter][const]") { + Vec ns = {1, 2, 5, 6, 3, 1, 7, -1, 5}; + const auto f = filter(LessThanValue{5}, ns); + Vec v(std::begin(f), std::end(f)); + Vec vc = {1, 2, 3, 1, -1}; + REQUIRE(v == vc); +} + +TEST_CASE("filter: const iterator can be compared to non-const iterator", + "[filter][const]") { + auto f = filter(LessThanValue{5}, Vec{}); + const auto& cf = f; + std::begin(f) == std::end(cf); +} + TEST_CASE("filter: iterator with lambda can be assigned", "[filter]") { Vec ns{}; auto ltf = [](int i) { return i < 5; }; From 033a10575a59d0b37954c60f461331a03e967266 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 4 Oct 2017 11:47:56 -0500 Subject: [PATCH 142/403] Adds support for const iteration to filter --- filter.hpp | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/filter.hpp b/filter.hpp index aa0de753..4b450b14 100644 --- a/filter.hpp +++ b/filter.hpp @@ -30,7 +30,7 @@ template class iter::impl::Filtered { private: Container container_; - FilterFunc filter_func_; + mutable FilterFunc filter_func_; friend FilterFn; @@ -43,12 +43,15 @@ class iter::impl::Filtered { public: Filtered(Filtered&&) = default; + template class Iterator : public std::iterator> { + iterator_traits_deref> { protected: - using Holder = DerefHolder>; - IteratorWrapper sub_iter_; - IteratorWrapper sub_end_; + template + friend class Iterator; + using Holder = DerefHolder>; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; Holder item_; FilterFunc* filter_func_; @@ -68,8 +71,8 @@ class iter::impl::Filtered { } public: - Iterator(IteratorWrapper&& sub_iter, - IteratorWrapper&& sub_end, FilterFunc& filter_func) + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, FilterFunc& filter_func) : sub_iter_{std::move(sub_iter)}, sub_end_{std::move(sub_end)}, filter_func_(&filter_func) { @@ -99,22 +102,34 @@ class iter::impl::Filtered { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return sub_iter_ != other.sub_iter_; } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } }; - Iterator begin() { + Iterator begin() { return {get_begin(container_), get_end(container_), filter_func_}; } - Iterator end() { + Iterator end() { return {get_end(container_), get_end(container_), filter_func_}; } + + Iterator> begin() const { + return {get_begin(as_const(container_)), get_end(as_const(container_)), + filter_func_}; + } + + Iterator> end() const { + return {get_end(as_const(container_)), get_end(as_const(container_)), + filter_func_}; + } }; #endif From 0cd7b66129c2111369efcbf603251f7bae63fd0f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 4 Oct 2017 12:18:28 -0500 Subject: [PATCH 143/403] Tests const iteration in filterfalse --- test/test_filterfalse.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/test_filterfalse.cpp b/test/test_filterfalse.cpp index 07726cf8..a2fc14b9 100644 --- a/test/test_filterfalse.cpp +++ b/test/test_filterfalse.cpp @@ -60,6 +60,21 @@ TEST_CASE("filterfalse: handles different callable types", "[filterfalse]") { } } +TEST_CASE("filterfalse: const iteration", "[filterfalse][const]") { + Vec ns = {1, 2, 5, 6, 3, 1, 7, -1, 5}; + const auto f = filterfalse(LessThanValue{5}, ns); + Vec v(std::begin(f), std::end(f)); + Vec vc = {5, 6, 7, 5}; + REQUIRE(v == vc); +} + +TEST_CASE("filterfalse: const iterator and non-const iterator can be compared", + "[filterfalse][const]") { + auto f = filterfalse(LessThanValue{5}, Vec{}); + const auto& cf = f; + std::begin(f) == std::end(cf); +} + TEST_CASE( "filterfalse: Works with different begin and end types", "[filterfalse]") { CharRange cr{'d'}; From 72b32bbb44d59956370b9e0f1d6babd9a447ffdf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 4 Oct 2017 12:42:45 -0500 Subject: [PATCH 144/403] Tests dropwhile with const iteration --- test/test_dropwhile.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/test_dropwhile.cpp b/test/test_dropwhile.cpp index 49b4e49a..5802c7a6 100644 --- a/test/test_dropwhile.cpp +++ b/test/test_dropwhile.cpp @@ -12,6 +12,20 @@ using iter::dropwhile; using Vec = const std::vector; +namespace { + class LessThanValue { + private: + int compare_val; + + public: + LessThanValue(int v) : compare_val(v) {} + + bool operator()(int i) { + return i < this->compare_val; + } + }; +} + TEST_CASE("dropwhile: skips initial elements", "[dropwhile]") { Vec ns{1, 2, 3, 4, 5, 6, 7, 8}; std::vector v; @@ -27,6 +41,21 @@ TEST_CASE("dropwhile: skips initial elements", "[dropwhile]") { REQUIRE(v == vc); } +TEST_CASE("dropwhile: const iteration", "[dropwhile][const]") { + Vec ns{1, 2, 3, 4, 5, 6, 7, 8}; + const auto d = dropwhile(LessThanValue{5}, ns); + Vec v(std::begin(d), std::end(d)); + Vec vc = {5, 6, 7, 8}; + REQUIRE(v == vc); +} + +TEST_CASE("dropwhile: const iterators can be compared to non-const iterators", + "[dropwhile][const]") { + auto d = dropwhile(LessThanValue{5}, Vec{}); + const auto& cd = d; + std::begin(d) == std::end(cd); +} + TEST_CASE( "dropwhile: Works with different begin and end types", "[dropwhile]") { CharRange cr{'f'}; From eb242b364b1c69b866409ae2497df0467f6da1bf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 4 Oct 2017 12:45:40 -0500 Subject: [PATCH 145/403] Adds support for const iteration in dropwhile --- dropwhile.hpp | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index 6e781baf..1c9c5737 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -22,7 +22,7 @@ template class iter::impl::Dropper { private: Container container_; - FilterFunc filter_func_; + mutable FilterFunc filter_func_; friend DropWhileFn; @@ -32,12 +32,15 @@ class iter::impl::Dropper { public: Dropper(Dropper&&) = default; + template class Iterator : public std::iterator> { + iterator_traits_deref> { private: - using Holder = DerefHolder>; - IteratorWrapper sub_iter_; - IteratorWrapper sub_end_; + template + friend class Iterator; + using Holder = DerefHolder>; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; Holder item_; FilterFunc* filter_func_; @@ -56,8 +59,8 @@ class iter::impl::Dropper { } public: - Iterator(IteratorWrapper&& sub_iter, - IteratorWrapper&& sub_end, FilterFunc& filter_func) + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, FilterFunc& filter_func) : sub_iter_{std::move(sub_iter)}, sub_end_{std::move(sub_end)}, filter_func_(&filter_func) { @@ -86,22 +89,34 @@ class iter::impl::Dropper { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return sub_iter_ != other.sub_iter_; } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } }; - Iterator begin() { + Iterator begin() { return {get_begin(container_), get_end(container_), filter_func_}; } - Iterator end() { + Iterator end() { return {get_end(container_), get_end(container_), filter_func_}; } + + Iterator> begin() const { + return {get_begin(as_const(container_)), get_end(as_const(container_)), + filter_func_}; + } + + Iterator> end() const { + return {get_end(as_const(container_)), get_end(as_const(container_)), + filter_func_}; + } }; #endif From faa62c5ff1062e800b859ec893acdccfbc011f9e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 4 Oct 2017 13:12:50 -0500 Subject: [PATCH 146/403] Tests const iteration in takewhile --- test/test_takewhile.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/test_takewhile.cpp b/test/test_takewhile.cpp index 14a739c1..30c572c0 100644 --- a/test/test_takewhile.cpp +++ b/test/test_takewhile.cpp @@ -57,6 +57,21 @@ TEST_CASE("takewhile: works with lambda, callable, and function pointer", } } +TEST_CASE("takewhile: supports const iteration", "[takewhile][const]") { + Vec ns = {1, 3, 5, 20, 2, 4, 6, 8}; + const auto tw = takewhile(UnderTen{}, ns); + Vec v(std::begin(tw), std::end(tw)); + Vec vc = {1, 3, 5}; + REQUIRE(v == vc); +} + +TEST_CASE("takewhile: const iterator and non-const iterator are comparable", + "[takewhile][const]") { + auto tw = takewhile(UnderTen{}, Vec{}); + const auto& ctw = tw; + std::begin(tw) == std::end(ctw); +} + TEST_CASE( "takewhile: Works with different begin and end types", "[takewhile]") { CharRange cr{'f'}; From e09dd229bee7b5c11ade67aaf2ad3e7d060aac21 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 4 Oct 2017 13:17:53 -0500 Subject: [PATCH 147/403] Adds support for const iteration to takewhile --- takewhile.hpp | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index af3eeeb9..d4b0e956 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -22,7 +22,7 @@ template class iter::impl::Taker { private: Container container_; - FilterFunc filter_func_; + mutable FilterFunc filter_func_; friend TakeWhileFn; @@ -33,12 +33,15 @@ class iter::impl::Taker { public: Taker(Taker&&) = default; + template class Iterator : public std::iterator> { + iterator_traits_deref> { private: - using Holder = DerefHolder>; - IteratorWrapper sub_iter_; - IteratorWrapper sub_end_; + template + friend class Iterator; + using Holder = DerefHolder>; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; Holder item_; FilterFunc* filter_func_; @@ -56,8 +59,8 @@ class iter::impl::Taker { } public: - Iterator(IteratorWrapper&& sub_iter, - IteratorWrapper&& sub_end, FilterFunc& filter_func) + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, FilterFunc& filter_func) : sub_iter_{std::move(sub_iter)}, sub_end_{std::move(sub_end)}, filter_func_(&filter_func) { @@ -87,22 +90,34 @@ class iter::impl::Taker { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return sub_iter_ != other.sub_iter_; } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } }; - Iterator begin() { + Iterator begin() { return {get_begin(container_), get_end(container_), filter_func_}; } - Iterator end() { + Iterator end() { return {get_end(container_), get_end(container_), filter_func_}; } + + Iterator> begin() const { + return {get_begin(as_const(container_)), get_end(as_const(container_)), + filter_func_}; + } + + Iterator> end() const { + return {get_end(as_const(container_)), get_end(as_const(container_)), + filter_func_}; + } }; #endif From 9bc5710eb29cf536bbbd4cead13466261080ae05 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 10:16:50 -0500 Subject: [PATCH 148/403] broken attempt --- starmap.hpp | 120 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 47 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index 3748f244..a970c09d 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -94,7 +94,7 @@ class iter::impl::StarMapper { template class iter::impl::TupleStarMapper { private: - Func func_; + mutable Func func_; TupType tup_; private: @@ -103,60 +103,77 @@ class iter::impl::TupleStarMapper { friend StarMapFn; - template - static decltype(auto) get_and_call_with_tuple(Func& f, TupType& t) { - return call_with_tuple(f, std::get(t)); - } - - using ResultType = decltype(get_and_call_with_tuple<0>(func_, tup_)); - using CallerFunc = ResultType (*)(Func&, TupType&); - - constexpr static std::array callers{ - {get_and_call_with_tuple...}}; - - using TraitsValue = std::remove_reference_t; - TupleStarMapper(Func f, TupType t) : func_(std::move(f)), tup_(std::forward(t)) {} public: - class Iterator : public std::iterator { - private: - Func* func_; - std::remove_reference_t* tup_; - std::size_t index_; - - public: - Iterator(Func& f, TupType& t, std::size_t i) - : func_{&f}, tup_{&t}, index_{i} {} + // this is a wrapper class to hold the aliases and functions needed for the Iterator. + // the bool IsConst is needed so I can define the operator== and operator!= outside of IteratorData. I have to have the two types of iterators compare equal to each other, but also can't rely on AsConst and TupType being different types, the IsConst distinguishes them. Without it, I risk redefining operator== and operator!= with the same iterator types + template + class IteratorData { + private: + template + static decltype(auto) get_and_call_with_tuple(Func& f, TupTypeT& t) { + return call_with_tuple(f, std::get(t)); + } - decltype(auto) operator*() { - return callers[index_](*func_, *tup_); - } + using ResultType = decltype(get_and_call_with_tuple<0>(func_, tup_)); + using CallerFunc = ResultType (*)(Func&, TupTypeT&); - auto operator-> () -> ArrowProxy { - return {**this}; - } + constexpr static std::array callers{ + {get_and_call_with_tuple...}}; - Iterator& operator++() { - ++index_; - return *this; - } + using TraitsValue = std::remove_reference_t; - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } + IteratorData() = delete; + public: + class Iterator : public std::iterator { + private: + Func* func_; + std::remove_reference_t* tup_; + std::size_t index_; + + public: + Iterator(Func& f, TupTypeT& t, std::size_t i) + : func_{&f}, tup_{&t}, index_{i} {} + + decltype(auto) operator*() { + return callers[index_](*func_, *tup_); + } + + auto operator-> () -> ArrowProxy { + return {**this}; + } + + Iterator& operator++() { + ++index_; + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + + // TODO + bool operator!=(const Iterator& other) const { + return index_ != other.index_; + } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } + }; + }; - bool operator!=(const Iterator& other) const { - return index_ != other.index_; - } + using Iterator = typename IteratorData::Iterator; + using ConstIterator = typename IteratorData, true>::Iterator; - bool operator==(const Iterator& other) const { - return !(*this != other); - } - }; + friend bool operator==(const Iterator& lhs, const ConstIterator& rhs) { + return lhs.index_ == rhs.index_; + } Iterator begin() { return {func_, tup_, 0}; @@ -165,13 +182,22 @@ class iter::impl::TupleStarMapper { Iterator end() { return {func_, tup_, sizeof...(Is)}; } + + ConstIterator begin() const { + return {func_, as_const(tup_), 0}; + } + + ConstIterator end() const { + return {func_, as_const(tup_), sizeof...(Is)}; + } }; template +template constexpr std::array< - typename iter::impl::TupleStarMapper::CallerFunc, + typename iter::impl::TupleStarMapper::template IteratorData::CallerFunc, sizeof...(Is)> - iter::impl::TupleStarMapper::callers; + iter::impl::TupleStarMapper::IteratorData::callers; struct iter::impl::StarMapFn : PipeableAndBindFirst { private: From ab2c736767a93a3dbe76466ec7bbdd6c3cfa0a9b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 10:28:59 -0500 Subject: [PATCH 149/403] Adds support for const iteration to starmap(tuple) --- starmap.hpp | 139 +++++++++++++++++++++++++--------------------------- 1 file changed, 68 insertions(+), 71 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index a970c09d..3f66ac1e 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -106,98 +106,95 @@ class iter::impl::TupleStarMapper { TupleStarMapper(Func f, TupType t) : func_(std::move(f)), tup_(std::forward(t)) {} - public: - // this is a wrapper class to hold the aliases and functions needed for the Iterator. - // the bool IsConst is needed so I can define the operator== and operator!= outside of IteratorData. I have to have the two types of iterators compare equal to each other, but also can't rely on AsConst and TupType being different types, the IsConst distinguishes them. Without it, I risk redefining operator== and operator!= with the same iterator types - template - class IteratorData { - private: - template - static decltype(auto) get_and_call_with_tuple(Func& f, TupTypeT& t) { - return call_with_tuple(f, std::get(t)); - } + // this is a wrapper class to hold the aliases and functions needed for the + // Iterator. + template + class IteratorData { + public: + template + static decltype(auto) get_and_call_with_tuple(Func& f, TupTypeT& t) { + return call_with_tuple(f, std::get(t)); + } - using ResultType = decltype(get_and_call_with_tuple<0>(func_, tup_)); - using CallerFunc = ResultType (*)(Func&, TupTypeT&); + using ResultType = decltype(get_and_call_with_tuple<0>(func_, tup_)); + using CallerFunc = ResultType (*)(Func&, TupTypeT&); - constexpr static std::array callers{ - {get_and_call_with_tuple...}}; + constexpr static std::array callers{ + {get_and_call_with_tuple...}}; - using TraitsValue = std::remove_reference_t; + using TraitsValue = std::remove_reference_t; - IteratorData() = delete; - public: - class Iterator : public std::iterator { - private: - Func* func_; - std::remove_reference_t* tup_; - std::size_t index_; - - public: - Iterator(Func& f, TupTypeT& t, std::size_t i) - : func_{&f}, tup_{&t}, index_{i} {} - - decltype(auto) operator*() { - return callers[index_](*func_, *tup_); - } - - auto operator-> () -> ArrowProxy { - return {**this}; - } - - Iterator& operator++() { - ++index_; - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - - // TODO - bool operator!=(const Iterator& other) const { - return index_ != other.index_; - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - }; + IteratorData() = delete; }; - using Iterator = typename IteratorData::Iterator; - using ConstIterator = typename IteratorData, true>::Iterator; + public: + template + class Iterator : public std::iterator::TraitsValue> { + private: + template + friend class Iterator; + Func* func_; + std::remove_reference_t* tup_; + std::size_t index_; - friend bool operator==(const Iterator& lhs, const ConstIterator& rhs) { - return lhs.index_ == rhs.index_; - } + public: + Iterator(Func& f, TupTypeT& t, std::size_t i) + : func_{&f}, tup_{&t}, index_{i} {} - Iterator begin() { + decltype(auto) operator*() { + return IteratorData::callers[index_](*func_, *tup_); + } + + auto operator-> () -> ArrowProxy { + return {**this}; + } + + Iterator& operator++() { + ++index_; + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + template + bool operator!=(const Iterator& other) const { + return index_ != other.index_; + } + + template + bool operator==(const Iterator& other) const { + return !(*this != other); + } + }; + + Iterator begin() { return {func_, tup_, 0}; } - Iterator end() { + Iterator end() { return {func_, tup_, sizeof...(Is)}; } - ConstIterator begin() const { + Iterator> begin() const { return {func_, as_const(tup_), 0}; } - ConstIterator end() const { + Iterator> end() const { return {func_, as_const(tup_), sizeof...(Is)}; } }; template -template -constexpr std::array< - typename iter::impl::TupleStarMapper::template IteratorData::CallerFunc, +template +constexpr std::array::template IteratorData::CallerFunc, sizeof...(Is)> - iter::impl::TupleStarMapper::IteratorData::callers; + iter::impl::TupleStarMapper::IteratorData::callers; struct iter::impl::StarMapFn : PipeableAndBindFirst { private: @@ -211,8 +208,8 @@ struct iter::impl::StarMapFn : PipeableAndBindFirst { template auto helper(Func func, TupType&& tup, std::true_type) const { return helper_with_tuples(std::move(func), std::forward(tup), - std::make_index_sequence< - std::tuple_size>::value>{}); + std::make_index_sequence>:: + value>{}); } // handles everything else From 62878fd507187986c29e2b1d6a13b80a3ad5c333 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 10:29:16 -0500 Subject: [PATCH 150/403] Tests starmap(tuple) with const iteration --- test/test_starmap.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/test_starmap.cpp b/test/test_starmap.cpp index 55e94503..36897f63 100644 --- a/test/test_starmap.cpp +++ b/test/test_starmap.cpp @@ -66,6 +66,24 @@ TEST_CASE("starmap: Works with different begin and end types", "[starmap]") { REQUIRE(v == vc); } +TEST_CASE("starmap: tuple of tuples const iteration", "[starmap][const]") { + using Vec = const std::vector; + auto tup = std::make_tuple(std::make_tuple(10, 19, 60), std::make_tuple(7)); + const auto sm = starmap(Callable{}, tup); + Vec v(std::begin(sm), std::end(sm)); +} + +TEST_CASE( + "starmap: tuple of tuples const iterators can be compared to non-const " + "iterator", + "[starmap][const]") { + auto tup = std::make_tuple(std::make_tuple(10, 19, 60), std::make_tuple(7)); + auto sm = starmap(Callable{}, tup); + const auto& csm = sm; + std::begin(sm) == std::end(csm); + std::begin(csm) == std::end(sm); +} + TEST_CASE("starmap: list of tuples", "[starmap]") { using Vec = const std::vector; using T = std::tuple; From fa2e3bc81fd8e3d1dacde0730f19ea14a80bb9e1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 10:47:03 -0500 Subject: [PATCH 151/403] Fixes error under clang The explicit trailing return caused an incomplete type issue in clang. Idk why, I've had too many issues with compilers messing up to care whether clang or gcc is right on this. --- starmap.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index 3f66ac1e..a4951f55 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -146,8 +146,8 @@ class iter::impl::TupleStarMapper { return IteratorData::callers[index_](*func_, *tup_); } - auto operator-> () -> ArrowProxy { - return {**this}; + auto operator-> () { + return ArrowProxy{**this}; } Iterator& operator++() { From 25687ada446cd83bbfafb2eacb61363c6380649b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 10:53:44 -0500 Subject: [PATCH 152/403] Silences clang unused warnings --- test/test_accumulate.cpp | 2 +- test/test_chunked.cpp | 2 +- test/test_dropwhile.cpp | 2 +- test/test_enumerate.cpp | 2 +- test/test_filter.cpp | 2 +- test/test_filterfalse.cpp | 2 +- test/test_starmap.cpp | 4 ++-- test/test_takewhile.cpp | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/test_accumulate.cpp b/test/test_accumulate.cpp index 4774dece..98058dbd 100644 --- a/test/test_accumulate.cpp +++ b/test/test_accumulate.cpp @@ -68,7 +68,7 @@ TEST_CASE("accumulate: const iterators", "[accumulate][const]") { TEST_CASE("accumulate: const iterators can be compared", "[accumulate][const]") { auto e = accumulate(std::string("hello")); const auto& ce = e; - std::begin(e) == std::end(ce); + (void)(std::begin(e) == std::end(ce)); } struct Integer { diff --git a/test/test_chunked.cpp b/test/test_chunked.cpp index f8c12f69..7e3165a0 100644 --- a/test/test_chunked.cpp +++ b/test/test_chunked.cpp @@ -49,7 +49,7 @@ TEST_CASE("chunked: const iterators can be compared to non-const iterators", "[chunked][const]") { auto c = chunked(Vec{}, 1); const auto& cc = c; - std::begin(c) == std::end(cc); + (void)(std::begin(c) == std::end(cc)); } TEST_CASE("chunked: len(iterable) % groupsize != 0", "[chunked]") { diff --git a/test/test_dropwhile.cpp b/test/test_dropwhile.cpp index 5802c7a6..1b4edcb5 100644 --- a/test/test_dropwhile.cpp +++ b/test/test_dropwhile.cpp @@ -53,7 +53,7 @@ TEST_CASE("dropwhile: const iterators can be compared to non-const iterators", "[dropwhile][const]") { auto d = dropwhile(LessThanValue{5}, Vec{}); const auto& cd = d; - std::begin(d) == std::end(cd); + (void)(std::begin(d) == std::end(cd)); } TEST_CASE( diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index 75272c2f..943dc245 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -59,7 +59,7 @@ TEST_CASE("const enumerate", "[enumerate][const]") { TEST_CASE("enumerate: const iterators can be compared", "[enumerate][const]") { auto e = enumerate(std::string("hello")); const auto& ce = e; - std::begin(e) == std::end(ce); + (void)(std::begin(e) == std::end(ce)); } TEST_CASE("Empty enumerate", "[enumerate]") { diff --git a/test/test_filter.cpp b/test/test_filter.cpp index f6950eb7..62b5f9a1 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -65,7 +65,7 @@ TEST_CASE("filter: const iterator can be compared to non-const iterator", "[filter][const]") { auto f = filter(LessThanValue{5}, Vec{}); const auto& cf = f; - std::begin(f) == std::end(cf); + (void)(std::begin(f) == std::end(cf)); } TEST_CASE("filter: iterator with lambda can be assigned", "[filter]") { diff --git a/test/test_filterfalse.cpp b/test/test_filterfalse.cpp index a2fc14b9..9e230ee1 100644 --- a/test/test_filterfalse.cpp +++ b/test/test_filterfalse.cpp @@ -72,7 +72,7 @@ TEST_CASE("filterfalse: const iterator and non-const iterator can be compared", "[filterfalse][const]") { auto f = filterfalse(LessThanValue{5}, Vec{}); const auto& cf = f; - std::begin(f) == std::end(cf); + (void)(std::begin(f) == std::end(cf)); } TEST_CASE( diff --git a/test/test_starmap.cpp b/test/test_starmap.cpp index 36897f63..fdab5de4 100644 --- a/test/test_starmap.cpp +++ b/test/test_starmap.cpp @@ -80,8 +80,8 @@ TEST_CASE( auto tup = std::make_tuple(std::make_tuple(10, 19, 60), std::make_tuple(7)); auto sm = starmap(Callable{}, tup); const auto& csm = sm; - std::begin(sm) == std::end(csm); - std::begin(csm) == std::end(sm); + (void)(std::begin(sm) == std::end(csm)); + (void)(std::begin(csm) == std::end(sm)); } TEST_CASE("starmap: list of tuples", "[starmap]") { diff --git a/test/test_takewhile.cpp b/test/test_takewhile.cpp index 30c572c0..bea9e6e2 100644 --- a/test/test_takewhile.cpp +++ b/test/test_takewhile.cpp @@ -69,7 +69,7 @@ TEST_CASE("takewhile: const iterator and non-const iterator are comparable", "[takewhile][const]") { auto tw = takewhile(UnderTen{}, Vec{}); const auto& ctw = tw; - std::begin(tw) == std::end(ctw); + (void)(std::begin(tw) == std::end(ctw)); } TEST_CASE( From 04c6373235c38415cef7b0401354f61209b48aeb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 12:40:39 -0500 Subject: [PATCH 153/403] Tests starmap(seq) with const iteration --- test/test_starmap.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/test_starmap.cpp b/test/test_starmap.cpp index fdab5de4..1b284738 100644 --- a/test/test_starmap.cpp +++ b/test/test_starmap.cpp @@ -27,6 +27,10 @@ namespace { return a + b + c; } + int operator()(int a, int b) { + return a + b; + } + int operator()(int a) { return a; } @@ -57,6 +61,26 @@ TEST_CASE("starmap: works with function pointer and lambda", "[starmap]") { REQUIRE(v == vc); } +TEST_CASE("starmap: vector of pairs const iteration", "[starmap][const]") { + using Vec = const std::vector; + const std::vector> v1 = {{1l, 2}, {3l, 11}, {6l, 7}}; + + const auto sm = starmap(Callable{}, v1); + std::vector v(std::begin(sm), std::end(sm)); + Vec vc = {3, 14, 13}; + REQUIRE(v == vc); +} + +TEST_CASE( + "starmap: vector of pairs const iterators can be compared to non-const " + "iterators", + "[starmap][const]") { + const std::vector> v1; + auto sm = starmap(Callable{}, v1); + const auto& csm = sm; + (void)(std::begin(sm) == std::end(csm)); +} + TEST_CASE("starmap: Works with different begin and end types", "[starmap]") { IntCharPairRange icr{{3, 'd'}}; using Vec = std::vector; From 806a0dc865afae2f833f4c4e1e5b9b04fa589105 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 12:41:16 -0500 Subject: [PATCH 154/403] Supports const iteration in starmap(seq) --- starmap.hpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index a4951f55..4f82d106 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -31,7 +31,7 @@ namespace iter { template class iter::impl::StarMapper { private: - Func func_; + mutable Func func_; Container container_; using StarIterDeref = std::remove_reference_t class Iterator : public std::iterator { private: + template + friend class Iterator; Func* func_; - IteratorWrapper sub_iter_; + IteratorWrapper sub_iter_; public: - Iterator(Func& f, IteratorWrapper&& sub_iter) + Iterator(Func& f, IteratorWrapper&& sub_iter) : func_(&f), sub_iter_(std::move(sub_iter)) {} - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return sub_iter_ != other.sub_iter_; } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } @@ -81,13 +86,21 @@ class iter::impl::StarMapper { } }; - Iterator begin() { + Iterator begin() { return {func_, get_begin(container_)}; } - Iterator end() { + Iterator end() { return {func_, get_end(container_)}; } + + Iterator> begin() const { + return {func_, get_begin(as_const(container_))}; + } + + Iterator> end() const { + return {func_, get_end(as_const(container_))}; + } }; // starmap for a tuple or pair of tuples or pairs From 254e9f53d4656af607de171c01f8b4d4fd4f942b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 13:13:10 -0500 Subject: [PATCH 155/403] Tests range iterators compare to const iterators --- test/test_range.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/test_range.cpp b/test/test_range.cpp index c7705d41..dab748e3 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -112,6 +112,12 @@ TEST_CASE("range: can create constexpr ranges", "[range]") { static_assert(f == 0.0, "range's begin has tho wrong value (float)"); } +TEST_CASE("range: const iterators compare to non-const iterators", "[range]") { + auto r = range(0); + const auto& cr = r; + (void)(std::begin(r) == std::end(cr)); +} + TEST_CASE("range: works with a variable start, stop, and step", "[range]") { constexpr int a = 10; constexpr int b = 100; From db13cb83ad9fa6488621c3a190d0f843914399f5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 13:14:58 -0500 Subject: [PATCH 156/403] Tests repeat iterators compare to const iterators --- test/test_repeat.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/test_repeat.cpp b/test/test_repeat.cpp index df42c99c..0fc62e72 100644 --- a/test/test_repeat.cpp +++ b/test/test_repeat.cpp @@ -50,6 +50,12 @@ TEST_CASE("repeat: can be used as constexpr", "[repeat]") { } } +TEST_CASE("repeat: iterators compare to const iterators", "[repeat]") { + auto r = repeat(1); + const auto& cr = r; + (void)(std::begin(r) == std::end(cr)); +} + TEST_CASE("repeat: two argument repeats a number of times", "[repeat]") { auto r = repeat('a', 3); std::string s(std::begin(r), std::end(r)); From 578c6e1750611282d97566abe10e3a0409bb4719 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 13:40:51 -0500 Subject: [PATCH 157/403] Tests compress with const iteration --- test/test_compress.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/test_compress.cpp b/test/test_compress.cpp index 5b13b345..1330e9c2 100644 --- a/test/test_compress.cpp +++ b/test/test_compress.cpp @@ -23,6 +23,23 @@ TEST_CASE("compress: alternating", "[compress]") { REQUIRE(v == vc); } +TEST_CASE("compress: const iteration ", "[compress][const]") { + std::vector ivec{1, 2, 3, 4, 5, 6}; + std::vector bvec{true, false, true, false, true, false}; + const auto c = compress(ivec, bvec); + Vec v(std::begin(c), std::end(c)); + Vec vc = {1, 3, 5}; + + REQUIRE(v == vc); +} + +TEST_CASE("compress: const iterators can be compared to non-const iterators", + "[compress][const]") { + auto c = compress(std::vector{}, std::vector{}); + const auto& cc = c; + (void)(std::begin(c) == std::end(cc)); +} + TEST_CASE("compress: consecutive falses", "[compress]") { std::vector ivec{1, 2, 3, 4, 5}; std::vector bvec{true, false, false, false, true}; From d029462b49be55edbc4f63e352efbacdf379a73a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 13:41:10 -0500 Subject: [PATCH 158/403] Adds support for compress with const iteration --- compress.hpp | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/compress.hpp b/compress.hpp index ca0da7d2..9c511215 100644 --- a/compress.hpp +++ b/compress.hpp @@ -26,23 +26,23 @@ class iter::impl::Compressed { friend Compressed iter::compress( Container&&, Selector&&); - // Selector::Iterator type - using selector_iter_type = decltype(get_begin(selectors_)); - Compressed(Container&& in_container, Selector&& in_selectors) : container_(std::forward(in_container)), selectors_(std::forward(in_selectors)) {} public: Compressed(Compressed&&) = default; + template class Iterator : public std::iterator> { + iterator_traits_deref> { private: - IteratorWrapper sub_iter_; - IteratorWrapper sub_end_; + template + friend class Iterator; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; - selector_iter_type selector_iter_; - selector_iter_type selector_end_; + IteratorWrapper selector_iter_; + IteratorWrapper selector_end_; void increment_iterators() { ++sub_iter_; @@ -57,9 +57,10 @@ class iter::impl::Compressed { } public: - Iterator(IteratorWrapper&& cont_iter, - IteratorWrapper&& cont_end, selector_iter_type&& sel_iter, - selector_iter_type&& sel_end) + Iterator(IteratorWrapper&& cont_iter, + IteratorWrapper&& cont_end, + IteratorWrapper&& sel_iter, + IteratorWrapper&& sel_end) : sub_iter_{std::move(cont_iter)}, sub_end_{std::move(cont_end)}, selector_iter_{std::move(sel_iter)}, @@ -67,11 +68,11 @@ class iter::impl::Compressed { skip_failures(); } - iterator_deref operator*() { + iterator_deref operator*() { return *sub_iter_; } - iterator_arrow operator->() { + iterator_arrow operator->() { return apply_arrow(sub_iter_); } @@ -87,25 +88,37 @@ class iter::impl::Compressed { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return sub_iter_ != other.sub_iter_ && selector_iter_ != other.selector_iter_; } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } }; - Iterator begin() { + Iterator begin() { return {get_begin(container_), get_end(container_), get_begin(selectors_), get_end(selectors_)}; } - Iterator end() { + Iterator end() { return {get_end(container_), get_end(container_), get_end(selectors_), get_end(selectors_)}; } + + Iterator, AsConst> begin() const { + return {get_begin(as_const(container_)), get_end(as_const(container_)), + get_begin(as_const(selectors_)), get_end(as_const(selectors_))}; + } + + Iterator, AsConst> end() const { + return {get_end(as_const(container_)), get_end(as_const(container_)), + get_end(as_const(selectors_)), get_end(as_const(selectors_))}; + } }; template From 7c0c9261cce758d696880bd8bc31364dfa3fbb16 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 13:45:12 -0500 Subject: [PATCH 159/403] Tests count with const iteration --- test/test_count.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/test_count.cpp b/test/test_count.cpp index d1f0ff65..f0f0de68 100644 --- a/test/test_count.cpp +++ b/test/test_count.cpp @@ -20,6 +20,18 @@ TEST_CASE("count: watch for 10 elements", "[count]") { REQUIRE(v == vc); } +TEST_CASE("count: const watch for 10 elements", "[count][const]") { + std::vector v{}; + const auto c = count(); + for (auto i : c) { + v.push_back(i); + if (i == 9) break; + } + + const std::vector vc{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + REQUIRE(v == vc); +} + TEST_CASE("count: start at 10", "[count]") { std::vector v{}; for (auto i : count(10)) { From 6ebe781e7956e9e340ac61f0d452e7415f15b8e0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 14:04:37 -0500 Subject: [PATCH 160/403] Tests cycle with const iteration --- test/test_cycle.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/test_cycle.cpp b/test/test_cycle.cpp index 39e3bb19..84981878 100644 --- a/test/test_cycle.cpp +++ b/test/test_cycle.cpp @@ -27,6 +27,31 @@ TEST_CASE("cycle: iterate twice", "[cycle]") { REQUIRE(v == vc); } +TEST_CASE("cycle: const iteration, iterate twice", "[cycle][const]") { + std::vector ns{2, 4, 6}; + std::vector v{}; + std::size_t count = 0; + const auto c = cycle(ns); + for (auto i : c) { + v.push_back(i); + ++count; + if (count == ns.size() * 2) { + break; + } + } + + auto vc = ns; + vc.insert(std::end(vc), std::begin(ns), std::end(ns)); + REQUIRE(v == vc); +} + +TEST_CASE("cycle: const iterators can be compared to non-const iterators", + "[cycle][const]") { + auto c = cycle(std::vector{}); + const auto& cc = c; + (void)(std::begin(c) == std::end(cc)); +} + TEST_CASE("cycle: Works with different begin and end types", "[cycle]") { constexpr auto sz = 'd' - 'a'; CharRange cr{'d'}; From 171d4e17754adbed6f484e81a5ed769b9d540fce Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 14:06:18 -0500 Subject: [PATCH 161/403] Adds support for const iteration to cycle --- cycle.hpp | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/cycle.hpp b/cycle.hpp index cd058335..21a92872 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -30,25 +30,28 @@ class iter::impl::Cycler { public: Cycler(Cycler&&) = default; + template class Iterator : public std::iterator> { + iterator_traits_deref> { private: - IteratorWrapper sub_iter_; - IteratorWrapper sub_begin_; - IteratorWrapper sub_end_; + template + friend class Iterator; + IteratorWrapper sub_iter_; + IteratorWrapper sub_begin_; + IteratorWrapper sub_end_; public: - Iterator(IteratorWrapper&& sub_iter, - IteratorWrapper&& sub_end) + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end) : sub_iter_{sub_iter}, sub_begin_{sub_iter}, sub_end_{std::move(sub_end)} {} - iterator_deref operator*() { + iterator_deref operator*() { return *sub_iter_; } - iterator_arrow operator->() { + iterator_arrow operator->() { return apply_arrow(sub_iter_); } @@ -67,22 +70,32 @@ class iter::impl::Cycler { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return sub_iter_ != other.sub_iter_; } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } }; - Iterator begin() { + Iterator begin() { return {get_begin(container_), get_end(container_)}; } - Iterator end() { + Iterator end() { return {get_end(container_), get_end(container_)}; } + + Iterator> begin() const { + return {get_begin(as_const(container_)), get_end(as_const(container_))}; + } + + Iterator> end() const { + return {get_end(as_const(container_)), get_end(as_const(container_))}; + } }; #endif From ef97f2460ab47022e44be9040b86a56a8eff5826 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 14:18:06 -0500 Subject: [PATCH 162/403] Tests const iteration in slice --- test/test_slice.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/test_slice.cpp b/test/test_slice.cpp index 385e6c12..38386b73 100644 --- a/test/test_slice.cpp +++ b/test/test_slice.cpp @@ -27,6 +27,23 @@ TEST_CASE("slice: take from beginning", "[slice]") { REQUIRE(v == vc); } +TEST_CASE("slice: const iteration", "[slice][const]") { + Vec ns = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; + + const auto sl = slice(ns, 5); + Vec v(std::begin(sl), std::end(sl)); + + Vec vc = {10, 11, 12, 13, 14}; + REQUIRE(v == vc); +} + +TEST_CASE("slice: const iterator can be compared to non-const iterator", + "[slice][const]") { + auto sl = slice(Vec{}, 1); + const auto& csl = sl; + (void)(std::begin(sl) == std::end(csl)); +} + TEST_CASE("slice: start and stop", "[slice]") { Vec ns = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; From d59bbd1f7dca233f792cad26a4ad2cfd9abe3320 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 14:18:31 -0500 Subject: [PATCH 163/403] Adds support for const iteration in slice --- slice.hpp | 45 +++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/slice.hpp b/slice.hpp index 1ee4252a..4ac9e1a0 100644 --- a/slice.hpp +++ b/slice.hpp @@ -35,18 +35,21 @@ class iter::impl::Sliced { public: Sliced(Sliced&&) = default; + template class Iterator : public std::iterator> { + iterator_traits_deref> { private: - IteratorWrapper sub_iter_; - IteratorWrapper sub_end_; + template + friend class Iterator; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; DifferenceType current_; DifferenceType stop_; DifferenceType step_; public: - Iterator(IteratorWrapper&& sub_iter, - IteratorWrapper&& sub_end, DifferenceType start, + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, DifferenceType start, DifferenceType stop, DifferenceType step) : sub_iter_{std::move(sub_iter)}, sub_end_{std::move(sub_end)}, @@ -54,11 +57,11 @@ class iter::impl::Sliced { stop_{stop}, step_{step} {} - iterator_deref operator*() { + iterator_deref operator*() { return *sub_iter_; } - iterator_arrow operator->() { + iterator_arrow operator->() { return apply_arrow(sub_iter_); } @@ -77,24 +80,37 @@ class iter::impl::Sliced { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return sub_iter_ != other.sub_iter_ && current_ != other.current_; } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } }; - Iterator begin() { + Iterator begin() { auto it = get_begin(container_); dumb_advance(it, get_end(container_), start_); return {std::move(it), get_end(container_), start_, stop_, step_}; } - Iterator end() { + Iterator end() { return {get_end(container_), get_end(container_), stop_, stop_, step_}; } + + Iterator> begin() const { + auto it = get_begin(as_const(container_)); + dumb_advance(it, get_end(as_const(container_)), start_); + return {std::move(it), get_end(as_const(container_)), start_, stop_, step_}; + } + + Iterator> end() const { + return {get_end(as_const(container_)), get_end(as_const(container_)), stop_, + stop_, step_}; + } }; struct iter::impl::SliceFn { @@ -109,9 +125,10 @@ struct iter::impl::SliceFn { private: friend SliceFn; - constexpr FnPartial( - DifferenceType start, DifferenceType stop, DifferenceType step) noexcept - : start_{start}, stop_{stop}, step_{step} {} + constexpr FnPartial(DifferenceType start, DifferenceType stop, + DifferenceType step) noexcept : start_{start}, + stop_{stop}, + step_{step} {} DifferenceType start_; DifferenceType stop_; DifferenceType step_; From 0d5f2e3c7fbe51a5eb9dbac866ce1ff157f02390 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 14:45:27 -0500 Subject: [PATCH 164/403] Test reversed with const iteration --- test/test_reversed.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/test_reversed.cpp b/test/test_reversed.cpp index 81ea1d4f..530a17fc 100644 --- a/test/test_reversed.cpp +++ b/test/test_reversed.cpp @@ -31,6 +31,21 @@ TEST_CASE("reversed: can reverse a vector", "[reversed]") { REQUIRE(v == vc); } +TEST_CASE("reversed: const iteration", "[reversed][const]") { + Vec ns = {10, 20, 30, 40}; + const auto r = reversed(ns); + Vec v(std::begin(r), std::end(r)); + Vec vc = {40, 30, 20, 10}; + REQUIRE(v == vc); +} + +TEST_CASE("reversed: const iterators can be compared to non-const iterators", + "[reversed][const]") { + auto r = reversed(Vec{}); + const auto& cr = r; + (void)(std::begin(r) == std::end(cr)); +} + #if 0 TEST_CASE("reversed: Works with different begin and end types", "[reversed]") { From 9d106985798a6431fe1013307161576044d1fa54 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 14:45:38 -0500 Subject: [PATCH 165/403] Adds support for const iteration to reversed --- reversed.hpp | 45 +++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/reversed.hpp b/reversed.hpp index 987b0cd5..4f3004e2 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -36,7 +36,9 @@ namespace iter { using ReverseIteratorWrapper = typename ReverseIteratorWrapperImplType, - impl::reverse_iterator_end_type>{}>::type; + impl:: + reverse_iterator_end_type>{}>:: + type; template class Reverser; @@ -55,31 +57,36 @@ class iter::impl::Reverser { Reverser(Container&& container) : container_(std::forward(container)) {} + template using reverse_iterator_deref = - decltype(*std::declval&>()); + decltype(*std::declval&>()); + template using reverse_iterator_traits_deref = - std::remove_reference_t; + std::remove_reference_t>; - using reverse_iterator_arrow = - detail::arrow>; + template + using reverse_iterator_arrow = detail::arrow>; public: Reverser(Reverser&&) = default; + template class Iterator : public std::iterator { + reverse_iterator_traits_deref> { private: - ReverseIteratorWrapper sub_iter_; + template + friend class Iterator; + ReverseIteratorWrapper sub_iter_; public: - Iterator(ReverseIteratorWrapper&& sub_iter) + Iterator(ReverseIteratorWrapper&& sub_iter) : sub_iter_{std::move(sub_iter)} {} - reverse_iterator_deref operator*() { + reverse_iterator_deref operator*() { return *sub_iter_; } - reverse_iterator_arrow operator->() { + reverse_iterator_arrow operator->() { return apply_arrow(sub_iter_); } @@ -94,22 +101,32 @@ class iter::impl::Reverser { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return sub_iter_ != other.sub_iter_; } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } }; - Iterator begin() { + Iterator begin() { return {std::rbegin(container_)}; } - Iterator end() { + Iterator end() { return {std::rend(container_)}; } + + Iterator> begin() const { + return {std::rbegin(as_const(container_))}; + } + + Iterator> end() const { + return {std::rend(as_const(container_))}; + } }; #endif From 7e774a3ee21bba98761378e200ec682ecfa3325c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 14:58:25 -0500 Subject: [PATCH 166/403] Tests const iteration in sliding_window --- test/test_sliding_window.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/test_sliding_window.cpp b/test/test_sliding_window.cpp index 21d93679..9c0b6a70 100644 --- a/test/test_sliding_window.cpp +++ b/test/test_sliding_window.cpp @@ -28,6 +28,23 @@ TEST_CASE("sliding_window: window of size 3", "[sliding_window]") { REQUIRE(v == vc); } +TEST_CASE("sliding_window: const iteration", "[sliding_window][const]") { + Vec ns = {10, 20, 30, 40, 50}; + std::vector> vc = {{10, 20, 30}, {20, 30, 40}, {30, 40, 50}}; + std::vector> v; + const auto sw = sliding_window(ns, 3); + for (auto&& win : sw) { + v.emplace_back(std::begin(win), std::end(win)); + } + REQUIRE(v == vc); +} + +TEST_CASE("sliding_window: const iterators can be compared to non-const iterators", "[sliding_window][const]") { + auto sw = sliding_window(Vec{}, 2); + const auto& csw = sw; + (void)(std::begin(sw) == std::end(csw)); +} + TEST_CASE("sliding_window: Works with different begin and end types", "[sliding_window]") { CharRange cr{'f'}; From dd5c6147913666bda3a4aef46ab50478f3e2928b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 14:58:43 -0500 Subject: [PATCH 167/403] Adds support for const iteration to sliding_window --- sliding_window.hpp | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index 84c0e4b1..e8b2204d 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -29,19 +29,23 @@ class iter::impl::WindowSlider { WindowSlider(Container&& container, std::size_t win_sz) : container_(std::forward(container)), window_size_{win_sz} {} - using IndexVector = std::deque>; - using DerefVec = IterIterWrapper; + template + using IndexVector = std::deque>; + template + using DerefVec = IterIterWrapper>; public: WindowSlider(WindowSlider&&) = default; - class Iterator : public std::iterator { + template + class Iterator : public std::iterator> { private: - IteratorWrapper sub_iter_; - DerefVec window_; + template friend class Iterator; + IteratorWrapper sub_iter_; + DerefVec window_; public: - Iterator(IteratorWrapper&& sub_iter, - IteratorWrapper&& sub_end, std::size_t window_sz) + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, std::size_t window_sz) : sub_iter_(std::move(sub_iter)) { std::size_t i{0}; while (i < window_sz && sub_iter_ != sub_end) { @@ -53,19 +57,21 @@ class iter::impl::WindowSlider { } } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return sub_iter_ != other.sub_iter_; } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } - DerefVec& operator*() { + DerefVec& operator*() { return window_; } - DerefVec* operator->() { + DerefVec* operator->() { return window_; } @@ -83,16 +89,27 @@ class iter::impl::WindowSlider { } }; - Iterator begin() { + Iterator begin() { return { (window_size_ != 0 ? IteratorWrapper{get_begin(container_)} : IteratorWrapper{get_end(container_)}), get_end(container_), window_size_}; } - Iterator end() { + Iterator end() { return {get_end(container_), get_end(container_), window_size_}; } + + Iterator> begin() const { + return { + (window_size_ != 0 ? IteratorWrapper>{get_begin(as_const(container_))} + : IteratorWrapper>{get_end(as_const(container_))}), + get_end(as_const(container_)), window_size_}; + } + + Iterator> end() const { + return {get_end(as_const(container_)), get_end(as_const(container_)), window_size_}; + } }; #endif From 826970713926d9eb0ebc70e98d9b830f021acbd3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 15:03:16 -0500 Subject: [PATCH 168/403] formatting --- sliding_window.hpp | 16 ++++++++++------ test/test_sliding_window.cpp | 4 +++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index e8b2204d..7c3135f5 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -37,9 +37,11 @@ class iter::impl::WindowSlider { public: WindowSlider(WindowSlider&&) = default; template - class Iterator : public std::iterator> { + class Iterator + : public std::iterator> { private: - template friend class Iterator; + template + friend class Iterator; IteratorWrapper sub_iter_; DerefVec window_; @@ -101,14 +103,16 @@ class iter::impl::WindowSlider { } Iterator> begin() const { - return { - (window_size_ != 0 ? IteratorWrapper>{get_begin(as_const(container_))} - : IteratorWrapper>{get_end(as_const(container_))}), + return {(window_size_ != 0 ? IteratorWrapper>{get_begin( + as_const(container_))} + : IteratorWrapper>{get_end( + as_const(container_))}), get_end(as_const(container_)), window_size_}; } Iterator> end() const { - return {get_end(as_const(container_)), get_end(as_const(container_)), window_size_}; + return {get_end(as_const(container_)), get_end(as_const(container_)), + window_size_}; } }; diff --git a/test/test_sliding_window.cpp b/test/test_sliding_window.cpp index 9c0b6a70..a302e1dc 100644 --- a/test/test_sliding_window.cpp +++ b/test/test_sliding_window.cpp @@ -39,7 +39,9 @@ TEST_CASE("sliding_window: const iteration", "[sliding_window][const]") { REQUIRE(v == vc); } -TEST_CASE("sliding_window: const iterators can be compared to non-const iterators", "[sliding_window][const]") { +TEST_CASE( + "sliding_window: const iterators can be compared to non-const iterators", + "[sliding_window][const]") { auto sw = sliding_window(Vec{}, 2); const auto& csw = sw; (void)(std::begin(sw) == std::end(csw)); From 9f6634999c777e7291c6ba29c8df23b937f36c58 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 20:57:16 -0500 Subject: [PATCH 169/403] Makes IteratorIterators comparable to each other --- internal/iteratoriterator.hpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/internal/iteratoriterator.hpp b/internal/iteratoriterator.hpp index 23bde9d5..70d63481 100644 --- a/internal/iteratoriterator.hpp +++ b/internal/iteratoriterator.hpp @@ -27,6 +27,7 @@ namespace iter { : public std::iterator())>::type> { + template friend class IteratorIterator; using Diff = std::ptrdiff_t; static_assert( std::is_same< @@ -41,11 +42,17 @@ namespace iter { IteratorIterator() = default; IteratorIterator(const TopIter& it) : sub_iter{it} {} - bool operator==(const IteratorIterator& other) const { + const TopIter& get() const { + return sub_iter; + } + + template + bool operator==(const IteratorIterator& other) const { return !(*this != other); } - bool operator!=(const IteratorIterator& other) const { + template + bool operator!=(const IteratorIterator& other) const { return this->sub_iter != other.sub_iter; } From 441bc37e4107847b9313019387203fef27c03279 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 20:59:48 -0500 Subject: [PATCH 170/403] Tests sorted with const iteration --- test/test_sorted.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test/test_sorted.cpp b/test/test_sorted.cpp index 054b1eda..930ca4f8 100644 --- a/test/test_sorted.cpp +++ b/test/test_sorted.cpp @@ -29,6 +29,21 @@ TEST_CASE("sorted: iterates through a vector in sorted order", "[sorted]") { REQUIRE(v == vc); } +TEST_CASE("sorted: const iteration", "[sorted][const]") { + Vec ns = {4, 0, 5, 1, 6, 7, 9, 3, 2, 8}; + const auto s = sorted(ns); + Vec v(std::begin(s), std::end(s)); + Vec vc = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + REQUIRE(v == vc); +} + +TEST_CASE("sorted: const iterators can be compared to non-const iterators", + "[sorted][const]") { + auto s = sorted(Vec{}); + const auto& cs = s; + (void)(std::begin(s) == std::end(cs)); +} + TEST_CASE("sorted: can modify elements through sorted", "[sorted]") { std::vector ns(3, 9); for (auto&& n : sorted(ns)) { @@ -193,7 +208,7 @@ TEST_CASE("sorted: moves rvalues and binds to lvalues", "[sorted]") { TEST_CASE("sorted: doesn't move or copy elements of iterable", "[sorted]") { using itertest::SolidInt; constexpr SolidInt arr[] = {{6}, {7}, {8}}; - for (auto &&i : sorted(arr, [](const SolidInt&lhs, const SolidInt&rhs) { + for (auto &&i : sorted(arr, [](const SolidInt &lhs, const SolidInt &rhs) { return lhs.getint() < rhs.getint(); })) { (void)i; From 320e72315096d4952018e96a1c5d696677cd867f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 21:06:02 -0500 Subject: [PATCH 171/403] Adds support for const iteration to sorted --- sorted.hpp | 140 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 119 insertions(+), 21 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index d5fdf050..3554d893 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -20,38 +20,136 @@ namespace iter { template class iter::impl::SortedView { private: - using IterIterWrap = IterIterWrapper>>; - using ItIt = iterator_type; + template + class SortedItersHolder { + public: + using IterIterWrap = + IterIterWrapper>>; + using ItIt = iterator_type; + using ConstItIt = void; + + private: + ContainerT container_; + IterIterWrap sorted_iters_; + + public: + SortedItersHolder(ContainerT&& container, CompareFunc compare_func) + : container_(std::forward(container)) { + // Fill the sorted_iters_ vector with an iterator to each + // element in the container_ + for (auto iter = get_begin(container_); iter != get_end(container_); + ++iter) { + sorted_iters_.get().push_back(iter); + } + + // sort by comparing the elements that the iterators point to + std::sort(get_begin(sorted_iters_.get()), get_end(sorted_iters_.get()), + [compare_func](iterator_type it1, + iterator_type it2) { + return compare_func(*it1, *it2); + }); + } + + ItIt begin() { + return sorted_iters_.begin(); + } + + ItIt end() { + return sorted_iters_.end(); + } + }; + + template + class SortedItersHolder&>()))>> { + public: + using IterIterWrap = + IterIterWrapper>>; + using ItIt = iterator_type; + + using ConstIterIterWrap = + IterIterWrapper>>>; + using ConstItIt = iterator_type>; + + private: + ContainerT container_; + IterIterWrap sorted_iters_; + ConstIterIterWrap const_sorted_iters_; + + public: + SortedItersHolder(ContainerT&& container, CompareFunc compare_func) + : container_(std::forward(container)) { + // TODO sort lazily + // Fill the sorted_iters_ vector with an iterator to each + // element in the container_ + for (auto iter = get_begin(container_); iter != get_end(container_); + ++iter) { + sorted_iters_.get().push_back(iter); + } + + // sort by comparing the elements that the iterators point to + std::sort(get_begin(sorted_iters_.get()), get_end(sorted_iters_.get()), + [compare_func](iterator_type it1, + iterator_type it2) { + return compare_func(*it1, *it2); + }); + + for (auto iter = get_begin(as_const(container_)); + iter != get_end(as_const(container_)); ++iter) { + const_sorted_iters_.get().push_back(iter); + } + + // sort by comparing the elements that the iterators point to + std::sort(get_begin(const_sorted_iters_.get()), + get_end(const_sorted_iters_.get()), + [compare_func](iterator_type> it1, + iterator_type> it2) { + return compare_func(*it1, *it2); + }); + } + + ItIt begin() { + return sorted_iters_.begin(); + } + + ItIt end() { + return sorted_iters_.end(); + } + + ConstItIt begin() const { + return const_sorted_iters_.begin(); + } + + ConstItIt end() const { + return const_sorted_iters_.end(); + } + }; friend SortedFn; - Container container_; - IterIterWrap sorted_iters_; + SortedItersHolder sorted_iters_holder_; SortedView(Container&& container, CompareFunc compare_func) - : container_(std::forward(container)) { - // Fill the sorted_iters_ vector with an iterator to each - // element in the container_ - for (auto iter = get_begin(container_); iter != get_end(container_); - ++iter) { - sorted_iters_.get().push_back(iter); - } - - // sort by comparing the elements that the iterators point to - std::sort(get_begin(sorted_iters_.get()), get_end(sorted_iters_.get()), - [compare_func](iterator_type it1, - iterator_type it2) { return compare_func(*it1, *it2); }); - } + : sorted_iters_holder_{ + std::forward(container), std::move(compare_func)} {} public: SortedView(SortedView&&) = default; - ItIt begin() { - return get_begin(sorted_iters_); + typename SortedItersHolder::ItIt begin() { + return sorted_iters_holder_.begin(); + } + + typename SortedItersHolder::ItIt end() { + return sorted_iters_holder_.end(); + } + + typename SortedItersHolder::ConstItIt begin() const { + return sorted_iters_holder_.begin(); } - ItIt end() { - return get_end(sorted_iters_); + typename SortedItersHolder::ConstItIt end() const { + return sorted_iters_holder_.end(); } }; From 18ccc55f677ec8f295de66b213129e0e3c87cd37 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 21:43:27 -0500 Subject: [PATCH 172/403] Test zip with const iteration --- test/test_zip.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/test_zip.cpp b/test/test_zip.cpp index b0312e1e..0b039c14 100644 --- a/test/test_zip.cpp +++ b/test/test_zip.cpp @@ -28,6 +28,27 @@ TEST_CASE("zip: Simple case, same length", "[zip]") { REQUIRE(v == vc); } +TEST_CASE("zip: const iteration", "[zip][const]") { + using Tu = std::tuple; + using ResVec = const std::vector; + std::vector iv{10, 20, 30}; + std::string s{"hey"}; + double arr[] = {1.0, 2.0, 4.0}; + + const auto z = zip(iv, s, arr); + ResVec v(std::begin(z), std::end(z)); + ResVec vc{Tu{10, 'h', 1.0}, Tu{20, 'e', 2.0}, Tu{30, 'y', 4.0}}; + REQUIRE(v == vc); +} + +TEST_CASE("zip: const iterators can be compared to non-const iterators", "[zip][const]") { + std::vector v; + std::string s; + auto z = zip(v, s); + const auto& cz = z; + (void)(std::begin(z) == std::end(cz)); +} + TEST_CASE( "zip: three sequences, one sequence has different begin and end", "[zip]") { using Tu = std::tuple; From c62dc0919e9dc2e795264fd48ad94254aa29fe45 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 21:43:40 -0500 Subject: [PATCH 173/403] Adds support for const iteration to zip --- zip.hpp | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/zip.hpp b/zip.hpp index c5142cc4..ffad6663 100644 --- a/zip.hpp +++ b/zip.hpp @@ -29,18 +29,21 @@ class iter::impl::Zipped { friend Zipped iter::impl::zip_impl( TupleType&&, std::index_sequence); - using ZipIterDeref = iterator_deref_tuple; + template + using ZipIterDeref = iterator_deref_tuple; Zipped(TupleType&& containers) : containers_(std::move(containers)) {} public: Zipped(Zipped&&) = default; - class Iterator : public std::iterator { + template + class Iterator : public std::iterator> { private: - iterator_tuple_type iters_; + template friend class Iterator; + iterator_tuple_type iters_; public: - Iterator(iterator_tuple_type&& iters) + Iterator(iterator_tuple_type&& iters) : iters_(std::move(iters)) {} Iterator& operator++() { @@ -54,7 +57,8 @@ class iter::impl::Zipped { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { if (sizeof...(Is) == 0) return false; bool results[] = { @@ -63,12 +67,13 @@ class iter::impl::Zipped { get_begin(results), get_end(results), [](bool b) { return b; }); } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } - ZipIterDeref operator*() { - return ZipIterDeref{(*std::get(iters_))...}; + ZipIterDeref operator*() { + return ZipIterDeref{(*std::get(iters_))...}; } auto operator-> () -> ArrowProxy { @@ -76,15 +81,25 @@ class iter::impl::Zipped { } }; - Iterator begin() { + Iterator begin() { return {iterator_tuple_type{ get_begin(std::get(containers_))...}}; } - Iterator end() { + Iterator end() { return { iterator_tuple_type{get_end(std::get(containers_))...}}; } + + Iterator> begin() const { + return {iterator_tuple_type>{ + get_begin(std::get(as_const(containers_)))...}}; + } + + Iterator> end() const { + return { + iterator_tuple_type>{get_end(std::get(as_const(containers_)))...}}; + } }; template From f9f595c01b5ff33ec24a947633a51994ce2c02ef Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 21:43:54 -0500 Subject: [PATCH 174/403] Tests imap with const iteration --- test/test_imap.cpp | 18 ++++++++++++++++++ zip.hpp | 10 ++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/test/test_imap.cpp b/test/test_imap.cpp index e7c2bcd2..db37d3f5 100644 --- a/test/test_imap.cpp +++ b/test/test_imap.cpp @@ -61,6 +61,24 @@ TEST_CASE("imap: works with lambda, callable, and function", "[imap]") { REQUIRE(v == vc); } +// TODO enable once zip supports const +#if 0 +TEST_CASE("imap: supports const iteration", "[imap][const]") { + Vec ns = {10, 20, 30}; + const auto m = imap(PlusOner{}, ns); + Vec v(std::begin(m), std::end(m)); + Vec vc = {11, 21, 31}; + REQUIRE(v == vc); +} + +TEST_CASE("imap: const iterators can be compared to non-const iterators", "[imap][const]") { + auto m = imap(PlusOner{}, Vec{}); + const auto& cm = m; + (void)(std::begin(m) == std::end(cm)); +} +#endif + + TEST_CASE("imap: Works with different begin and end types", "[imap]") { CharRange cr{'d'}; auto m = imap([](char c) { return std::toupper(c); }, cr); diff --git a/zip.hpp b/zip.hpp index ffad6663..5cf73135 100644 --- a/zip.hpp +++ b/zip.hpp @@ -37,9 +37,11 @@ class iter::impl::Zipped { public: Zipped(Zipped&&) = default; template - class Iterator : public std::iterator> { + class Iterator : public std::iterator> { private: - template friend class Iterator; + template + friend class Iterator; iterator_tuple_type iters_; public: @@ -97,8 +99,8 @@ class iter::impl::Zipped { } Iterator> end() const { - return { - iterator_tuple_type>{get_end(std::get(as_const(containers_)))...}}; + return {iterator_tuple_type>{ + get_end(std::get(as_const(containers_)))...}}; } }; From 0d401eb459a21acbe117c48e6702e229de753871 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 5 Oct 2017 21:46:16 -0500 Subject: [PATCH 175/403] formatting --- test/test_zip.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_zip.cpp b/test/test_zip.cpp index 0b039c14..7b18712c 100644 --- a/test/test_zip.cpp +++ b/test/test_zip.cpp @@ -41,7 +41,8 @@ TEST_CASE("zip: const iteration", "[zip][const]") { REQUIRE(v == vc); } -TEST_CASE("zip: const iterators can be compared to non-const iterators", "[zip][const]") { +TEST_CASE("zip: const iterators can be compared to non-const iterators", + "[zip][const]") { std::vector v; std::string s; auto z = zip(v, s); From f4c298db5437977f962ce182e36614ad0d9a07cb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 6 Oct 2017 17:37:49 -0500 Subject: [PATCH 176/403] Tests zip with an rvalue right and const iteration --- test/test_zip.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_zip.cpp b/test/test_zip.cpp index 7b18712c..74538cfa 100644 --- a/test/test_zip.cpp +++ b/test/test_zip.cpp @@ -36,6 +36,7 @@ TEST_CASE("zip: const iteration", "[zip][const]") { double arr[] = {1.0, 2.0, 4.0}; const auto z = zip(iv, s, arr); + ResVec v(std::begin(z), std::end(z)); ResVec vc{Tu{10, 'h', 1.0}, Tu{20, 'e', 2.0}, Tu{30, 'y', 4.0}}; REQUIRE(v == vc); @@ -45,7 +46,7 @@ TEST_CASE("zip: const iterators can be compared to non-const iterators", "[zip][const]") { std::vector v; std::string s; - auto z = zip(v, s); + auto z = zip(std::vector{}, s); const auto& cz = z; (void)(std::begin(z) == std::end(cz)); } From 41e31a89260bc75dd39dbb6d3d0fe0e61ae7da20 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 6 Oct 2017 17:39:46 -0500 Subject: [PATCH 177/403] Fixes zip with const iteration --- internal/iter_tuples.hpp | 18 +++++++++++-- zip.hpp | 56 +++++++++++++++++++++++----------------- 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/internal/iter_tuples.hpp b/internal/iter_tuples.hpp index cfba2cf3..99fdfffe 100644 --- a/internal/iter_tuples.hpp +++ b/internal/iter_tuples.hpp @@ -10,12 +10,18 @@ namespace iter { template std::tuple...> iterator_tuple_deref_helper( const std::tuple&); - } - namespace detail { template std::tuple...> iterator_tuple_type_helper( const std::tuple&); + + template + std::tuple>...> + const_iterator_tuple_deref_helper(const std::tuple&); + + template + std::tuple>...> + const_iterator_tuple_type_helper(const std::tuple&); } // Given a tuple template argument, evaluates to a tuple of iterators // for the template argument's contained types. @@ -23,6 +29,10 @@ namespace iter { using iterator_tuple_type = decltype(detail::iterator_tuple_type_helper(std::declval())); + template + using const_iterator_tuple_type = decltype( + detail::const_iterator_tuple_type_helper(std::declval())); + // Given a tuple template argument, evaluates to a tuple of // what the iterators for the template argument's contained types // dereference to @@ -30,6 +40,10 @@ namespace iter { using iterator_deref_tuple = decltype( detail::iterator_tuple_deref_helper(std::declval())); + template + using const_iterator_deref_tuple = decltype( + detail::const_iterator_tuple_deref_helper(std::declval())); + // function absorbing all arguments passed to it. used when // applying a function to a parameter pack but not passing the evaluated // results anywhere diff --git a/zip.hpp b/zip.hpp index 5cf73135..7958234b 100644 --- a/zip.hpp +++ b/zip.hpp @@ -29,24 +29,26 @@ class iter::impl::Zipped { friend Zipped iter::impl::zip_impl( TupleType&&, std::index_sequence); - template - using ZipIterDeref = iterator_deref_tuple; - Zipped(TupleType&& containers) : containers_(std::move(containers)) {} public: Zipped(Zipped&&) = default; - template - class Iterator : public std::iterator> { + + // template templates here because I need to defer evaluation in the const + // iteration case for types that don't have non-const begin() and end(). If I + // passed in the actual types of the tuples of iterators and the type for + // deref they'd need to be known in the function declarations below. + template class IteratorTuple, + template class TupleDeref> + class Iterator + : public std::iterator> { private: - template + template class, template class> friend class Iterator; - iterator_tuple_type iters_; + IteratorTuple iters_; public: - Iterator(iterator_tuple_type&& iters) - : iters_(std::move(iters)) {} + Iterator(IteratorTuple&& iters) : iters_(std::move(iters)) {} Iterator& operator++() { absorb(++std::get(iters_)...); @@ -59,8 +61,9 @@ class iter::impl::Zipped { return ret; } - template - bool operator!=(const Iterator& other) const { + template class IT, + template class TD> + bool operator!=(const Iterator& other) const { if (sizeof...(Is) == 0) return false; bool results[] = { @@ -69,13 +72,14 @@ class iter::impl::Zipped { get_begin(results), get_end(results), [](bool b) { return b; }); } - template - bool operator==(const Iterator& other) const { + template class IT, + template class TD> + bool operator==(const Iterator& other) const { return !(*this != other); } - ZipIterDeref operator*() { - return ZipIterDeref{(*std::get(iters_))...}; + TupleDeref operator*() { + return TupleDeref{(*std::get(iters_))...}; } auto operator-> () -> ArrowProxy { @@ -83,24 +87,28 @@ class iter::impl::Zipped { } }; - Iterator begin() { + Iterator begin() { return {iterator_tuple_type{ get_begin(std::get(containers_))...}}; } - Iterator end() { + Iterator end() { return { iterator_tuple_type{get_end(std::get(containers_))...}}; } - Iterator> begin() const { - return {iterator_tuple_type>{ - get_begin(std::get(as_const(containers_)))...}}; + Iterator, const_iterator_tuple_type, + const_iterator_deref_tuple> + begin() const { + return {const_iterator_tuple_type>{ + get_begin(as_const(std::get(containers_)))...}}; } - Iterator> end() const { - return {iterator_tuple_type>{ - get_end(std::get(as_const(containers_)))...}}; + Iterator, const_iterator_tuple_type, + const_iterator_deref_tuple> + end() const { + return {const_iterator_tuple_type>{ + get_end(as_const(std::get(containers_)))...}}; } }; From 409daa57457e594fbd1f2053afa6eac3013dff41 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 6 Oct 2017 20:03:06 -0500 Subject: [PATCH 178/403] Tests zip_longst with const iteration --- test/test_zip_longest.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/test_zip_longest.cpp b/test/test_zip_longest.cpp index 85b8ee31..be6091f5 100644 --- a/test/test_zip_longest.cpp +++ b/test/test_zip_longest.cpp @@ -97,6 +97,32 @@ TEST_CASE( REQUIRE(v == vc); } +TEST_CASE("zip_longest: const iteration", "[zip_longest][const]") { + // using TP = const_opt_tuple; + using TP = std::tuple; + using ResVec = std::vector; + + char cr[] = {'a', 'b'}; + + ResVec v; + const auto zl = zip_longest(std::vector{10, 20}, cr); + + for (auto&& p : zl) { + v.push_back(TP{*std::get<0>(p), *std::get<1>(p)}); + } + ResVec vc{TP{10, 'a'}, TP{20, 'b'}}; + REQUIRE(v == vc); +} + +TEST_CASE("zip_longest: const iterators can be compared to non-const iterators", + "[zip_longest][const]") { + auto zl = zip_longest(std::vector{}); + const auto& czl = zl; + std::begin(zl); + std::begin(czl); + (void)(std::begin(zl) == std::end(czl)); +} + TEST_CASE( "zip longest: when all are empty, terminates right away", "[zip_longest]") { const std::vector ivec{}; From 59da248945848e2d126238c27a587f73db9561cf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 6 Oct 2017 20:03:52 -0500 Subject: [PATCH 179/403] Adds support for const iteration to zip_longest --- internal/iterbase.hpp | 10 +++++++ zip_longest.hpp | 67 ++++++++++++++++++++++++++++++++----------- 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 3ac7409f..2b0ec98d 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -74,6 +74,11 @@ namespace iter { template using iterator_type = decltype(get_begin(std::declval())); + // iterator_type is the type of C's iterator + template + using const_iterator_type = decltype( + get_begin(std::declval&>())); + // iterator_deref is the type obtained by dereferencing an iterator // to an object of type C template @@ -86,6 +91,11 @@ namespace iter { using const_iterator_deref = decltype(*std::declval&>()); + // the type of dereferencing a const_iterator + template + using const_iterator_type_deref = + decltype(*std::declval&>()); + template using iterator_traits_deref = std::remove_reference_t>; diff --git a/zip_longest.hpp b/zip_longest.hpp index 00c15cbd..428751c0 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -30,24 +30,36 @@ class iter::impl::ZippedLongest { friend ZippedLongest zip_longest_impl( TupleType&&, std::index_sequence); - template - using OptType = - boost::optional>>; + template + using OptType = boost::optional>>>; - using ZipIterDeref = std::tuple...>; + template + using ConstOptType = + boost::optional>>>; + + template class OptTempl> + using ZipIterDeref = std::tuple...>; ZippedLongest(TupleType&& containers) : containers_(std::move(containers)) {} public: ZippedLongest(ZippedLongest&&) = default; - class Iterator : public std::iterator { + template class IterTuple, + template class OptTempl> + class Iterator : public std::iterator> { private: - iterator_tuple_type iters_; - iterator_tuple_type ends_; + template class, + template class> + friend class Iterator; + IterTuple iters_; + IterTuple ends_; public: - Iterator(iterator_tuple_type&& iters, - iterator_tuple_type&& ends) + Iterator(IterTuple&& iters, IterTuple&& ends) : iters_(std::move(iters)), ends_(std::move(ends)) {} Iterator& operator++() { @@ -65,7 +77,9 @@ class iter::impl::ZippedLongest { return ret; } - bool operator!=(const Iterator& other) const { + template class TT, + template class TU> + bool operator!=(const Iterator& other) const { if (sizeof...(Is) == 0) return false; bool results[] = { @@ -74,14 +88,17 @@ class iter::impl::ZippedLongest { get_begin(results), get_end(results), [](bool b) { return b; }); } - bool operator==(const Iterator& other) const { + template class TT, + template class TU> + bool operator==(const Iterator& other) const { return !(*this != other); } - ZipIterDeref operator*() { - return ZipIterDeref{((std::get(iters_) != std::get(ends_)) - ? OptType{*std::get(iters_)} - : OptType{})...}; + ZipIterDeref operator*() { + return ZipIterDeref{ + ((std::get(iters_) != std::get(ends_)) + ? OptTempl{*std::get(iters_)} + : OptTempl{})...}; } auto operator-> () -> ArrowProxy { @@ -89,17 +106,33 @@ class iter::impl::ZippedLongest { } }; - Iterator begin() { + Iterator begin() { return { iterator_tuple_type{get_begin(std::get(containers_))...}, iterator_tuple_type{get_end(std::get(containers_))...}}; } - Iterator end() { + Iterator end() { return { iterator_tuple_type{get_end(std::get(containers_))...}, iterator_tuple_type{get_end(std::get(containers_))...}}; } + + Iterator, const_iterator_tuple_type, ConstOptType> begin() + const { + return {const_iterator_tuple_type>{ + get_begin(as_const(std::get(containers_)))...}, + const_iterator_tuple_type>{ + get_end(as_const(std::get(containers_)))...}}; + } + + Iterator, const_iterator_tuple_type, ConstOptType> end() + const { + return {const_iterator_tuple_type>{ + get_end(as_const(std::get(containers_)))...}, + const_iterator_tuple_type>{ + get_end(as_const(std::get(containers_)))...}}; + } }; template From 846f31231b5b97a528648d702ae94e92a77bb864 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 12 Oct 2017 11:33:46 -0500 Subject: [PATCH 180/403] Lazily evaluates sorted iterators. This way if the sorted view is only used in a const or a non-const context, but not both, it will only do the sorting for the one it needs. --- sorted.hpp | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index 3554d893..fa6f7c19 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -69,17 +69,19 @@ class iter::impl::SortedView { using ConstIterIterWrap = IterIterWrapper>>>; - using ConstItIt = iterator_type>; + using ConstItIt = iterator_type; private: ContainerT container_; + mutable CompareFunc compare_func_; IterIterWrap sorted_iters_; - ConstIterIterWrap const_sorted_iters_; + mutable ConstIterIterWrap const_sorted_iters_; - public: - SortedItersHolder(ContainerT&& container, CompareFunc compare_func) - : container_(std::forward(container)) { - // TODO sort lazily + void populate_sorted_iters() const = delete; + void populate_sorted_iters() { + if (!sorted_iters_.empty()) { + return; + } // Fill the sorted_iters_ vector with an iterator to each // element in the container_ for (auto iter = get_begin(container_); iter != get_end(container_); @@ -89,11 +91,16 @@ class iter::impl::SortedView { // sort by comparing the elements that the iterators point to std::sort(get_begin(sorted_iters_.get()), get_end(sorted_iters_.get()), - [compare_func](iterator_type it1, - iterator_type it2) { - return compare_func(*it1, *it2); + [this](iterator_type it1, iterator_type it2) { + return compare_func_(*it1, *it2); }); + } + void populate_const_sorted_iters() = delete; + void populate_const_sorted_iters() const { + if (!const_sorted_iters_.empty()) { + return; + } for (auto iter = get_begin(as_const(container_)); iter != get_end(as_const(container_)); ++iter) { const_sorted_iters_.get().push_back(iter); @@ -102,25 +109,34 @@ class iter::impl::SortedView { // sort by comparing the elements that the iterators point to std::sort(get_begin(const_sorted_iters_.get()), get_end(const_sorted_iters_.get()), - [compare_func](iterator_type> it1, + [this](iterator_type> it1, iterator_type> it2) { - return compare_func(*it1, *it2); + return compare_func_(*it1, *it2); }); } + public: + SortedItersHolder(ContainerT&& container, CompareFunc compare_func) + : container_(std::forward(container)), + compare_func_(std::move(compare_func)) {} + ItIt begin() { + populate_sorted_iters(); return sorted_iters_.begin(); } ItIt end() { + populate_sorted_iters(); return sorted_iters_.end(); } ConstItIt begin() const { + populate_const_sorted_iters(); return const_sorted_iters_.begin(); } ConstItIt end() const { + populate_const_sorted_iters(); return const_sorted_iters_.end(); } }; From 0c0f61b9a8bf37fdf9b6c29de920f2e18a0e3b72 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 16:51:08 -0500 Subject: [PATCH 181/403] Tests combinations with const iteration --- test/test_combinations.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/test_combinations.cpp b/test/test_combinations.cpp index 974b0798..f5c153cf 100644 --- a/test/test_combinations.cpp +++ b/test/test_combinations.cpp @@ -37,6 +37,28 @@ TEST_CASE("combinations: Simple combination of 4", "[combinations]") { REQUIRE(ans == sc); } +TEST_CASE("combinations: const iteration", "[combinations][const]") { + std::string s{"ABCD"}; + CharCombSet sc; + const auto comb = combinations(s, 2); + for (auto&& v : comb) { + sc.emplace_back(std::begin(v), std::end(v)); + } + + CharCombSet ans = { + {'A', 'B'}, {'A', 'C'}, {'A', 'D'}, {'B', 'C'}, {'B', 'D'}, {'C', 'D'}}; + REQUIRE(ans == sc); +} + +TEST_CASE( + "combinations: const iterators can be compared to non-const iterators", + "[combinations][const]") { + std::string s{"ABC"}; + auto c = combinations(s, 2); + const auto& cc = c; + (void)(std::begin(c) == std::end(cc)); +} + TEST_CASE("combinations: Works with different begin and end types", "[combinations]") { CharRange cr{'e'}; From 79280d25191cd2c9166ad2a4c668c5ab7439b08b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 16:51:27 -0500 Subject: [PATCH 182/403] Adds support for const iteration to combinations --- combinations.hpp | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index fe6c31ac..f32f00d5 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -29,21 +29,26 @@ class iter::impl::Combinator { Combinator(Container&& container, std::size_t length) : container_(std::forward(container)), length_{length} {} - using IndexVector = std::vector>; - using CombIteratorDeref = IterIterWrapper; + template + using IndexVector = std::vector>; + template + using CombIteratorDeref = IterIterWrapper>; public: Combinator(Combinator&&) = default; - class Iterator - : public std::iterator { + template + class Iterator : public std::iterator> { private: + template + friend class Iterator; constexpr static const int COMPLETE = -1; - std::remove_reference_t* container_p_; - CombIteratorDeref indices_; + std::remove_reference_t* container_p_; + CombIteratorDeref indices_; int steps_{}; public: - Iterator(Container& container, std::size_t n) + Iterator(ContainerT& container, std::size_t n) : container_p_{&container}, indices_{n} { if (n == 0) { steps_ = COMPLETE; @@ -63,11 +68,11 @@ class iter::impl::Combinator { } } - CombIteratorDeref& operator*() { + CombIteratorDeref& operator*() { return indices_; } - CombIteratorDeref* operator->() { + CombIteratorDeref* operator->() { return &indices_; } @@ -111,22 +116,32 @@ class iter::impl::Combinator { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return !(*this == other); } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return steps_ == other.steps_; } }; - Iterator begin() { + Iterator begin() { return {container_, length_}; } - Iterator end() { + Iterator end() { return {container_, 0}; } + + Iterator> begin() const { + return {as_const(container_), length_}; + } + + Iterator> end() const { + return {as_const(container_), 0}; + } }; #endif From 54071024bfa2f3b024183433f84858a551959543 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 17:01:21 -0500 Subject: [PATCH 183/403] Tests comb_w_repl with const iteration --- test/test_combinations_with_replacement.cpp | 23 +++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/test_combinations_with_replacement.cpp b/test/test_combinations_with_replacement.cpp index 905450f5..61f30120 100644 --- a/test/test_combinations_with_replacement.cpp +++ b/test/test_combinations_with_replacement.cpp @@ -33,6 +33,29 @@ TEST_CASE("combinations_with_replacement: Simple combination", REQUIRE(ans == sc); } +TEST_CASE("combinations_with_replacement: const iteration", + "[combinations_with_replacement]") { + std::string s{"ABC"}; + CharCombSet sc; + const auto cwr = combinations_with_replacement(s, 2); + for (auto v : cwr) { + sc.emplace_back(std::begin(v), std::end(v)); + } + CharCombSet ans = { + {'A', 'A'}, {'A', 'B'}, {'A', 'C'}, {'B', 'B'}, {'B', 'C'}, {'C', 'C'}}; + REQUIRE(ans == sc); +} + +TEST_CASE( + "combinations_with_replacement: const iterators can be compared to " + "non-const iterators", + "[combinations_with_replacement][const]") { + std::string s{"AB"}; + auto cwr = combinations_with_replacement(s, 2); + const auto& ccwr = cwr; + (void)(std::begin(cwr) == std::end(ccwr)); +} + TEST_CASE( "combinations_with_replacement: Works with different begin and end types", "[combinations_with_replacement]") { From 83426af6d7cc46783154a84f88b178d329d930ed Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 17:03:27 -0500 Subject: [PATCH 184/403] Adds support for const iteration to comb_w_repl --- combinations_with_replacement.hpp | 41 +++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 0467147c..dab28c9a 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -29,32 +29,37 @@ class iter::impl::CombinatorWithReplacement { CombinatorWithReplacement(Container&& container, std::size_t n) : container_(std::forward(container)), length_{n} {} - using IndexVector = std::vector>; - using CombIteratorDeref = IterIterWrapper; + template + using IndexVector = std::vector>; + template + using CombIteratorDeref = IterIterWrapper>; public: CombinatorWithReplacement(CombinatorWithReplacement&&) = default; - class Iterator - : public std::iterator { + template + class Iterator : public std::iterator> { private: + template + friend class Iterator; constexpr static const int COMPLETE = -1; - std::remove_reference_t* container_p_; - CombIteratorDeref indices_; + std::remove_reference_t* container_p_; + CombIteratorDeref indices_; int steps_; public: - Iterator(Container& in_container, std::size_t n) + Iterator(ContainerT& in_container, std::size_t n) : container_p_{&in_container}, indices_(n, get_begin(in_container)), steps_{(get_begin(in_container) != get_end(in_container) && n) ? 0 : COMPLETE} {} - CombIteratorDeref& operator*() { + CombIteratorDeref& operator*() { return indices_; } - CombIteratorDeref* operator->() { + CombIteratorDeref* operator->() { return &indices_; } @@ -90,22 +95,32 @@ class iter::impl::CombinatorWithReplacement { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return !(*this == other); } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return steps_ == other.steps_; } }; - Iterator begin() { + Iterator begin() { return {container_, length_}; } - Iterator end() { + Iterator end() { return {container_, 0}; } + + Iterator> begin() const { + return {as_const(container_), length_}; + } + + Iterator> end() const { + return {as_const(container_), 0}; + } }; #endif From 735a0ed3f38642c6ad8b10bea359e44688c22221 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 17:14:18 -0500 Subject: [PATCH 185/403] Tests permutations with const iteration --- test/test_permutations.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/test_permutations.cpp b/test/test_permutations.cpp index d07c6ffd..b6b6fdae 100644 --- a/test/test_permutations.cpp +++ b/test/test_permutations.cpp @@ -31,6 +31,27 @@ TEST_CASE("permutations: basic test, 3 element sequence", "[permutations]") { REQUIRE(v == vc); } +TEST_CASE("permutations: const iteration", "[permutations][const]") { + const std::vector ns = {1, 7, 9}; + + IntPermSet v; + const auto perm = permutations(ns); + for (auto&& st : perm) { + v.emplace(std::begin(st), std::end(st)); + } + const IntPermSet vc = { + {1, 7, 9}, {1, 9, 7}, {7, 1, 9}, {7, 9, 1}, {9, 1, 7}, {9, 7, 1}}; + REQUIRE(v == vc); +} + +TEST_CASE( + "permutations: const iterators can be compared to non-const iteration", + "[permutations][const]") { + auto p = permutations(std::vector{}); + const auto& cp = p; + (void)(std::begin(p) == std::end(cp)); +} + TEST_CASE("permutations: Works with different begin and end types", "[permutations]") { CharRange cr{'d'}; From e99c784fc0a296c02b7b37fe4b554e8f85be4f67 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 17:14:59 -0500 Subject: [PATCH 186/403] Adds support for permutations with const iteration --- permutations.hpp | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/permutations.hpp b/permutations.hpp index 540ae62b..faae1fe2 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -26,8 +26,10 @@ class iter::impl::Permuter { friend PermutationsFn; Container container_; - using IndexVector = std::vector>; - using Permutable = IterIterWrapper; + template + using IndexVector = std::vector>; + template + using Permutable = IterIterWrapper>; Permuter(Container&& container) : container_(std::forward(container)) {} @@ -35,20 +37,24 @@ class iter::impl::Permuter { public: Permuter(Permuter&&) = default; - class Iterator : public std::iterator { + template + class Iterator + : public std::iterator> { private: + template + friend class Iterator; static constexpr const int COMPLETE = -1; - static bool cmp_iters(IteratorWrapper lhs, - IteratorWrapper rhs) noexcept { + static bool cmp_iters(IteratorWrapper lhs, + IteratorWrapper rhs) noexcept { return *lhs < *rhs; } - Permutable working_set_; + Permutable working_set_; int steps_{}; public: - Iterator(IteratorWrapper&& sub_iter, - IteratorWrapper&& sub_end) + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end) : steps_{sub_iter != sub_end ? 0 : COMPLETE} { // done like this instead of using vector ctor with // two iterators because that causes a substitution @@ -61,11 +67,11 @@ class iter::impl::Permuter { cmp_iters); } - Permutable& operator*() { + Permutable& operator*() { return working_set_; } - Permutable* operator->() { + Permutable* operator->() { return &working_set_; } @@ -84,22 +90,32 @@ class iter::impl::Permuter { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return !(*this == other); } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return steps_ == other.steps_; } }; - Iterator begin() { + Iterator begin() { return {get_begin(container_), get_end(container_)}; } - Iterator end() { + Iterator end() { return {get_end(container_), get_end(container_)}; } + + Iterator> begin() const { + return {get_begin(as_const(container_)), get_end(as_const(container_))}; + } + + Iterator> end() const { + return {get_end(as_const(container_)), get_end(as_const(container_))}; + } }; #endif From e3c142a758d625cfc65b4f5e6f41cc5221819e62 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 17:34:15 -0500 Subject: [PATCH 187/403] Tests powerset with const iteration --- test/test_powerset.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/test_powerset.cpp b/test/test_powerset.cpp index cfc8515d..b56d43e0 100644 --- a/test/test_powerset.cpp +++ b/test/test_powerset.cpp @@ -32,6 +32,29 @@ TEST_CASE("powerset: basic test, [1, 2, 3]", "[powerset]") { REQUIRE(v == vc); } +TEST_CASE("powerset: const iteration", "[powerset][const]") { + const std::vector ns = {1, 2, 3}; + IntPermSet v; + const auto ps = powerset(ns); + for (auto&& st : ps) { + v.emplace(std::begin(st), std::end(st)); + } + + const IntPermSet vc = { + std::multiset{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}; + REQUIRE(v == vc); +} + +// TODO this doesn't work because two different Powersetter::Iterator types use +// two different Combinator types +#if 0 +TEST_CASE("powerset: const iterators can be compared to non-const iterators", "[powerset][const]") { + auto ps = powerset(std::vector{}); + const auto& cps = ps; + (void)(std::begin(ps) == std::end(cps)); +} +#endif + TEST_CASE("powerset: Works with different begin and end types", "[powerset]") { CharRange cr{'d'}; using CharPermSet = std::multiset>; From 3041ccf2f0621830db0022a7161d1fbe04ae24f3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 17:34:30 -0500 Subject: [PATCH 188/403] Adds support for const iteration to powerset You can't compare const iterators to non-const iterators due to the issue described in the test_powerset.cpp TODO --- powerset.hpp | 53 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/powerset.hpp b/powerset.hpp index 9c369e98..2997d569 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -25,7 +25,8 @@ template class iter::impl::Powersetter { private: Container container_; - using CombinatorType = decltype(combinations(std::declval(), 0)); + template + using CombinatorType = decltype(combinations(std::declval(), 0)); friend PowersetFn; @@ -35,20 +36,25 @@ class iter::impl::Powersetter { public: Powersetter(Powersetter&&) = default; - class Iterator - : public std::iterator { + template + class Iterator : public std::iterator> { private: - std::remove_reference_t* container_p_; +#if 0 + template friend class Iterator; +#endif + std::remove_reference_t* container_p_; std::size_t set_size_{}; - std::shared_ptr comb_; - iterator_type comb_iter_; - iterator_type comb_end_; + std::shared_ptr> comb_; + iterator_type> comb_iter_; + iterator_type> comb_end_; public: - Iterator(Container& container, std::size_t sz) + Iterator(ContainerT& container, std::size_t sz) : container_p_{&container}, set_size_{sz}, - comb_{std::make_shared(combinations(container, sz))}, + comb_{std::make_shared>( + combinations(container, sz))}, comb_iter_{get_begin(*comb_)}, comb_end_{get_end(*comb_)} {} @@ -56,7 +62,7 @@ class iter::impl::Powersetter { ++comb_iter_; if (comb_iter_ == comb_end_) { ++set_size_; - comb_ = std::make_shared( + comb_ = std::make_shared>( combinations(*container_p_, set_size_)); comb_iter_ = get_begin(*comb_); @@ -71,11 +77,11 @@ class iter::impl::Powersetter { return ret; } - iterator_deref operator*() { + iterator_deref> operator*() { return *comb_iter_; } - iterator_arrow operator->() { + iterator_arrow> operator->() { apply_arrow(comb_iter_); } @@ -86,15 +92,34 @@ class iter::impl::Powersetter { bool operator==(const Iterator& other) const { return set_size_ == other.set_size_ && comb_iter_ == other.comb_iter_; } +#if 0 + template + bool operator!=(const Iterator& other) const { + return !(*this == other); + } + + template + bool operator==(const Iterator& other) const { + return set_size_ == other.set_size_ && comb_iter_ == other.comb_iter_; + } +#endif }; - Iterator begin() { + Iterator begin() { return {container_, 0}; } - Iterator end() { + Iterator end() { return {container_, dumb_size(container_) + 1}; } + + Iterator> begin() const { + return {as_const(container_), 0}; + } + + Iterator> end() const { + return {as_const(container_), dumb_size(as_const(container_)) + 1}; + } }; #endif From c41ef5a7cf7a5acfbd833c391f1ae8d5ec8e783e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 20:34:21 -0500 Subject: [PATCH 189/403] Tests unique_everseen with const iteration --- test/test_unique_everseen.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/test_unique_everseen.cpp b/test/test_unique_everseen.cpp index 03bc6439..c34bb74d 100644 --- a/test/test_unique_everseen.cpp +++ b/test/test_unique_everseen.cpp @@ -20,6 +20,22 @@ TEST_CASE("unique everseen: adjacent repeating values", "[unique_everseen]") { REQUIRE(v == vc); } +TEST_CASE("unique everseen: const iteration", "[unique_everseen][const]") { + Vec ns = {1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 8, 8, 8, 9, 9}; + const auto ue = unique_everseen(ns); + Vec v(std::begin(ue), std::end(ue)); + Vec vc = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + REQUIRE(v == vc); +} + +TEST_CASE( + "unique everseen: const iterators can be compared to non-const iterators", + "[unique_everseen][const]") { + auto ue = unique_everseen(std::vector{}); + const auto& cue = ue; + (void)(std::begin(ue) == std::end(cue)); +} + TEST_CASE( "unique everseen: nonadjacent repeating values", "[unique_everseen]") { Vec ns = {1, 2, 3, 4, 3, 2, 1, 5, 6}; From aa411cccbe530d953ac96caf1c1b951c74ca5c52 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 20:34:35 -0500 Subject: [PATCH 190/403] Fixes const reference build can't do const T&, needs const std::remove_reference_t& The intricacies of this aliasing will never cease to hurt me. --- unique_everseen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unique_everseen.hpp b/unique_everseen.hpp index 3db10b99..35322ca8 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -17,7 +17,7 @@ namespace iter { auto operator()(Container&& container) const { using elem_type = impl::iterator_deref; auto func = [elem_seen = std::unordered_set>()]( - const elem_type& e) mutable { + const std::remove_reference_t& e) mutable { return elem_seen.insert(e).second; }; return filter(func, std::forward(container)); From fd53ed368cc63a7c91dd29e1187e046963c42db8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 21:02:33 -0500 Subject: [PATCH 191/403] Tests groupby with const iteration --- test/test_groupby.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/test/test_groupby.cpp b/test/test_groupby.cpp index cc1b824a..1089f210 100644 --- a/test/test_groupby.cpp +++ b/test/test_groupby.cpp @@ -69,6 +69,53 @@ TEST_CASE("groupby: works with lambda, callable, and function pointer") { REQUIRE(groups == gc); } +TEST_CASE("groupby: const iteration", "[groupby][const]") { + std::vector keys; + std::vector> groups; + + SECTION("Function pointer") { + SECTION("lvalue") { + const auto g = groupby(vec, length); + for (auto&& gb : g) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + SECTION("rvalue") { + const auto g = groupby(std::vector(vec), length); + for (auto&& gb : g) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + } + + SECTION("Callable object") { + const auto g = groupby(vec, Sizer{}); + for (auto&& gb : g) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + + SECTION("lambda function") { + const auto g = groupby(vec, [](const std::string& s) { return s.size(); }); + for (auto&& gb : g) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + + const std::vector kc = {2, 3, 5}; + REQUIRE(keys == kc); + + const std::vector> gc = { + {"hi", "ab", "ho"}, {"abc", "def"}, {"abcde", "efghi"}, + }; + + REQUIRE(groups == gc); +} + TEST_CASE("groupby: Works with different begin and end types", "[groupby]") { CharRange cr{'f'}; std::vector keys; From 52764e47a1bad69d881194f9c95dd132376e7588 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 21:03:36 -0500 Subject: [PATCH 192/403] Supports const iteration in groupby --- groupby.hpp | 85 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 1a06e60f..5bc555f0 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -32,11 +32,12 @@ template class iter::impl::GroupProducer { private: Container container_; - KeyFunc key_func_; + mutable KeyFunc key_func_; friend GroupByFn; - using key_func_ret = std::result_of_t)>; + template + using key_func_ret = std::result_of_t)>; GroupProducer(Container&& container, KeyFunc key_func) : container_(std::forward(container)), key_func_(key_func) {} @@ -44,25 +45,31 @@ class iter::impl::GroupProducer { public: GroupProducer(GroupProducer&&) = default; + template class Iterator; + template class Group; private: - using KeyGroupPair = std::pair; - using Holder = DerefHolder>; + template + using KeyGroupPair = std::pair, Group>; + template + using Holder = DerefHolder>; public: - class Iterator : public std::iterator { + template + class Iterator : public std::iterator> { private: - IteratorWrapper sub_iter_; - IteratorWrapper sub_end_; - Holder item_; + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; + Holder item_; KeyFunc* key_func_; - std::unique_ptr current_key_group_pair_; + std::unique_ptr> current_key_group_pair_; public: - Iterator(IteratorWrapper&& sub_iter, - IteratorWrapper&& sub_end, KeyFunc& key_func) + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, KeyFunc& key_func) : sub_iter_{std::move(sub_iter)}, sub_end_{std::move(sub_end)}, key_func_(&key_func) { @@ -94,12 +101,12 @@ class iter::impl::GroupProducer { // NOTE the implicitly generated move constructor would // be wrong - KeyGroupPair& operator*() { + KeyGroupPair& operator*() { set_key_group_pair(); return *current_key_group_pair_; } - KeyGroupPair* operator->() { + KeyGroupPair* operator->() { set_key_group_pair(); return current_key_group_pair_.get(); } @@ -118,6 +125,7 @@ class iter::impl::GroupProducer { return ret; } + // TODO template bool operator!=(const Iterator& other) const { return sub_iter_ != other.sub_iter_; } @@ -139,32 +147,34 @@ class iter::impl::GroupProducer { return !(sub_iter_ != sub_end_); } - typename Holder::reference get() { + typename Holder::reference get() { return item_.get(); } - typename Holder::pointer get_ptr() { + typename Holder::pointer get_ptr() { return item_.get_ptr(); } - key_func_ret next_key() { + key_func_ret next_key() { return (*key_func_)(item_.get()); } void set_key_group_pair() { if (!current_key_group_pair_) { - current_key_group_pair_ = std::make_unique( - (*key_func_)(item_.get()), Group{*this, next_key()}); + current_key_group_pair_ = std::make_unique>( + (*key_func_)(item_.get()), Group{*this, next_key()}); } } }; + template class Group { private: - friend Iterator; + template + friend class Iterator; friend class GroupIterator; - Iterator& owner_; - key_func_ret key_; + Iterator& owner_; + key_func_ret key_; // completed is set if a Group is iterated through // completely. It is checked in the destructor, and @@ -177,7 +187,8 @@ class iter::impl::GroupProducer { // when called. bool completed = false; - Group(Iterator& owner, key_func_ret key) : owner_(owner), key_(key) {} + Group(Iterator& owner, key_func_ret key) + : owner_(owner), key_(key) {} public: ~Group() { @@ -188,15 +199,16 @@ class iter::impl::GroupProducer { } // move-constructible, non-copy-constructible, non-assignable - Group(Group&& other) noexcept - : owner_(other.owner_), key_{other.key_}, completed{other.completed} { + Group(Group&& other) noexcept : owner_(other.owner_), + key_{other.key_}, + completed{other.completed} { other.completed = true; } class GroupIterator : public std::iterator> { + iterator_traits_deref> { private: - std::remove_reference_t* key_; + std::remove_reference_t>* key_; Group* group_p_; bool not_at_end() { @@ -205,7 +217,8 @@ class iter::impl::GroupProducer { } public: - GroupIterator(Group* group_p, key_func_ret& key) + // TODO template this? idk if it's relevant here + GroupIterator(Group* group_p, key_func_ret& key) : key_{&key}, group_p_{group_p} {} bool operator!=(const GroupIterator& other) const { @@ -231,11 +244,11 @@ class iter::impl::GroupProducer { return ret; } - iterator_deref operator*() { + iterator_deref operator*() { return group_p_->owner_.get(); } - typename Holder::pointer operator->() { + typename Holder::pointer operator->() { return group_p_->owner_.get_ptr(); } }; @@ -249,13 +262,23 @@ class iter::impl::GroupProducer { } }; - Iterator begin() { + Iterator begin() { return {get_begin(container_), get_end(container_), key_func_}; } - Iterator end() { + Iterator end() { return {get_end(container_), get_end(container_), key_func_}; } + + Iterator> begin() const { + return {get_begin(as_const(container_)), get_end(as_const(container_)), + key_func_}; + } + + Iterator> end() const { + return {get_end(as_const(container_)), get_end(as_const(container_)), + key_func_}; + } }; #endif From 923cd77b3f5c17578ae3dbe89e341767d9f44730 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 21:17:56 -0500 Subject: [PATCH 193/403] Tests groupby const and nonconst iterators compare --- test/test_groupby.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/test/test_groupby.cpp b/test/test_groupby.cpp index 1089f210..d6d508fa 100644 --- a/test/test_groupby.cpp +++ b/test/test_groupby.cpp @@ -75,7 +75,8 @@ TEST_CASE("groupby: const iteration", "[groupby][const]") { SECTION("Function pointer") { SECTION("lvalue") { - const auto g = groupby(vec, length); + std::vector local_vec(vec); + const auto g = groupby(local_vec, length); for (auto&& gb : g) { keys.push_back(gb.first); groups.emplace_back(std::begin(gb.second), std::end(gb.second)); @@ -116,6 +117,23 @@ TEST_CASE("groupby: const iteration", "[groupby][const]") { REQUIRE(groups == gc); } +TEST_CASE("groupby: iterators compare equal to non-const iterators", + "[groupby][const]") { + auto gb = groupby(std::vector{"hi"}, length); + const auto& cgb = gb; + + auto gb_it = std::begin(gb); + (void)(gb_it == std::end(cgb)); + +// TODO figure out how to make GroupIterator and +// GroupIterator> comparable +#if 0 + auto group = std::begin(gb_it->second); + const auto& cgroup = group; + (void)(std::begin(group) == std::begin(cgroup)); +#endif +} + TEST_CASE("groupby: Works with different begin and end types", "[groupby]") { CharRange cr{'f'}; std::vector keys; From 34f373d7f71135add8c72d093610c30ae2de9379 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 21:18:54 -0500 Subject: [PATCH 194/403] Supports const iter == non-const iter --- groupby.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 5bc555f0..f25d145b 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -61,6 +61,8 @@ class iter::impl::GroupProducer { class Iterator : public std::iterator> { private: + template + friend class Iterator; IteratorWrapper sub_iter_; IteratorWrapper sub_end_; Holder item_; @@ -125,12 +127,13 @@ class iter::impl::GroupProducer { return ret; } - // TODO template - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return sub_iter_ != other.sub_iter_; } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } From 7d4349b197c758a6b4f8676ba5049f659a4d83e9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 21:37:56 -0500 Subject: [PATCH 195/403] Tests unique_justseen with const iteration --- test/test_unique_justseen.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/test/test_unique_justseen.cpp b/test/test_unique_justseen.cpp index 3d7dabc7..2614aa89 100644 --- a/test/test_unique_justseen.cpp +++ b/test/test_unique_justseen.cpp @@ -10,7 +10,7 @@ using iter::unique_justseen; -using Vec = const std::vector; +using Vec = std::vector; TEST_CASE("unique justseen: adjacent repeating values", "[unique_justseen]") { Vec ns = {1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 8, 8, 8, 9, 9}; @@ -20,6 +20,22 @@ TEST_CASE("unique justseen: adjacent repeating values", "[unique_justseen]") { REQUIRE(v == vc); } +TEST_CASE("unique justseen: const iteration", "[unique_justseen][const]") { + Vec ns = {1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 8, 8, 8, 9, 9}; + const auto uj = unique_justseen(ns); + Vec v(std::begin(uj), std::end(uj)); + Vec vc = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + REQUIRE(v == vc); +} + +TEST_CASE( + "unique justseen: const iterator can be compared to non-const iterators", + "[unique_justseen][const]") { + auto uj = unique_justseen(Vec{}); + const auto& cuj = uj; + (void)(std::begin(uj) == std::begin(cuj)); +} + TEST_CASE("unique justseen: some repeating values", "[unique_justseen]") { Vec ns = {1, 2, 2, 3, 4, 4, 5, 6, 6}; std::vector v; From dc392622b6fc9aa0bc2da8ec5fdb358201205a94 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 15 Oct 2017 21:38:12 -0500 Subject: [PATCH 196/403] Supports for const iteration to unique_justseen --- unique_justseen.hpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/unique_justseen.hpp b/unique_justseen.hpp index 5e5e3170..2d63b7ea 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -12,11 +12,9 @@ namespace iter { struct UniqueJustseenFn : Pipeable { template auto operator()(Container&& container) const { - // explicit return type in lambda so reference types are preserved - return imap( - [](auto&& group) -> impl::iterator_deref { - return *get_begin(group.second); - }, + // decltype(auto) return type in lambda so reference types are preserved + return imap([](auto&& group) -> decltype( + auto) { return *get_begin(group.second); }, groupby(std::forward(container))); } }; From 9d177cc29a6352c84e8aae36915aa2f897e363e6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 16 Oct 2017 12:11:13 -0500 Subject: [PATCH 197/403] Tests const iteration of product --- test/test_product.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/test_product.cpp b/test/test_product.cpp index 5f7e701d..d7c113d9 100644 --- a/test/test_product.cpp +++ b/test/test_product.cpp @@ -30,6 +30,29 @@ TEST_CASE("product: basic test, two sequences", "[product]") { REQUIRE(v == vc); } +TEST_CASE("product: const iteration", "[product][const]") { + using TP = std::tuple; + using ResType = std::vector; + + Vec n1 = {0, 1}; + const std::string s{"abc"}; + + const auto p = product(n1, s); + ResType v(std::begin(p), std::end(p)); + ResType vc = { + TP{0, 'a'}, TP{0, 'b'}, TP{0, 'c'}, TP{1, 'a'}, TP{1, 'b'}, TP{1, 'c'}}; + + REQUIRE(v == vc); +} + +TEST_CASE("product: const iterators can be compared to non-const iterators", + "[product][const]") { + std::string s; + auto p = product(Vec{}, s); + const auto& cp = p; + (void)(std::begin(p) == std::end(cp)); +} + TEST_CASE("product: two sequences where one has different begin and end", "[product]") { using TP = std::tuple; From eaa08e0e3ac281e36900ef712c41a7e8ee1cce18 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 16 Oct 2017 12:12:33 -0500 Subject: [PATCH 198/403] Supports const iteration in product --- product.hpp | 62 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/product.hpp b/product.hpp index 6a8c9bbe..941eddae 100644 --- a/product.hpp +++ b/product.hpp @@ -34,8 +34,9 @@ class iter::impl::Productor { template friend class Productor; + template using ProdIterDeref = - std::tuple, iterator_deref...>; + std::tuple, iterator_deref...>; private: Container container_; @@ -46,20 +47,23 @@ class iter::impl::Productor { public: Productor(Productor&&) = default; - class Iterator - : public std::iterator { - private: - using RestIter = typename Productor::Iterator; - IteratorWrapper sub_iter_; - IteratorWrapper sub_begin_; + private: + template + class IteratorTempl : public std::iterator> { + private: + template + friend class IteratorTempl; + IteratorWrapper sub_iter_; + IteratorWrapper sub_begin_; RestIter rest_iter_; RestIter rest_end_; public: constexpr static const bool is_base_iter = false; - Iterator(IteratorWrapper&& sub_iter, RestIter&& rest_iter, + IteratorTempl(IteratorWrapper&& sub_iter, RestIter&& rest_iter, RestIter&& rest_end) : sub_iter_{sub_iter}, sub_begin_{sub_iter}, @@ -70,7 +74,7 @@ class iter::impl::Productor { sub_iter_ = sub_begin_; } - Iterator& operator++() { + IteratorTempl& operator++() { ++rest_iter_; if (!(rest_iter_ != rest_end_)) { rest_iter_.reset(); @@ -79,31 +83,40 @@ class iter::impl::Productor { return *this; } - Iterator operator++(int) { + IteratorTempl operator++(int) { auto ret = *this; ++*this; return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const IteratorTempl& other) const { return sub_iter_ != other.sub_iter_ && (RestIter::is_base_iter || rest_iter_ != other.rest_iter_); } - bool operator==(const Iterator& other) const { + template + bool operator==(const IteratorTempl& other) const { return !(*this != other); } - ProdIterDeref operator*() { + ProdIterDeref operator*() { return std::tuple_cat( - std::tuple>{*sub_iter_}, *rest_iter_); + std::tuple>{*sub_iter_}, *rest_iter_); } - ArrowProxy operator->() { + ArrowProxy> operator->() { return {**this}; } }; + using RestIter = typename Productor::Iterator; + using RestConstIter = typename Productor::ConstIterator; + + public: + using Iterator = IteratorTempl; + using ConstIterator = IteratorTempl, RestConstIter>; + Iterator begin() { return {get_begin(container_), get_begin(rest_products_), get_end(rest_products_)}; @@ -113,6 +126,16 @@ class iter::impl::Productor { return { get_end(container_), get_end(rest_products_), get_end(rest_products_)}; } + + ConstIterator begin() const { + return {get_begin(as_const(container_)), + get_begin(as_const(rest_products_)), get_end(as_const(rest_products_))}; + } + + ConstIterator end() const { + return {get_end(as_const(container_)), get_end(as_const(rest_products_)), + get_end(as_const(rest_products_))}; + } }; template <> @@ -148,6 +171,7 @@ class iter::impl::Productor<> { return {}; } }; + using ConstIterator = Iterator; Iterator begin() { return {}; @@ -156,6 +180,14 @@ class iter::impl::Productor<> { Iterator end() { return {}; } + + ConstIterator begin() const { + return {}; + } + + ConstIterator end() const { + return {}; + } }; template From a828a722feb3adca053343d7596cf851a3446e13 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 16 Oct 2017 13:57:54 -0500 Subject: [PATCH 199/403] Tests chain with const iteration --- test/test_chain.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/test_chain.cpp b/test/test_chain.cpp index fbb28cc4..00701495 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -26,6 +26,25 @@ TEST_CASE("chain: three strings", "[chain]") { REQUIRE(v == vc); } +TEST_CASE("chain: const iteration", "[chain][const]") { + std::string s1{"abc"}; + /* const */ std::string s2{"mno"}; + auto ch = chain(s1, s2, std::string{"xyz"}); + + Vec v(std::begin(ch), std::end(ch)); + Vec vc{'a', 'b', 'c', 'm', 'n', 'o', 'x', 'y', 'z'}; + + REQUIRE(v == vc); +} + +#if 0 +TEST_CASE("chain: const iterators can be compared to non-const itertors", "[chain][const]") { + auto ch = chain(std::string{}, std::string{}); + const auto& cch = ch; + (void)(std::begin(ch) == std::end(cch)); +} +#endif + TEST_CASE("chain: with different container types", "[chain]") { std::string s1{"abc"}; std::list li{'m', 'n', 'o'}; @@ -184,6 +203,23 @@ TEST_CASE("chain.from_iterable: basic test", "[chain.from_iterable]") { REQUIRE(v == vc); } +#if 0 +TEST_CASE("chain.from_iterable: const iteration", "[chain.from_iterable][const]") { + std::vector sv{"abc", "xyz"}; + const auto ch = chain.from_iterable(sv); + std::vector v(std::begin(ch), std::end(ch)); + + std::vector vc{'a', 'b', 'c', 'x', 'y', 'z'}; + REQUIRE(v == vc); +} + +TEST_CASE("chain.from_iterable: const iterators can be compared to non-const iterators", "[chain.from_iterable][const]") { + auto ch = chain.from_iterable(std::vector{}); + const auto& cch = ch; + (void)(std::begin(ch) == std::end(cch)); +} +#endif + TEST_CASE("chain.fromm_iterable: Works with different begin and end types", "[chain.from_iterable]") { std::vector crv = {{'c'}, {'d'}}; From c09a13eb501cf2d1dd25ab60b7ada3bdf7f3cbf4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 16 Oct 2017 13:59:00 -0500 Subject: [PATCH 200/403] Adds support for const iteration to chain --- chain.hpp | 175 +++++++++++++++++++++++++++----------------- test/test_chain.cpp | 1 + 2 files changed, 108 insertions(+), 68 deletions(-) diff --git a/chain.hpp b/chain.hpp index 90f553e1..ae7e74ef 100644 --- a/chain.hpp +++ b/chain.hpp @@ -33,95 +33,105 @@ class iter::impl::Chained { private: friend ChainMaker; - static_assert(std::tuple_size>::value == sizeof...(Is), - "tuple size != sizeof Is"); - - static_assert( - are_same>...>::value, - "All chained iterables must have iterators that " - "dereference to the same type, including cv-qualifiers " - "and references."); - - using IterTupType = iterator_tuple_type; - using DerefType = iterator_deref>; - using ArrowType = iterator_arrow>; - - template - static DerefType get_and_deref(IterTupType& iters) { - return *std::get(iters); - } + template + class IteratorData { + IteratorData() = delete; + static_assert( + std::tuple_size>::value == sizeof...(Is), + "tuple size != sizeof Is"); + + static_assert( + are_same>...>::value, + "All chained iterables must have iterators that " + "dereference to the same type, including cv-qualifiers " + "and references."); - template - static ArrowType get_and_arrow(IterTupType& iters) { - return apply_arrow(std::get(iters)); - } + public: + using IterTupType = iterator_tuple_type; + using DerefType = iterator_deref>; + using ArrowType = iterator_arrow>; - template - static void get_and_increment(IterTupType& iters) { - ++std::get(iters); - } + template + static DerefType get_and_deref(IterTupType& iters) { + return *std::get(iters); + } - template - static bool get_and_check_not_equal( - const IterTupType& lhs, const IterTupType& rhs) { - return std::get(lhs) != std::get(rhs); - } + template + static ArrowType get_and_arrow(IterTupType& iters) { + return apply_arrow(std::get(iters)); + } - using DerefFunc = DerefType (*)(IterTupType&); - using ArrowFunc = ArrowType (*)(IterTupType&); - using IncFunc = void (*)(IterTupType&); - using NeqFunc = bool (*)(const IterTupType&, const IterTupType&); + template + static void get_and_increment(IterTupType& iters) { + ++std::get(iters); + } - constexpr static std::array derefers{ - {get_and_deref...}}; + template + static bool get_and_check_not_equal( + const IterTupType& lhs, const IterTupType& rhs) { + return std::get(lhs) != std::get(rhs); + } - constexpr static std::array arrowers{ - {get_and_arrow...}}; + using DerefFunc = DerefType (*)(IterTupType&); + using ArrowFunc = ArrowType (*)(IterTupType&); + using IncFunc = void (*)(IterTupType&); + using NeqFunc = bool (*)(const IterTupType&, const IterTupType&); - constexpr static std::array incrementers{ - {get_and_increment...}}; + constexpr static std::array derefers{ + {get_and_deref...}}; - constexpr static std::array neq_comparers{ - {get_and_check_not_equal...}}; + constexpr static std::array arrowers{ + {get_and_arrow...}}; - using TraitsValue = iterator_traits_deref>; + constexpr static std::array incrementers{ + {get_and_increment...}}; + + constexpr static std::array neq_comparers{ + {get_and_check_not_equal...}}; + + using TraitsValue = + iterator_traits_deref>; + }; - private: Chained(TupType&& t) : tup_(std::move(t)) {} TupType tup_; public: Chained(Chained&&) = default; - class Iterator : public std::iterator { + template + class Iterator : public std::iterator::TraitsValue> { private: + using IterData = IteratorData; std::size_t index_; - IterTupType iters_; - IterTupType ends_; + typename IterData::IterTupType iters_; + typename IterData::IterTupType ends_; void check_for_end_and_adjust() { - while ( - index_ < sizeof...(Is) && !(neq_comparers[index_](iters_, ends_))) { + while (index_ < sizeof...(Is) + && !(IterData::neq_comparers[index_](iters_, ends_))) { ++index_; } } public: - Iterator(std::size_t i, IterTupType&& iters, IterTupType&& ends) + Iterator(std::size_t i, typename IterData::IterTupType&& iters, + typename IterData::IterTupType&& ends) : index_{i}, iters_(std::move(iters)), ends_(std::move(ends)) { check_for_end_and_adjust(); } decltype(auto) operator*() { - return derefers[index_](iters_); + return IterData::derefers[index_](iters_); } decltype(auto) operator-> () { - return arrowers[index_](iters_); + return IterData::arrowers[index_](iters_); } Iterator& operator++() { - incrementers[index_](iters_); + IterData::incrementers[index_](iters_); check_for_end_and_adjust(); return *this; } @@ -132,10 +142,11 @@ class iter::impl::Chained { return ret; } + // TODO make const and non-const iterators comparable bool operator!=(const Iterator& other) const { return index_ != other.index_ || (index_ != sizeof...(Is) - && neq_comparers[index_](iters_, other.iters_)); + && IterData::neq_comparers[index_](iters_, other.iters_)); } bool operator==(const Iterator& other) const { @@ -143,36 +154,64 @@ class iter::impl::Chained { } }; - Iterator begin() { - return {0, IterTupType{get_begin(std::get(tup_))...}, - IterTupType{get_end(std::get(tup_))...}}; + Iterator begin() { + return {0, typename IteratorData::IterTupType{get_begin( + std::get(tup_))...}, + typename IteratorData::IterTupType{ + get_end(std::get(tup_))...}}; } - Iterator end() { - return {sizeof...(Is), IterTupType{get_end(std::get(tup_))...}, - IterTupType{get_end(std::get(tup_))...}}; + Iterator end() { + return {sizeof...(Is), typename IteratorData::IterTupType{get_end( + std::get(tup_))...}, + typename IteratorData::IterTupType{ + get_end(std::get(tup_))...}}; + } + + Iterator> begin() const { + return {0, typename IteratorData>::IterTupType{get_begin( + as_const(std::get(tup_)))...}, + typename IteratorData>::IterTupType{ + get_end(as_const(std::get(tup_)))...}}; + } + + Iterator> end() const { + return {sizeof...(Is), + typename IteratorData>::IterTupType{ + get_end(as_const(std::get(tup_)))...}, + typename IteratorData>::IterTupType{ + get_end(as_const(std::get(tup_)))...}}; } }; +// jesus christ. what have I done. template -constexpr std::array::DerefFunc, +template +constexpr std::array::template IteratorData::DerefFunc, sizeof...(Is)> - iter::impl::Chained::derefers; + iter::impl::Chained::IteratorData::derefers; template -constexpr std::array::ArrowFunc, +template +constexpr std::array::template IteratorData::ArrowFunc, sizeof...(Is)> - iter::impl::Chained::arrowers; + iter::impl::Chained::IteratorData::arrowers; template -constexpr std::array::IncFunc, +template +constexpr std::array::template IteratorData::IncFunc, sizeof...(Is)> - iter::impl::Chained::incrementers; + iter::impl::Chained::IteratorData::incrementers; template -constexpr std::array::NeqFunc, +template +constexpr std::array::template IteratorData::NeqFunc, sizeof...(Is)> - iter::impl::Chained::neq_comparers; + iter::impl::Chained::IteratorData::neq_comparers; template class iter::impl::ChainedFromIterable { diff --git a/test/test_chain.cpp b/test/test_chain.cpp index 00701495..8213c2cc 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -37,6 +37,7 @@ TEST_CASE("chain: const iteration", "[chain][const]") { REQUIRE(v == vc); } +// TODO make this work #if 0 TEST_CASE("chain: const iterators can be compared to non-const itertors", "[chain][const]") { auto ch = chain(std::string{}, std::string{}); From 92992d0b2e8b1cec6c3b8be66f119737b07d4910 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 16 Oct 2017 19:36:38 -0500 Subject: [PATCH 201/403] Tests chain.from_iterable with const iteration --- test/test_chain.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/test/test_chain.cpp b/test/test_chain.cpp index 8213c2cc..32b9f184 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -204,8 +204,8 @@ TEST_CASE("chain.from_iterable: basic test", "[chain.from_iterable]") { REQUIRE(v == vc); } -#if 0 -TEST_CASE("chain.from_iterable: const iteration", "[chain.from_iterable][const]") { +TEST_CASE( + "chain.from_iterable: const iteration", "[chain.from_iterable][const]") { std::vector sv{"abc", "xyz"}; const auto ch = chain.from_iterable(sv); std::vector v(std::begin(ch), std::end(ch)); @@ -214,12 +214,15 @@ TEST_CASE("chain.from_iterable: const iteration", "[chain.from_iterable][const]" REQUIRE(v == vc); } -TEST_CASE("chain.from_iterable: const iterators can be compared to non-const iterators", "[chain.from_iterable][const]") { - auto ch = chain.from_iterable(std::vector{}); +TEST_CASE( + "chain.from_iterable: const iterators can be compared to non-const " + "iterators", + "[chain.from_iterable][const]") { + std::vector> v{}; + auto ch = chain.from_iterable(v); const auto& cch = ch; (void)(std::begin(ch) == std::end(cch)); } -#endif TEST_CASE("chain.fromm_iterable: Works with different begin and end types", "[chain.from_iterable]") { From e64c3b56bf9fd10940a88cda23866f25db88da56 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 16 Oct 2017 19:36:53 -0500 Subject: [PATCH 202/403] Adds support for const iteration to chain.from_iterable --- chain.hpp | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/chain.hpp b/chain.hpp index ae7e74ef..11be814f 100644 --- a/chain.hpp +++ b/chain.hpp @@ -223,14 +223,17 @@ class iter::impl::ChainedFromIterable { public: ChainedFromIterable(ChainedFromIterable&&) = default; + template class Iterator : public std::iterator>> { + iterator_traits_deref>> { private: - using SubContainer = iterator_deref; + template + friend class Iterator; + using SubContainer = iterator_deref; using SubIter = IteratorWrapper; - IteratorWrapper top_level_iter_; - IteratorWrapper top_level_end_; + IteratorWrapper top_level_iter_; + IteratorWrapper top_level_end_; std::unique_ptr sub_iter_p_; std::unique_ptr sub_end_p_; @@ -238,8 +241,11 @@ class iter::impl::ChainedFromIterable { return sub_iter ? std::make_unique(*sub_iter) : nullptr; } - bool sub_iters_differ(const Iterator& other) const { - if (sub_iter_p_ == other.sub_iter_p_) { + template + bool sub_iters_differ(const Iterator& other) const { + // checking if they're the same also handles them both being nullptr + if (static_cast(sub_iter_p_.get()) + == static_cast(other.sub_iter_p_.get())) { return false; } if (sub_iter_p_ == nullptr || other.sub_iter_p_ == nullptr) { @@ -251,8 +257,8 @@ class iter::impl::ChainedFromIterable { } public: - Iterator(IteratorWrapper&& top_iter, - IteratorWrapper&& top_end) + Iterator(IteratorWrapper&& top_iter, + IteratorWrapper&& top_end) : top_level_iter_{std::move(top_iter)}, top_level_end_{std::move(top_end)}, sub_iter_p_{!(top_iter != top_end) @@ -308,31 +314,41 @@ class iter::impl::ChainedFromIterable { return ret; } - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return top_level_iter_ != other.top_level_iter_ || sub_iters_differ(other); } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } - iterator_deref> operator*() { + iterator_deref> operator*() { return **sub_iter_p_; } - iterator_arrow> operator->() { + iterator_arrow> operator->() { return apply_arrow(*sub_iter_p_); } }; - Iterator begin() { + Iterator begin() { return {get_begin(container_), get_end(container_)}; } - Iterator end() { + Iterator end() { return {get_end(container_), get_end(container_)}; } + + Iterator> begin() const { + return {get_begin(as_const(container_)), get_end(as_const(container_))}; + } + + Iterator> end() const { + return {get_end(as_const(container_)), get_end(as_const(container_))}; + } }; class iter::impl::ChainMaker { From e8d6cc5d9c2f73cb5fea48cecd340dde70d76e0b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 16 Oct 2017 19:43:07 -0500 Subject: [PATCH 203/403] Some iterator type disagreement thing --- test/helpers.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/helpers.hpp b/test/helpers.hpp index 76b4c359..e1d5a3cf 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -110,7 +110,8 @@ namespace itertest { BasicIterable(const BasicIterable& other) : data{new T[other.size]}, size{other.size} { other.was_copied_from_ = true; - for (auto it = begin(*this), o_it = begin(other); o_it != end(other); + auto o_it = begin(other); + for (auto it = begin(*this); o_it != end(other); ++it, ++o_it) { *it = *o_it; } From 0cecd1618acf2a9fdf925a99a3dcfa6ca7524208 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 20 Oct 2017 16:32:43 -0500 Subject: [PATCH 204/403] fixes include imap.hpp -> starmap.hpp --- test/test_starmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_starmap.cpp b/test/test_starmap.cpp index 1b284738..210694f5 100644 --- a/test/test_starmap.cpp +++ b/test/test_starmap.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" From 3b0034677a351a3d4406856858c2ea01abdc83f8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 26 Oct 2017 12:58:48 -0500 Subject: [PATCH 205/403] qualifies calls to as_const with ::impl ADL is screwing me on this in C++17, it doesn't know whether to use iter::impl::as_const or std::as_const when the argument is std::anything --- accumulate.hpp | 4 ++-- chain.hpp | 12 ++++++------ chunked.hpp | 4 ++-- combinations.hpp | 4 ++-- combinations_with_replacement.hpp | 4 ++-- compress.hpp | 8 ++++---- cycle.hpp | 4 ++-- dropwhile.hpp | 4 ++-- enumerate.hpp | 4 ++-- filter.hpp | 4 ++-- groupby.hpp | 4 ++-- internal/iterbase.hpp | 2 +- permutations.hpp | 4 ++-- powerset.hpp | 4 ++-- product.hpp | 8 ++++---- reversed.hpp | 4 ++-- slice.hpp | 8 ++++---- sliding_window.hpp | 8 ++++---- sorted.hpp | 4 ++-- starmap.hpp | 8 ++++---- takewhile.hpp | 4 ++-- zip.hpp | 4 ++-- zip_longest.hpp | 8 ++++---- 23 files changed, 61 insertions(+), 61 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index d533a8d7..f67d87f5 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -119,12 +119,12 @@ class iter::impl::Accumulator { return {get_end(container_), get_end(container_), accumulate_func_}; } Iterator> begin() const { - return {get_begin(as_const(container_)), get_end(as_const(container_)), + return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_)), accumulate_func_}; } Iterator> end() const { - return {get_end(as_const(container_)), get_end(as_const(container_)), + return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), accumulate_func_}; } }; diff --git a/chain.hpp b/chain.hpp index 11be814f..6ae9b245 100644 --- a/chain.hpp +++ b/chain.hpp @@ -170,17 +170,17 @@ class iter::impl::Chained { Iterator> begin() const { return {0, typename IteratorData>::IterTupType{get_begin( - as_const(std::get(tup_)))...}, + impl::as_const(std::get(tup_)))...}, typename IteratorData>::IterTupType{ - get_end(as_const(std::get(tup_)))...}}; + get_end(impl::as_const(std::get(tup_)))...}}; } Iterator> end() const { return {sizeof...(Is), typename IteratorData>::IterTupType{ - get_end(as_const(std::get(tup_)))...}, + get_end(impl::as_const(std::get(tup_)))...}, typename IteratorData>::IterTupType{ - get_end(as_const(std::get(tup_)))...}}; + get_end(impl::as_const(std::get(tup_)))...}}; } }; @@ -343,11 +343,11 @@ class iter::impl::ChainedFromIterable { } Iterator> begin() const { - return {get_begin(as_const(container_)), get_end(as_const(container_))}; + return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_))}; } Iterator> end() const { - return {get_end(as_const(container_)), get_end(as_const(container_))}; + return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_))}; } }; diff --git a/chunked.hpp b/chunked.hpp index bf152a3f..316a3a17 100644 --- a/chunked.hpp +++ b/chunked.hpp @@ -115,12 +115,12 @@ class iter::impl::Chunker { } Iterator> begin() const { - return {get_begin(as_const(container_)), get_end(as_const(container_)), + return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_)), chunk_size_}; } Iterator> end() const { - return {get_end(as_const(container_)), get_end(as_const(container_)), + return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), chunk_size_}; } }; diff --git a/combinations.hpp b/combinations.hpp index f32f00d5..163fa678 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -136,11 +136,11 @@ class iter::impl::Combinator { } Iterator> begin() const { - return {as_const(container_), length_}; + return {impl::as_const(container_), length_}; } Iterator> end() const { - return {as_const(container_), 0}; + return {impl::as_const(container_), 0}; } }; diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index dab28c9a..cc76e250 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -115,11 +115,11 @@ class iter::impl::CombinatorWithReplacement { } Iterator> begin() const { - return {as_const(container_), length_}; + return {impl::as_const(container_), length_}; } Iterator> end() const { - return {as_const(container_), 0}; + return {impl::as_const(container_), 0}; } }; diff --git a/compress.hpp b/compress.hpp index 9c511215..50e64017 100644 --- a/compress.hpp +++ b/compress.hpp @@ -111,13 +111,13 @@ class iter::impl::Compressed { } Iterator, AsConst> begin() const { - return {get_begin(as_const(container_)), get_end(as_const(container_)), - get_begin(as_const(selectors_)), get_end(as_const(selectors_))}; + return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_)), + get_begin(impl::as_const(selectors_)), get_end(impl::as_const(selectors_))}; } Iterator, AsConst> end() const { - return {get_end(as_const(container_)), get_end(as_const(container_)), - get_end(as_const(selectors_)), get_end(as_const(selectors_))}; + return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), + get_end(impl::as_const(selectors_)), get_end(impl::as_const(selectors_))}; } }; diff --git a/cycle.hpp b/cycle.hpp index 21a92872..06988870 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -90,11 +90,11 @@ class iter::impl::Cycler { } Iterator> begin() const { - return {get_begin(as_const(container_)), get_end(as_const(container_))}; + return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_))}; } Iterator> end() const { - return {get_end(as_const(container_)), get_end(as_const(container_))}; + return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_))}; } }; diff --git a/dropwhile.hpp b/dropwhile.hpp index 1c9c5737..dc2432cf 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -109,12 +109,12 @@ class iter::impl::Dropper { } Iterator> begin() const { - return {get_begin(as_const(container_)), get_end(as_const(container_)), + return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_)), filter_func_}; } Iterator> end() const { - return {get_end(as_const(container_)), get_end(as_const(container_)), + return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), filter_func_}; } }; diff --git a/enumerate.hpp b/enumerate.hpp index a79c1a41..05230525 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -120,11 +120,11 @@ class iter::impl::Enumerable { } Iterator> begin() const { - return {get_begin(as_const(container_)), start_}; + return {get_begin(impl::as_const(container_)), start_}; } Iterator> end() const { - return {get_end(as_const(container_)), start_}; + return {get_end(impl::as_const(container_)), start_}; } }; #endif diff --git a/filter.hpp b/filter.hpp index 4b450b14..8a3502e8 100644 --- a/filter.hpp +++ b/filter.hpp @@ -122,12 +122,12 @@ class iter::impl::Filtered { } Iterator> begin() const { - return {get_begin(as_const(container_)), get_end(as_const(container_)), + return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_)), filter_func_}; } Iterator> end() const { - return {get_end(as_const(container_)), get_end(as_const(container_)), + return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), filter_func_}; } }; diff --git a/groupby.hpp b/groupby.hpp index f25d145b..ac8ba01f 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -274,12 +274,12 @@ class iter::impl::GroupProducer { } Iterator> begin() const { - return {get_begin(as_const(container_)), get_end(as_const(container_)), + return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_)), key_func_}; } Iterator> end() const { - return {get_end(as_const(container_)), get_end(as_const(container_)), + return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), key_func_}; } }; diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 2b0ec98d..88d487ba 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -60,7 +60,7 @@ namespace iter { void as_const(T&&) = delete; template - using AsConst = decltype(as_const(std::declval())); + using AsConst = decltype(impl::as_const(std::declval())); // gcc CWG 1558 template diff --git a/permutations.hpp b/permutations.hpp index faae1fe2..b10f898d 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -110,11 +110,11 @@ class iter::impl::Permuter { } Iterator> begin() const { - return {get_begin(as_const(container_)), get_end(as_const(container_))}; + return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_))}; } Iterator> end() const { - return {get_end(as_const(container_)), get_end(as_const(container_))}; + return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_))}; } }; diff --git a/powerset.hpp b/powerset.hpp index 2997d569..d5c56619 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -114,11 +114,11 @@ class iter::impl::Powersetter { } Iterator> begin() const { - return {as_const(container_), 0}; + return {impl::as_const(container_), 0}; } Iterator> end() const { - return {as_const(container_), dumb_size(as_const(container_)) + 1}; + return {impl::as_const(container_), dumb_size(impl::as_const(container_)) + 1}; } }; diff --git a/product.hpp b/product.hpp index 941eddae..7f569632 100644 --- a/product.hpp +++ b/product.hpp @@ -128,13 +128,13 @@ class iter::impl::Productor { } ConstIterator begin() const { - return {get_begin(as_const(container_)), - get_begin(as_const(rest_products_)), get_end(as_const(rest_products_))}; + return {get_begin(impl::as_const(container_)), + get_begin(impl::as_const(rest_products_)), get_end(impl::as_const(rest_products_))}; } ConstIterator end() const { - return {get_end(as_const(container_)), get_end(as_const(rest_products_)), - get_end(as_const(rest_products_))}; + return {get_end(impl::as_const(container_)), get_end(impl::as_const(rest_products_)), + get_end(impl::as_const(rest_products_))}; } }; diff --git a/reversed.hpp b/reversed.hpp index 4f3004e2..08517fb7 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -121,11 +121,11 @@ class iter::impl::Reverser { } Iterator> begin() const { - return {std::rbegin(as_const(container_))}; + return {std::rbegin(impl::as_const(container_))}; } Iterator> end() const { - return {std::rend(as_const(container_))}; + return {std::rend(impl::as_const(container_))}; } }; diff --git a/slice.hpp b/slice.hpp index 4ac9e1a0..f29922d0 100644 --- a/slice.hpp +++ b/slice.hpp @@ -102,13 +102,13 @@ class iter::impl::Sliced { } Iterator> begin() const { - auto it = get_begin(as_const(container_)); - dumb_advance(it, get_end(as_const(container_)), start_); - return {std::move(it), get_end(as_const(container_)), start_, stop_, step_}; + auto it = get_begin(impl::as_const(container_)); + dumb_advance(it, get_end(impl::as_const(container_)), start_); + return {std::move(it), get_end(impl::as_const(container_)), start_, stop_, step_}; } Iterator> end() const { - return {get_end(as_const(container_)), get_end(as_const(container_)), stop_, + return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), stop_, stop_, step_}; } }; diff --git a/sliding_window.hpp b/sliding_window.hpp index 7c3135f5..62da80d8 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -104,14 +104,14 @@ class iter::impl::WindowSlider { Iterator> begin() const { return {(window_size_ != 0 ? IteratorWrapper>{get_begin( - as_const(container_))} + impl::as_const(container_))} : IteratorWrapper>{get_end( - as_const(container_))}), - get_end(as_const(container_)), window_size_}; + impl::as_const(container_))}), + get_end(impl::as_const(container_)), window_size_}; } Iterator> end() const { - return {get_end(as_const(container_)), get_end(as_const(container_)), + return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), window_size_}; } }; diff --git a/sorted.hpp b/sorted.hpp index fa6f7c19..24701488 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -101,8 +101,8 @@ class iter::impl::SortedView { if (!const_sorted_iters_.empty()) { return; } - for (auto iter = get_begin(as_const(container_)); - iter != get_end(as_const(container_)); ++iter) { + for (auto iter = get_begin(impl::as_const(container_)); + iter != get_end(impl::as_const(container_)); ++iter) { const_sorted_iters_.get().push_back(iter); } diff --git a/starmap.hpp b/starmap.hpp index 4f82d106..27639195 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -95,11 +95,11 @@ class iter::impl::StarMapper { } Iterator> begin() const { - return {func_, get_begin(as_const(container_))}; + return {func_, get_begin(impl::as_const(container_))}; } Iterator> end() const { - return {func_, get_end(as_const(container_))}; + return {func_, get_end(impl::as_const(container_))}; } }; @@ -194,11 +194,11 @@ class iter::impl::TupleStarMapper { } Iterator> begin() const { - return {func_, as_const(tup_), 0}; + return {func_, impl::as_const(tup_), 0}; } Iterator> end() const { - return {func_, as_const(tup_), sizeof...(Is)}; + return {func_, impl::as_const(tup_), sizeof...(Is)}; } }; diff --git a/takewhile.hpp b/takewhile.hpp index d4b0e956..8d6694ba 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -110,12 +110,12 @@ class iter::impl::Taker { } Iterator> begin() const { - return {get_begin(as_const(container_)), get_end(as_const(container_)), + return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_)), filter_func_}; } Iterator> end() const { - return {get_end(as_const(container_)), get_end(as_const(container_)), + return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), filter_func_}; } }; diff --git a/zip.hpp b/zip.hpp index 7958234b..3bb4ccdb 100644 --- a/zip.hpp +++ b/zip.hpp @@ -101,14 +101,14 @@ class iter::impl::Zipped { const_iterator_deref_tuple> begin() const { return {const_iterator_tuple_type>{ - get_begin(as_const(std::get(containers_)))...}}; + get_begin(impl::as_const(std::get(containers_)))...}}; } Iterator, const_iterator_tuple_type, const_iterator_deref_tuple> end() const { return {const_iterator_tuple_type>{ - get_end(as_const(std::get(containers_)))...}}; + get_end(impl::as_const(std::get(containers_)))...}}; } }; diff --git a/zip_longest.hpp b/zip_longest.hpp index 428751c0..eb73aaac 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -121,17 +121,17 @@ class iter::impl::ZippedLongest { Iterator, const_iterator_tuple_type, ConstOptType> begin() const { return {const_iterator_tuple_type>{ - get_begin(as_const(std::get(containers_)))...}, + get_begin(impl::as_const(std::get(containers_)))...}, const_iterator_tuple_type>{ - get_end(as_const(std::get(containers_)))...}}; + get_end(impl::as_const(std::get(containers_)))...}}; } Iterator, const_iterator_tuple_type, ConstOptType> end() const { return {const_iterator_tuple_type>{ - get_end(as_const(std::get(containers_)))...}, + get_end(impl::as_const(std::get(containers_)))...}, const_iterator_tuple_type>{ - get_end(as_const(std::get(containers_)))...}}; + get_end(impl::as_const(std::get(containers_)))...}}; } }; From 22250a8f407cdeecc6459f1f6330f61a62ca9b38 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 26 Oct 2017 13:10:52 -0500 Subject: [PATCH 206/403] structed binding declaration in enumerate example --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b7f97e62..ae67923f 100644 --- a/README.md +++ b/README.md @@ -221,15 +221,13 @@ enumerate --------- Continually "yields" containers similar to pairs. They are basic structs with a -.index and a .element. Usage appears as: +.index and a .element, and also work with structured binding declarations. +Usage appears as: ```c++ vector vec{2, 4, 6, 8}; -for (auto&& e : enumerate(vec)) { - cout << e.index - << ": " - << e.element - << '\n'; +for (auto&& [i, e] : enumerate(vec)) { + cout << i << ": " << e << '\n'; } ``` From 67a67b22f17a5a6edf6b8585bf5e6e4f4ecca035 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 26 Oct 2017 13:11:24 -0500 Subject: [PATCH 207/403] formatting --- accumulate.hpp | 8 ++++---- chain.hpp | 6 ++++-- chunked.hpp | 8 ++++---- compress.hpp | 12 ++++++++---- cycle.hpp | 6 ++++-- dropwhile.hpp | 8 ++++---- filter.hpp | 8 ++++---- groupby.hpp | 8 ++++---- permutations.hpp | 6 ++++-- powerset.hpp | 3 ++- product.hpp | 6 ++++-- range.hpp | 15 ++++++++++----- slice.hpp | 7 ++++--- sliding_window.hpp | 4 ++-- takewhile.hpp | 8 ++++---- 15 files changed, 66 insertions(+), 47 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index f67d87f5..25440d58 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -119,13 +119,13 @@ class iter::impl::Accumulator { return {get_end(container_), get_end(container_), accumulate_func_}; } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_)), - accumulate_func_}; + return {get_begin(impl::as_const(container_)), + get_end(impl::as_const(container_)), accumulate_func_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), - accumulate_func_}; + return {get_end(impl::as_const(container_)), + get_end(impl::as_const(container_)), accumulate_func_}; } }; diff --git a/chain.hpp b/chain.hpp index 6ae9b245..1f840903 100644 --- a/chain.hpp +++ b/chain.hpp @@ -343,11 +343,13 @@ class iter::impl::ChainedFromIterable { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_))}; + return {get_begin(impl::as_const(container_)), + get_end(impl::as_const(container_))}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_))}; + return {get_end(impl::as_const(container_)), + get_end(impl::as_const(container_))}; } }; diff --git a/chunked.hpp b/chunked.hpp index 316a3a17..06f0a2aa 100644 --- a/chunked.hpp +++ b/chunked.hpp @@ -115,13 +115,13 @@ class iter::impl::Chunker { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_)), - chunk_size_}; + return {get_begin(impl::as_const(container_)), + get_end(impl::as_const(container_)), chunk_size_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), - chunk_size_}; + return {get_end(impl::as_const(container_)), + get_end(impl::as_const(container_)), chunk_size_}; } }; diff --git a/compress.hpp b/compress.hpp index 50e64017..5ebc97ff 100644 --- a/compress.hpp +++ b/compress.hpp @@ -111,13 +111,17 @@ class iter::impl::Compressed { } Iterator, AsConst> begin() const { - return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_)), - get_begin(impl::as_const(selectors_)), get_end(impl::as_const(selectors_))}; + return {get_begin(impl::as_const(container_)), + get_end(impl::as_const(container_)), + get_begin(impl::as_const(selectors_)), + get_end(impl::as_const(selectors_))}; } Iterator, AsConst> end() const { - return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), - get_end(impl::as_const(selectors_)), get_end(impl::as_const(selectors_))}; + return {get_end(impl::as_const(container_)), + get_end(impl::as_const(container_)), + get_end(impl::as_const(selectors_)), + get_end(impl::as_const(selectors_))}; } }; diff --git a/cycle.hpp b/cycle.hpp index 06988870..c6ee4662 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -90,11 +90,13 @@ class iter::impl::Cycler { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_))}; + return {get_begin(impl::as_const(container_)), + get_end(impl::as_const(container_))}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_))}; + return {get_end(impl::as_const(container_)), + get_end(impl::as_const(container_))}; } }; diff --git a/dropwhile.hpp b/dropwhile.hpp index dc2432cf..1a23c823 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -109,13 +109,13 @@ class iter::impl::Dropper { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_)), - filter_func_}; + return {get_begin(impl::as_const(container_)), + get_end(impl::as_const(container_)), filter_func_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), - filter_func_}; + return {get_end(impl::as_const(container_)), + get_end(impl::as_const(container_)), filter_func_}; } }; diff --git a/filter.hpp b/filter.hpp index 8a3502e8..b92c2ce3 100644 --- a/filter.hpp +++ b/filter.hpp @@ -122,13 +122,13 @@ class iter::impl::Filtered { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_)), - filter_func_}; + return {get_begin(impl::as_const(container_)), + get_end(impl::as_const(container_)), filter_func_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), - filter_func_}; + return {get_end(impl::as_const(container_)), + get_end(impl::as_const(container_)), filter_func_}; } }; diff --git a/groupby.hpp b/groupby.hpp index ac8ba01f..12a0e471 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -274,13 +274,13 @@ class iter::impl::GroupProducer { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_)), - key_func_}; + return {get_begin(impl::as_const(container_)), + get_end(impl::as_const(container_)), key_func_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), - key_func_}; + return {get_end(impl::as_const(container_)), + get_end(impl::as_const(container_)), key_func_}; } }; diff --git a/permutations.hpp b/permutations.hpp index b10f898d..39c073e5 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -110,11 +110,13 @@ class iter::impl::Permuter { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_))}; + return {get_begin(impl::as_const(container_)), + get_end(impl::as_const(container_))}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_))}; + return {get_end(impl::as_const(container_)), + get_end(impl::as_const(container_))}; } }; diff --git a/powerset.hpp b/powerset.hpp index d5c56619..8e5278f4 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -118,7 +118,8 @@ class iter::impl::Powersetter { } Iterator> end() const { - return {impl::as_const(container_), dumb_size(impl::as_const(container_)) + 1}; + return { + impl::as_const(container_), dumb_size(impl::as_const(container_)) + 1}; } }; diff --git a/product.hpp b/product.hpp index 7f569632..9f4d9dc7 100644 --- a/product.hpp +++ b/product.hpp @@ -129,11 +129,13 @@ class iter::impl::Productor { ConstIterator begin() const { return {get_begin(impl::as_const(container_)), - get_begin(impl::as_const(rest_products_)), get_end(impl::as_const(rest_products_))}; + get_begin(impl::as_const(rest_products_)), + get_end(impl::as_const(rest_products_))}; } ConstIterator end() const { - return {get_end(impl::as_const(container_)), get_end(impl::as_const(rest_products_)), + return {get_end(impl::as_const(container_)), + get_end(impl::as_const(rest_products_)), get_end(impl::as_const(rest_products_))}; } }; diff --git a/range.hpp b/range.hpp index 3d2df9b8..348fd9ab 100644 --- a/range.hpp +++ b/range.hpp @@ -37,7 +37,8 @@ namespace iter { public: constexpr RangeIterData() noexcept = default; constexpr RangeIterData(T in_value, T in_step) noexcept - : value_{in_value}, step_{in_step} {} + : value_{in_value}, + step_{in_step} {} constexpr T value() const noexcept { return value_; @@ -72,7 +73,9 @@ namespace iter { public: constexpr RangeIterData() noexcept = default; constexpr RangeIterData(T in_start, T in_step) noexcept - : start_{in_start}, value_{in_start}, step_{in_step} {} + : start_{in_start}, + value_{in_start}, + step_{in_step} {} constexpr T value() const noexcept { return value_; @@ -120,8 +123,9 @@ class iter::impl::Range { constexpr Range(T stop) noexcept : start_{0}, stop_{stop}, step_{1} {} - constexpr Range(T start, T stop, T step = 1) noexcept - : start_{start}, stop_{stop}, step_{step} {} + constexpr Range(T start, T stop, T step = 1) noexcept : start_{start}, + stop_{stop}, + step_{step} {} public: // the reference type here is T, which doesn't strictly follow all @@ -165,7 +169,8 @@ class iter::impl::Range { constexpr Iterator() noexcept = default; constexpr Iterator(T in_value, T in_step, bool in_is_end) noexcept - : data(in_value, in_step), is_end{in_is_end} {} + : data(in_value, in_step), + is_end{in_is_end} {} constexpr T operator*() const noexcept { return data.value(); diff --git a/slice.hpp b/slice.hpp index f29922d0..59ea7885 100644 --- a/slice.hpp +++ b/slice.hpp @@ -104,12 +104,13 @@ class iter::impl::Sliced { Iterator> begin() const { auto it = get_begin(impl::as_const(container_)); dumb_advance(it, get_end(impl::as_const(container_)), start_); - return {std::move(it), get_end(impl::as_const(container_)), start_, stop_, step_}; + return {std::move(it), get_end(impl::as_const(container_)), start_, stop_, + step_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), stop_, - stop_, step_}; + return {get_end(impl::as_const(container_)), + get_end(impl::as_const(container_)), stop_, stop_, step_}; } }; diff --git a/sliding_window.hpp b/sliding_window.hpp index 62da80d8..ae478de8 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -111,8 +111,8 @@ class iter::impl::WindowSlider { } Iterator> end() const { - return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), - window_size_}; + return {get_end(impl::as_const(container_)), + get_end(impl::as_const(container_)), window_size_}; } }; diff --git a/takewhile.hpp b/takewhile.hpp index 8d6694ba..ad823b0d 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -110,13 +110,13 @@ class iter::impl::Taker { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), get_end(impl::as_const(container_)), - filter_func_}; + return {get_begin(impl::as_const(container_)), + get_end(impl::as_const(container_)), filter_func_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), get_end(impl::as_const(container_)), - filter_func_}; + return {get_end(impl::as_const(container_)), + get_end(impl::as_const(container_)), filter_func_}; } }; From 2bd12d74061a9c3ca92e46e6de0a75e7635fe707 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 18 Nov 2017 10:28:39 -0600 Subject: [PATCH 208/403] updates max value description of count() The doc description of hitting the max was old. fixed. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0d138f3d..6bf1907c 100644 --- a/README.md +++ b/README.md @@ -380,11 +380,11 @@ step of 1.
`count(i, st)` will start counting from `i` with a step of `st`. *Technical limitations*: Unlike Python which can use its long integer -types when needed, count() will eventually exceed the +types when needed, count() would eventually exceed the maximum possible value for its type (or minimum with a negative step). -When using a signed type it is up to the API user to ensure this does -not happen. If the limit is exceeded for signed types, the result is -undefined (as per the C++ standard). +`count` is actually implemented as a `range` with the stopping point +being the `std::numeric_limits::max()` for the integral type (`long` +by default) The below will print `0 1 2` ... etc ```c++ From f0f141cb9215f49ec65c0f306bde4c63a17d378c Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Fri, 5 Jan 2018 15:46:43 -0800 Subject: [PATCH 209/403] adds missing includes for --- test/test_permutations.cpp | 1 + test/test_powerset.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/test/test_permutations.cpp b/test/test_permutations.cpp index b6b6fdae..5da85fc8 100644 --- a/test/test_permutations.cpp +++ b/test/test_permutations.cpp @@ -3,6 +3,7 @@ #include "helpers.hpp" #include +#include #include #include diff --git a/test/test_powerset.cpp b/test/test_powerset.cpp index b56d43e0..c18dd1f7 100644 --- a/test/test_powerset.cpp +++ b/test/test_powerset.cpp @@ -5,6 +5,7 @@ #undef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE #include +#include #include #include From f364ebb39f360327911f180cd20b737e98dda42f Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Fri, 5 Jan 2018 15:54:05 -0800 Subject: [PATCH 210/403] Adds files for bazel build I didn't put in a test_all because you can just use bazel test :all --- .gitignore | 1 + BUILD | 42 ++++++++++++++++++++++++++++++++++++++++++ WORKSPACE | 0 test/BUILD | 39 +++++++++++++++++++++++++++++++++++++++ test/make_tests.bzl | 8 ++++++++ 5 files changed, 90 insertions(+) create mode 100644 .gitignore create mode 100644 BUILD create mode 100644 WORKSPACE create mode 100644 test/BUILD create mode 100644 test/make_tests.bzl diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ac51a054 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bazel-* diff --git a/BUILD b/BUILD new file mode 100644 index 00000000..8b162b86 --- /dev/null +++ b/BUILD @@ -0,0 +1,42 @@ +cc_library( + name = "cppitertools", + hdrs = [ + "accumulate.hpp", + "chain.hpp", + "chunked.hpp", + "combinations.hpp", + "combinations_with_replacement.hpp", + "compress.hpp", + "count.hpp", + "cycle.hpp", + "dropwhile.hpp", + "enumerate.hpp", + "filter.hpp", + "filterfalse.hpp", + "groupby.hpp", + "imap.hpp", + "itertools.hpp", + "permutations.hpp", + "powerset.hpp", + "product.hpp", + "range.hpp", + "repeat.hpp", + "reversed.hpp", + "slice.hpp", + "sliding_window.hpp", + "sorted.hpp", + "starmap.hpp", + "takewhile.hpp", + "unique_everseen.hpp", + "unique_justseen.hpp", + "zip.hpp", + "zip_longest.hpp", + ], + srcs = [ + "internal/iter_tuples.hpp", + "internal/iterator_wrapper.hpp", + "internal/iteratoriterator.hpp", + "internal/iterbase.hpp", + ], + visibility = ["//visibility:public"], +) diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 00000000..e69de29b diff --git a/test/BUILD b/test/BUILD new file mode 100644 index 00000000..c2206754 --- /dev/null +++ b/test/BUILD @@ -0,0 +1,39 @@ +load("make_tests", "itertools_tests") + +progs = [ + "accumulate", + "chain", + "chunked", + "combinations", + "combinations_with_replacement", + "compress", + "count", + "cycle", + "dropwhile", + "enumerate", + "filter", + "filterfalse", + "groupby", + "imap", + "permutations", + "powerset", + "product", + "range", + "repeat", + "reversed", + "slice", + "sliding_window", + "starmap", + "sorted", + "takewhile", + "unique_everseen", + "unique_justseen", + "zip", + "iteratoriterator", + "iterator_wrapper", + "iterbase", + "mixed", + "helpers", +] + +itertools_tests(progs) diff --git a/test/make_tests.bzl b/test/make_tests.bzl new file mode 100644 index 00000000..80919522 --- /dev/null +++ b/test/make_tests.bzl @@ -0,0 +1,8 @@ +def itertools_tests(progs): + for p in progs: + native.cc_test( + name = "test_{}".format(p), + srcs = ["test_{}.cpp".format(p), "test_main.cpp", "catch.hpp", "helpers.hpp"], + deps = ["//:cppitertools",], + copts = ["-I.", "-std=c++14", "-Wall", "-Wextra", "-pedantic", "-g"], + ) From b8a37d75b05b283c21b18ec0d6c1f65f297dfbef Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Fri, 5 Jan 2018 15:46:43 -0800 Subject: [PATCH 211/403] adds missing includes for --- test/test_permutations.cpp | 1 + test/test_powerset.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/test/test_permutations.cpp b/test/test_permutations.cpp index b6b6fdae..5da85fc8 100644 --- a/test/test_permutations.cpp +++ b/test/test_permutations.cpp @@ -3,6 +3,7 @@ #include "helpers.hpp" #include +#include #include #include diff --git a/test/test_powerset.cpp b/test/test_powerset.cpp index b56d43e0..c18dd1f7 100644 --- a/test/test_powerset.cpp +++ b/test/test_powerset.cpp @@ -5,6 +5,7 @@ #undef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE #include +#include #include #include From 37354c4da95c3c4776e99dc37f52b69cc972fb27 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Fri, 5 Jan 2018 15:54:05 -0800 Subject: [PATCH 212/403] Adds files for bazel build I didn't put in a test_all because you can just use bazel test :all --- .gitignore | 1 + BUILD | 42 ++++++++++++++++++++++++++++++++++++++++++ WORKSPACE | 0 test/BUILD | 39 +++++++++++++++++++++++++++++++++++++++ test/make_tests.bzl | 8 ++++++++ 5 files changed, 90 insertions(+) create mode 100644 .gitignore create mode 100644 BUILD create mode 100644 WORKSPACE create mode 100644 test/BUILD create mode 100644 test/make_tests.bzl diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ac51a054 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bazel-* diff --git a/BUILD b/BUILD new file mode 100644 index 00000000..8b162b86 --- /dev/null +++ b/BUILD @@ -0,0 +1,42 @@ +cc_library( + name = "cppitertools", + hdrs = [ + "accumulate.hpp", + "chain.hpp", + "chunked.hpp", + "combinations.hpp", + "combinations_with_replacement.hpp", + "compress.hpp", + "count.hpp", + "cycle.hpp", + "dropwhile.hpp", + "enumerate.hpp", + "filter.hpp", + "filterfalse.hpp", + "groupby.hpp", + "imap.hpp", + "itertools.hpp", + "permutations.hpp", + "powerset.hpp", + "product.hpp", + "range.hpp", + "repeat.hpp", + "reversed.hpp", + "slice.hpp", + "sliding_window.hpp", + "sorted.hpp", + "starmap.hpp", + "takewhile.hpp", + "unique_everseen.hpp", + "unique_justseen.hpp", + "zip.hpp", + "zip_longest.hpp", + ], + srcs = [ + "internal/iter_tuples.hpp", + "internal/iterator_wrapper.hpp", + "internal/iteratoriterator.hpp", + "internal/iterbase.hpp", + ], + visibility = ["//visibility:public"], +) diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 00000000..e69de29b diff --git a/test/BUILD b/test/BUILD new file mode 100644 index 00000000..c2206754 --- /dev/null +++ b/test/BUILD @@ -0,0 +1,39 @@ +load("make_tests", "itertools_tests") + +progs = [ + "accumulate", + "chain", + "chunked", + "combinations", + "combinations_with_replacement", + "compress", + "count", + "cycle", + "dropwhile", + "enumerate", + "filter", + "filterfalse", + "groupby", + "imap", + "permutations", + "powerset", + "product", + "range", + "repeat", + "reversed", + "slice", + "sliding_window", + "starmap", + "sorted", + "takewhile", + "unique_everseen", + "unique_justseen", + "zip", + "iteratoriterator", + "iterator_wrapper", + "iterbase", + "mixed", + "helpers", +] + +itertools_tests(progs) diff --git a/test/make_tests.bzl b/test/make_tests.bzl new file mode 100644 index 00000000..80919522 --- /dev/null +++ b/test/make_tests.bzl @@ -0,0 +1,8 @@ +def itertools_tests(progs): + for p in progs: + native.cc_test( + name = "test_{}".format(p), + srcs = ["test_{}.cpp".format(p), "test_main.cpp", "catch.hpp", "helpers.hpp"], + deps = ["//:cppitertools",], + copts = ["-I.", "-std=c++14", "-Wall", "-Wextra", "-pedantic", "-g"], + ) From b8ce1c3c4659758fe0a096d743fef66362039868 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Mon, 8 Jan 2018 09:08:41 -0800 Subject: [PATCH 213/403] std=c++17 --- test/make_tests.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/make_tests.bzl b/test/make_tests.bzl index 80919522..883f0576 100644 --- a/test/make_tests.bzl +++ b/test/make_tests.bzl @@ -4,5 +4,5 @@ def itertools_tests(progs): name = "test_{}".format(p), srcs = ["test_{}.cpp".format(p), "test_main.cpp", "catch.hpp", "helpers.hpp"], deps = ["//:cppitertools",], - copts = ["-I.", "-std=c++14", "-Wall", "-Wextra", "-pedantic", "-g"], + copts = ["-I.", "-std=c++17", "-Wall", "-Wextra", "-pedantic", "-g"], ) From f1c222a6a59cf66c0411c3f07966bbd6c2b4befd Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Mon, 8 Jan 2018 09:19:19 -0800 Subject: [PATCH 214/403] Switches catch download link to use catchorg --- test/download_catch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/download_catch.sh b/test/download_catch.sh index f88f5643..2988d1b6 100755 --- a/test/download_catch.sh +++ b/test/download_catch.sh @@ -1,2 +1,2 @@ #!/usr/bin/env sh -wget -c https://raw.githubusercontent.com/philsquared/Catch/master/single_include/catch.hpp +wget -c https://github.com/catchorg/Catch2/releases/download/v2.0.1/catch.hpp From 542b6c1b3a3bdd6416198e5a4128e792654a3a37 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Mon, 8 Jan 2018 09:19:19 -0800 Subject: [PATCH 215/403] Switches catch download link to use catchorg --- test/download_catch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/download_catch.sh b/test/download_catch.sh index f88f5643..2988d1b6 100755 --- a/test/download_catch.sh +++ b/test/download_catch.sh @@ -1,2 +1,2 @@ #!/usr/bin/env sh -wget -c https://raw.githubusercontent.com/philsquared/Catch/master/single_include/catch.hpp +wget -c https://github.com/catchorg/Catch2/releases/download/v2.0.1/catch.hpp From 16e31a042922e5bc93726a1f66987ebdbd5cd7f0 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Mon, 8 Jan 2018 10:35:35 -0800 Subject: [PATCH 216/403] if constexpr instead of tag dispatch in sign check also some formatting got in there --- range.hpp | 51 ++++++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/range.hpp b/range.hpp index 348fd9ab..145cdfab 100644 --- a/range.hpp +++ b/range.hpp @@ -37,8 +37,7 @@ namespace iter { public: constexpr RangeIterData() noexcept = default; constexpr RangeIterData(T in_value, T in_step) noexcept - : value_{in_value}, - step_{in_step} {} + : value_{in_value}, step_{in_step} {} constexpr T value() const noexcept { return value_; @@ -73,9 +72,7 @@ namespace iter { public: constexpr RangeIterData() noexcept = default; constexpr RangeIterData(T in_start, T in_step) noexcept - : start_{in_start}, - value_{in_start}, - step_{in_step} {} + : start_{in_start}, value_{in_start}, step_{in_step} {} constexpr T value() const noexcept { return value_; @@ -123,9 +120,8 @@ class iter::impl::Range { constexpr Range(T stop) noexcept : start_{0}, stop_{stop}, step_{1} {} - constexpr Range(T start, T stop, T step = 1) noexcept : start_{start}, - stop_{stop}, - step_{step} {} + constexpr Range(T start, T stop, T step = 1) noexcept + : start_{start}, stop_{stop}, step_{step} {} public: // the reference type here is T, which doesn't strictly follow all @@ -138,39 +134,36 @@ class iter::impl::Range { iter::detail::RangeIterData data; bool is_end; - // compare unsigned values - static bool not_equal_to_impl(const Iterator& iter, - const Iterator& end_iter, std::true_type) noexcept { - assert(!iter.is_end); - assert(end_iter.is_end); - return iter.data.value() < end_iter.data.value(); - } - - // compare signed values - static bool not_equal_to_impl(const Iterator& iter, - const Iterator& end_iter, std::false_type) noexcept { - assert(!iter.is_end); - assert(end_iter.is_end); - return !(iter.data.step() > 0 - && iter.data.value() >= end_iter.data.value()) - && !(iter.data.step() < 0 - && iter.data.value() <= end_iter.data.value()); + // first argument must be regular iterator + // second argument must be end iterator + static bool not_equal_to_impl( + const Iterator& lhs, const Iterator& rhs) noexcept { + assert(!lhs.is_end); + assert(rhs.is_end); + if + constexpr(std::is_unsigned{}) { + return lhs.data.value() < rhs.data.value(); + } + else { + return !(lhs.data.step() > 0 && lhs.data.value() >= rhs.data.value()) + && !(lhs.data.step() < 0 + && lhs.data.value() <= rhs.data.value()); + } } static bool not_equal_to_end( const Iterator& lhs, const Iterator& rhs) noexcept { if (rhs.is_end) { - return not_equal_to_impl(lhs, rhs, std::is_unsigned{}); + return not_equal_to_impl(lhs, rhs); } - return not_equal_to_impl(rhs, lhs, std::is_unsigned{}); + return not_equal_to_impl(rhs, lhs); } public: constexpr Iterator() noexcept = default; constexpr Iterator(T in_value, T in_step, bool in_is_end) noexcept - : data(in_value, in_step), - is_end{in_is_end} {} + : data(in_value, in_step), is_end{in_is_end} {} constexpr T operator*() const noexcept { return data.value(); From bde4cfb44ed44e4b767595c04c45003199e69aa7 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Mon, 8 Jan 2018 10:52:03 -0800 Subject: [PATCH 217/403] if constexpr instead of tag dispatch Instead of tag dispatching on whether something is tuple-like, constexpr if on it instead. --- starmap.hpp | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index 08829d15..e83fbb24 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -217,34 +217,25 @@ struct iter::impl::StarMapFn : PipeableAndBindFirst { return {std::move(func), std::forward(tup)}; } - // handles tuple-like types - template - auto helper(Func func, TupType&& tup, std::true_type) const { - return helper_with_tuples(std::move(func), std::forward(tup), - std::make_index_sequence>:: - value>{}); - } - - // handles everything else - template - StarMapper helper( - Func func, Container&& container, std::false_type) const { - return {std::move(func), std::forward(container)}; - } - template - struct is_tuple_like : public std::false_type {}; + struct is_tuple_like : std::false_type {}; template struct is_tuple_like>::value)>> - : public std::true_type {}; + : std::true_type {}; public: template auto operator()(Func func, Seq&& sequence) const { - return helper( - std::move(func), std::forward(sequence), is_tuple_like{}); + if constexpr (is_tuple_like{}) { + return helper_with_tuples(std::move(func), std::forward(sequence), + std::make_index_sequence>:: + value>{}); + } else { + return StarMapper{ + std::move(func), std::forward(sequence)}; + } } using PipeableAndBindFirst::operator(); From e8fe728f123869d1ee4fa70896603c7bfa23368f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 4 Mar 2018 20:20:16 -0500 Subject: [PATCH 218/403] Adds : and .bzl to build rule --- test/BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/BUILD b/test/BUILD index c2206754..5c7c5d9c 100644 --- a/test/BUILD +++ b/test/BUILD @@ -1,4 +1,4 @@ -load("make_tests", "itertools_tests") +load(":make_tests.bzl", "itertools_tests") progs = [ "accumulate", From 46b625916359f5fc031d16f22559335de25efe34 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 4 Mar 2018 20:20:16 -0500 Subject: [PATCH 219/403] Adds : and .bzl to build rule --- test/BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/BUILD b/test/BUILD index c2206754..5c7c5d9c 100644 --- a/test/BUILD +++ b/test/BUILD @@ -1,4 +1,4 @@ -load("make_tests", "itertools_tests") +load(":make_tests.bzl", "itertools_tests") progs = [ "accumulate", From 940d06716ac7a21d727f8e5d95ba25e35ef3d2d9 Mon Sep 17 00:00:00 2001 From: Nikolas Vanderhoof Date: Sun, 4 Mar 2018 22:19:35 -0500 Subject: [PATCH 220/403] Remove use of std::iterator --- accumulate.hpp | 8 +++++++- chain.hpp | 18 ++++++++++++++---- chunked.hpp | 9 +++++++-- combinations.hpp | 9 +++++++-- combinations_with_replacement.hpp | 9 +++++++-- compress.hpp | 9 +++++++-- cycle.hpp | 9 +++++++-- dropwhile.hpp | 9 +++++++-- enumerate.hpp | 9 +++++++-- filter.hpp | 9 +++++++-- groupby.hpp | 18 ++++++++++++++---- internal/iteratoriterator.hpp | 10 ++++++---- permutations.hpp | 9 +++++++-- powerset.hpp | 9 +++++++-- product.hpp | 17 ++++++++++++++--- range.hpp | 9 +++++++-- repeat.hpp | 16 ++++++++++++++-- reversed.hpp | 9 +++++++-- slice.hpp | 9 +++++++-- sliding_window.hpp | 9 +++++++-- starmap.hpp | 18 ++++++++++++++---- takewhile.hpp | 9 +++++++-- zip.hpp | 9 +++++++-- zip_longest.hpp | 9 +++++++-- 24 files changed, 202 insertions(+), 56 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 25440d58..3e419d8b 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -39,7 +39,7 @@ class iter::impl::Accumulator { Accumulator(Accumulator&&) = default; template - class Iterator : public std::iterator { + class Iterator { private: template friend class Iterator; @@ -49,6 +49,12 @@ class iter::impl::Accumulator { std::unique_ptr acc_val_; public: + using iterator_category = std::input_iterator_tag; + using value_type = AccumVal; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, AccumulateFunc& accumulate_fun) : sub_iter_{std::move(sub_iter)}, diff --git a/chain.hpp b/chain.hpp index 1f840903..64aeb19d 100644 --- a/chain.hpp +++ b/chain.hpp @@ -100,8 +100,7 @@ class iter::impl::Chained { Chained(Chained&&) = default; template - class Iterator : public std::iterator::TraitsValue> { + class Iterator { private: using IterData = IteratorData; std::size_t index_; @@ -116,6 +115,12 @@ class iter::impl::Chained { } public: + using iterator_category = std::input_iterator_tag; + using value_type = typename IteratorData::TraitsValue; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(std::size_t i, typename IterData::IterTupType&& iters, typename IterData::IterTupType&& ends) : index_{i}, iters_(std::move(iters)), ends_(std::move(ends)) { @@ -224,8 +229,7 @@ class iter::impl::ChainedFromIterable { public: ChainedFromIterable(ChainedFromIterable&&) = default; template - class Iterator : public std::iterator>> { + class Iterator { private: template friend class Iterator; @@ -257,6 +261,12 @@ class iter::impl::ChainedFromIterable { } public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref>; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& top_iter, IteratorWrapper&& top_end) : top_level_iter_{std::move(top_iter)}, diff --git a/chunked.hpp b/chunked.hpp index 06f0a2aa..33d194d1 100644 --- a/chunked.hpp +++ b/chunked.hpp @@ -41,8 +41,7 @@ class iter::impl::Chunker { public: Chunker(Chunker&&) = default; template - class Iterator - : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -66,6 +65,12 @@ class iter::impl::Chunker { } public: + using iterator_category = std::input_iterator_tag; + using value_type = DerefVec; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, std::size_t s) : sub_iter_{std::move(sub_iter)}, diff --git a/combinations.hpp b/combinations.hpp index 163fa678..afdefe4a 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -37,8 +37,7 @@ class iter::impl::Combinator { public: Combinator(Combinator&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -48,6 +47,12 @@ class iter::impl::Combinator { int steps_{}; public: + using iterator_category = std::input_iterator_tag; + using value_type = CombIteratorDeref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(ContainerT& container, std::size_t n) : container_p_{&container}, indices_{n} { if (n == 0) { diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index cc76e250..5b26f4ed 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -37,8 +37,7 @@ class iter::impl::CombinatorWithReplacement { public: CombinatorWithReplacement(CombinatorWithReplacement&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -48,6 +47,12 @@ class iter::impl::CombinatorWithReplacement { int steps_; public: + using iterator_category = std::input_iterator_tag; + using value_type = CombIteratorDeref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(ContainerT& in_container, std::size_t n) : container_p_{&in_container}, indices_(n, get_begin(in_container)), diff --git a/compress.hpp b/compress.hpp index 5ebc97ff..60a48244 100644 --- a/compress.hpp +++ b/compress.hpp @@ -33,8 +33,7 @@ class iter::impl::Compressed { public: Compressed(Compressed&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -57,6 +56,12 @@ class iter::impl::Compressed { } public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& cont_iter, IteratorWrapper&& cont_end, IteratorWrapper&& sel_iter, diff --git a/cycle.hpp b/cycle.hpp index c6ee4662..30cbefb0 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -31,8 +31,7 @@ class iter::impl::Cycler { public: Cycler(Cycler&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -41,6 +40,12 @@ class iter::impl::Cycler { IteratorWrapper sub_end_; public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end) : sub_iter_{sub_iter}, diff --git a/dropwhile.hpp b/dropwhile.hpp index 1a23c823..939f696e 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -33,8 +33,7 @@ class iter::impl::Dropper { public: Dropper(Dropper&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -59,6 +58,12 @@ class iter::impl::Dropper { } public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, FilterFunc& filter_func) : sub_iter_{std::move(sub_iter)}, diff --git a/enumerate.hpp b/enumerate.hpp index 05230525..8a7bc97e 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -68,8 +68,7 @@ class iter::impl::Enumerable { // index_. Each call to ++ increments both of these data members. // Each dereference returns an IterYield. template - class Iterator - : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -77,6 +76,12 @@ class iter::impl::Enumerable { Index index_; public: + using iterator_category = std::input_iterator_tag; + using value_type = IterYield; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, Index start) : sub_iter_{std::move(sub_iter)}, index_{start} {} diff --git a/filter.hpp b/filter.hpp index b92c2ce3..a8c04004 100644 --- a/filter.hpp +++ b/filter.hpp @@ -44,8 +44,7 @@ class iter::impl::Filtered { Filtered(Filtered&&) = default; template - class Iterator : public std::iterator> { + class Iterator { protected: template friend class Iterator; @@ -71,6 +70,12 @@ class iter::impl::Filtered { } public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, FilterFunc& filter_func) : sub_iter_{std::move(sub_iter)}, diff --git a/groupby.hpp b/groupby.hpp index 12a0e471..d0d9276b 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -58,8 +58,7 @@ class iter::impl::GroupProducer { public: template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -70,6 +69,12 @@ class iter::impl::GroupProducer { std::unique_ptr> current_key_group_pair_; public: + using iterator_category = std::input_iterator_tag; + using value_type = KeyGroupPair; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, KeyFunc& key_func) : sub_iter_{std::move(sub_iter)}, @@ -208,8 +213,7 @@ class iter::impl::GroupProducer { other.completed = true; } - class GroupIterator : public std::iterator> { + class GroupIterator { private: std::remove_reference_t>* key_; Group* group_p_; @@ -220,6 +224,12 @@ class iter::impl::GroupProducer { } public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + // TODO template this? idk if it's relevant here GroupIterator(Group* group_p, key_func_ret& key) : key_{&key}, group_p_{group_p} {} diff --git a/internal/iteratoriterator.hpp b/internal/iteratoriterator.hpp index 70d63481..af7ceefc 100644 --- a/internal/iteratoriterator.hpp +++ b/internal/iteratoriterator.hpp @@ -23,10 +23,7 @@ namespace iter { : std::true_type {}; template - class IteratorIterator - : public std::iterator())>::type> { + class IteratorIterator { template friend class IteratorIterator; using Diff = std::ptrdiff_t; static_assert( @@ -39,6 +36,11 @@ namespace iter { TopIter sub_iter; public: + using iterator_category = std::random_access_iterator_tag; + using value_type = std::remove_reference_t())>; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; IteratorIterator() = default; IteratorIterator(const TopIter& it) : sub_iter{it} {} diff --git a/permutations.hpp b/permutations.hpp index 39c073e5..40945040 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -38,8 +38,7 @@ class iter::impl::Permuter { Permuter(Permuter&&) = default; template - class Iterator - : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -53,6 +52,12 @@ class iter::impl::Permuter { int steps_{}; public: + using iterator_category = std::input_iterator_tag; + using value_type = Permutable; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end) : steps_{sub_iter != sub_end ? 0 : COMPLETE} { diff --git a/powerset.hpp b/powerset.hpp index 8e5278f4..af270634 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -37,8 +37,7 @@ class iter::impl::Powersetter { Powersetter(Powersetter&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: #if 0 template friend class Iterator; @@ -50,6 +49,12 @@ class iter::impl::Powersetter { iterator_type> comb_end_; public: + using iterator_category = std::input_iterator_tag; + using value_type = CombinatorType; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(ContainerT& container, std::size_t sz) : container_p_{&container}, set_size_{sz}, diff --git a/product.hpp b/product.hpp index 9f4d9dc7..af3deea6 100644 --- a/product.hpp +++ b/product.hpp @@ -50,8 +50,7 @@ class iter::impl::Productor { private: template - class IteratorTempl : public std::iterator> { + class IteratorTempl { private: template friend class IteratorTempl; @@ -62,6 +61,12 @@ class iter::impl::Productor { RestIter rest_end_; public: + using iterator_category = std::input_iterator_tag; + using value_type = ProdIterDeref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + constexpr static const bool is_base_iter = false; IteratorTempl(IteratorWrapper&& sub_iter, RestIter&& rest_iter, RestIter&& rest_end) @@ -144,8 +149,14 @@ template <> class iter::impl::Productor<> { public: Productor(Productor&&) = default; - class Iterator : public std::iterator> { + class Iterator { public: + using iterator_category = std::input_iterator_tag; + using value_type = std::tuple<>; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + constexpr static const bool is_base_iter = true; void reset() {} diff --git a/range.hpp b/range.hpp index 348fd9ab..c71a6854 100644 --- a/range.hpp +++ b/range.hpp @@ -132,8 +132,7 @@ class iter::impl::Range { // of the rules, but std::vector::iterator::reference isn't // a reference type either, this isn't any worse - class Iterator : public std::iterator { + class Iterator { private: iter::detail::RangeIterData data; bool is_end; @@ -166,6 +165,12 @@ class iter::impl::Range { } public: + using iterator_category = std::forward_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + constexpr Iterator() noexcept = default; constexpr Iterator(T in_value, T in_step, bool in_is_end) noexcept diff --git a/repeat.hpp b/repeat.hpp index 1073d750..01739c6c 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -34,12 +34,18 @@ class iter::impl::RepeaterWithCount { public: RepeaterWithCount(RepeaterWithCount&&) = default; - class Iterator : public std::iterator { + class Iterator { private: const TPlain* elem_; int count_; public: + using iterator_category = std::input_iterator_tag; + using value_type = const TPlain; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + constexpr Iterator(const TPlain* e, int c) : elem_{e}, count_{c} {} Iterator& operator++() { @@ -108,11 +114,17 @@ class iter::impl::Repeater { public: Repeater(Repeater&&) = default; - class Iterator : public std::iterator { + class Iterator { private: const TPlain* elem_; public: + using iterator_category = std::input_iterator_tag; + using value_type = const TPlain; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + constexpr Iterator(const TPlain* e) : elem_{e} {} constexpr const Iterator& operator++() const { diff --git a/reversed.hpp b/reversed.hpp index 08517fb7..b76ad801 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -71,14 +71,19 @@ class iter::impl::Reverser { public: Reverser(Reverser&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; ReverseIteratorWrapper sub_iter_; public: + using iterator_category = std::input_iterator_tag; + using value_type = reverse_iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(ReverseIteratorWrapper&& sub_iter) : sub_iter_{std::move(sub_iter)} {} diff --git a/slice.hpp b/slice.hpp index 59ea7885..53114943 100644 --- a/slice.hpp +++ b/slice.hpp @@ -36,8 +36,7 @@ class iter::impl::Sliced { public: Sliced(Sliced&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -48,6 +47,12 @@ class iter::impl::Sliced { DifferenceType step_; public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, DifferenceType start, DifferenceType stop, DifferenceType step) diff --git a/sliding_window.hpp b/sliding_window.hpp index ae478de8..cf843894 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -37,8 +37,7 @@ class iter::impl::WindowSlider { public: WindowSlider(WindowSlider&&) = default; template - class Iterator - : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -46,6 +45,12 @@ class iter::impl::WindowSlider { DerefVec window_; public: + using iterator_category = std::input_iterator_tag; + using value_type = DerefVec; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, std::size_t window_sz) : sub_iter_(std::move(sub_iter)) { diff --git a/starmap.hpp b/starmap.hpp index 27639195..66e2956a 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -44,8 +44,7 @@ class iter::impl::StarMapper { public: template - class Iterator - : public std::iterator { + class Iterator { private: template friend class Iterator; @@ -53,6 +52,12 @@ class iter::impl::StarMapper { IteratorWrapper sub_iter_; public: + using iterator_category = std::input_iterator_tag; + using value_type = StarIterDeref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(Func& f, IteratorWrapper&& sub_iter) : func_(&f), sub_iter_(std::move(sub_iter)) {} @@ -142,8 +147,7 @@ class iter::impl::TupleStarMapper { public: template - class Iterator : public std::iterator::TraitsValue> { + class Iterator { private: template friend class Iterator; @@ -152,6 +156,12 @@ class iter::impl::TupleStarMapper { std::size_t index_; public: + using iterator_category = std::input_iterator_tag; + using value_type = typename IteratorData::TraitsValue; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(Func& f, TupTypeT& t, std::size_t i) : func_{&f}, tup_{&t}, index_{i} {} diff --git a/takewhile.hpp b/takewhile.hpp index ad823b0d..eb0fd801 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -34,8 +34,7 @@ class iter::impl::Taker { Taker(Taker&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -59,6 +58,12 @@ class iter::impl::Taker { } public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, FilterFunc& filter_func) : sub_iter_{std::move(sub_iter)}, diff --git a/zip.hpp b/zip.hpp index 3bb4ccdb..a7f2f19d 100644 --- a/zip.hpp +++ b/zip.hpp @@ -40,14 +40,19 @@ class iter::impl::Zipped { // deref they'd need to be known in the function declarations below. template class IteratorTuple, template class TupleDeref> - class Iterator - : public std::iterator> { + class Iterator { private: template class, template class> friend class Iterator; IteratorTuple iters_; public: + using iterator_category = std::input_iterator_tag; + using value_type = TupleDeref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorTuple&& iters) : iters_(std::move(iters)) {} Iterator& operator++() { diff --git a/zip_longest.hpp b/zip_longest.hpp index eb73aaac..ba6ea3c5 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -49,8 +49,7 @@ class iter::impl::ZippedLongest { ZippedLongest(ZippedLongest&&) = default; template class IterTuple, template class OptTempl> - class Iterator : public std::iterator> { + class Iterator { private: template class, template class> @@ -59,6 +58,12 @@ class iter::impl::ZippedLongest { IterTuple ends_; public: + using iterator_category = std::input_iterator_tag; + using value_type = ZipIterDeref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IterTuple&& iters, IterTuple&& ends) : iters_(std::move(iters)), ends_(std::move(ends)) {} From 2914ce2c8339213ddfd977a66d3b057ec3b52d63 Mon Sep 17 00:00:00 2001 From: Nikolas Vanderhoof Date: Mon, 5 Mar 2018 04:39:15 -0500 Subject: [PATCH 221/403] Fix Range::Iterator::reference Range::Iterator::reference == Range::Iterator::value_type --- range.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/range.hpp b/range.hpp index c71a6854..9287e5f2 100644 --- a/range.hpp +++ b/range.hpp @@ -169,7 +169,7 @@ class iter::impl::Range { using value_type = T; using difference_type = std::ptrdiff_t; using pointer = value_type*; - using reference = value_type&; + using reference = value_type; constexpr Iterator() noexcept = default; From 10b332bc2823a5d2713322f2f73b8fbf19d6c394 Mon Sep 17 00:00:00 2001 From: Nikolas Vanderhoof Date: Sun, 4 Mar 2018 22:19:35 -0500 Subject: [PATCH 222/403] Remove use of std::iterator --- accumulate.hpp | 8 +++++++- chain.hpp | 18 ++++++++++++++---- chunked.hpp | 9 +++++++-- combinations.hpp | 9 +++++++-- combinations_with_replacement.hpp | 9 +++++++-- compress.hpp | 9 +++++++-- cycle.hpp | 9 +++++++-- dropwhile.hpp | 9 +++++++-- enumerate.hpp | 9 +++++++-- filter.hpp | 9 +++++++-- groupby.hpp | 18 ++++++++++++++---- internal/iteratoriterator.hpp | 10 ++++++---- permutations.hpp | 9 +++++++-- powerset.hpp | 9 +++++++-- product.hpp | 17 ++++++++++++++--- range.hpp | 9 +++++++-- repeat.hpp | 16 ++++++++++++++-- reversed.hpp | 9 +++++++-- slice.hpp | 9 +++++++-- sliding_window.hpp | 9 +++++++-- starmap.hpp | 18 ++++++++++++++---- takewhile.hpp | 9 +++++++-- zip.hpp | 9 +++++++-- zip_longest.hpp | 9 +++++++-- 24 files changed, 202 insertions(+), 56 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 7dd27120..f2210847 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -39,7 +39,7 @@ class iter::impl::Accumulator { Accumulator(Accumulator&&) = default; template - class Iterator : public std::iterator { + class Iterator { private: template friend class Iterator; @@ -49,6 +49,12 @@ class iter::impl::Accumulator { std::optional acc_val_; public: + using iterator_category = std::input_iterator_tag; + using value_type = AccumVal; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, AccumulateFunc& accumulate_fun) : sub_iter_{std::move(sub_iter)}, diff --git a/chain.hpp b/chain.hpp index 2430d219..b3c0d5e9 100644 --- a/chain.hpp +++ b/chain.hpp @@ -100,8 +100,7 @@ class iter::impl::Chained { Chained(Chained&&) = default; template - class Iterator : public std::iterator::TraitsValue> { + class Iterator { private: using IterData = IteratorData; std::size_t index_; @@ -116,6 +115,12 @@ class iter::impl::Chained { } public: + using iterator_category = std::input_iterator_tag; + using value_type = typename IteratorData::TraitsValue; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(std::size_t i, typename IterData::IterTupType&& iters, typename IterData::IterTupType&& ends) : index_{i}, iters_(std::move(iters)), ends_(std::move(ends)) { @@ -224,8 +229,7 @@ class iter::impl::ChainedFromIterable { public: ChainedFromIterable(ChainedFromIterable&&) = default; template - class Iterator : public std::iterator>> { + class Iterator { private: template friend class Iterator; @@ -238,6 +242,12 @@ class iter::impl::ChainedFromIterable { std::optional sub_end_p_; public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref>; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& top_iter, IteratorWrapper&& top_end) : top_level_iter_{std::move(top_iter)}, diff --git a/chunked.hpp b/chunked.hpp index 06f0a2aa..33d194d1 100644 --- a/chunked.hpp +++ b/chunked.hpp @@ -41,8 +41,7 @@ class iter::impl::Chunker { public: Chunker(Chunker&&) = default; template - class Iterator - : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -66,6 +65,12 @@ class iter::impl::Chunker { } public: + using iterator_category = std::input_iterator_tag; + using value_type = DerefVec; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, std::size_t s) : sub_iter_{std::move(sub_iter)}, diff --git a/combinations.hpp b/combinations.hpp index 163fa678..afdefe4a 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -37,8 +37,7 @@ class iter::impl::Combinator { public: Combinator(Combinator&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -48,6 +47,12 @@ class iter::impl::Combinator { int steps_{}; public: + using iterator_category = std::input_iterator_tag; + using value_type = CombIteratorDeref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(ContainerT& container, std::size_t n) : container_p_{&container}, indices_{n} { if (n == 0) { diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index cc76e250..5b26f4ed 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -37,8 +37,7 @@ class iter::impl::CombinatorWithReplacement { public: CombinatorWithReplacement(CombinatorWithReplacement&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -48,6 +47,12 @@ class iter::impl::CombinatorWithReplacement { int steps_; public: + using iterator_category = std::input_iterator_tag; + using value_type = CombIteratorDeref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(ContainerT& in_container, std::size_t n) : container_p_{&in_container}, indices_(n, get_begin(in_container)), diff --git a/compress.hpp b/compress.hpp index 5ebc97ff..60a48244 100644 --- a/compress.hpp +++ b/compress.hpp @@ -33,8 +33,7 @@ class iter::impl::Compressed { public: Compressed(Compressed&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -57,6 +56,12 @@ class iter::impl::Compressed { } public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& cont_iter, IteratorWrapper&& cont_end, IteratorWrapper&& sel_iter, diff --git a/cycle.hpp b/cycle.hpp index c6ee4662..30cbefb0 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -31,8 +31,7 @@ class iter::impl::Cycler { public: Cycler(Cycler&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -41,6 +40,12 @@ class iter::impl::Cycler { IteratorWrapper sub_end_; public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end) : sub_iter_{sub_iter}, diff --git a/dropwhile.hpp b/dropwhile.hpp index 1a23c823..939f696e 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -33,8 +33,7 @@ class iter::impl::Dropper { public: Dropper(Dropper&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -59,6 +58,12 @@ class iter::impl::Dropper { } public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, FilterFunc& filter_func) : sub_iter_{std::move(sub_iter)}, diff --git a/enumerate.hpp b/enumerate.hpp index 05230525..8a7bc97e 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -68,8 +68,7 @@ class iter::impl::Enumerable { // index_. Each call to ++ increments both of these data members. // Each dereference returns an IterYield. template - class Iterator - : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -77,6 +76,12 @@ class iter::impl::Enumerable { Index index_; public: + using iterator_category = std::input_iterator_tag; + using value_type = IterYield; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, Index start) : sub_iter_{std::move(sub_iter)}, index_{start} {} diff --git a/filter.hpp b/filter.hpp index b92c2ce3..a8c04004 100644 --- a/filter.hpp +++ b/filter.hpp @@ -44,8 +44,7 @@ class iter::impl::Filtered { Filtered(Filtered&&) = default; template - class Iterator : public std::iterator> { + class Iterator { protected: template friend class Iterator; @@ -71,6 +70,12 @@ class iter::impl::Filtered { } public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, FilterFunc& filter_func) : sub_iter_{std::move(sub_iter)}, diff --git a/groupby.hpp b/groupby.hpp index 8ea482f1..4f4255eb 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -59,8 +59,7 @@ class iter::impl::GroupProducer { public: template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -71,6 +70,12 @@ class iter::impl::GroupProducer { std::optional> current_key_group_pair_; public: + using iterator_category = std::input_iterator_tag; + using value_type = KeyGroupPair; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, KeyFunc& key_func) : sub_iter_{std::move(sub_iter)}, @@ -209,8 +214,7 @@ class iter::impl::GroupProducer { other.completed = true; } - class GroupIterator : public std::iterator> { + class GroupIterator { private: std::remove_reference_t>* key_; Group* group_p_; @@ -221,6 +225,12 @@ class iter::impl::GroupProducer { } public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + // TODO template this? idk if it's relevant here GroupIterator(Group* group_p, key_func_ret& key) : key_{&key}, group_p_{group_p} {} diff --git a/internal/iteratoriterator.hpp b/internal/iteratoriterator.hpp index cfddac5b..87ed74d1 100644 --- a/internal/iteratoriterator.hpp +++ b/internal/iteratoriterator.hpp @@ -23,10 +23,7 @@ namespace iter { : std::true_type {}; template - class IteratorIterator - : public std::iterator())>::type> { + class IteratorIterator { template friend class IteratorIterator; using Diff = std::ptrdiff_t; static_assert( @@ -39,6 +36,11 @@ namespace iter { TopIter sub_iter; public: + using iterator_category = std::random_access_iterator_tag; + using value_type = std::remove_reference_t())>; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; IteratorIterator() = default; IteratorIterator(const TopIter& it) : sub_iter{it} {} diff --git a/permutations.hpp b/permutations.hpp index 39c073e5..40945040 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -38,8 +38,7 @@ class iter::impl::Permuter { Permuter(Permuter&&) = default; template - class Iterator - : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -53,6 +52,12 @@ class iter::impl::Permuter { int steps_{}; public: + using iterator_category = std::input_iterator_tag; + using value_type = Permutable; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end) : steps_{sub_iter != sub_end ? 0 : COMPLETE} { diff --git a/powerset.hpp b/powerset.hpp index 8e5278f4..af270634 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -37,8 +37,7 @@ class iter::impl::Powersetter { Powersetter(Powersetter&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: #if 0 template friend class Iterator; @@ -50,6 +49,12 @@ class iter::impl::Powersetter { iterator_type> comb_end_; public: + using iterator_category = std::input_iterator_tag; + using value_type = CombinatorType; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(ContainerT& container, std::size_t sz) : container_p_{&container}, set_size_{sz}, diff --git a/product.hpp b/product.hpp index 9f4d9dc7..af3deea6 100644 --- a/product.hpp +++ b/product.hpp @@ -50,8 +50,7 @@ class iter::impl::Productor { private: template - class IteratorTempl : public std::iterator> { + class IteratorTempl { private: template friend class IteratorTempl; @@ -62,6 +61,12 @@ class iter::impl::Productor { RestIter rest_end_; public: + using iterator_category = std::input_iterator_tag; + using value_type = ProdIterDeref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + constexpr static const bool is_base_iter = false; IteratorTempl(IteratorWrapper&& sub_iter, RestIter&& rest_iter, RestIter&& rest_end) @@ -144,8 +149,14 @@ template <> class iter::impl::Productor<> { public: Productor(Productor&&) = default; - class Iterator : public std::iterator> { + class Iterator { public: + using iterator_category = std::input_iterator_tag; + using value_type = std::tuple<>; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + constexpr static const bool is_base_iter = true; void reset() {} diff --git a/range.hpp b/range.hpp index 145cdfab..ee1fbba9 100644 --- a/range.hpp +++ b/range.hpp @@ -128,8 +128,7 @@ class iter::impl::Range { // of the rules, but std::vector::iterator::reference isn't // a reference type either, this isn't any worse - class Iterator : public std::iterator { + class Iterator { private: iter::detail::RangeIterData data; bool is_end; @@ -160,6 +159,12 @@ class iter::impl::Range { } public: + using iterator_category = std::forward_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + constexpr Iterator() noexcept = default; constexpr Iterator(T in_value, T in_step, bool in_is_end) noexcept diff --git a/repeat.hpp b/repeat.hpp index 1073d750..01739c6c 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -34,12 +34,18 @@ class iter::impl::RepeaterWithCount { public: RepeaterWithCount(RepeaterWithCount&&) = default; - class Iterator : public std::iterator { + class Iterator { private: const TPlain* elem_; int count_; public: + using iterator_category = std::input_iterator_tag; + using value_type = const TPlain; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + constexpr Iterator(const TPlain* e, int c) : elem_{e}, count_{c} {} Iterator& operator++() { @@ -108,11 +114,17 @@ class iter::impl::Repeater { public: Repeater(Repeater&&) = default; - class Iterator : public std::iterator { + class Iterator { private: const TPlain* elem_; public: + using iterator_category = std::input_iterator_tag; + using value_type = const TPlain; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + constexpr Iterator(const TPlain* e) : elem_{e} {} constexpr const Iterator& operator++() const { diff --git a/reversed.hpp b/reversed.hpp index 08517fb7..b76ad801 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -71,14 +71,19 @@ class iter::impl::Reverser { public: Reverser(Reverser&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; ReverseIteratorWrapper sub_iter_; public: + using iterator_category = std::input_iterator_tag; + using value_type = reverse_iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(ReverseIteratorWrapper&& sub_iter) : sub_iter_{std::move(sub_iter)} {} diff --git a/slice.hpp b/slice.hpp index 59ea7885..53114943 100644 --- a/slice.hpp +++ b/slice.hpp @@ -36,8 +36,7 @@ class iter::impl::Sliced { public: Sliced(Sliced&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -48,6 +47,12 @@ class iter::impl::Sliced { DifferenceType step_; public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, DifferenceType start, DifferenceType stop, DifferenceType step) diff --git a/sliding_window.hpp b/sliding_window.hpp index ae478de8..cf843894 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -37,8 +37,7 @@ class iter::impl::WindowSlider { public: WindowSlider(WindowSlider&&) = default; template - class Iterator - : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -46,6 +45,12 @@ class iter::impl::WindowSlider { DerefVec window_; public: + using iterator_category = std::input_iterator_tag; + using value_type = DerefVec; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, std::size_t window_sz) : sub_iter_(std::move(sub_iter)) { diff --git a/starmap.hpp b/starmap.hpp index e83fbb24..371f2ffe 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -44,8 +44,7 @@ class iter::impl::StarMapper { public: template - class Iterator - : public std::iterator { + class Iterator { private: template friend class Iterator; @@ -53,6 +52,12 @@ class iter::impl::StarMapper { IteratorWrapper sub_iter_; public: + using iterator_category = std::input_iterator_tag; + using value_type = StarIterDeref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(Func& f, IteratorWrapper&& sub_iter) : func_(&f), sub_iter_(std::move(sub_iter)) {} @@ -142,8 +147,7 @@ class iter::impl::TupleStarMapper { public: template - class Iterator : public std::iterator::TraitsValue> { + class Iterator { private: template friend class Iterator; @@ -152,6 +156,12 @@ class iter::impl::TupleStarMapper { std::size_t index_; public: + using iterator_category = std::input_iterator_tag; + using value_type = typename IteratorData::TraitsValue; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(Func& f, TupTypeT& t, std::size_t i) : func_{&f}, tup_{&t}, index_{i} {} diff --git a/takewhile.hpp b/takewhile.hpp index ad823b0d..eb0fd801 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -34,8 +34,7 @@ class iter::impl::Taker { Taker(Taker&&) = default; template - class Iterator : public std::iterator> { + class Iterator { private: template friend class Iterator; @@ -59,6 +58,12 @@ class iter::impl::Taker { } public: + using iterator_category = std::input_iterator_tag; + using value_type = iterator_traits_deref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, FilterFunc& filter_func) : sub_iter_{std::move(sub_iter)}, diff --git a/zip.hpp b/zip.hpp index 3bb4ccdb..a7f2f19d 100644 --- a/zip.hpp +++ b/zip.hpp @@ -40,14 +40,19 @@ class iter::impl::Zipped { // deref they'd need to be known in the function declarations below. template class IteratorTuple, template class TupleDeref> - class Iterator - : public std::iterator> { + class Iterator { private: template class, template class> friend class Iterator; IteratorTuple iters_; public: + using iterator_category = std::input_iterator_tag; + using value_type = TupleDeref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IteratorTuple&& iters) : iters_(std::move(iters)) {} Iterator& operator++() { diff --git a/zip_longest.hpp b/zip_longest.hpp index eb73aaac..ba6ea3c5 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -49,8 +49,7 @@ class iter::impl::ZippedLongest { ZippedLongest(ZippedLongest&&) = default; template class IterTuple, template class OptTempl> - class Iterator : public std::iterator> { + class Iterator { private: template class, template class> @@ -59,6 +58,12 @@ class iter::impl::ZippedLongest { IterTuple ends_; public: + using iterator_category = std::input_iterator_tag; + using value_type = ZipIterDeref; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + Iterator(IterTuple&& iters, IterTuple&& ends) : iters_(std::move(iters)), ends_(std::move(ends)) {} From e0d1213f7ef18152ce1d633f6e1e1752563e07d7 Mon Sep 17 00:00:00 2001 From: Nikolas Vanderhoof Date: Mon, 5 Mar 2018 04:39:15 -0500 Subject: [PATCH 223/403] Fix Range::Iterator::reference Range::Iterator::reference == Range::Iterator::value_type --- range.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/range.hpp b/range.hpp index ee1fbba9..8a9a4791 100644 --- a/range.hpp +++ b/range.hpp @@ -163,7 +163,7 @@ class iter::impl::Range { using value_type = T; using difference_type = std::ptrdiff_t; using pointer = value_type*; - using reference = value_type&; + using reference = value_type; constexpr Iterator() noexcept = default; From c12a8bc9078447028b27c67b1a699502037f79ba Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 14:57:00 -0400 Subject: [PATCH 224/403] Remove using declarations for as_const and void_t They were in there to avoid conflict with c++14. --- accumulate.hpp | 8 ++++---- chain.hpp | 16 ++++++++-------- chunked.hpp | 8 ++++---- combinations.hpp | 4 ++-- combinations_with_replacement.hpp | 4 ++-- compress.hpp | 16 ++++++++-------- cycle.hpp | 8 ++++---- dropwhile.hpp | 8 ++++---- enumerate.hpp | 4 ++-- filter.hpp | 8 ++++---- groupby.hpp | 8 ++++---- internal/iterbase.hpp | 7 +------ permutations.hpp | 8 ++++---- powerset.hpp | 4 ++-- product.hpp | 12 ++++++------ reversed.hpp | 4 ++-- slice.hpp | 10 +++++----- sliding_window.hpp | 10 +++++----- sorted.hpp | 6 +++--- starmap.hpp | 8 ++++---- takewhile.hpp | 8 ++++---- zip.hpp | 4 ++-- zip_longest.hpp | 8 ++++---- 23 files changed, 88 insertions(+), 93 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index f2210847..9d431dc4 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -106,13 +106,13 @@ class iter::impl::Accumulator { return {get_end(container_), get_end(container_), accumulate_func_}; } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), - get_end(impl::as_const(container_)), accumulate_func_}; + return {get_begin(std::as_const(container_)), + get_end(std::as_const(container_)), accumulate_func_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), - get_end(impl::as_const(container_)), accumulate_func_}; + return {get_end(std::as_const(container_)), + get_end(std::as_const(container_)), accumulate_func_}; } }; diff --git a/chain.hpp b/chain.hpp index b3c0d5e9..fcdfef7f 100644 --- a/chain.hpp +++ b/chain.hpp @@ -175,17 +175,17 @@ class iter::impl::Chained { Iterator> begin() const { return {0, typename IteratorData>::IterTupType{get_begin( - impl::as_const(std::get(tup_)))...}, + std::as_const(std::get(tup_)))...}, typename IteratorData>::IterTupType{ - get_end(impl::as_const(std::get(tup_)))...}}; + get_end(std::as_const(std::get(tup_)))...}}; } Iterator> end() const { return {sizeof...(Is), typename IteratorData>::IterTupType{ - get_end(impl::as_const(std::get(tup_)))...}, + get_end(std::as_const(std::get(tup_)))...}, typename IteratorData>::IterTupType{ - get_end(impl::as_const(std::get(tup_)))...}}; + get_end(std::as_const(std::get(tup_)))...}}; } }; @@ -311,13 +311,13 @@ class iter::impl::ChainedFromIterable { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), - get_end(impl::as_const(container_))}; + return {get_begin(std::as_const(container_)), + get_end(std::as_const(container_))}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), - get_end(impl::as_const(container_))}; + return {get_end(std::as_const(container_)), + get_end(std::as_const(container_))}; } }; diff --git a/chunked.hpp b/chunked.hpp index 33d194d1..87f0a0de 100644 --- a/chunked.hpp +++ b/chunked.hpp @@ -120,13 +120,13 @@ class iter::impl::Chunker { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), - get_end(impl::as_const(container_)), chunk_size_}; + return {get_begin(std::as_const(container_)), + get_end(std::as_const(container_)), chunk_size_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), - get_end(impl::as_const(container_)), chunk_size_}; + return {get_end(std::as_const(container_)), + get_end(std::as_const(container_)), chunk_size_}; } }; diff --git a/combinations.hpp b/combinations.hpp index afdefe4a..bfee2c86 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -141,11 +141,11 @@ class iter::impl::Combinator { } Iterator> begin() const { - return {impl::as_const(container_), length_}; + return {std::as_const(container_), length_}; } Iterator> end() const { - return {impl::as_const(container_), 0}; + return {std::as_const(container_), 0}; } }; diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 5b26f4ed..5455a6e4 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -120,11 +120,11 @@ class iter::impl::CombinatorWithReplacement { } Iterator> begin() const { - return {impl::as_const(container_), length_}; + return {std::as_const(container_), length_}; } Iterator> end() const { - return {impl::as_const(container_), 0}; + return {std::as_const(container_), 0}; } }; diff --git a/compress.hpp b/compress.hpp index 60a48244..f4606ef8 100644 --- a/compress.hpp +++ b/compress.hpp @@ -116,17 +116,17 @@ class iter::impl::Compressed { } Iterator, AsConst> begin() const { - return {get_begin(impl::as_const(container_)), - get_end(impl::as_const(container_)), - get_begin(impl::as_const(selectors_)), - get_end(impl::as_const(selectors_))}; + return {get_begin(std::as_const(container_)), + get_end(std::as_const(container_)), + get_begin(std::as_const(selectors_)), + get_end(std::as_const(selectors_))}; } Iterator, AsConst> end() const { - return {get_end(impl::as_const(container_)), - get_end(impl::as_const(container_)), - get_end(impl::as_const(selectors_)), - get_end(impl::as_const(selectors_))}; + return {get_end(std::as_const(container_)), + get_end(std::as_const(container_)), + get_end(std::as_const(selectors_)), + get_end(std::as_const(selectors_))}; } }; diff --git a/cycle.hpp b/cycle.hpp index 30cbefb0..1d3ecaef 100644 --- a/cycle.hpp +++ b/cycle.hpp @@ -95,13 +95,13 @@ class iter::impl::Cycler { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), - get_end(impl::as_const(container_))}; + return {get_begin(std::as_const(container_)), + get_end(std::as_const(container_))}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), - get_end(impl::as_const(container_))}; + return {get_end(std::as_const(container_)), + get_end(std::as_const(container_))}; } }; diff --git a/dropwhile.hpp b/dropwhile.hpp index 939f696e..d4ac6594 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -114,13 +114,13 @@ class iter::impl::Dropper { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), - get_end(impl::as_const(container_)), filter_func_}; + return {get_begin(std::as_const(container_)), + get_end(std::as_const(container_)), filter_func_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), - get_end(impl::as_const(container_)), filter_func_}; + return {get_end(std::as_const(container_)), + get_end(std::as_const(container_)), filter_func_}; } }; diff --git a/enumerate.hpp b/enumerate.hpp index 8a7bc97e..b36a0103 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -125,11 +125,11 @@ class iter::impl::Enumerable { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), start_}; + return {get_begin(std::as_const(container_)), start_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), start_}; + return {get_end(std::as_const(container_)), start_}; } }; #endif diff --git a/filter.hpp b/filter.hpp index a8c04004..2187b46c 100644 --- a/filter.hpp +++ b/filter.hpp @@ -127,13 +127,13 @@ class iter::impl::Filtered { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), - get_end(impl::as_const(container_)), filter_func_}; + return {get_begin(std::as_const(container_)), + get_end(std::as_const(container_)), filter_func_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), - get_end(impl::as_const(container_)), filter_func_}; + return {get_end(std::as_const(container_)), + get_end(std::as_const(container_)), filter_func_}; } }; diff --git a/groupby.hpp b/groupby.hpp index 4f4255eb..7cf00b4e 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -285,13 +285,13 @@ class iter::impl::GroupProducer { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), - get_end(impl::as_const(container_)), key_func_}; + return {get_begin(std::as_const(container_)), + get_end(std::as_const(container_)), key_func_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), - get_end(impl::as_const(container_)), key_func_}; + return {get_end(std::as_const(container_)), + get_end(std::as_const(container_)), key_func_}; } }; diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 7ddc1c2a..60e31517 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -47,13 +47,8 @@ namespace iter { using type = T; }; - // TODO get rid of these and explicitly use std:: everywhere once master is - // on C++17 - using std::as_const; - using std::void_t; - template - using AsConst = decltype(impl::as_const(std::declval())); + using AsConst = decltype(std::as_const(std::declval())); // iterator_type is the type of C's iterator template diff --git a/permutations.hpp b/permutations.hpp index 40945040..e10872d4 100644 --- a/permutations.hpp +++ b/permutations.hpp @@ -115,13 +115,13 @@ class iter::impl::Permuter { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), - get_end(impl::as_const(container_))}; + return {get_begin(std::as_const(container_)), + get_end(std::as_const(container_))}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), - get_end(impl::as_const(container_))}; + return {get_end(std::as_const(container_)), + get_end(std::as_const(container_))}; } }; diff --git a/powerset.hpp b/powerset.hpp index af270634..3439069d 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -119,12 +119,12 @@ class iter::impl::Powersetter { } Iterator> begin() const { - return {impl::as_const(container_), 0}; + return {std::as_const(container_), 0}; } Iterator> end() const { return { - impl::as_const(container_), dumb_size(impl::as_const(container_)) + 1}; + std::as_const(container_), dumb_size(std::as_const(container_)) + 1}; } }; diff --git a/product.hpp b/product.hpp index af3deea6..74671462 100644 --- a/product.hpp +++ b/product.hpp @@ -133,15 +133,15 @@ class iter::impl::Productor { } ConstIterator begin() const { - return {get_begin(impl::as_const(container_)), - get_begin(impl::as_const(rest_products_)), - get_end(impl::as_const(rest_products_))}; + return {get_begin(std::as_const(container_)), + get_begin(std::as_const(rest_products_)), + get_end(std::as_const(rest_products_))}; } ConstIterator end() const { - return {get_end(impl::as_const(container_)), - get_end(impl::as_const(rest_products_)), - get_end(impl::as_const(rest_products_))}; + return {get_end(std::as_const(container_)), + get_end(std::as_const(rest_products_)), + get_end(std::as_const(rest_products_))}; } }; diff --git a/reversed.hpp b/reversed.hpp index b76ad801..fcf04d27 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -126,11 +126,11 @@ class iter::impl::Reverser { } Iterator> begin() const { - return {std::rbegin(impl::as_const(container_))}; + return {std::rbegin(std::as_const(container_))}; } Iterator> end() const { - return {std::rend(impl::as_const(container_))}; + return {std::rend(std::as_const(container_))}; } }; diff --git a/slice.hpp b/slice.hpp index 53114943..22855645 100644 --- a/slice.hpp +++ b/slice.hpp @@ -107,15 +107,15 @@ class iter::impl::Sliced { } Iterator> begin() const { - auto it = get_begin(impl::as_const(container_)); - dumb_advance(it, get_end(impl::as_const(container_)), start_); - return {std::move(it), get_end(impl::as_const(container_)), start_, stop_, + auto it = get_begin(std::as_const(container_)); + dumb_advance(it, get_end(std::as_const(container_)), start_); + return {std::move(it), get_end(std::as_const(container_)), start_, stop_, step_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), - get_end(impl::as_const(container_)), stop_, stop_, step_}; + return {get_end(std::as_const(container_)), + get_end(std::as_const(container_)), stop_, stop_, step_}; } }; diff --git a/sliding_window.hpp b/sliding_window.hpp index cf843894..fcb41e00 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -109,15 +109,15 @@ class iter::impl::WindowSlider { Iterator> begin() const { return {(window_size_ != 0 ? IteratorWrapper>{get_begin( - impl::as_const(container_))} + std::as_const(container_))} : IteratorWrapper>{get_end( - impl::as_const(container_))}), - get_end(impl::as_const(container_)), window_size_}; + std::as_const(container_))}), + get_end(std::as_const(container_)), window_size_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), - get_end(impl::as_const(container_)), window_size_}; + return {get_end(std::as_const(container_)), + get_end(std::as_const(container_)), window_size_}; } }; diff --git a/sorted.hpp b/sorted.hpp index 24701488..a45cc75c 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -61,7 +61,7 @@ class iter::impl::SortedView { template class SortedItersHolder&>()))>> { + std::void_t&>()))>> { public: using IterIterWrap = IterIterWrapper>>; @@ -101,8 +101,8 @@ class iter::impl::SortedView { if (!const_sorted_iters_.empty()) { return; } - for (auto iter = get_begin(impl::as_const(container_)); - iter != get_end(impl::as_const(container_)); ++iter) { + for (auto iter = get_begin(std::as_const(container_)); + iter != get_end(std::as_const(container_)); ++iter) { const_sorted_iters_.get().push_back(iter); } diff --git a/starmap.hpp b/starmap.hpp index 371f2ffe..384bf8f3 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -100,11 +100,11 @@ class iter::impl::StarMapper { } Iterator> begin() const { - return {func_, get_begin(impl::as_const(container_))}; + return {func_, get_begin(std::as_const(container_))}; } Iterator> end() const { - return {func_, get_end(impl::as_const(container_))}; + return {func_, get_end(std::as_const(container_))}; } }; @@ -204,11 +204,11 @@ class iter::impl::TupleStarMapper { } Iterator> begin() const { - return {func_, impl::as_const(tup_), 0}; + return {func_, std::as_const(tup_), 0}; } Iterator> end() const { - return {func_, impl::as_const(tup_), sizeof...(Is)}; + return {func_, std::as_const(tup_), sizeof...(Is)}; } }; diff --git a/takewhile.hpp b/takewhile.hpp index eb0fd801..e4b3f001 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -115,13 +115,13 @@ class iter::impl::Taker { } Iterator> begin() const { - return {get_begin(impl::as_const(container_)), - get_end(impl::as_const(container_)), filter_func_}; + return {get_begin(std::as_const(container_)), + get_end(std::as_const(container_)), filter_func_}; } Iterator> end() const { - return {get_end(impl::as_const(container_)), - get_end(impl::as_const(container_)), filter_func_}; + return {get_end(std::as_const(container_)), + get_end(std::as_const(container_)), filter_func_}; } }; diff --git a/zip.hpp b/zip.hpp index a7f2f19d..6cd26351 100644 --- a/zip.hpp +++ b/zip.hpp @@ -106,14 +106,14 @@ class iter::impl::Zipped { const_iterator_deref_tuple> begin() const { return {const_iterator_tuple_type>{ - get_begin(impl::as_const(std::get(containers_)))...}}; + get_begin(std::as_const(std::get(containers_)))...}}; } Iterator, const_iterator_tuple_type, const_iterator_deref_tuple> end() const { return {const_iterator_tuple_type>{ - get_end(impl::as_const(std::get(containers_)))...}}; + get_end(std::as_const(std::get(containers_)))...}}; } }; diff --git a/zip_longest.hpp b/zip_longest.hpp index ba6ea3c5..c73383c6 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -126,17 +126,17 @@ class iter::impl::ZippedLongest { Iterator, const_iterator_tuple_type, ConstOptType> begin() const { return {const_iterator_tuple_type>{ - get_begin(impl::as_const(std::get(containers_)))...}, + get_begin(std::as_const(std::get(containers_)))...}, const_iterator_tuple_type>{ - get_end(impl::as_const(std::get(containers_)))...}}; + get_end(std::as_const(std::get(containers_)))...}}; } Iterator, const_iterator_tuple_type, ConstOptType> end() const { return {const_iterator_tuple_type>{ - get_end(impl::as_const(std::get(containers_)))...}, + get_end(std::as_const(std::get(containers_)))...}, const_iterator_tuple_type>{ - get_end(impl::as_const(std::get(containers_)))...}}; + get_end(std::as_const(std::get(containers_)))...}}; } }; From 16d996e8677ff14daf776b507bf3306836cb4f45 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 15:38:27 -0400 Subject: [PATCH 225/403] Tests imap with pointer-to-member --- test/test_imap.cpp | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/test/test_imap.cpp b/test/test_imap.cpp index db37d3f5..b2be404d 100644 --- a/test/test_imap.cpp +++ b/test/test_imap.cpp @@ -61,6 +61,38 @@ TEST_CASE("imap: works with lambda, callable, and function", "[imap]") { REQUIRE(v == vc); } +TEST_CASE("imap: works with pointer to member", "[imap]") { + using itertest::Point; + std::vector ps = {{3, 6}, {20, 25}}; + std::vector v; + SECTION("with pointer to member function") { + auto im = imap(&Point::get_y, ps); + v.assign(std::begin(im), std::end(im)); + } + + SECTION("with pointer to data member") { + auto im = imap(&Point::y, ps); + v.assign(std::begin(im), std::end(im)); + } + + Vec vc = {6, 25}; + REQUIRE(v == vc); +} + +TEST_CASE("imap: works with pointer to member function taking argument") { + using itertest::Point; + std::vector ps = {{10, 20}, {6, 8}, {3, 15}}; + std::vector strs = {"a", "point", "pos"}; + + auto im = imap(&Point::prefix, ps, strs); + + std::vector v(std::begin(im), std::end(im)); + const std::vector vc = { + "a(10, 20)", "point(6, 8)", "pos(3, 15)"}; + + REQUIRE(v == vc); +} + // TODO enable once zip supports const #if 0 TEST_CASE("imap: supports const iteration", "[imap][const]") { @@ -77,7 +109,6 @@ TEST_CASE("imap: const iterators can be compared to non-const iterators", "[imap (void)(std::begin(m) == std::end(cm)); } #endif - TEST_CASE("imap: Works with different begin and end types", "[imap]") { CharRange cr{'d'}; From 2337c507e28efc2710e138bdcd536634025e292a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 15:39:14 -0400 Subject: [PATCH 226/403] Tests starmap with pointer-to-member --- test/test_starmap.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/test_starmap.cpp b/test/test_starmap.cpp index 210694f5..bb98a349 100644 --- a/test/test_starmap.cpp +++ b/test/test_starmap.cpp @@ -61,6 +61,17 @@ TEST_CASE("starmap: works with function pointer and lambda", "[starmap]") { REQUIRE(v == vc); } +TEST_CASE("starmap: works with pointer to member function", "[starmap]") { + using itertest::Point; + std::vector> tup = { + {{10, 20}, "a"}, {{6, 8}, "point"}, {{3, 15}, "pos"}}; + auto sm = starmap(&Point::prefix, tup); + std::vector v(std::begin(sm), std::end(sm)); + const std::vector vc = { + "a(10, 20)", "point(6, 8)", "pos(3, 15)"}; + REQUIRE(v == vc); +} + TEST_CASE("starmap: vector of pairs const iteration", "[starmap][const]") { using Vec = const std::vector; const std::vector> v1 = {{1l, 2}, {3l, 11}, {6l, 7}}; From a68bc082e7e44454aed6f0f77f191e66ae6dbcd9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 15:43:17 -0400 Subject: [PATCH 227/403] Adds Point for testing --- test/helpers.hpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/test/helpers.hpp b/test/helpers.hpp index 1a65f9e3..584c540e 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -3,6 +3,7 @@ #include +#include #include #include #include @@ -111,8 +112,7 @@ namespace itertest { : data{new T[other.size]}, size{other.size} { other.was_copied_from_ = true; auto o_it = begin(other); - for (auto it = begin(*this); o_it != end(other); - ++it, ++o_it) { + for (auto it = begin(*this); o_it != end(other); ++it, ++o_it) { *it = *o_it; } } @@ -211,6 +211,23 @@ namespace itertest { && !std::is_copy_assignable::value && !std::is_move_assignable::value && std::is_move_constructible::value> {}; + + struct Point { + int x; + int y; + int get_x() const { + return x; + } + int get_y() const { + return y; + } + + std::string prefix(const std::string& str) { + std::ostringstream ss; + ss << str << "(" << x << ", " << y << ")"; + return ss.str(); + } + }; } template class DiffEndRange { From 17ad9774852ed19e813a04db078d3e8d57973f84 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 15:45:34 -0400 Subject: [PATCH 228/403] Uses std::invoke is call_with_tuple This lets imap and starmap support pointer to member function and pointer to data member arguments. --- internal/iter_tuples.hpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/internal/iter_tuples.hpp b/internal/iter_tuples.hpp index 99fdfffe..5b3a5cda 100644 --- a/internal/iter_tuples.hpp +++ b/internal/iter_tuples.hpp @@ -4,6 +4,8 @@ #include "iterator_wrapper.hpp" #include "iterbase.hpp" +#include + namespace iter { namespace impl { namespace detail { @@ -54,8 +56,9 @@ namespace iter { template decltype(auto) call_with_tuple_impl( Func&& mf, TupleType&& tup, std::index_sequence) { - return mf(std::forward>>(std::get(tup))...); + return std::invoke( + mf, std::forward>>(std::get(tup))...); } } From 38dc638b9deabe7482fa9673eb7e6e21a81197b3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 18:28:08 -0400 Subject: [PATCH 229/403] Tests filter with pointer to member --- test/test_filter.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/test_filter.cpp b/test/test_filter.cpp index 62b5f9a1..73f684ee 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -53,6 +53,24 @@ TEST_CASE("filter: handles different callable types", "[filter]") { } } +TEST_CASE("filter: handles pointer to member", "[filter]") { + using itertest::Point; + const std::vector ps = {{0, 3}, {4, 0}, {0, 1}, {-1, -1}}; + std::vector v; + SECTION("with pointer to data member") { + auto f = filter(&Point::x, ps); + v.assign(std::begin(f), std::end(f)); + } + + SECTION("with pointer to member function") { + auto f = filter(&Point::get_x, ps); + v.assign(std::begin(f), std::end(f)); + } + + const std::vector vc = {{4, 0}, {-1, -1}}; + REQUIRE(v == vc); +} + TEST_CASE("filter: const iteration", "[filter][const]") { Vec ns = {1, 2, 5, 6, 3, 1, 7, -1, 5}; const auto f = filter(LessThanValue{5}, ns); From 0ce5d03131ce04cf27a45ef21dfcf299a72b1bee Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 18:28:39 -0400 Subject: [PATCH 230/403] Adds == and != operators to Point --- test/helpers.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/helpers.hpp b/test/helpers.hpp index 584c540e..65d856d8 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -227,6 +227,14 @@ namespace itertest { ss << str << "(" << x << ", " << y << ")"; return ss.str(); } + + bool operator==(Point other) const { + return x == other.x && y == other.y; + } + + bool operator!=(Point other) const { + return !(*this == other); + } }; } template From 374cfbc2d86758dc7dadf9821870ac734b82e99b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 18:33:23 -0400 Subject: [PATCH 231/403] Uses std::invoke in filter To support pointer-to-member --- filter.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/filter.hpp b/filter.hpp index 2187b46c..0676917b 100644 --- a/filter.hpp +++ b/filter.hpp @@ -4,6 +4,7 @@ #include "internal/iterator_wrapper.hpp" #include "internal/iterbase.hpp" +#include #include #include #include @@ -64,7 +65,8 @@ class iter::impl::Filtered { // increment until the iterator points to is true on the // predicate. Called by constructor and operator++ void skip_failures() { - while (sub_iter_ != sub_end_ && !(*filter_func_)(item_.get())) { + while ( + sub_iter_ != sub_end_ && !std::invoke(*filter_func_, item_.get())) { inc_sub_iter(); } } From 001eaaf19ba746a99646b58e4bafce57c2af7ba9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 18:41:23 -0400 Subject: [PATCH 232/403] Makes Point printable by catch --- test/helpers.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/helpers.hpp b/test/helpers.hpp index 65d856d8..ec0180cf 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -3,6 +3,7 @@ #include +#include #include #include #include @@ -222,7 +223,7 @@ namespace itertest { return y; } - std::string prefix(const std::string& str) { + std::string prefix(const std::string& str) const { std::ostringstream ss; ss << str << "(" << x << ", " << y << ")"; return ss.str(); @@ -235,6 +236,10 @@ namespace itertest { bool operator!=(Point other) const { return !(*this == other); } + + friend std::ostream& operator<<(std::ostream& out, const Point& p) { + return out << p.prefix(""); + } }; } template From e70b220026c303cf981fa2bd7b4562560a1061f1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 18:42:19 -0400 Subject: [PATCH 233/403] Tests filterfalse with pointer to member --- test/test_filterfalse.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/test_filterfalse.cpp b/test/test_filterfalse.cpp index 9e230ee1..7a74a0df 100644 --- a/test/test_filterfalse.cpp +++ b/test/test_filterfalse.cpp @@ -60,6 +60,24 @@ TEST_CASE("filterfalse: handles different callable types", "[filterfalse]") { } } +TEST_CASE("filterfalse: handles pointer to member", "[filterfalse]") { + using itertest::Point; + const std::vector ps = {{0, 3}, {4, 0}, {0, 1}, {-1, -1}}; + std::vector v; + SECTION("with pointer to data member") { + auto f = filterfalse(&Point::x, ps); + v.assign(std::begin(f), std::end(f)); + } + + SECTION("with pointer to member function") { + auto f = filterfalse(&Point::get_x, ps); + v.assign(std::begin(f), std::end(f)); + } + + const std::vector vc = {{0, 3}, {0, 1}}; + REQUIRE(v == vc); +} + TEST_CASE("filterfalse: const iteration", "[filterfalse][const]") { Vec ns = {1, 2, 5, 6, 3, 1, 7, -1, 5}; const auto f = filterfalse(LessThanValue{5}, ns); From 2eb21d34a5451bb87bd4ea8ff967eb8b57b5a39e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 18:42:46 -0400 Subject: [PATCH 234/403] Uses std::invoke in filterfalse To support pointer to member --- filterfalse.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/filterfalse.hpp b/filterfalse.hpp index 9de7a3df..f0f22628 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -4,6 +4,7 @@ #include "filter.hpp" #include "internal/iterbase.hpp" +#include #include namespace iter { @@ -22,13 +23,13 @@ namespace iter { // Calls the filter_func_ template bool operator()(const T& item) const { - return !bool(filter_func_(item)); + return !bool(std::invoke(filter_func_, item)); } // with non-const incase FilterFunc::operator() is non-const template bool operator()(const T& item) { - return !bool(filter_func_(item)); + return !bool(std::invoke(filter_func_, item)); } }; From 11f476fd39692ba3a55636c5b6dbe84961c1765f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 18:46:53 -0400 Subject: [PATCH 235/403] filterfalse example to print non-empty strings --- examples/filterfalse_examples.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/filterfalse_examples.cpp b/examples/filterfalse_examples.cpp index 772005a8..f03debfa 100644 --- a/examples/filterfalse_examples.cpp +++ b/examples/filterfalse_examples.cpp @@ -26,4 +26,10 @@ int main() { for (auto&& i : iter::filterfalse(ns)) { std::cout << i << '\n'; } + + // only print non-empty strings + std::vector words {"hello", "", "", "world", "", "goodbye", ""}; + for (auto&& s : iter::filterfalse(&std::string::empty, words)) { + std::cout << s << '\n'; + } } From 5dd671957fc738a6e55291764702a628d034653b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 18:57:49 -0400 Subject: [PATCH 236/403] Tests dropwhile with pointer to member --- test/test_dropwhile.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/test_dropwhile.cpp b/test/test_dropwhile.cpp index 1b4edcb5..38e686aa 100644 --- a/test/test_dropwhile.cpp +++ b/test/test_dropwhile.cpp @@ -41,6 +41,33 @@ TEST_CASE("dropwhile: skips initial elements", "[dropwhile]") { REQUIRE(v == vc); } +TEST_CASE("dropwhile: handles pointer to member", "[dropwhile]") { + using itertest::Point; + const std::vector ps = { + {5, 0}, {3, 5}, {2, 1}, {0, 1}, {2, 2}, {6, 0}}; + std::vector v; + SECTION("with pointer to data member") { + auto dw = dropwhile(&Point::x, ps); + v.assign(std::begin(dw), std::end(dw)); + } + + SECTION("with pointer to member function") { + auto dw = dropwhile(&Point::get_x, ps); + v.assign(std::begin(dw), std::end(dw)); + } + + const std::vector vc = {{0, 1}, {2, 2}, {6, 0}}; + REQUIRE(v == vc); +} + +TEST_CASE("dropwhile: drop empty strings at front", "[dropwhile]") { + const std::vector words = {"", "", "check", "", "test"}; + auto dw = dropwhile(&std::string::empty, words); + const std::vector v(std::begin(dw), std::end(dw)); + const std::vector vc = {"check", "", "test"}; + REQUIRE(v == vc); +} + TEST_CASE("dropwhile: const iteration", "[dropwhile][const]") { Vec ns{1, 2, 3, 4, 5, 6, 7, 8}; const auto d = dropwhile(LessThanValue{5}, ns); From 93d9bd4f5e735934e95f901d1206997f5a85f668 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 18:59:19 -0400 Subject: [PATCH 237/403] Uses std::invoke in dropwhile To support pointer to member --- dropwhile.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index d4ac6594..ca190471 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -5,6 +5,7 @@ #include "internal/iterator_wrapper.hpp" #include "internal/iterbase.hpp" +#include #include #include @@ -52,7 +53,7 @@ class iter::impl::Dropper { // skip all values for which the predicate is true void skip_passes() { - while (sub_iter_ != sub_end_ && (*filter_func_)(item_.get())) { + while (sub_iter_ != sub_end_ && std::invoke(*filter_func_, item_.get())) { inc_sub_iter(); } } From dd50796169d18470fc1778fb9ce5ea2a56e00722 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 19:02:48 -0400 Subject: [PATCH 238/403] Tests takewhile with pointer to member --- test/test_takewhile.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/test_takewhile.cpp b/test/test_takewhile.cpp index bea9e6e2..23ad8462 100644 --- a/test/test_takewhile.cpp +++ b/test/test_takewhile.cpp @@ -57,6 +57,25 @@ TEST_CASE("takewhile: works with lambda, callable, and function pointer", } } +TEST_CASE("takewhile: handles pointer to member", "[takewhile]") { + using itertest::Point; + const std::vector ps = { + {5, 0}, {3, 5}, {2, 1}, {0, 1}, {2, 2}, {6, 0}}; + std::vector v; + SECTION("with pointer to data member") { + auto tw = takewhile(&Point::x, ps); + v.assign(std::begin(tw), std::end(tw)); + } + + SECTION("with pointer to member function") { + auto tw = takewhile(&Point::get_x, ps); + v.assign(std::begin(tw), std::end(tw)); + } + + const std::vector vc = {{5, 0}, {3, 5}, {2, 1}}; + REQUIRE(v == vc); +} + TEST_CASE("takewhile: supports const iteration", "[takewhile][const]") { Vec ns = {1, 3, 5, 20, 2, 4, 6, 8}; const auto tw = takewhile(UnderTen{}, ns); From 56525bc4007e212f58e64d30aecad4e779149ee0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 19:07:51 -0400 Subject: [PATCH 239/403] Uses std::invoke in takewhile To support pointer to member --- takewhile.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/takewhile.hpp b/takewhile.hpp index e4b3f001..8e28fcf2 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -5,6 +5,7 @@ #include "internal/iterator_wrapper.hpp" #include "internal/iterbase.hpp" +#include #include #include @@ -52,7 +53,7 @@ class iter::impl::Taker { } void check_current() { - if (sub_iter_ != sub_end_ && !(*filter_func_)(item_.get())) { + if (sub_iter_ != sub_end_ && !std::invoke(*filter_func_, item_.get())) { sub_iter_ = sub_end_; } } From 5d6497e69208075f8a4e43817c74c3ef526fc4f9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 19:54:23 -0400 Subject: [PATCH 240/403] Tests groupby with pointer to member --- test/test_groupby.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/test_groupby.cpp b/test/test_groupby.cpp index d6d508fa..1f86a40e 100644 --- a/test/test_groupby.cpp +++ b/test/test_groupby.cpp @@ -59,6 +59,13 @@ TEST_CASE("groupby: works with lambda, callable, and function pointer") { } } + SECTION("pointer to member") { + for (auto&& gb : groupby(vec, &std::string::size)) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + const std::vector kc = {2, 3, 5}; REQUIRE(keys == kc); @@ -69,6 +76,39 @@ TEST_CASE("groupby: works with lambda, callable, and function pointer") { REQUIRE(groups == gc); } +TEST_CASE("groupby: handles pointer to member", "[groupby]") { + using itertest::Point; + const std::vector ps = { + {0, 2}, {0, 4}, {1, 3}, {1, 7}, {1, 10}, {1, 12}, {3, 5}}; + + std::vector> groups; + std::vector keys; + + SECTION("with pointer to data member") { + auto g = groupby(ps, &Point::x); + for (auto&& gb : g) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + + SECTION("with pointer member function") { + auto g = groupby(ps, &Point::get_x); + for (auto&& gb : g) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + + const std::vector kc = {0, 1, 3}; + REQUIRE(keys == kc); + + const std::vector> gc = { + {{0, 2}, {0, 4}}, {{1, 3}, {1, 7}, {1, 10}, {1, 12}}, {{3, 5}}}; + + REQUIRE(groups == gc); +} + TEST_CASE("groupby: const iteration", "[groupby][const]") { std::vector keys; std::vector> groups; From 0febc1dd3c5d130ca0673e939dee62ec5f1d497d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 19:54:38 -0400 Subject: [PATCH 241/403] Uses std::invoke in groupby To support pointer to member --- groupby.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 7cf00b4e..a496ba67 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -6,6 +6,7 @@ #include "internal/iterator_wrapper.hpp" #include "internal/iterbase.hpp" +#include #include #include #include @@ -165,13 +166,13 @@ class iter::impl::GroupProducer { } key_func_ret next_key() { - return (*key_func_)(item_.get()); + return std::invoke(*key_func_, item_.get()); } void set_key_group_pair() { if (!current_key_group_pair_) { - current_key_group_pair_.emplace( - (*key_func_)(item_.get()), Group{*this, next_key()}); + current_key_group_pair_.emplace(std::invoke(*key_func_, item_.get()), + Group{*this, next_key()}); } } }; @@ -208,9 +209,8 @@ class iter::impl::GroupProducer { } // move-constructible, non-copy-constructible, non-assignable - Group(Group&& other) noexcept : owner_(other.owner_), - key_{other.key_}, - completed{other.completed} { + Group(Group&& other) noexcept + : owner_(other.owner_), key_{other.key_}, completed{other.completed} { other.completed = true; } From 5d041a451957352d6128084e37ab0e8787b94556 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 20:25:04 -0400 Subject: [PATCH 242/403] Adds left_of comparison function to Point --- test/helpers.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/helpers.hpp b/test/helpers.hpp index ec0180cf..01063643 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -240,6 +240,10 @@ namespace itertest { friend std::ostream& operator<<(std::ostream& out, const Point& p) { return out << p.prefix(""); } + + bool left_of(Point other) const { + return x < other.x; + } }; } template From 1757cfccce1f9984fa62927a1416b8d925a1d9c1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 20:26:14 -0400 Subject: [PATCH 243/403] Tests sorted with pointer to member function --- test/test_sorted.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/test_sorted.cpp b/test/test_sorted.cpp index 930ca4f8..1c584bd0 100644 --- a/test/test_sorted.cpp +++ b/test/test_sorted.cpp @@ -29,6 +29,15 @@ TEST_CASE("sorted: iterates through a vector in sorted order", "[sorted]") { REQUIRE(v == vc); } +TEST_CASE("sorted: handles pointer to member function", "[sorted]") { + using itertest::Point; + const std::vector ps = {{5, 0}, {3, 0}, {10, 0}, {6, 0}}; + auto s = sorted(ps, &Point::left_of); + const std::vector v(std::begin(s), std::end(s)); + const std::vector vc = {{3, 0}, {5, 0}, {6, 0}, {10, 0}}; + REQUIRE(v == vc); +} + TEST_CASE("sorted: const iteration", "[sorted][const]") { Vec ns = {4, 0, 5, 1, 6, 7, 9, 3, 2, 8}; const auto s = sorted(ns); @@ -208,7 +217,7 @@ TEST_CASE("sorted: moves rvalues and binds to lvalues", "[sorted]") { TEST_CASE("sorted: doesn't move or copy elements of iterable", "[sorted]") { using itertest::SolidInt; constexpr SolidInt arr[] = {{6}, {7}, {8}}; - for (auto &&i : sorted(arr, [](const SolidInt &lhs, const SolidInt &rhs) { + for (auto &&i : sorted(arr, [](const SolidInt&lhs, const SolidInt&rhs) { return lhs.getint() < rhs.getint(); })) { (void)i; From b1cfc428bec8f81da200f3e7043a71662ed5016b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 20:26:44 -0400 Subject: [PATCH 244/403] Uses std::invoke in sorted To support pointer to member --- sorted.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index a45cc75c..4e963228 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -5,6 +5,7 @@ #include "internal/iterbase.hpp" #include +#include #include #include @@ -44,9 +45,9 @@ class iter::impl::SortedView { // sort by comparing the elements that the iterators point to std::sort(get_begin(sorted_iters_.get()), get_end(sorted_iters_.get()), - [compare_func](iterator_type it1, - iterator_type it2) { - return compare_func(*it1, *it2); + [compare_func]( + iterator_type it1, iterator_type it2) { + return std::invoke(compare_func, *it1, *it2); }); } @@ -92,7 +93,7 @@ class iter::impl::SortedView { // sort by comparing the elements that the iterators point to std::sort(get_begin(sorted_iters_.get()), get_end(sorted_iters_.get()), [this](iterator_type it1, iterator_type it2) { - return compare_func_(*it1, *it2); + return std::invoke(compare_func_, *it1, *it2); }); } @@ -110,7 +111,7 @@ class iter::impl::SortedView { std::sort(get_begin(const_sorted_iters_.get()), get_end(const_sorted_iters_.get()), [this](iterator_type> it1, - iterator_type> it2) { + iterator_type> it2) { return compare_func_(*it1, *it2); }); } From 3e48a5d9a4def3817f54d8afdd5a546f8828a166 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 20:45:16 -0400 Subject: [PATCH 245/403] Adds add() function to Point This function is stupid, only using it for testing purproses. Give me a break, math kids. --- test/helpers.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/helpers.hpp b/test/helpers.hpp index 01063643..7c466145 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -244,6 +244,10 @@ namespace itertest { bool left_of(Point other) const { return x < other.x; } + + Point add(Point other) const { + return {x + other.x, y + other.y}; + } }; } template From 7b6714fbbc41758f826345f18c0227003ea18c89 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 20:45:58 -0400 Subject: [PATCH 246/403] Tests accumulate with pointer to member function --- test/test_accumulate.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/test_accumulate.cpp b/test/test_accumulate.cpp index 53b3a7e4..3b4ba572 100644 --- a/test/test_accumulate.cpp +++ b/test/test_accumulate.cpp @@ -45,6 +45,15 @@ TEST_CASE("accumulate: With subtraction lambda", "[accumulate]") { REQUIRE(v == vc); } +TEST_CASE("accumulate: handles pointer to member function", "[accumulate]") { + using itertest::Point; + std::vector ps = {{1, 2}, {10, 50}, {300, 600}}; + auto a = accumulate(ps, &Point::add); + const std::vector v(std::begin(a), std::end(a)); + const std::vector vc = {{1, 2}, {11, 52}, {311, 652}}; + REQUIRE(v == vc); +} + TEST_CASE("accumulate: const iterators", "[accumulate][const]") { std::vector v; SECTION("lvalue") { @@ -65,7 +74,8 @@ TEST_CASE("accumulate: const iterators", "[accumulate][const]") { REQUIRE(v == vc); } -TEST_CASE("accumulate: const iterators can be compared", "[accumulate][const]") { +TEST_CASE( + "accumulate: const iterators can be compared", "[accumulate][const]") { auto e = accumulate(std::string("hello")); const auto& ce = e; (void)(std::begin(e) == std::end(ce)); From bf133cf888af72950a09f7d2852cff8bfa2cded4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 31 Mar 2018 20:46:51 -0400 Subject: [PATCH 247/403] Uses std::invoke in accumulate To support pointer to member functions --- accumulate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accumulate.hpp b/accumulate.hpp index 9d431dc4..5d1e6d68 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -76,7 +76,7 @@ class iter::impl::Accumulator { Iterator& operator++() { ++sub_iter_; if (sub_iter_ != sub_end_) { - *acc_val_ = (*accumulate_func_)(*acc_val_, *sub_iter_); + *acc_val_ = std::invoke(*accumulate_func_, *acc_val_, *sub_iter_); } return *this; } From 835559ab67b3ba1efd49c523b77c7a0801e8bdf8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Apr 2018 22:38:58 -0400 Subject: [PATCH 248/403] Removes call_with_tuple, uses std::apply --- internal/iter_tuples.hpp | 18 ------------------ starmap.hpp | 18 ++++++++++-------- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/internal/iter_tuples.hpp b/internal/iter_tuples.hpp index 5b3a5cda..c71f8dee 100644 --- a/internal/iter_tuples.hpp +++ b/internal/iter_tuples.hpp @@ -51,24 +51,6 @@ namespace iter { // results anywhere template void absorb(Ts&&...) {} - - namespace detail { - template - decltype(auto) call_with_tuple_impl( - Func&& mf, TupleType&& tup, std::index_sequence) { - return std::invoke( - mf, std::forward>>(std::get(tup))...); - } - } - - // expand a TupleType into individual arguments when calling a Func - template - decltype(auto) call_with_tuple(Func&& mf, TupleType&& tup) { - constexpr auto TUP_SIZE = std::tuple_size>::value; - return detail::call_with_tuple_impl(std::forward(mf), - std::forward(tup), std::make_index_sequence{}); - } } } diff --git a/starmap.hpp b/starmap.hpp index 384bf8f3..681e9926 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -35,7 +35,7 @@ class iter::impl::StarMapper { Container container_; using StarIterDeref = std::remove_reference_t>()))>; + std::apply(func_, std::declval>()))>; StarMapper(Func f, Container&& c) : func_(std::move(f)), container_(std::forward(c)) {} @@ -83,7 +83,7 @@ class iter::impl::StarMapper { } decltype(auto) operator*() { - return call_with_tuple(*func_, *sub_iter_); + return std::apply(*func_, *sub_iter_); } auto operator-> () -> ArrowProxy { @@ -131,7 +131,7 @@ class iter::impl::TupleStarMapper { public: template static decltype(auto) get_and_call_with_tuple(Func& f, TupTypeT& t) { - return call_with_tuple(f, std::get(t)); + return std::apply(f, std::get(t)); } using ResultType = decltype(get_and_call_with_tuple<0>(func_, tup_)); @@ -238,11 +238,13 @@ struct iter::impl::StarMapFn : PipeableAndBindFirst { public: template auto operator()(Func func, Seq&& sequence) const { - if constexpr (is_tuple_like{}) { - return helper_with_tuples(std::move(func), std::forward(sequence), - std::make_index_sequence>:: - value>{}); - } else { + if + constexpr(is_tuple_like{}) { + return helper_with_tuples(std::move(func), std::forward(sequence), + std::make_index_sequence>:: + value>{}); + } + else { return StarMapper{ std::move(func), std::forward(sequence)}; } From 5941b43ab4430a7afb314a25f345d2de33109449 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Apr 2018 22:54:41 -0400 Subject: [PATCH 249/403] Removes definitions for constexpr data members static constexpr data members are implicitly inline in c++17. --- chain.hpp | 33 ++------------------------------- starmap.hpp | 7 ------- 2 files changed, 2 insertions(+), 38 deletions(-) diff --git a/chain.hpp b/chain.hpp index fcdfef7f..d7e52f28 100644 --- a/chain.hpp +++ b/chain.hpp @@ -189,35 +189,6 @@ class iter::impl::Chained { } }; -// jesus christ. what have I done. -template -template -constexpr std::array::template IteratorData::DerefFunc, - sizeof...(Is)> - iter::impl::Chained::IteratorData::derefers; - -template -template -constexpr std::array::template IteratorData::ArrowFunc, - sizeof...(Is)> - iter::impl::Chained::IteratorData::arrowers; - -template -template -constexpr std::array::template IteratorData::IncFunc, - sizeof...(Is)> - iter::impl::Chained::IteratorData::incrementers; - -template -template -constexpr std::array::template IteratorData::NeqFunc, - sizeof...(Is)> - iter::impl::Chained::IteratorData::neq_comparers; - template class iter::impl::ChainedFromIterable { private: @@ -316,8 +287,8 @@ class iter::impl::ChainedFromIterable { } Iterator> end() const { - return {get_end(std::as_const(container_)), - get_end(std::as_const(container_))}; + return { + get_end(std::as_const(container_)), get_end(std::as_const(container_))}; } }; diff --git a/starmap.hpp b/starmap.hpp index 681e9926..0952bd1d 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -212,13 +212,6 @@ class iter::impl::TupleStarMapper { } }; -template -template -constexpr std::array::template IteratorData::CallerFunc, - sizeof...(Is)> - iter::impl::TupleStarMapper::IteratorData::callers; - struct iter::impl::StarMapFn : PipeableAndBindFirst { private: template From 693e73f8a34b67fd55008f20aa69bb5050d3dbb0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Apr 2018 23:04:43 -0400 Subject: [PATCH 250/403] formatting for if constexpr Needed to update my clang-format to 6.0 --- starmap.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index 0952bd1d..614e6b75 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -231,13 +231,11 @@ struct iter::impl::StarMapFn : PipeableAndBindFirst { public: template auto operator()(Func func, Seq&& sequence) const { - if - constexpr(is_tuple_like{}) { - return helper_with_tuples(std::move(func), std::forward(sequence), - std::make_index_sequence>:: - value>{}); - } - else { + if constexpr (is_tuple_like{}) { + return helper_with_tuples(std::move(func), std::forward(sequence), + std::make_index_sequence< + std::tuple_size>::value>{}); + } else { return StarMapper{ std::move(func), std::forward(sequence)}; } From 22c83df10e5f1e2a489c1ac24a3939ad307f1ca2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 1 Apr 2018 23:09:46 -0400 Subject: [PATCH 251/403] No closing namespace comments Since I keep namespaces as short as possible, mostly just for declarations, I don't think the closing comments are helpful. --- .clang-format | 1 + 1 file changed, 1 insertion(+) diff --git a/.clang-format b/.clang-format index b5f272f2..650739d3 100644 --- a/.clang-format +++ b/.clang-format @@ -7,5 +7,6 @@ AllowShortLoopsOnASingleLine: false BreakBeforeBinaryOperators: NonAssignment DerivePointerAlignment: false NamespaceIndentation: All +FixNamespaceComments: false ... From 9beb6867dc19dce16ed6b817d237cefccaf931fb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 3 Apr 2018 14:11:09 -0400 Subject: [PATCH 252/403] Removes explicit tuple types c++17 explicit tuple constructor rules are relaxed --- chain.hpp | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/chain.hpp b/chain.hpp index d7e52f28..2b08ae9d 100644 --- a/chain.hpp +++ b/chain.hpp @@ -160,32 +160,23 @@ class iter::impl::Chained { }; Iterator begin() { - return {0, typename IteratorData::IterTupType{get_begin( - std::get(tup_))...}, - typename IteratorData::IterTupType{ - get_end(std::get(tup_))...}}; + return {0, {get_begin(std::get(tup_))...}, + {get_end(std::get(tup_))...}}; } Iterator end() { - return {sizeof...(Is), typename IteratorData::IterTupType{get_end( - std::get(tup_))...}, - typename IteratorData::IterTupType{ - get_end(std::get(tup_))...}}; + return {sizeof...(Is), {get_end(std::get(tup_))...}, + {get_end(std::get(tup_))...}}; } Iterator> begin() const { - return {0, typename IteratorData>::IterTupType{get_begin( - std::as_const(std::get(tup_)))...}, - typename IteratorData>::IterTupType{ - get_end(std::as_const(std::get(tup_)))...}}; + return {0, {get_begin(std::as_const(std::get(tup_)))...}, + {get_end(std::as_const(std::get(tup_)))...}}; } Iterator> end() const { - return {sizeof...(Is), - typename IteratorData>::IterTupType{ - get_end(std::as_const(std::get(tup_)))...}, - typename IteratorData>::IterTupType{ - get_end(std::as_const(std::get(tup_)))...}}; + return {sizeof...(Is), {get_end(std::as_const(std::get(tup_)))...}, + {get_end(std::as_const(std::get(tup_)))...}}; } }; From 90ed62469419cdc9671f9f2b92f945061c409986 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 3 Apr 2018 15:06:21 -0400 Subject: [PATCH 253/403] Removes explicit tuple types from zip returns --- zip.hpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/zip.hpp b/zip.hpp index 6cd26351..2c041513 100644 --- a/zip.hpp +++ b/zip.hpp @@ -84,7 +84,7 @@ class iter::impl::Zipped { } TupleDeref operator*() { - return TupleDeref{(*std::get(iters_))...}; + return {(*std::get(iters_))...}; } auto operator-> () -> ArrowProxy { @@ -93,27 +93,23 @@ class iter::impl::Zipped { }; Iterator begin() { - return {iterator_tuple_type{ - get_begin(std::get(containers_))...}}; + return {{get_begin(std::get(containers_))...}}; } Iterator end() { - return { - iterator_tuple_type{get_end(std::get(containers_))...}}; + return {{get_end(std::get(containers_))...}}; } Iterator, const_iterator_tuple_type, const_iterator_deref_tuple> begin() const { - return {const_iterator_tuple_type>{ - get_begin(std::as_const(std::get(containers_)))...}}; + return {{get_begin(std::as_const(std::get(containers_)))...}}; } Iterator, const_iterator_tuple_type, const_iterator_deref_tuple> end() const { - return {const_iterator_tuple_type>{ - get_end(std::as_const(std::get(containers_)))...}}; + return {{get_end(std::as_const(std::get(containers_)))...}}; } }; From 786f67099e814b9dcb8fed16a390b0c0282695df Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 11 Apr 2018 11:46:40 -0400 Subject: [PATCH 254/403] Removes explicit tuple types in zip_longest return --- zip_longest.hpp | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index c73383c6..3762119e 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -31,13 +31,12 @@ class iter::impl::ZippedLongest { TupleType&&, std::index_sequence); template - using OptType = boost::optional>>>; + using OptType = boost::optional>>>; template - using ConstOptType = - boost::optional>>>; + using ConstOptType = boost::optional>>>; template class OptTempl> @@ -100,10 +99,9 @@ class iter::impl::ZippedLongest { } ZipIterDeref operator*() { - return ZipIterDeref{ - ((std::get(iters_) != std::get(ends_)) - ? OptTempl{*std::get(iters_)} - : OptTempl{})...}; + return {((std::get(iters_) != std::get(ends_)) + ? OptTempl{*std::get(iters_)} + : OptTempl{})...}; } auto operator-> () -> ArrowProxy { @@ -112,31 +110,25 @@ class iter::impl::ZippedLongest { }; Iterator begin() { - return { - iterator_tuple_type{get_begin(std::get(containers_))...}, - iterator_tuple_type{get_end(std::get(containers_))...}}; + return {{get_begin(std::get(containers_))...}, + {get_end(std::get(containers_))...}}; } Iterator end() { - return { - iterator_tuple_type{get_end(std::get(containers_))...}, - iterator_tuple_type{get_end(std::get(containers_))...}}; + return {{get_end(std::get(containers_))...}, + {get_end(std::get(containers_))...}}; } Iterator, const_iterator_tuple_type, ConstOptType> begin() const { - return {const_iterator_tuple_type>{ - get_begin(std::as_const(std::get(containers_)))...}, - const_iterator_tuple_type>{ - get_end(std::as_const(std::get(containers_)))...}}; + return {{get_begin(std::as_const(std::get(containers_)))...}, + {get_end(std::as_const(std::get(containers_)))...}}; } Iterator, const_iterator_tuple_type, ConstOptType> end() const { - return {const_iterator_tuple_type>{ - get_end(std::as_const(std::get(containers_)))...}, - const_iterator_tuple_type>{ - get_end(std::as_const(std::get(containers_)))...}}; + return {{get_end(std::as_const(std::get(containers_)))...}, + {get_end(std::as_const(std::get(containers_)))...}}; } }; From b53c4d66b101b8d26d163cc513d9287ee0b041b3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 11 Apr 2018 11:55:30 -0400 Subject: [PATCH 255/403] Adds instructions for running tests --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index bef2be14..46ee3750 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,31 @@ tools except for `zip_longest` which must be included separately. You may also include individual pieces with the relevant header (`#include ` for example). + +### Running tests +You may use either `scons` or `bazel` to build the tests. `scons` seems +to work better with viewing the test output, but the same `bazel` command +can be run from any directory. + +To run tests with scons you must be within the `test` directory + +```sh +test$ # build and run all tests +test$ scons +test$ ./test_all +test$ # build and run a specific test +test$ scons test_enumerate +test$ ./test_enumerate +test$ valgrind ./test_enumerate +``` + +`bazel` absolute commands can be run from any directory inside the project + +```sh +$ bazel test //test:all # runs all tests +$ bazel test //test:test_enumerate # runs a specific test +``` + #### Requirements of passed objects Most itertools will work with iterables using InputIterators and not copy or move any underlying elements. The itertools that need ForwardIterators or From e0fdcfacde04ae582b26e79f18bc00ea1ccb7178 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 11 Apr 2018 12:46:18 -0400 Subject: [PATCH 256/403] Tests that enumerate provides references --- test/test_enumerate.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index 3f061cc1..d5fb4238 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -56,6 +56,14 @@ TEST_CASE("const enumerate", "[enumerate][const]") { REQUIRE(v == vc); } +TEST_CASE("enumerate: can modify underlying sequence", "[enumerate]") { + std::string s = "abc"; + for (auto&& [i, c] : enumerate(s)) { + c = '-'; + } + REQUIRE(s == "---"); +} + TEST_CASE("enumerate: const iterators can be compared", "[enumerate][const]") { auto e = enumerate(std::string("hello")); const auto& ce = e; From e8dff8e8facce3b50dd8a60a261293543e5996d4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 11 Apr 2018 12:46:36 -0400 Subject: [PATCH 257/403] Removes & from .element in enumerate iter yield If the underlying sequence provides references, this will still be a reference type, if it doesn't then this shouldn't have been a reference type in the first place. Just lucky this didn't cause a problem for anyone before (that I heard about at least). --- enumerate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enumerate.hpp b/enumerate.hpp index b36a0103..6580b783 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -25,7 +25,7 @@ namespace iter { public: typename BasePair::first_type index = BasePair::first; - typename BasePair::second_type& element = BasePair::second; + typename BasePair::second_type element = BasePair::second; }; template From ea1035ffa7379a1bedea065451e4b7d800dc6d1f Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Tue, 8 May 2018 15:35:54 -0700 Subject: [PATCH 258/403] Tests product with 50 of the same container. --- test/test_product.cpp | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/test/test_product.cpp b/test/test_product.cpp index d7c113d9..aa7ed1bb 100644 --- a/test/test_product.cpp +++ b/test/test_product.cpp @@ -93,15 +93,33 @@ TEST_CASE("product: with repeat", "[product]") { ResType v(std::begin(p), std::end(p)); ResType vc = { - TP{'h', 'h', 'h'}, TP{'h', 'h', 'o'}, TP{'h', 'h', 'p'}, - TP{'h', 'o', 'h'}, TP{'h', 'o', 'o'}, TP{'h', 'o', 'p'}, - TP{'h', 'p', 'h'}, TP{'h', 'p', 'o'}, TP{'h', 'p', 'p'}, - TP{'o', 'h', 'h'}, TP{'o', 'h', 'o'}, TP{'o', 'h', 'p'}, - TP{'o', 'o', 'h'}, TP{'o', 'o', 'o'}, TP{'o', 'o', 'p'}, - TP{'o', 'p', 'h'}, TP{'o', 'p', 'o'}, TP{'o', 'p', 'p'}, - TP{'p', 'h', 'h'}, TP{'p', 'h', 'o'}, TP{'p', 'h', 'p'}, - TP{'p', 'o', 'h'}, TP{'p', 'o', 'o'}, TP{'p', 'o', 'p'}, - TP{'p', 'p', 'h'}, TP{'p', 'p', 'o'}, TP{'p', 'p', 'p'}, + TP{'h', 'h', 'h'}, + TP{'h', 'h', 'o'}, + TP{'h', 'h', 'p'}, + TP{'h', 'o', 'h'}, + TP{'h', 'o', 'o'}, + TP{'h', 'o', 'p'}, + TP{'h', 'p', 'h'}, + TP{'h', 'p', 'o'}, + TP{'h', 'p', 'p'}, + TP{'o', 'h', 'h'}, + TP{'o', 'h', 'o'}, + TP{'o', 'h', 'p'}, + TP{'o', 'o', 'h'}, + TP{'o', 'o', 'o'}, + TP{'o', 'o', 'p'}, + TP{'o', 'p', 'h'}, + TP{'o', 'p', 'o'}, + TP{'o', 'p', 'p'}, + TP{'p', 'h', 'h'}, + TP{'p', 'h', 'o'}, + TP{'p', 'h', 'p'}, + TP{'p', 'o', 'h'}, + TP{'p', 'o', 'o'}, + TP{'p', 'o', 'p'}, + TP{'p', 'p', 'h'}, + TP{'p', 'p', 'o'}, + TP{'p', 'p', 'p'}, }; REQUIRE(v == vc); } @@ -186,6 +204,12 @@ TEST_CASE("product: binds to lvalues and moves rvalues", "[product]") { } } +TEST_CASE("product: handles a lot of containers values", "[product]") { + constexpr char str[] = ""; + auto p = product<50>(str); + p.begin(); +} + TEST_CASE("product: doesn't move or copy elements of iterable", "[product]") { constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}}; for (auto&& t : product(arr)) { From d32698ec3b0b00550219440475e4b12461ab76a6 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Tue, 8 May 2018 15:36:09 -0700 Subject: [PATCH 259/403] Flattens product implementation This is a combination of the zip() and chain() implementations. Prior to this, product() with around 18 or more containers was seeing very slow compile times, and then seg faults at runtime. --- product.hpp | 290 +++++++++++++++++++++++++--------------------------- 1 file changed, 140 insertions(+), 150 deletions(-) diff --git a/product.hpp b/product.hpp index 74671462..cf7be30e 100644 --- a/product.hpp +++ b/product.hpp @@ -1,6 +1,7 @@ #ifndef ITER_PRODUCT_HPP_ #define ITER_PRODUCT_HPP_ +#include "internal/iter_tuples.hpp" #include "internal/iterator_wrapper.hpp" #include "internal/iterbase.hpp" @@ -11,79 +12,110 @@ namespace iter { namespace impl { - template + template class Productor; - template - class Productor; - - template <> - class Productor<>; + template + Productor product_impl( + TupleType&& containers, std::index_sequence); } - - template - impl::Productor product(Containers&&...); } -// specialization for at least 1 template argument -template -class iter::impl::Productor { - friend Productor iter::product( - Container&&, RestContainers&&...); - - template - friend class Productor; - - template - using ProdIterDeref = - std::tuple, iterator_deref...>; +template +class iter::impl::Productor { + friend Productor iter::impl::product_impl( + TupleType&&, std::index_sequence); private: - Container container_; - Productor rest_products_; - Productor(Container&& container, RestContainers&&... rest) - : container_(std::forward(container)), - rest_products_{std::forward(rest)...} {} + TupleType containers_; + + Productor(TupleType&& containers) : containers_(std::move(containers)) {} public: Productor(Productor&&) = default; private: - template + template + class IteratorData { + IteratorData() = delete; + static_assert( + std::tuple_size>::value == sizeof...(Is), + "tuple size != sizeof Is"); + + public: + using IterTupType = iterator_tuple_type; + + template + static bool equal(const IterTupType& lhs, const IterTupType& rhs) { + return !(std::get(lhs) != std::get(rhs)); + } + + // returns true if incremented, false if wrapped around + template + static bool get_and_increment_with_wraparound(IterTupType& iters, + const IterTupType& begin_iters, const IterTupType& end_iters) { + // if already at the end, we're looking at an empty container + if (equal(iters, end_iters)) { + return false; + } + + ++std::get(iters); + + if (equal(iters, end_iters)) { + std::get(iters) = std::get(begin_iters); + return false; + } + + return true; + } + using IncFunc = bool (*)( + IterTupType&, const IterTupType&, const IterTupType&); + + constexpr static std::array incrementers{ + {get_and_increment_with_wraparound...}}; + }; + + // template templates here because I need to defer evaluation in the const + // iteration case for types that don't have non-const begin() and end(). If I + // passed in the actual types of the tuples of iterators and the type for + // deref they'd need to be known in the function declarations below. + template class IteratorTuple, + template class TupleDeref> class IteratorTempl { private: - template + template class, template class> friend class IteratorTempl; - IteratorWrapper sub_iter_; - IteratorWrapper sub_begin_; - - RestIter rest_iter_; - RestIter rest_end_; + IteratorTuple iters_; + IteratorTuple begin_iters_; + IteratorTuple end_iters_; public: using iterator_category = std::input_iterator_tag; - using value_type = ProdIterDeref; + using value_type = TupleDeref; using difference_type = std::ptrdiff_t; using pointer = value_type*; using reference = value_type&; - constexpr static const bool is_base_iter = false; - IteratorTempl(IteratorWrapper&& sub_iter, RestIter&& rest_iter, - RestIter&& rest_end) - : sub_iter_{sub_iter}, - sub_begin_{sub_iter}, - rest_iter_{rest_iter}, - rest_end_{rest_end} {} - - void reset() { - sub_iter_ = sub_begin_; - } + IteratorTempl(IteratorTuple&& iters, + IteratorTuple&& end_iters) + : iters_(std::move(iters)), + begin_iters_(iters_), + end_iters_(std::move(end_iters)) {} IteratorTempl& operator++() { - ++rest_iter_; - if (!(rest_iter_ != rest_end_)) { - rest_iter_.reset(); - ++sub_iter_; + static constexpr int NUM_ELEMENTS = sizeof...(Is); + int i = NUM_ELEMENTS - 1; + bool done = false; + while (i >= 0) { + if (IteratorData::incrementers[i]( + iters_, begin_iters_, end_iters_)) { + done = true; + break; + } + --i; + } + if (i < 0 && !done) { + iters_ = end_iters_; } return *this; } @@ -94,150 +126,108 @@ class iter::impl::Productor { return ret; } - template - bool operator!=(const IteratorTempl& other) const { - return sub_iter_ != other.sub_iter_ - && (RestIter::is_base_iter || rest_iter_ != other.rest_iter_); + template class IT, + template class TD> + bool operator!=(const IteratorTempl& other) const { + if (sizeof...(Is) == 0) return false; + + bool results[] = { + true, (std::get(iters_) != std::get(other.iters_))...}; + return std::all_of( + get_begin(results), get_end(results), [](bool b) { return b; }); } - template - bool operator==(const IteratorTempl& other) const { + template class IT, + template class TD> + bool operator==(const IteratorTempl& other) const { return !(*this != other); } - ProdIterDeref operator*() { - return std::tuple_cat( - std::tuple>{*sub_iter_}, *rest_iter_); + TupleDeref operator*() { + return {(*std::get(iters_))...}; } - ArrowProxy> operator->() { + auto operator-> () -> ArrowProxy { return {**this}; } }; - using RestIter = typename Productor::Iterator; - using RestConstIter = typename Productor::ConstIterator; + using Iterator = + IteratorTempl; + using ConstIterator = IteratorTempl, + const_iterator_tuple_type, const_iterator_deref_tuple>; public: - using Iterator = IteratorTempl; - using ConstIterator = IteratorTempl, RestConstIter>; - Iterator begin() { - return {get_begin(container_), get_begin(rest_products_), - get_end(rest_products_)}; + return {{get_begin(std::get(containers_))...}, + {get_end(std::get(containers_))...}}; } Iterator end() { - return { - get_end(container_), get_end(rest_products_), get_end(rest_products_)}; + return {{get_end(std::get(containers_))...}, + {get_end(std::get(containers_))...}}; } ConstIterator begin() const { - return {get_begin(std::as_const(container_)), - get_begin(std::as_const(rest_products_)), - get_end(std::as_const(rest_products_))}; + return {{get_begin(std::as_const(std::get(containers_)))...}, + {get_end(std::as_const(std::get(containers_)))...}}; } ConstIterator end() const { - return {get_end(std::as_const(container_)), - get_end(std::as_const(rest_products_)), - get_end(std::as_const(rest_products_))}; + return {{get_end(std::as_const(std::get(containers_)))...}, + {get_end(std::as_const(std::get(containers_)))...}}; } }; -template <> -class iter::impl::Productor<> { - public: - Productor(Productor&&) = default; - class Iterator { - public: - using iterator_category = std::input_iterator_tag; - using value_type = std::tuple<>; - using difference_type = std::ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; - - constexpr static const bool is_base_iter = true; - - void reset() {} - - Iterator& operator++() { - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - // see note in zip about base case operator!= - bool operator!=(const Iterator&) const { - return false; - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - - std::tuple<> operator*() const { - return {}; - } - }; - using ConstIterator = Iterator; +namespace iter::impl { + template + Productor product_impl( + TupleType&& containers, std::index_sequence) { + return {std::move(containers)}; + } +} - Iterator begin() { - return {}; +namespace iter { + template + decltype(auto) product(Containers&&... containers) { + return impl::product_impl( + std::tuple(std::forward(containers)...), + std::index_sequence_for{}); } - Iterator end() { - return {}; + constexpr std::array, 1> product() { + return {{}}; } - ConstIterator begin() const { - return {}; +} + +namespace iter::impl { + // rvalue must be copied, lvalue and const lvalue references can be bound + template + decltype(auto) product_repeat( + std::index_sequence, Container&& container) { + return product(((void)Is, Container(container))...); } - ConstIterator end() const { - return {}; + template + decltype(auto) product_repeat( + std::index_sequence, Container& container) { + return product(((void)Is, container)...); } -}; -template -iter::impl::Productor iter::product(Containers&&... containers) { - return {std::forward(containers)...}; + template + decltype(auto) product_repeat( + std::index_sequence, const Container& container) { + return product(((void)Is, container)...); + } } namespace iter { - namespace impl { - // rvalue must be copied, lvalue and const lvalue references can be bound - template - decltype(auto) product_repeat( - std::index_sequence, Container&& container) { - return product(((void)Is, Container(container))...); - } - - template - decltype(auto) product_repeat( - std::index_sequence, Container& container) { - return product(((void)Is, container)...); - } - - template - decltype(auto) product_repeat( - std::index_sequence, const Container& container) { - return product(((void)Is, container)...); - } - } template decltype(auto) product(Container&& container) { return impl::product_repeat( std::make_index_sequence{}, std::forward(container)); } - - constexpr std::array, 1> product() { - return {{}}; - } } #endif From c8ae589972d97564d4ff84080c7860cdc5ee44bb Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Tue, 8 May 2018 17:58:22 -0700 Subject: [PATCH 260/403] Passes IterTupType to product's IteratorData --- product.hpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/product.hpp b/product.hpp index cf7be30e..5e0bae30 100644 --- a/product.hpp +++ b/product.hpp @@ -35,16 +35,14 @@ class iter::impl::Productor { Productor(Productor&&) = default; private: - template + template class IteratorData { IteratorData() = delete; static_assert( - std::tuple_size>::value == sizeof...(Is), + std::tuple_size>::value == sizeof...(Is), "tuple size != sizeof Is"); public: - using IterTupType = iterator_tuple_type; - template static bool equal(const IterTupType& lhs, const IterTupType& rhs) { return !(std::get(lhs) != std::get(rhs)); @@ -85,9 +83,10 @@ class iter::impl::Productor { private: template class, template class> friend class IteratorTempl; - IteratorTuple iters_; - IteratorTuple begin_iters_; - IteratorTuple end_iters_; + using IterTupType = IteratorTuple; + IterTupType iters_; + IterTupType begin_iters_; + IterTupType end_iters_; public: using iterator_category = std::input_iterator_tag; @@ -107,7 +106,7 @@ class iter::impl::Productor { int i = NUM_ELEMENTS - 1; bool done = false; while (i >= 0) { - if (IteratorData::incrementers[i]( + if (IteratorData::incrementers[i]( iters_, begin_iters_, end_iters_)) { done = true; break; From 5ee4304cb88a4c31ff273dcaf98bdb370f5dce87 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Tue, 8 May 2018 18:03:59 -0700 Subject: [PATCH 261/403] Cleans up product increment --- product.hpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/product.hpp b/product.hpp index 5e0bae30..7fc6acc8 100644 --- a/product.hpp +++ b/product.hpp @@ -103,17 +103,15 @@ class iter::impl::Productor { IteratorTempl& operator++() { static constexpr int NUM_ELEMENTS = sizeof...(Is); - int i = NUM_ELEMENTS - 1; - bool done = false; - while (i >= 0) { + bool performed_increment = false; + for (int i = NUM_ELEMENTS - 1; i >= 0; --i) { if (IteratorData::incrementers[i]( iters_, begin_iters_, end_iters_)) { - done = true; + performed_increment = true; break; } - --i; } - if (i < 0 && !done) { + if (!performed_increment) { iters_ = end_iters_; } return *this; From 1f4560a4c0afdb24cc9ebee8af65a95ee4a76158 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Fri, 11 May 2018 17:31:31 -0700 Subject: [PATCH 262/403] Attempting to build on windows --- test/SConstruct | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/SConstruct b/test/SConstruct index 5c4bc272..171bf49d 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -1,15 +1,15 @@ import os +import platform + +cc_flags = ["-I.", "-std=c++17", "-Wall",] + +if platform != "Windows": + cc_flags += ["-Wextra", "-pedantic", "-g", '-I/usr/local/include'] env = Environment( ENV = os.environ, - CXXFLAGS= ['-g', '-Wall', '-Wextra', - '-pedantic', '-std=c++17', - '-I/usr/local/include', '-I.'], - CPPPATH='..', - LINKFLAGS=['-L/usr/local/lib']) - -# allows highighting to print to terminal from compiler output -env['ENV']['TERM'] = os.environ['TERM'] + CXXFLAGS= cc_flags, + CPPPATH='..') progs = Split( ''' From ba3b5de472c23b679a4cf1abfa463a8f6c51fe19 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Fri, 11 May 2018 17:37:50 -0700 Subject: [PATCH 263/403] Don't check for catch on windows --- test/SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SConstruct b/test/SConstruct index 171bf49d..53a2649b 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -53,7 +53,7 @@ progs = Split( conf = Configure(env) # if catch isn't available, exit -if not conf.CheckCXXHeader('catch.hpp'): +if platform != 'Windows' and not conf.CheckCXXHeader('catch.hpp'): print("WARNING: catch.hpp not found, run ./download_catch.sh first") print("note: you may receive this warning if the c++ compiler specified " "by CXX at the top of the SConstruct file is invalid.") From 76d4048b1b54b225dcab0db25f8aea8c90904b59 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Fri, 11 May 2018 17:40:22 -0700 Subject: [PATCH 264/403] Fixes platform check --- test/SConstruct | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/SConstruct b/test/SConstruct index 53a2649b..9d1e64c4 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -1,9 +1,11 @@ import os import platform +print('platform:', platform.system()) + cc_flags = ["-I.", "-std=c++17", "-Wall",] -if platform != "Windows": +if platform.system() != "Windows": cc_flags += ["-Wextra", "-pedantic", "-g", '-I/usr/local/include'] env = Environment( @@ -53,7 +55,7 @@ progs = Split( conf = Configure(env) # if catch isn't available, exit -if platform != 'Windows' and not conf.CheckCXXHeader('catch.hpp'): +if platform.system() != 'Windows' and not conf.CheckCXXHeader('catch.hpp'): print("WARNING: catch.hpp not found, run ./download_catch.sh first") print("note: you may receive this warning if the c++ compiler specified " "by CXX at the top of the SConstruct file is invalid.") From 2ade01e733749562855a64a16e0fb890c5677783 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Fri, 11 May 2018 17:45:23 -0700 Subject: [PATCH 265/403] Fixes windows std flag --- test/SConstruct | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/SConstruct b/test/SConstruct index 9d1e64c4..5966a145 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -1,12 +1,14 @@ import os import platform -print('platform:', platform.system()) +print("platform:", platform.system()) -cc_flags = ["-I.", "-std=c++17", "-Wall",] +cc_flags = ["-I.", "-Wall",] -if platform.system() != "Windows": - cc_flags += ["-Wextra", "-pedantic", "-g", '-I/usr/local/include'] +if platform.system() == "Windows": + cc_flags += ["-std:c++17"] +else: + cc_flags += ["-Wextra", "-std=c++17", "-pedantic", "-g", '-I/usr/local/include'] env = Environment( ENV = os.environ, From a3b4e0b033ac01017ec4e3b7716b2a034249e980 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 13 May 2018 22:27:52 -0400 Subject: [PATCH 266/403] Replaces std::result_of with std::invoke_result std::result_of is deprecated --- accumulate.hpp | 4 ++-- groupby.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 5d1e6d68..0d43a20e 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -28,8 +28,8 @@ class iter::impl::Accumulator { friend AccumulateFn; - using AccumVal = std::remove_reference_t, iterator_deref)>>; + using AccumVal = std::remove_reference_t, iterator_deref>>; Accumulator(Container&& container, AccumulateFunc accumulate_func) : container_(std::forward(container)), diff --git a/groupby.hpp b/groupby.hpp index a496ba67..4f2fffb5 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -39,7 +39,7 @@ class iter::impl::GroupProducer { friend GroupByFn; template - using key_func_ret = std::result_of_t)>; + using key_func_ret = std::invoke_result_t>; GroupProducer(Container&& container, KeyFunc key_func) : container_(std::forward(container)), key_func_(key_func) {} From 9e72b897e0a7777d684768aa784d89cb44721ab8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 16 May 2018 01:56:14 -0400 Subject: [PATCH 267/403] Revert "Fixes windows std flag" This reverts commit 2ade01e733749562855a64a16e0fb890c5677783. --- test/SConstruct | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/SConstruct b/test/SConstruct index 5966a145..9d1e64c4 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -1,14 +1,12 @@ import os import platform -print("platform:", platform.system()) +print('platform:', platform.system()) -cc_flags = ["-I.", "-Wall",] +cc_flags = ["-I.", "-std=c++17", "-Wall",] -if platform.system() == "Windows": - cc_flags += ["-std:c++17"] -else: - cc_flags += ["-Wextra", "-std=c++17", "-pedantic", "-g", '-I/usr/local/include'] +if platform.system() != "Windows": + cc_flags += ["-Wextra", "-pedantic", "-g", '-I/usr/local/include'] env = Environment( ENV = os.environ, From d2cbc3d4f04a385a422c7a98a24fc60f268b393c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 16 May 2018 01:56:23 -0400 Subject: [PATCH 268/403] Revert "Fixes platform check" This reverts commit 76d4048b1b54b225dcab0db25f8aea8c90904b59. --- test/SConstruct | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/SConstruct b/test/SConstruct index 9d1e64c4..53a2649b 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -1,11 +1,9 @@ import os import platform -print('platform:', platform.system()) - cc_flags = ["-I.", "-std=c++17", "-Wall",] -if platform.system() != "Windows": +if platform != "Windows": cc_flags += ["-Wextra", "-pedantic", "-g", '-I/usr/local/include'] env = Environment( @@ -55,7 +53,7 @@ progs = Split( conf = Configure(env) # if catch isn't available, exit -if platform.system() != 'Windows' and not conf.CheckCXXHeader('catch.hpp'): +if platform != 'Windows' and not conf.CheckCXXHeader('catch.hpp'): print("WARNING: catch.hpp not found, run ./download_catch.sh first") print("note: you may receive this warning if the c++ compiler specified " "by CXX at the top of the SConstruct file is invalid.") From 1c93b1599ef154a262581e2bc7551507e61e3fd3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 16 May 2018 01:56:31 -0400 Subject: [PATCH 269/403] Revert "Don't check for catch on windows" This reverts commit ba3b5de472c23b679a4cf1abfa463a8f6c51fe19. --- test/SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SConstruct b/test/SConstruct index 53a2649b..171bf49d 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -53,7 +53,7 @@ progs = Split( conf = Configure(env) # if catch isn't available, exit -if platform != 'Windows' and not conf.CheckCXXHeader('catch.hpp'): +if not conf.CheckCXXHeader('catch.hpp'): print("WARNING: catch.hpp not found, run ./download_catch.sh first") print("note: you may receive this warning if the c++ compiler specified " "by CXX at the top of the SConstruct file is invalid.") From 1ed3ff88bac354e4ebb3dfc89af962acf2f613cf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 16 May 2018 01:56:40 -0400 Subject: [PATCH 270/403] Revert "Attempting to build on windows" This reverts commit 1f4560a4c0afdb24cc9ebee8af65a95ee4a76158. --- test/SConstruct | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/SConstruct b/test/SConstruct index 171bf49d..5c4bc272 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -1,15 +1,15 @@ import os -import platform - -cc_flags = ["-I.", "-std=c++17", "-Wall",] - -if platform != "Windows": - cc_flags += ["-Wextra", "-pedantic", "-g", '-I/usr/local/include'] env = Environment( ENV = os.environ, - CXXFLAGS= cc_flags, - CPPPATH='..') + CXXFLAGS= ['-g', '-Wall', '-Wextra', + '-pedantic', '-std=c++17', + '-I/usr/local/include', '-I.'], + CPPPATH='..', + LINKFLAGS=['-L/usr/local/lib']) + +# allows highighting to print to terminal from compiler output +env['ENV']['TERM'] = os.environ['TERM'] progs = Split( ''' From 739780b331f0395d492b722080db30e49bb32df8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 16 May 2018 10:23:30 -0400 Subject: [PATCH 271/403] Adds default initializer for range::iter::is_end --- range.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/range.hpp b/range.hpp index 8a9a4791..d4727b4b 100644 --- a/range.hpp +++ b/range.hpp @@ -131,7 +131,7 @@ class iter::impl::Range { class Iterator { private: iter::detail::RangeIterData data; - bool is_end; + bool is_end{}; // first argument must be regular iterator // second argument must be end iterator From e3a4c1fb79fefc21ae153209f965a62717699b6e Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Wed, 20 Jun 2018 16:40:33 -0700 Subject: [PATCH 272/403] Uses DerefHolder in chain.from_iterable Previously chain.from_iterable couldn't accept an iterable that yielded rvalues. --- chain.hpp | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/chain.hpp b/chain.hpp index 2b08ae9d..8a0522e3 100644 --- a/chain.hpp +++ b/chain.hpp @@ -200,9 +200,22 @@ class iter::impl::ChainedFromIterable { IteratorWrapper top_level_iter_; IteratorWrapper top_level_end_; + DerefHolder sub_iterable_; std::optional sub_iter_p_; std::optional sub_end_p_; + void next_sub_iterable() { + if (top_level_iter_ != top_level_end_) { + sub_iterable_.reset(*top_level_iter_); + sub_iter_p_ = + std::make_optional(get_begin(sub_iterable_.get())); + sub_end_p_ = std::make_optional(get_end(sub_iterable_.get())); + } else { + sub_iter_p_.reset(); + sub_end_p_.reset(); + } + } + public: using iterator_category = std::input_iterator_tag; using value_type = iterator_traits_deref>; @@ -213,27 +226,15 @@ class iter::impl::ChainedFromIterable { Iterator(IteratorWrapper&& top_iter, IteratorWrapper&& top_end) : top_level_iter_{std::move(top_iter)}, - top_level_end_{std::move(top_end)}, - sub_iter_p_{!(top_iter != top_end) - ? // iter == end ? - std::nullopt - : std::make_optional(get_begin(*top_iter))}, - sub_end_p_{!(top_iter != top_end) - ? // iter == end ? - std::nullopt - : std::make_optional(get_end(*top_iter))} {} + top_level_end_{std::move(top_end)} { + next_sub_iterable(); + } Iterator& operator++() { ++*sub_iter_p_; if (!(*sub_iter_p_ != *sub_end_p_)) { ++top_level_iter_; - if (top_level_iter_ != top_level_end_) { - sub_iter_p_ = get_begin(*top_level_iter_); - sub_end_p_ = get_end(*top_level_iter_); - } else { - sub_iter_p_.reset(); - sub_end_p_.reset(); - } + next_sub_iterable(); } return *this; } From c09fcf03e9fdf7334649c3794f8af8aaa9e25fcf Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Wed, 20 Jun 2018 16:58:30 -0700 Subject: [PATCH 273/403] chain.from_iterable(imap([](auto v){return v},x)) The key point is that the imap callable returns values, not references. --- test/test_mixed.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/test_mixed.cpp b/test/test_mixed.cpp index ecf65091..c4da12b2 100644 --- a/test/test_mixed.cpp +++ b/test/test_mixed.cpp @@ -143,3 +143,16 @@ TEST_CASE("filter into enumerate with pipe", "[filter][enumerate]") { const Vec vc = {{0, 42}, {1, 44}}; REQUIRE(v == vc); } + +TEST_CASE("chain.from_iterable: accept imap result that yields rvalues", + "[chain.from_iterable][imap]") { + using iter::chain; + using iter::imap; + const std::vector> ns = {{'a'}, {'q'}, {'x', 'z'}}; + auto ch = iter::chain.from_iterable(iter::imap([](auto v) { return v; }, ns)); + const std::vector v(std::begin(ch), std::end(ch)); + + const std::vector vc = {'a', 'q', 'x', 'z'}; + + REQUIRE(v == vc); +} From 08a40b593d3e4d0541003183995c0d11a9d8ef08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-R=20Boyer?= Date: Sat, 8 Sep 2018 22:37:10 -0400 Subject: [PATCH 274/403] Added CMake files for better cross-platform build support. - Currently on MSVC cl 19.15.26726, only 5/34 test files compile and pass tests --- examples/CMakeLists.txt | 22 ++++++++++++++++++++++ test/CMakeLists.txt | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 examples/CMakeLists.txt create mode 100644 test/CMakeLists.txt diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 00000000..23cf493a --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,22 @@ +# Note that some examples currently use boost.optional which we do no not search for in this file. +# You might have to use the "keep going" option to continue building on errors if boost.optional is not in the include path. +# For example, building with MSVC (from an examples/buildMsvc directory): +# set CXX=cl.exe +# cmake .. -G Ninja +# cmake --build . -- -k99 + +cmake_minimum_required(VERSION 3.8) +project(cppitertools_examples CXX) +set (CMAKE_CXX_STANDARD 17) + +include_directories( + .. +) + +file(GLOB _examples_files "*_examples.cpp") + +foreach(_file_cpp ${_examples_files}) + get_filename_component(_name_cpp "${_file_cpp}" NAME) + get_filename_component(_name_without_extension "${_name_cpp}" NAME_WE) + add_executable(${_name_without_extension} ${_file_cpp}) +endforeach() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 00000000..315e4b04 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,32 @@ +# Note that some examples currently use boost.optional which we do no not search for in this file. +# You might have to use the "keep going" option to continue building on errors if boost.optional is not in the include path. +# For example, building with MSVC (from a test/buildMsvc directory): +# set CXX=cl.exe +# cmake .. -G Ninja +# cmake --build . -- -k99 + +cmake_minimum_required(VERSION 3.8) +project(cppitertools_tests CXX) +set (CMAKE_CXX_STANDARD 17) + +include_directories( + .. +) + +include(CheckIncludeFileCXX) +set(CMAKE_REQUIRED_INCLUDES ${PROJECT_SOURCE_DIR}) +CHECK_INCLUDE_FILE_CXX(catch.hpp _has_catch) +if(NOT "${_has_catch}") + message("WARNING: catch.hpp not found, run ./download_catch.sh from test/ directory first") +endif() + +file(GLOB test_sources RELATIVE ${PROJECT_SOURCE_DIR} "test_*.cpp") +list(REMOVE_ITEM test_sources test_main.cpp) +add_library(test_main OBJECT test_main.cpp) + +foreach(_source_cpp ${test_sources}) + get_filename_component(_name_without_extension "${_source_cpp}" NAME_WE) + add_executable(${_name_without_extension} ${_source_cpp} $) +endforeach() + +add_executable(test_all ${test_sources} $) From 39158fb150056ad2d0ae611d947b6aa5b63027eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-R=20Boyer?= Date: Sun, 9 Sep 2018 00:04:28 -0400 Subject: [PATCH 275/403] - Use of C++17 is_same_v instead of instatiating is_same or using ::value (but kept tests using old syntax). - Fixed bug that operators * and -> should be const in IteratorIterator as they do not modify the iterator. - Changed name of template parameter from Container to T in iterator_type, because of a bug in MSVC. - Used an explicit decltype, instead of decltype(auto), in TupleStarMapper::IteratorData::get_and_call_with_tuple because MSVC was not able to deduce it. - Fixed bug in filterfalse_examples where was not included. Result with MSVC: - All tests pass and examples are running, in release build. - 4/34 test files fail in debug, because of STL assertion failure. --- examples/filterfalse_examples.cpp | 1 + internal/iterator_wrapper.hpp | 6 +++--- internal/iteratoriterator.hpp | 4 ++-- internal/iterbase.hpp | 4 ++-- reversed.hpp | 4 ++-- starmap.hpp | 2 +- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/examples/filterfalse_examples.cpp b/examples/filterfalse_examples.cpp index f03debfa..dd937cee 100644 --- a/examples/filterfalse_examples.cpp +++ b/examples/filterfalse_examples.cpp @@ -1,6 +1,7 @@ #include #include +#include #include bool greater_than_four(int i) { diff --git a/internal/iterator_wrapper.hpp b/internal/iterator_wrapper.hpp index a9c3f5d9..2d91fc02 100644 --- a/internal/iterator_wrapper.hpp +++ b/internal/iterator_wrapper.hpp @@ -32,15 +32,15 @@ namespace iter { template using IteratorWrapper = typename IteratorWrapperImplType, - impl::iterator_end_type>{}>::type; + std::is_same_v, + impl::iterator_end_type>>::type; } } template class iter::impl::IteratorWrapperImpl { private: - static_assert(!std::is_same{}); + static_assert(!std::is_same_v); SubIter& sub_iter() { auto* sub = std::get_if(&sub_iter_or_end_); assert(sub); diff --git a/internal/iteratoriterator.hpp b/internal/iteratoriterator.hpp index 87ed74d1..a01c0d27 100644 --- a/internal/iteratoriterator.hpp +++ b/internal/iteratoriterator.hpp @@ -80,11 +80,11 @@ namespace iter { return ret; } - auto operator*() -> decltype(**sub_iter) { + auto operator*() const -> decltype(**sub_iter) { return **this->sub_iter; } - auto operator-> () -> decltype(*sub_iter) { + auto operator-> () const -> decltype(*sub_iter) { return *this->sub_iter; } diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 60e31517..6232c300 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -51,8 +51,8 @@ namespace iter { using AsConst = decltype(std::as_const(std::declval())); // iterator_type is the type of C's iterator - template - using iterator_type = decltype(get_begin(std::declval())); + template //TODO: See bug https://developercommunity.visualstudio.com/content/problem/252157/sfinae-error-depends-on-name-of-template-parameter.html for why we use T instead of Container. Should be changed back to Container when that bug is fixed in MSVC. + using iterator_type = decltype(get_begin(std::declval())); // iterator_type is the type of C's iterator template diff --git a/reversed.hpp b/reversed.hpp index fcf04d27..3b914bb1 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -35,9 +35,9 @@ namespace iter { template using ReverseIteratorWrapper = typename ReverseIteratorWrapperImplType, + std::is_same_v, impl:: - reverse_iterator_end_type>{}>:: + reverse_iterator_end_type>>:: type; template diff --git a/starmap.hpp b/starmap.hpp index 614e6b75..d3fb678b 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -130,7 +130,7 @@ class iter::impl::TupleStarMapper { class IteratorData { public: template - static decltype(auto) get_and_call_with_tuple(Func& f, TupTypeT& t) { + static auto get_and_call_with_tuple(Func& f, TupTypeT& t) -> decltype(std::apply(f, std::get(t))) { //TODO: Remove duplicated expression in decltype, using decltype(auto) as return type, when all compilers correctly deduce type (i.e. MSVC cl 19.15 does not do it). return std::apply(f, std::get(t)); } From 9d6bf0e918f3bfb711733a70c20afed3592fb953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-R=20Boyer?= Date: Sun, 9 Sep 2018 00:50:07 -0400 Subject: [PATCH 276/403] =?UTF-8?q?-=20Fixed=20bug=20in=20combinations=20a?= =?UTF-8?q?nd=20combinations=5Fwith=5Freplacement,=20where=20rbegin()-1=20?= =?UTF-8?q?was=20used=20but=20is=20undefined=20behavior=20(see=20C++17=20[?= =?UTF-8?q?bidirectional.iterators]=20and=20[random.access.iterators]).=20?= =?UTF-8?q?-=20Fixed=20incorrect=20test=20in=20test=5Fsorted=20that=20was?= =?UTF-8?q?=20not=20checking=20the=20result=20of=20the=20comparision,=20bu?= =?UTF-8?q?t=20is=20disabled=20for=20now=20as=20it=20compares=20iterators?= =?UTF-8?q?=20on=20different=20containers,=20which=20is=20undefined=20beha?= =?UTF-8?q?vior=20(see=20C++17=20[forward.iterators]=C2=B62).=20-=20Now=20?= =?UTF-8?q?all=20tests=20are=20passing=20with=20MSVC.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- combinations.hpp | 5 +++-- combinations_with_replacement.hpp | 5 +++-- test/test_sorted.cpp | 7 ++++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index bfee2c86..7572142c 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -94,10 +94,11 @@ class iter::impl::Combinator { if (!(dumb_next(*iter, dist) != get_end(*container_p_))) { if ((iter + 1) != indices_.get().rend()) { size_t inc = 1; - for (auto down = iter; down != indices_.get().rbegin() - 1; - --down) { + for (auto down = iter; ; --down) { (*down) = dumb_next(*(iter + 1), 1 + inc); ++inc; + if (down == indices_.get().rbegin()) + break; } } else { steps_ = COMPLETE; diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index 5455a6e4..b7e20d7d 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -74,9 +74,10 @@ class iter::impl::CombinatorWithReplacement { ++(*iter); if (!(*iter != get_end(*container_p_))) { if ((iter + 1) != indices_.get().rend()) { - for (auto down = iter; down != indices_.get().rbegin() - 1; - --down) { + for (auto down = iter; ; --down) { (*down) = dumb_next(*(iter + 1)); + if (down == indices_.get().rbegin()) + break; } } else { steps_ = COMPLETE; diff --git a/test/test_sorted.cpp b/test/test_sorted.cpp index 1c584bd0..7c31a638 100644 --- a/test/test_sorted.cpp +++ b/test/test_sorted.cpp @@ -46,11 +46,12 @@ TEST_CASE("sorted: const iteration", "[sorted][const]") { REQUIRE(v == vc); } +//FIXME: This test currently fails (STL assertion fails on MSVC with debug library, simple test failure on gcc). The problem is 'sorted' will sort twice, once for non-const and once for const container; the resulting iterators are thus not on the same container (violating domain of == as specified in C++17 [forward.iterators]¶2). Remove [!hide] tag when fixed. TEST_CASE("sorted: const iterators can be compared to non-const iterators", - "[sorted][const]") { - auto s = sorted(Vec{}); + "[sorted][const][!hide]") { + auto s = sorted(Vec{1}); const auto& cs = s; - (void)(std::begin(s) == std::end(cs)); + REQUIRE(std::begin(s) == std::begin(cs)); } TEST_CASE("sorted: can modify elements through sorted", "[sorted]") { From 32f4dc22dbd04cc5c9c4b71ebedcffd2eb93b9da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-R=20Boyer?= Date: Sun, 9 Sep 2018 12:12:28 -0400 Subject: [PATCH 277/403] - Corrected all warnings at /W4 with MSVC (except in test_starmap, where it would slightly change tests) - Replaced std::all_of and any_of by fold expressions --- product.hpp | 9 +++------ test/test_accumulate.cpp | 2 +- test/test_mixed.cpp | 4 ++-- test/test_sorted.cpp | 6 +++--- test/test_unique_everseen.cpp | 6 +++--- test/test_unique_justseen.cpp | 6 +++--- test/test_zip_longest.cpp | 4 ++-- zip.hpp | 9 +++------ zip_longest.hpp | 7 +------ 9 files changed, 21 insertions(+), 32 deletions(-) diff --git a/product.hpp b/product.hpp index 7fc6acc8..38836fba 100644 --- a/product.hpp +++ b/product.hpp @@ -126,12 +126,9 @@ class iter::impl::Productor { template class IT, template class TD> bool operator!=(const IteratorTempl& other) const { - if (sizeof...(Is) == 0) return false; - - bool results[] = { - true, (std::get(iters_) != std::get(other.iters_))...}; - return std::all_of( - get_begin(results), get_end(results), [](bool b) { return b; }); + if constexpr (sizeof...(Is) == 0) return false; + else + return (... && (std::get(iters_) != std::get(other.iters_))); } template class IT, diff --git a/test/test_accumulate.cpp b/test/test_accumulate.cpp index 3b4ba572..02467fb2 100644 --- a/test/test_accumulate.cpp +++ b/test/test_accumulate.cpp @@ -93,7 +93,7 @@ TEST_CASE("accumulate: intermidate type need not be default constructible", "[accumulate]") { std::vector v = {{2}, {3}, {10}}; auto a = accumulate(v, std::plus{}); - std::begin(a); + (void)std::begin(a); } TEST_CASE("accumulate: binds reference when it should", "[accumulate]") { diff --git a/test/test_mixed.cpp b/test/test_mixed.cpp index c4da12b2..46d47f03 100644 --- a/test/test_mixed.cpp +++ b/test/test_mixed.cpp @@ -21,8 +21,8 @@ class MyUnMovable { constexpr int get_val() const { return val; } - void set_val(int val) { - this->val = val; + void set_val(int new_val) { + this->val = new_val; } bool operator==(const MyUnMovable& other) const { diff --git a/test/test_sorted.cpp b/test/test_sorted.cpp index 7c31a638..ff151576 100644 --- a/test/test_sorted.cpp +++ b/test/test_sorted.cpp @@ -68,12 +68,12 @@ char inc_vowels(char c) { } TEST_CASE("sorted: Works with different begin and end types", "[sorted]") { - using Vec = std::vector; + using VecC = std::vector; CharRange cr{'g'}; auto s = sorted(cr, [](char x, char y) { return inc_vowels(x) < inc_vowels(y); }); - Vec v(s.begin(), s.end()); - Vec vc{'b', 'c', 'd', 'f', 'a', 'e'}; + VecC v(s.begin(), s.end()); + VecC vc{'b', 'c', 'd', 'f', 'a', 'e'}; REQUIRE(v == vc); } diff --git a/test/test_unique_everseen.cpp b/test/test_unique_everseen.cpp index c34bb74d..d70de075 100644 --- a/test/test_unique_everseen.cpp +++ b/test/test_unique_everseen.cpp @@ -65,10 +65,10 @@ TEST_CASE( TEST_CASE("unique everseen: Works with different begin and end types", "[unique_everseen]") { CharRange cr{'d'}; - using Vec = std::vector; + using VecC = std::vector; auto ue = unique_everseen(cr); - Vec v(ue.begin(), ue.end()); - Vec vc{'a', 'b', 'c'}; + VecC v(ue.begin(), ue.end()); + VecC vc{'a', 'b', 'c'}; REQUIRE(v == vc); } diff --git a/test/test_unique_justseen.cpp b/test/test_unique_justseen.cpp index 2614aa89..c6671e5f 100644 --- a/test/test_unique_justseen.cpp +++ b/test/test_unique_justseen.cpp @@ -54,10 +54,10 @@ TEST_CASE("unique justseen: some repeating values", "[unique_justseen]") { TEST_CASE("unique justseen: Works with different begin and end types", "[unique_justseen]") { CharRange cr{'d'}; - using Vec = std::vector; + using VecC = std::vector; auto uj = unique_justseen(cr); - Vec v(uj.begin(), uj.end()); - Vec vc{'a', 'b', 'c'}; + VecC v(uj.begin(), uj.end()); + VecC vc{'a', 'b', 'c'}; REQUIRE(v == vc); } diff --git a/test/test_zip_longest.cpp b/test/test_zip_longest.cpp index a737b6b7..4759a412 100644 --- a/test/test_zip_longest.cpp +++ b/test/test_zip_longest.cpp @@ -118,8 +118,8 @@ TEST_CASE("zip_longest: const iterators can be compared to non-const iterators", "[zip_longest][const]") { auto zl = zip_longest(std::vector{}); const auto& czl = zl; - std::begin(zl); - std::begin(czl); + (void)std::begin(zl); + (void)std::begin(czl); (void)(std::begin(zl) == std::end(czl)); } diff --git a/zip.hpp b/zip.hpp index 2c041513..ee973b9e 100644 --- a/zip.hpp +++ b/zip.hpp @@ -69,12 +69,9 @@ class iter::impl::Zipped { template class IT, template class TD> bool operator!=(const Iterator& other) const { - if (sizeof...(Is) == 0) return false; - - bool results[] = { - true, (std::get(iters_) != std::get(other.iters_))...}; - return std::all_of( - get_begin(results), get_end(results), [](bool b) { return b; }); + if constexpr (sizeof...(Is) == 0) return false; + else + return (... && (std::get(iters_) != std::get(other.iters_))); } template class IT, diff --git a/zip_longest.hpp b/zip_longest.hpp index 3762119e..89e637e3 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -84,12 +84,7 @@ class iter::impl::ZippedLongest { template class TT, template class TU> bool operator!=(const Iterator& other) const { - if (sizeof...(Is) == 0) return false; - - bool results[] = { - false, (std::get(iters_) != std::get(other.iters_))...}; - return std::any_of( - get_begin(results), get_end(results), [](bool b) { return b; }); + return (... || (std::get(iters_) != std::get(other.iters_))); } template class TT, From 419a22acb403eaeda1361e3a60236d5aa788e38f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-R=20Boyer?= Date: Sun, 9 Sep 2018 12:14:06 -0400 Subject: [PATCH 278/403] - Corrected warnings at /W4 with MSVC in test_starmap (slightly changes the types used in the tests) --- test/test_starmap.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/test_starmap.cpp b/test/test_starmap.cpp index bb98a349..4c12b7c1 100644 --- a/test/test_starmap.cpp +++ b/test/test_starmap.cpp @@ -27,8 +27,8 @@ namespace { return a + b + c; } - int operator()(int a, int b) { - return a + b; + int operator()(double a, int b) { + return int(a + b); } int operator()(int a) { @@ -39,7 +39,7 @@ namespace { TEST_CASE("starmap: works with function pointer and lambda", "[starmap]") { using Vec = const std::vector; - const std::vector> v1 = {{1l, 2}, {3l, 11}, {6l, 7}}; + const std::vector> v1 = {{1l, 2}, {3l, 11}, {6l, 7}}; Vec vc = {2l, 33l, 42l}; std::vector v; @@ -74,7 +74,7 @@ TEST_CASE("starmap: works with pointer to member function", "[starmap]") { TEST_CASE("starmap: vector of pairs const iteration", "[starmap][const]") { using Vec = const std::vector; - const std::vector> v1 = {{1l, 2}, {3l, 11}, {6l, 7}}; + const std::vector> v1 = {{1.0, 2}, {3.0, 11}, {6.0, 7}}; const auto sm = starmap(Callable{}, v1); std::vector v(std::begin(sm), std::end(sm)); @@ -121,7 +121,7 @@ TEST_CASE( TEST_CASE("starmap: list of tuples", "[starmap]") { using Vec = const std::vector; - using T = std::tuple; + using T = std::tuple; std::list li = {T{"hey", 42, 'a'}, T{"there", 3, 'b'}, T{"yall", 5, 'c'}}; auto sm = starmap(g, li); @@ -172,7 +172,7 @@ TEST_CASE("starmap: moves rvalues, binds to lvalues", "[starmap]") { TEST_CASE("starmap: iterator meets requirements", "[starmap]") { std::string s{}; const std::vector> v1; - auto sm = starmap([](long a, int b) { return a * b; }, v1); + auto sm = starmap([](double a, int b) { return a * b; }, v1); REQUIRE(itertest::IsIterator::value); } From 54d6d5a6dfce9c5851ce78843b3f96be18246280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-R=20Boyer?= Date: Sun, 30 Sep 2018 20:18:54 -0400 Subject: [PATCH 279/403] - IteratorIterator operator[] is now const, as required by RandomAccessIterator - Removed incorrect operaror - where (2 - it) would give (it - 2) - Added tests to cover all methods in iteratoriterator.hpp --- internal/iteratoriterator.hpp | 7 +-- test/test_iteratoriterator.cpp | 106 +++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 6 deletions(-) diff --git a/internal/iteratoriterator.hpp b/internal/iteratoriterator.hpp index a01c0d27..3993a4d0 100644 --- a/internal/iteratoriterator.hpp +++ b/internal/iteratoriterator.hpp @@ -115,16 +115,11 @@ namespace iter { return it; } - friend IteratorIterator operator-(Diff n, IteratorIterator it) { - it -= n; - return it; - } - Diff operator-(const IteratorIterator& rhs) const { return this->sub_iter - rhs.sub_iter; } - auto operator[](Diff idx) -> decltype(*sub_iter[idx]) { + auto operator[](Diff idx) const -> decltype(*sub_iter[idx]) { return *sub_iter[idx]; } diff --git a/test/test_iteratoriterator.cpp b/test/test_iteratoriterator.cpp index c4442f7a..dd2c4987 100644 --- a/test/test_iteratoriterator.cpp +++ b/test/test_iteratoriterator.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "catch.hpp" @@ -61,3 +62,108 @@ TEST_CASE("Iterate over a vector of string iterators", "[iteratoriterator]") { std::iterator_traits::reference>::value, "iterator is mis marked"); } + +TEST_CASE("IteratorIterator supports mutable RandomAccessIterator operators", + "[iteratoriterator]") { + using std::vector; + struct S { + int value; + }; + vector v = {{2}, {4}, {6}, {8}}; + + IterIterWrapper::iterator>> itr; + itr.get().push_back(std::begin(v) + 1); + itr.get().push_back(std::end(v) - 1); + itr.get().push_back(std::begin(v)); + + // RandomAccessIterator (and ForwardIterator): + auto a = itr.begin(); + auto r = a; + auto r2 = r; + ((r += 2) -= 2) += 2; + REQUIRE(&(++r2) == &r2); // Required by OutputIterator. + REQUIRE(&(*r2++) == &a[1]); + REQUIRE(r == r2); + auto test_const_or_not = [&itr](auto& a, auto& b) { + REQUIRE(!(b == a)); + REQUIRE(b == a + 2); + REQUIRE(b == 2 + a); + REQUIRE(b - 2 == a); + REQUIRE(&a[2] == &b[0]); + REQUIRE(b - a == 2); + REQUIRE(a < b); + REQUIRE(!(a < a)); + REQUIRE(b > a); + REQUIRE(!(a > a)); + REQUIRE(a <= b); + REQUIRE(!(b <= a)); + REQUIRE(a <= a); + REQUIRE(b >= a); + REQUIRE(!(a >= b)); + REQUIRE(a >= a); + + // InputIterator: + REQUIRE(b != a); + REQUIRE(!(a != a)); + REQUIRE(&(*a) != &(*b)); + REQUIRE(&(a->value) == &(*a).value); + + // Added methods, not from ...Iterator: + REQUIRE(a.get() == std::begin(itr.get())); + }; + test_const_or_not(a, r); + test_const_or_not(std::as_const(a), r); + test_const_or_not(a, std::as_const(r)); + test_const_or_not(std::as_const(a), std::as_const(r)); + + // BidirectionalIterator (and RandomAccessIterator): + REQUIRE((--r)-- == a + 1); + REQUIRE(r == a); + REQUIRE(&(*r2--) == &a[2]); + + // OutputIterator (and RandomAccessIterator): + *r++ = {10}; + REQUIRE(r == a + 1); + REQUIRE(v[1].value == 10); + *++r = {12}; + REQUIRE(r == a + 2); + REQUIRE(v[0].value == 12); + *r = {14}; + REQUIRE(r == a + 2); + REQUIRE(v[0].value == 14); + a[1] = {16}; + REQUIRE(a == itr.begin()); + REQUIRE(v[3].value == 16); +} + +TEST_CASE("IterIterWrapper supports several SequenceContainer methodes", + "[iteratoriterator]") { + using std::vector; + vector v = {2, 4, 6, 8}; + + IterIterWrapper::iterator>> itr; + itr.get().push_back(std::begin(v) + 1); + itr.get().push_back(std::end(v) - 1); + + auto test_const_or_not = [&v](auto& c) { + REQUIRE(c.at(0) == 4); + REQUIRE(c.at(1) == 8); + REQUIRE(c[0] == 4); + REQUIRE(c[1] == 8); + REQUIRE(!c.empty()); + REQUIRE(c.size() == 2); + REQUIRE(*c.begin() == 4); + REQUIRE(*(c.end() - 1) == 8); + REQUIRE(*c.cbegin() == 4); + REQUIRE(*(c.cend() - 1) == 8); + REQUIRE(*c.rbegin() == 8); + REQUIRE(*(c.rend() - 1) == 4); + REQUIRE(*c.crbegin() == 8); + REQUIRE(*(c.crend() - 1) == 4); + + // Added methods, not from SequenceContainer: + REQUIRE(c.get()[0] == std::begin(v) + 1); + }; + test_const_or_not(itr); + test_const_or_not(std::as_const(itr)); +} From 06e592338617519fe8279a1e79d042b8c2aaaf48 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 19 Oct 2018 11:09:35 -0400 Subject: [PATCH 280/403] s/protected/private in Filter Iterator It should have been private afaict, but this matters because of gcc bug 87652 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87652# --- filter.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filter.hpp b/filter.hpp index 0676917b..10a793c6 100644 --- a/filter.hpp +++ b/filter.hpp @@ -46,7 +46,7 @@ class iter::impl::Filtered { template class Iterator { - protected: + private: template friend class Iterator; using Holder = DerefHolder>; From 829254264e9259a1e99fd364a5e3dcba3a86daac Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 20 Oct 2018 20:13:40 -0400 Subject: [PATCH 281/403] Messing with travis --- .travis.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..bbe56ec9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,20 @@ +language: cpp + +script: scons + +before_script: cd test + +matrix: + # works on Precise and Trusty + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-7 + env: + - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" + +before_install: + - eval "${MATRIX_EVAL}" From 58d4776b924569f8d472d749e3e18dafc652ab8f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 21 Oct 2018 02:25:33 -0400 Subject: [PATCH 282/403] Uses CXX from enviroment to build tests if provided --- test/SConstruct | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/SConstruct b/test/SConstruct index 5c4bc272..8c884bf6 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -11,6 +11,11 @@ env = Environment( # allows highighting to print to terminal from compiler output env['ENV']['TERM'] = os.environ['TERM'] +try: + env.Replace(CXX=os.environ['CXX']) +except KeyError: + pass + progs = Split( ''' accumulate From dd0e49943b950f5e48a27ef23f2b9ea0d675539d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 21 Oct 2018 11:55:03 -0400 Subject: [PATCH 283/403] If clang, use libc++ --- test/SConstruct | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/SConstruct b/test/SConstruct index 8c884bf6..e338b923 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -16,6 +16,10 @@ try: except KeyError: pass +if env['CXX'].startswith('clang++'): + env['CXXFLAGS'].append('-stdlib=libc++') + env['LINKFLAGS'].append('-stdlib=libc++') + progs = Split( ''' accumulate From f61f46a0a6f037ae8fe3e3a5b243899851e03883 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 22 Oct 2018 13:48:50 -0400 Subject: [PATCH 284/403] specifies linker libs for clang --- test/SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SConstruct b/test/SConstruct index e338b923..5122d8d4 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -18,7 +18,7 @@ except KeyError: if env['CXX'].startswith('clang++'): env['CXXFLAGS'].append('-stdlib=libc++') - env['LINKFLAGS'].append('-stdlib=libc++') + env['LINKFLAGS'].extend(['-lc++', '-lc++abi']) progs = Split( ''' From 008493b21627f36cda42ef95b9c9c324d37f198b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 22 Oct 2018 14:07:59 -0400 Subject: [PATCH 285/403] Revert "specifies linker libs for clang" This reverts commit f61f46a0a6f037ae8fe3e3a5b243899851e03883. --- test/SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SConstruct b/test/SConstruct index 5122d8d4..e338b923 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -18,7 +18,7 @@ except KeyError: if env['CXX'].startswith('clang++'): env['CXXFLAGS'].append('-stdlib=libc++') - env['LINKFLAGS'].extend(['-lc++', '-lc++abi']) + env['LINKFLAGS'].append('-stdlib=libc++') progs = Split( ''' From d2663addceb9a27e04f67acc72c58eb479c14278 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 27 Oct 2018 16:41:41 -0400 Subject: [PATCH 286/403] Uses custom test class for pointer to mem function Looking at the discussion on a clang bug, although the error I'm seeing isn't related, the code I had wasn't guaranteed to be portable anyway. https://bugs.llvm.org/show_bug.cgi?id=39463 --- test/helpers.hpp | 21 ++++++++++++++++++ test/test_dropwhile.cpp | 11 +++++----- test/test_groupby.cpp | 48 ++++++++++++++++++++++++++++++----------- 3 files changed, 62 insertions(+), 18 deletions(-) diff --git a/test/helpers.hpp b/test/helpers.hpp index 7c466145..aa80cd3c 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -31,6 +31,27 @@ namespace itertest { SolidInt(SolidInt&&) = delete; }; + class Integer { + private: + int i_{}; + + public: + constexpr Integer(int i) : i_{i} {} + constexpr bool is_zero() const { + return i_ == 0; + } + constexpr bool operator==(const Integer& other) const { + return i_ == other.i_; + } + constexpr bool operator!=(const Integer& other) const { + return i_ != other.i_; + } + + constexpr bool is_positive() const { + return i_ > 0; + } + }; + namespace { struct DoubleDereferenceError : std::exception { const char* what() const noexcept override { diff --git a/test/test_dropwhile.cpp b/test/test_dropwhile.cpp index 38e686aa..55370092 100644 --- a/test/test_dropwhile.cpp +++ b/test/test_dropwhile.cpp @@ -60,11 +60,12 @@ TEST_CASE("dropwhile: handles pointer to member", "[dropwhile]") { REQUIRE(v == vc); } -TEST_CASE("dropwhile: drop empty strings at front", "[dropwhile]") { - const std::vector words = {"", "", "check", "", "test"}; - auto dw = dropwhile(&std::string::empty, words); - const std::vector v(std::begin(dw), std::end(dw)); - const std::vector vc = {"check", "", "test"}; +TEST_CASE("dropwhile: drop zeros from front", "[dropwhile]") { + using itertest::Integer; + const std::vector nums = {0, 0, 3, 4, 0, 5, 0}; + auto dw = dropwhile(&Integer::is_zero, nums); + const std::vector v(std::begin(dw), std::end(dw)); + const std::vector vc = {3, 4, 0, 5, 0}; REQUIRE(v == vc); } diff --git a/test/test_groupby.cpp b/test/test_groupby.cpp index 1f86a40e..0069da14 100644 --- a/test/test_groupby.cpp +++ b/test/test_groupby.cpp @@ -59,24 +59,36 @@ TEST_CASE("groupby: works with lambda, callable, and function pointer") { } } - SECTION("pointer to member") { - for (auto&& gb : groupby(vec, &std::string::size)) { - keys.push_back(gb.first); - groups.emplace_back(std::begin(gb.second), std::end(gb.second)); - } - } - const std::vector kc = {2, 3, 5}; REQUIRE(keys == kc); const std::vector> gc = { - {"hi", "ab", "ho"}, {"abc", "def"}, {"abcde", "efghi"}, + {"hi", "ab", "ho"}, + {"abc", "def"}, + {"abcde", "efghi"}, }; REQUIRE(groups == gc); } -TEST_CASE("groupby: handles pointer to member", "[groupby]") { +TEST_CASE("groupby: handles pointer to member function", "[groupby]") { + std::vector nums = { + 10, 20, 30, -5, 40, -6, -7, 50, 60, -8, -9, -10, -11, 70}; + + std::vector> groups; + std::vector keys; + for (auto&& gb : groupby(nums, &itertest::Integer::is_positive)) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + const std::vector kc = {true, false, true, false, true, false, true}; + const std::vector> gc = { + {10, 20, 30}, {-5}, {40}, {-6, -7}, {50, 60}, {-8, -9, -10, -11}, {70}}; + REQUIRE(keys == kc); + REQUIRE(groups == gc); +} + +TEST_CASE("groupby: handles pointer to data member", "[groupby]") { using itertest::Point; const std::vector ps = { {0, 2}, {0, 4}, {1, 3}, {1, 7}, {1, 10}, {1, 12}, {3, 5}}; @@ -151,7 +163,9 @@ TEST_CASE("groupby: const iteration", "[groupby][const]") { REQUIRE(keys == kc); const std::vector> gc = { - {"hi", "ab", "ho"}, {"abc", "def"}, {"abcde", "efghi"}, + {"hi", "ab", "ho"}, + {"abc", "def"}, + {"abcde", "efghi"}, }; REQUIRE(groups == gc); @@ -203,7 +217,8 @@ TEST_CASE("groupby: groups can be skipped completely", "[groupby]") { REQUIRE(keys == kc); const std::vector> gc = { - {"hi", "ab", "ho"}, {"abcde", "efghi"}, + {"hi", "ab", "ho"}, + {"abcde", "efghi"}, }; REQUIRE(groups == gc); @@ -226,7 +241,9 @@ TEST_CASE("groupby: groups can be skipped partially", "[groupby]") { REQUIRE(keys == kc); const std::vector> gc = { - {"hi", "ab", "ho"}, {"abc"}, {"abcde", "efghi"}, + {"hi", "ab", "ho"}, + {"abc"}, + {"abcde", "efghi"}, }; REQUIRE(groups == gc); @@ -253,7 +270,12 @@ TEST_CASE("groupby: single argument uses elements as keys", "[groupby]") { REQUIRE(keys == kc); std::vector> gc = { - {5, 5}, {6, 6}, {19, 19, 19, 19}, {69}, {0}, {10, 10}, + {5, 5}, + {6, 6}, + {19, 19, 19, 19}, + {69}, + {0}, + {10, 10}, }; REQUIRE(groups == gc); From 8e55c430740031ec09d3344055f64f671717cfca Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 27 Oct 2018 16:56:48 -0400 Subject: [PATCH 287/403] Adds script to install new enough libc++ on travis --- .install-libcxx-travis.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .install-libcxx-travis.sh diff --git a/.install-libcxx-travis.sh b/.install-libcxx-travis.sh new file mode 100644 index 00000000..158cebef --- /dev/null +++ b/.install-libcxx-travis.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +if [[ "${COMPILER}" = clang++* ]]; then + echo "using clang, install libc++" + sudo apt-get install -y dpkg + wget -c http://launchpadlibrarian.net/360656578/libc++-helpers_6.0-2_all.deb + sudo dpkg -i libc++-helpers_6.0-2_all.deb + wget -c http://launchpadlibrarian.net/360656583/libc++abi1_6.0-2_amd64.deb + sudo dpkg -i libc++abi1_6.0-2_amd64.deb + wget -c http://launchpadlibrarian.net/360656580/libc++1_6.0-2_amd64.deb + sudo dpkg -i libc++1_6.0-2_amd64.deb + wget -c http://launchpadlibrarian.net/360656576/libc++-dev_6.0-2_amd64.deb + sudo dpkg -i libc++-dev_6.0-2_amd64.deb + wget -c http://launchpadlibrarian.net/360656581/libc++abi-dev_6.0-2_amd64.deb + sudo dpkg -i libc++abi-dev_6.0-2_amd64.deb + sudo apt-get install -f +fi From a19b44774fb7637de6dd8812d54c9ccb38841ecb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 27 Oct 2018 16:58:10 -0400 Subject: [PATCH 288/403] Removes conditions from libcxx install script --- .install-libcxx-travis.sh | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/.install-libcxx-travis.sh b/.install-libcxx-travis.sh index 158cebef..e108ea9e 100644 --- a/.install-libcxx-travis.sh +++ b/.install-libcxx-travis.sh @@ -1,17 +1,14 @@ #!/usr/bin/env bash -if [[ "${COMPILER}" = clang++* ]]; then - echo "using clang, install libc++" - sudo apt-get install -y dpkg - wget -c http://launchpadlibrarian.net/360656578/libc++-helpers_6.0-2_all.deb - sudo dpkg -i libc++-helpers_6.0-2_all.deb - wget -c http://launchpadlibrarian.net/360656583/libc++abi1_6.0-2_amd64.deb - sudo dpkg -i libc++abi1_6.0-2_amd64.deb - wget -c http://launchpadlibrarian.net/360656580/libc++1_6.0-2_amd64.deb - sudo dpkg -i libc++1_6.0-2_amd64.deb - wget -c http://launchpadlibrarian.net/360656576/libc++-dev_6.0-2_amd64.deb - sudo dpkg -i libc++-dev_6.0-2_amd64.deb - wget -c http://launchpadlibrarian.net/360656581/libc++abi-dev_6.0-2_amd64.deb - sudo dpkg -i libc++abi-dev_6.0-2_amd64.deb - sudo apt-get install -f -fi +sudo apt-get install -y dpkg +wget -c http://launchpadlibrarian.net/360656578/libc++-helpers_6.0-2_all.deb +sudo dpkg -i libc++-helpers_6.0-2_all.deb +wget -c http://launchpadlibrarian.net/360656583/libc++abi1_6.0-2_amd64.deb +sudo dpkg -i libc++abi1_6.0-2_amd64.deb +wget -c http://launchpadlibrarian.net/360656580/libc++1_6.0-2_amd64.deb +sudo dpkg -i libc++1_6.0-2_amd64.deb +wget -c http://launchpadlibrarian.net/360656576/libc++-dev_6.0-2_amd64.deb +sudo dpkg -i libc++-dev_6.0-2_amd64.deb +wget -c http://launchpadlibrarian.net/360656581/libc++abi-dev_6.0-2_amd64.deb +sudo dpkg -i libc++abi-dev_6.0-2_amd64.deb +sudo apt-get install -f From 9f37bf7049dc6987cbc785fc5ca642a4924e0ff1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 27 Oct 2018 17:37:16 -0400 Subject: [PATCH 289/403] Removes shebang from libcxx install --- .install-libcxx-travis.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/.install-libcxx-travis.sh b/.install-libcxx-travis.sh index e108ea9e..98b18fb0 100644 --- a/.install-libcxx-travis.sh +++ b/.install-libcxx-travis.sh @@ -1,5 +1,3 @@ -#!/usr/bin/env bash - sudo apt-get install -y dpkg wget -c http://launchpadlibrarian.net/360656578/libc++-helpers_6.0-2_all.deb sudo dpkg -i libc++-helpers_6.0-2_all.deb From 4c14dd96a58d74ad38ce98deff96d874777c0a48 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 27 Oct 2018 17:44:48 -0400 Subject: [PATCH 290/403] Travis build for gcc-[7,8] and clang-[5.0, 6.0] Using libc++ with clang. --- .travis.yml | 70 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index bbe56ec9..d4d97a0d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,43 @@ language: cpp - -script: scons - -before_script: cd test +dist: trusty +sudo: require matrix: - # works on Precise and Trusty + include: + - os: linux + compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-5.0 + packages: + - clang-5.0 + - clang++-5.0 + - valgrind + - gcc-8-base + - libc6 + - libgcc1 + env: + - COMPILER=clang++-5.0 + - USE_LIBCXX=1 + - os: linux + compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-6.0 + packages: + - clang-6.0 + - clang++-6.0 + - valgrind + - gcc-8-base + - libc6 + - libgcc1 + env: + - COMPILER=clang++-6.0 + - USE_LIBCXX=1 - os: linux addons: apt: @@ -13,8 +45,30 @@ matrix: - ubuntu-toolchain-r-test packages: - g++-7 + - valgrind + env: + - COMPILER=g++-7 + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-8 + - valgrind env: - - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" + - COMPILER=g++-8 + +script: + - ${COMPILER} --version + - CXX="${COMPILER}" scons + - ./test_all + - valgrind ./test_all + -before_install: - - eval "${MATRIX_EVAL}" +before_script: + - if [ -n "${USE_LIBCXX}" ]; then + bash .install-libcxx-travis.sh; + fi + - cd test + - ./download_catch.sh From 2e80258e03014af64021d0a222eb6d68500a522e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 27 Oct 2018 18:13:49 -0400 Subject: [PATCH 291/403] Conditional public data members for gcc bug gcc bug preventing these friend declarations from working https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87651 I'd rather not have these be public on every branch, in case someone is crazy enough to try to access `iters_` they'll hopefully at least get an error using one of their compilers. Fixes #48 --- internal/iterbase.hpp | 23 ++++++++++++++++++----- product.hpp | 9 +++++++-- zip.hpp | 8 +++++++- zip_longest.hpp | 4 ++++ 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 6232c300..c857af52 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -15,6 +15,14 @@ #include #include +// see gcc bug 87651 +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87651 +#ifdef __GNUC__ +#define NO_GCC_FRIEND_ERROR __GNUC__ < 8 +#else +#define NO_GCC_FRIEND_ERROR 1 +#endif + namespace iter { namespace impl { namespace get_iters { @@ -51,8 +59,13 @@ namespace iter { using AsConst = decltype(std::as_const(std::declval())); // iterator_type is the type of C's iterator - template //TODO: See bug https://developercommunity.visualstudio.com/content/problem/252157/sfinae-error-depends-on-name-of-template-parameter.html for why we use T instead of Container. Should be changed back to Container when that bug is fixed in MSVC. - using iterator_type = decltype(get_begin(std::declval())); + template // TODO: See bug + // https://developercommunity.visualstudio.com/content/problem/252157/sfinae-error-depends-on-name-of-template-parameter.html + // for why we use T instead of Container. Should be + // changed back to Container when that bug is fixed in + // MSVC. + using iterator_type = + decltype(get_begin(std::declval())); // iterator_type is the type of C's iterator template @@ -152,9 +165,9 @@ namespace iter { template struct is_random_access_iter::iterator_category, - std::random_access_iterator_tag>::value>> : std::true_type {}; + std::enable_if_t< + std::is_same::iterator_category, + std::random_access_iterator_tag>::value>> : std::true_type {}; template using has_random_access_iter = is_random_access_iter>; diff --git a/product.hpp b/product.hpp index 38836fba..38c68243 100644 --- a/product.hpp +++ b/product.hpp @@ -80,9 +80,14 @@ class iter::impl::Productor { template class IteratorTuple, template class TupleDeref> class IteratorTempl { +#if NO_GCC_FRIEND_ERROR private: template class, template class> friend class IteratorTempl; +#else + public: +#endif + using IterTupType = IteratorTuple; IterTupType iters_; IterTupType begin_iters_; @@ -126,7 +131,8 @@ class iter::impl::Productor { template class IT, template class TD> bool operator!=(const IteratorTempl& other) const { - if constexpr (sizeof...(Is) == 0) return false; + if constexpr (sizeof...(Is) == 0) + return false; else return (... && (std::get(iters_) != std::get(other.iters_))); } @@ -192,7 +198,6 @@ namespace iter { constexpr std::array, 1> product() { return {{}}; } - } namespace iter::impl { diff --git a/zip.hpp b/zip.hpp index ee973b9e..89e2e287 100644 --- a/zip.hpp +++ b/zip.hpp @@ -41,9 +41,14 @@ class iter::impl::Zipped { template class IteratorTuple, template class TupleDeref> class Iterator { + // see gcc bug 87651 +#if NO_GCC_FRIEND_ERROR private: template class, template class> friend class Iterator; +#else + public: +#endif IteratorTuple iters_; public: @@ -69,7 +74,8 @@ class iter::impl::Zipped { template class IT, template class TD> bool operator!=(const Iterator& other) const { - if constexpr (sizeof...(Is) == 0) return false; + if constexpr (sizeof...(Is) == 0) + return false; else return (... && (std::get(iters_) != std::get(other.iters_))); } diff --git a/zip_longest.hpp b/zip_longest.hpp index 89e637e3..238ec569 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -49,10 +49,14 @@ class iter::impl::ZippedLongest { template class IterTuple, template class OptTempl> class Iterator { +#if NO_GCC_FRIEND_ERROR private: template class, template class> friend class Iterator; +#else + public: +#endif IterTuple iters_; IterTuple ends_; From b92529f8362903bcd3c349090b77e777f8e95913 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 27 Oct 2018 18:19:21 -0400 Subject: [PATCH 292/403] formatting from msvc fix merge --- internal/iterbase.hpp | 14 +++++++------- product.hpp | 5 +++-- zip.hpp | 5 +++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index c857af52..e3d0d862 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -59,13 +59,13 @@ namespace iter { using AsConst = decltype(std::as_const(std::declval())); // iterator_type is the type of C's iterator - template // TODO: See bug - // https://developercommunity.visualstudio.com/content/problem/252157/sfinae-error-depends-on-name-of-template-parameter.html - // for why we use T instead of Container. Should be - // changed back to Container when that bug is fixed in - // MSVC. - using iterator_type = - decltype(get_begin(std::declval())); + // TODO: See bug + // https://developercommunity.visualstudio.com/content/problem/252157/sfinae-error-depends-on-name-of-template-parameter.html + // for why we use T instead of Container. Should be + // changed back to Container when that bug is fixed in + // MSVC. + template + using iterator_type = decltype(get_begin(std::declval())); // iterator_type is the type of C's iterator template diff --git a/product.hpp b/product.hpp index 38c68243..d7bc61e9 100644 --- a/product.hpp +++ b/product.hpp @@ -131,10 +131,11 @@ class iter::impl::Productor { template class IT, template class TD> bool operator!=(const IteratorTempl& other) const { - if constexpr (sizeof...(Is) == 0) + if constexpr (sizeof...(Is) == 0) { return false; - else + } else { return (... && (std::get(iters_) != std::get(other.iters_))); + } } template class IT, diff --git a/zip.hpp b/zip.hpp index 89e2e287..abadf45c 100644 --- a/zip.hpp +++ b/zip.hpp @@ -74,10 +74,11 @@ class iter::impl::Zipped { template class IT, template class TD> bool operator!=(const Iterator& other) const { - if constexpr (sizeof...(Is) == 0) + if constexpr (sizeof...(Is) == 0) { return false; - else + } else { return (... && (std::get(iters_) != std::get(other.iters_))); + } } template class IT, From 3f6ff3c56077efa805902b5d32b593409d79c8ff Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 27 Oct 2018 18:29:40 -0400 Subject: [PATCH 293/403] Adds travis build status --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 46ee3750..95f52602 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![Build Status](https://travis-ci.com/ryanhaining/cppitertools.svg?branch=master)](https://travis-ci.com/ryanhaining/cppitertools) + CPPItertools ============ Range-based for loop add-ons inspired by the Python builtins and itertools From eb07f97c1b8317510636c10b6e45c03a6b8bbaf8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 28 Oct 2018 00:30:45 -0400 Subject: [PATCH 294/403] remove test_zip_longest.cpp from CMakeLists.txt Just until I get boost worked out on appveyor --- test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 315e4b04..7d593210 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -22,6 +22,7 @@ endif() file(GLOB test_sources RELATIVE ${PROJECT_SOURCE_DIR} "test_*.cpp") list(REMOVE_ITEM test_sources test_main.cpp) +list(REMOVE_ITEM test_sources test_zip_longest.cpp) # until I get boost figured out with appveyor add_library(test_main OBJECT test_main.cpp) foreach(_source_cpp ${test_sources}) From 94d2c4a81956c6f386a17381da0d760c367aaf16 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 28 Oct 2018 01:02:59 -0400 Subject: [PATCH 295/403] Adds boost check to CMakeLists.txt --- test/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7d593210..e9140f47 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -9,10 +9,13 @@ cmake_minimum_required(VERSION 3.8) project(cppitertools_tests CXX) set (CMAKE_CXX_STANDARD 17) +find_package(Boost 1.60.0 REQUIRED) include_directories( .. + ${Boost_INCLUDE_DIRS} ) + include(CheckIncludeFileCXX) set(CMAKE_REQUIRED_INCLUDES ${PROJECT_SOURCE_DIR}) CHECK_INCLUDE_FILE_CXX(catch.hpp _has_catch) @@ -22,7 +25,6 @@ endif() file(GLOB test_sources RELATIVE ${PROJECT_SOURCE_DIR} "test_*.cpp") list(REMOVE_ITEM test_sources test_main.cpp) -list(REMOVE_ITEM test_sources test_zip_longest.cpp) # until I get boost figured out with appveyor add_library(test_main OBJECT test_main.cpp) foreach(_source_cpp ${test_sources}) From ede675ef161e0376dbe289f6a70c0ebde776efbb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 28 Oct 2018 01:36:24 -0400 Subject: [PATCH 296/403] Updates catch version. Was pretty out of date. yikes. --- test/download_catch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/download_catch.sh b/test/download_catch.sh index 2988d1b6..0cae9fd7 100755 --- a/test/download_catch.sh +++ b/test/download_catch.sh @@ -1,2 +1,2 @@ #!/usr/bin/env sh -wget -c https://github.com/catchorg/Catch2/releases/download/v2.0.1/catch.hpp +wget -c https://github.com/catchorg/Catch2/releases/download/v2.4.2/catch.hpp From 9bd671772e804c106b4522eae59a4347ffe0613b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 28 Oct 2018 01:54:04 -0400 Subject: [PATCH 297/403] Adds appveyor status --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 95f52602..e6744f18 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.com/ryanhaining/cppitertools.svg?branch=master)](https://travis-ci.com/ryanhaining/cppitertools) + CPPItertools ============ @@ -10,6 +10,12 @@ evaluation wherever possible. Follow [@cppitertools](https://twitter.com/cppitertools) for updates. +#### Build and Test Status +Status | Compilers +---- | ---- +[![Travis Build Status](https://travis-ci.com/ryanhaining/cppitertools.svg?branch=master)](https://travis-ci.com/ryanhaining/cppitertools) | gcc-7 gcc-8 clang-5.0 clang-6.0 +[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/ryanhaining/cppitertools?svg=true)](https://ci.appveyor.com/project/ryanhaining/cppitertools) | MSVC 2017 + #### Table of Contents [range](#range)
[enumerate](#enumerate)
From 55fb813a88b9fa2ef083f09cc927e9ead056d14e Mon Sep 17 00:00:00 2001 From: Tony RIVIERE Date: Sat, 22 Dec 2018 02:20:22 +0100 Subject: [PATCH 298/403] fix chain.from_iterable() when subiterables are empty --- chain.hpp | 14 +++++++++++++- internal/iterator_wrapper.hpp | 4 ++++ test/test_chain.cpp | 10 ++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/chain.hpp b/chain.hpp index 8a0522e3..d289a6a3 100644 --- a/chain.hpp +++ b/chain.hpp @@ -204,7 +204,14 @@ class iter::impl::ChainedFromIterable { std::optional sub_iter_p_; std::optional sub_end_p_; - void next_sub_iterable() { + void advance_while_empty_sub_iterable() { + while (top_level_iter_ != top_level_end_ && sub_iter_p_ == sub_end_p_) { + ++top_level_iter_; + update_sub_iterable(); + } + } + + void update_sub_iterable() { if (top_level_iter_ != top_level_end_) { sub_iterable_.reset(*top_level_iter_); sub_iter_p_ = @@ -216,6 +223,11 @@ class iter::impl::ChainedFromIterable { } } + void next_sub_iterable() { + update_sub_iterable(); + advance_while_empty_sub_iterable(); + } + public: using iterator_category = std::input_iterator_tag; using value_type = iterator_traits_deref>; diff --git a/internal/iterator_wrapper.hpp b/internal/iterator_wrapper.hpp index 2d91fc02..f068da97 100644 --- a/internal/iterator_wrapper.hpp +++ b/internal/iterator_wrapper.hpp @@ -94,6 +94,10 @@ class iter::impl::IteratorWrapperImpl { } not_equal; return std::visit(not_equal, sub_iter_or_end_, other.sub_iter_or_end_); } + + bool operator==(const IteratorWrapperImpl& other) const { + return !(*this != other); + } }; #endif diff --git a/test/test_chain.cpp b/test/test_chain.cpp index 32b9f184..6caabe3f 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -233,6 +233,16 @@ TEST_CASE("chain.fromm_iterable: Works with different begin and end types", REQUIRE(v == vc); } +TEST_CASE("chain.from_iterable: Works with empty subiterable", + "[chain.from_iterable]") { + std::vector> ivv{ + {}, {2, 4, 6}, {}, {8, 10, 12}, {14, 16, 18}, {}}; + auto ch = chain.from_iterable(ivv); + const std::vector v(std::begin(ch), std::end(ch)); + const std::vector vi = {2, 4, 6, 8, 10, 12, 14, 16, 18}; + REQUIRE(v == vi); +} + TEST_CASE( "chain.from_iterable: iterators cant be copy constructed " "and assigned", From af1e317864baeb7dee913b7219ffe4382ed885c7 Mon Sep 17 00:00:00 2001 From: Tony RIVIERE Date: Sat, 22 Dec 2018 02:52:49 +0100 Subject: [PATCH 299/403] Modify get_begin() get_end() to use either member functions if exist or use ADL in order to solve issues when ADL fails. --- internal/iterbase.hpp | 57 ++++++++++++++++++++++++++++++------------ test/test_iterbase.cpp | 28 +++++++++++++++++++++ 2 files changed, 69 insertions(+), 16 deletions(-) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index e3d0d862..7b460bf5 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -26,25 +26,50 @@ namespace iter { namespace impl { namespace get_iters { - // This has to be set up in a really weird way. - // This looks at first as if it could be - // decltype(auto) get_begin(T& t) { - // using std::begin; - // return begin(t); - // } - // However, without return types in the declaration, SFINAE gets - // messed up everywhere. - using std::begin; - // TODO add constexpr for c++17 + // begin() for C arrays + template + T* get_begin_impl(T (&array)[N], int) { + return array; + } + + // Prefer member begin(). + template ().begin())> + I get_begin_impl(T& r, int) { + return r.begin(); + } + + // Use ADL otherwises. + template ()))> + I get_begin_impl(T& r, long) { + return begin(r); + } + template - auto get_begin(T& t) -> decltype(begin(t)) { - return begin(t); + auto get_begin(T& t) -> decltype(get_begin_impl(std::declval(), 42)) { + return get_begin_impl(t, 42); } - using std::end; - // TODO add constexpr for c++17 + + // end() for C arrays + template + T* get_end_impl(T (&array)[N], int) { + return array + N; + } + + // Prefer member end(). + template ().end())> + I get_end_impl(T& r, int) { + return r.end(); + } + + // Use ADL otherwise. + template ()))> + I get_end_impl(T& r, long) { + return end(r); + } + template - auto get_end(T& t) -> decltype(end(t)) { - return end(t); + auto get_end(T& t) -> decltype(get_end_impl(std::declval(), 42)) { + return get_end_impl(t, 42); } } using get_iters::get_begin; diff --git a/test/test_iterbase.cpp b/test/test_iterbase.cpp index fecfb9a4..d27c4f7f 100644 --- a/test/test_iterbase.cpp +++ b/test/test_iterbase.cpp @@ -94,3 +94,31 @@ TEST_CASE("get_begin returns correct type", "[iterbase]") { std::vector v; REQUIRE((std::is_same{})); } + +namespace NS1 { + + struct Dummy { + auto begin() { + return 0; + } + auto end() { + return 0; + } + }; + + template + auto begin(T& t) { + return t.begin(); + } + + template + auto end(T& t) { + return t.end(); + } + +} // namespace NS1 + +TEST_CASE("Detects is_iterable with ADL conflicts", "[iterbase]") { + REQUIRE(iter::impl::is_iterable); + REQUIRE(iter::impl::is_iterable>); +} \ No newline at end of file From bcf48559b7fc762d87836212cb7b9cd44046c411 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 21 Dec 2018 22:35:42 -0500 Subject: [PATCH 300/403] Tests that arrays are iterable --- test/test_iterbase.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/test_iterbase.cpp b/test/test_iterbase.cpp index d27c4f7f..89c7fef9 100644 --- a/test/test_iterbase.cpp +++ b/test/test_iterbase.cpp @@ -119,6 +119,10 @@ namespace NS1 { } // namespace NS1 TEST_CASE("Detects is_iterable with ADL conflicts", "[iterbase]") { + int a[1]{}; + const int b[1]{}; REQUIRE(iter::impl::is_iterable); REQUIRE(iter::impl::is_iterable>); -} \ No newline at end of file + REQUIRE(iter::impl::is_iterable); + REQUIRE(iter::impl::is_iterable); +} From 520df7af0e509bec29fe73e31034b94ce57e50f1 Mon Sep 17 00:00:00 2001 From: Misha Brukman Date: Sat, 5 Jan 2019 23:42:20 -0500 Subject: [PATCH 301/403] Fixed typos, capitalizations, and added commas. --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e6744f18..d53c8da9 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Range-based for loop add-ons inspired by the Python builtins and itertools library. Like itertools and the Python3 builtins, this library uses lazy evaluation wherever possible. -*Note*: Everthing is inside the `iter` namespace. +*Note*: Everything is inside the `iter` namespace. Follow [@cppitertools](https://twitter.com/cppitertools) for updates. @@ -95,7 +95,7 @@ underlying iterables, but if anything noteworthy is needed it is described in this document. #### Guarantees of implementations -By implementations I mean the objects returned by the API's functions. All of +By implementations, I mean the objects returned by the API's functions. All of the implementation classes are move-constructible, not copy-constructible, not assignable. All iterators that work over another iterable are tagged as InputIterators and behave as such. @@ -104,11 +104,11 @@ as InputIterators and behave as such. If you find anything not working as you expect, not compiling when you believe it should, a divergence from the python itertools behavior, or any sort of error, please let me know. The preferable means would be to open an issue on -github. If you want to talk about an issue that you don't feel would be -appropriate as a github issue (or you just don't want to open one), -You can email me directly with whatever code you have that describes the -problem, I've been pretty responsive in the past. If I believe you are -"misusing" the library I'll try to put the blame on myself for being unclear +GitHub. If you want to talk about an issue that you don't feel would be +appropriate as a GitHub issue (or you just don't want to open one), +you can email me directly with whatever code you have that describes the +problem; I've been pretty responsive in the past. If I believe you are +"misusing" the library, I'll try to put the blame on myself for being unclear in this document and take the steps to clarify it. So please, contact me with any concerns, I'm open to feedback. @@ -150,8 +150,8 @@ result, itertools can be mixed and nested. #### Pipe syntax -Wherever it makes sense I've implemented the "pipe" operator that has become -common in similar libraries. When the syntax is available it is done by pulling +Wherever it makes sense, I've implemented the "pipe" operator that has become +common in similar libraries. When the syntax is available, it is done by pulling out the iterable from the call and placing it before the tool. For example: ```c++ @@ -411,7 +411,7 @@ step of 1.
`count(i, st)` will start counting from `i` with a step of `st`. *Technical limitations*: Unlike Python which can use its long integer -types when needed, count() would eventually exceed the +types when needed, `count()` would eventually exceed the maximum possible value for its type (or minimum with a negative step). `count` is actually implemented as a `range` with the stopping point being the `std::numeric_limits::max()` for the integral type (`long` @@ -749,7 +749,7 @@ chunked chunked will yield subsequent chunkes of an iterable in blocks of a specified size. The final chunk may be shorter than the rest if the chunk size given -does not evenly divide the length of the iterable +does not evenly divide the length of the iterable. Example usage: ```c++ From 44207cdd947dc765d29951384823ac4fbafb29ed Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 9 Mar 2019 13:17:59 -0500 Subject: [PATCH 302/403] Puts main.cpp in own bazel cc_library Fixes #53 --- test/BUILD | 6 ++++++ test/make_tests.bzl | 9 ++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/test/BUILD b/test/BUILD index 5c7c5d9c..b7bdc149 100644 --- a/test/BUILD +++ b/test/BUILD @@ -36,4 +36,10 @@ progs = [ "helpers", ] +cc_library( + name = "test_main", + srcs = ["test_main.cpp", "catch.hpp"], + copts = ["-std=c++17", "-g"] +) + itertools_tests(progs) diff --git a/test/make_tests.bzl b/test/make_tests.bzl index 883f0576..68a428b8 100644 --- a/test/make_tests.bzl +++ b/test/make_tests.bzl @@ -2,7 +2,10 @@ def itertools_tests(progs): for p in progs: native.cc_test( name = "test_{}".format(p), - srcs = ["test_{}.cpp".format(p), "test_main.cpp", "catch.hpp", "helpers.hpp"], - deps = ["//:cppitertools",], - copts = ["-I.", "-std=c++17", "-Wall", "-Wextra", "-pedantic", "-g"], + srcs = ["test_{}.cpp".format(p), "catch.hpp", "helpers.hpp"], + deps = [ + "//:cppitertools", + ":test_main", + ], + copts = ["-I.", "-std=c++17", "-Wall", "-Wextra", "-pedantic", "-g"], ) From b7a3c38a388da3f24714c73dd7d34c823d80043d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 22 Mar 2019 18:10:24 -0400 Subject: [PATCH 303/403] Adds range .start() .step() and .stop() First part of #55 --- range.hpp | 22 +++++++++++++------ test/test_range.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/range.hpp b/range.hpp index d4727b4b..c30f35f0 100644 --- a/range.hpp +++ b/range.hpp @@ -124,6 +124,18 @@ class iter::impl::Range { : start_{start}, stop_{stop}, step_{step} {} public: + constexpr T start() const noexcept { + return start_; + } + + constexpr T stop() const noexcept { + return stop_; + } + + constexpr T step() const noexcept { + return step_; + } + // the reference type here is T, which doesn't strictly follow all // of the rules, but std::vector::iterator::reference isn't // a reference type either, this isn't any worse @@ -139,11 +151,9 @@ class iter::impl::Range { const Iterator& lhs, const Iterator& rhs) noexcept { assert(!lhs.is_end); assert(rhs.is_end); - if - constexpr(std::is_unsigned{}) { - return lhs.data.value() < rhs.data.value(); - } - else { + if constexpr (std::is_unsigned{}) { + return lhs.data.value() < rhs.data.value(); + } else { return !(lhs.data.step() > 0 && lhs.data.value() >= rhs.data.value()) && !(lhs.data.step() < 0 && lhs.data.value() <= rhs.data.value()); @@ -183,7 +193,7 @@ class iter::impl::Range { return *this; } - Iterator operator++(int)noexcept { + Iterator operator++(int) noexcept { auto ret = *this; ++*this; return ret; diff --git a/test/test_range.cpp b/test/test_range.cpp index dab748e3..23833e03 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -10,6 +10,58 @@ using Vec = const std::vector; using iter::range; +TEST_CASE("range: .start(), .stop(), and .step()", "[range]") { + SECTION("one arg") { + auto r = range(3); + REQUIRE(r.start() == 0); + REQUIRE(r.stop() == 3); + REQUIRE(r.step() == 1); + + // make sure iterators aren't changing the value + auto it = r.begin(); + ++it; + + REQUIRE(r.start() == 0); + REQUIRE(r.stop() == 3); + REQUIRE(r.step() == 1); + } + + SECTION("two args") { + auto r = range(2, 10); + REQUIRE(r.start() == 2); + REQUIRE(r.stop() == 10); + REQUIRE(r.step() == 1); + } + + SECTION("three args") { + auto r = range(-6, 20, 3); + REQUIRE(r.start() == -6); + REQUIRE(r.stop() == 20); + REQUIRE(r.step() == 3); + } + + SECTION("one arg (double)") { + auto r = range(3.5); + REQUIRE(r.start() == 0); + REQUIRE(r.stop() == Approx(3.5)); + REQUIRE(r.step() == Approx(1.0)); + } + + SECTION("two args (double)") { + auto r = range(20.1, 31.7); + REQUIRE(r.start() == Approx(20.1)); + REQUIRE(r.stop() == Approx(31.7)); + REQUIRE(r.step() == Approx(1.0)); + } + + SECTION("three args (double)") { + auto r = range(-6.3, 5.7, 0.1); + REQUIRE(r.start() == Approx(-6.3)); + REQUIRE(r.stop() == Approx(5.7)); + REQUIRE(r.step() == Approx(0.1)); + } +} + TEST_CASE("range: works with only stop", "[range]") { auto r = range(5); Vec v(std::begin(r), std::end(r)); From 449d9de526f8b953e2ec307946a43f5f5a2e09cd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Apr 2019 01:32:46 -0400 Subject: [PATCH 304/403] Updates catch version to 2.6.0 --- test/download_catch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/download_catch.sh b/test/download_catch.sh index 0cae9fd7..487e1233 100755 --- a/test/download_catch.sh +++ b/test/download_catch.sh @@ -1,2 +1,2 @@ #!/usr/bin/env sh -wget -c https://github.com/catchorg/Catch2/releases/download/v2.4.2/catch.hpp +wget -c https://github.com/catchorg/Catch2/releases/download/v2.6.0/catch.hpp From a24fcdcf40dd76ce5b46cde363be8c3231e7b940 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Apr 2019 01:34:37 -0400 Subject: [PATCH 305/403] Adds .size() to range Second Part of #55. Not supporting floating point types. I can't yet get the float version perfect. --- range.hpp | 37 ++++++++++++++++++++++++++++++------- test/test_range.cpp | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/range.hpp b/range.hpp index c30f35f0..fb222c7c 100644 --- a/range.hpp +++ b/range.hpp @@ -123,6 +123,17 @@ class iter::impl::Range { constexpr Range(T start, T stop, T step = 1) noexcept : start_{start}, stop_{stop}, step_{step} {} + // if val is "before" the stopping point. + static constexpr bool is_within_range( + T val, T stop_val, [[maybe_unused]] T step_val) { + if constexpr (std::is_unsigned{}) { + return val < stop_val; + } else { + return !(step_val > 0 && val >= stop_val) + && !(step_val < 0 && val <= stop_val); + } + } + public: constexpr T start() const noexcept { return start_; @@ -136,6 +147,23 @@ class iter::impl::Range { return step_; } + constexpr std::size_t size() const noexcept { + static_assert(!std::is_floating_point_v, + "range size() not supperted with floating point types"); + if (!is_within_range(start(), stop(), step())) { + return 0; + } + + auto diff = stop() - start(); + auto res = diff / step(); + assert(res >= 0); + auto result = static_cast(res); + if (diff % step()) { + ++result; + } + return result; + } + // the reference type here is T, which doesn't strictly follow all // of the rules, but std::vector::iterator::reference isn't // a reference type either, this isn't any worse @@ -151,13 +179,8 @@ class iter::impl::Range { const Iterator& lhs, const Iterator& rhs) noexcept { assert(!lhs.is_end); assert(rhs.is_end); - if constexpr (std::is_unsigned{}) { - return lhs.data.value() < rhs.data.value(); - } else { - return !(lhs.data.step() > 0 && lhs.data.value() >= rhs.data.value()) - && !(lhs.data.step() < 0 - && lhs.data.value() <= rhs.data.value()); - } + return is_within_range( + lhs.data.value(), rhs.data.value(), lhs.data.step()); } static bool not_equal_to_end( diff --git a/test/test_range.cpp b/test/test_range.cpp index 23833e03..7bfa85ac 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -312,3 +312,42 @@ TEST_CASE("range: iterator meets forward iterator requirements", "[range]") { REQUIRE(itertest::IsForwardIterator::value); REQUIRE(itertest::IsForwardIterator::value); } + +TEMPLATE_TEST_CASE("range: .size() with signed integrals", "[range]", + signed char, short, int, long, long long) { + constexpr TestType N = 5; + constexpr TestType INC = 1; + for (TestType start = -N; start < N; start += INC) { + for (TestType stop = -N; stop < N; stop += INC) { + for (TestType step = -N; step < N; step += INC) { + if (step == 0) { + continue; + } + auto r = range(start, stop, step); + REQUIRE(r.size() + == static_cast( + std::distance(std::begin(r), std::end(r)))); + } + } + } +} + +TEMPLATE_TEST_CASE("range: .size() with unsigned integrals", "[range]", + unsigned char, unsigned short, unsigned int, unsigned long, + unsigned long long) { + constexpr TestType N = 5; + constexpr TestType INC = 1; + for (TestType start = 0; start < N; start += INC) { + for (TestType stop = 0; stop < N; stop += INC) { + for (TestType step = 0; step < N; step += INC) { + if (step == 0) { + continue; + } + auto r = range(start, stop, step); + REQUIRE(r.size() + == static_cast( + std::distance(std::begin(r), std::end(r)))); + } + } + } +} From 0e1765270dbb7254416e251f8764c2895977e236 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Apr 2019 01:49:25 -0400 Subject: [PATCH 306/403] Adds range operator[] To the range object, not to the iterator. --- range.hpp | 4 ++++ test/test_range.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/range.hpp b/range.hpp index fb222c7c..2efa7396 100644 --- a/range.hpp +++ b/range.hpp @@ -147,6 +147,10 @@ class iter::impl::Range { return step_; } + constexpr T operator[](std::size_t index) const noexcept { + return start() + (step() * index); + } + constexpr std::size_t size() const noexcept { static_assert(!std::is_floating_point_v, "range size() not supperted with floating point types"); diff --git a/test/test_range.cpp b/test/test_range.cpp index 7bfa85ac..4a25211a 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -313,6 +313,38 @@ TEST_CASE("range: iterator meets forward iterator requirements", "[range]") { REQUIRE(itertest::IsForwardIterator::value); } +TEST_CASE("range: operator[] simple tests", "[range]") { + SECTION("range(start)") { + auto r = range(4); + REQUIRE(r[0] == 0); + REQUIRE(r[1] == 1); + REQUIRE(r[2] == 2); + REQUIRE(r[3] == 3); + } + SECTION("range(start, stop)") { + auto r = range(10, 14); + REQUIRE(r[0] == 10); + REQUIRE(r[1] == 11); + REQUIRE(r[2] == 12); + REQUIRE(r[3] == 13); + } + SECTION("range(start, stop, step)") { + auto r = range(20, 30, 3); + REQUIRE(r[0] == 20); + REQUIRE(r[1] == 23); + REQUIRE(r[2] == 26); + REQUIRE(r[3] == 29); + } + SECTION("range(start, stop, step) with double") { + auto r = range(50.0, 50.99, 0.2); + REQUIRE(r[0] == Approx(50.0)); + REQUIRE(r[1] == Approx(50.2)); + REQUIRE(r[2] == Approx(50.4)); + REQUIRE(r[3] == Approx(50.6)); + REQUIRE(r[4] == Approx(50.8)); + } +} + TEMPLATE_TEST_CASE("range: .size() with signed integrals", "[range]", signed char, short, int, long, long long) { constexpr TestType N = 5; From 97bfd33cdc268426b20f189c13d3ed88f5e1f4c2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 14 Apr 2019 02:08:41 -0400 Subject: [PATCH 307/403] Adds range updates to README --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index d53c8da9..1c85fd38 100644 --- a/README.md +++ b/README.md @@ -250,6 +250,12 @@ recomputed at each step to avoid accumulating floating point inaccuracies (`value = start + (step * steps_taken`). The result of the latter is a bit slower but more accurate. +`range` also supports the following operations: + - `.size()` to get the number of elements in the range (not enabled for + floating point ranges). + - Accessors for `.start()`, `.stop()`, and `.step()`. + - Indexing. Given a range `r`, `r[n]` is the `n`th element in the range. + enumerate --------- From f6573bd394a24c5febf2943453d354d2adacaad8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 7 Jun 2019 00:00:34 -0400 Subject: [PATCH 308/403] Small fix and cleanup to DerefHolder get_ptr() wasn't valid for DerefHolder with values --- internal/iterbase.hpp | 29 +++++++++++++++++++---------- test/test_iterbase.cpp | 3 +++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 7b460bf5..df1df2ba 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -7,6 +7,7 @@ // also applies to the name of the file. No user code should include // this file directly. +#include #include #include #include @@ -276,28 +277,32 @@ namespace iter { // it could still be an rvalue reference using TPlain = std::remove_reference_t; - std::optional item_p; + std::optional item_p_; public: using reference = TPlain&; using pointer = TPlain*; + static constexpr bool stores_value = true; + DerefHolder() = default; reference get() { - return *this->item_p; + assert(item_p_.has_value()); + return *item_p_; } pointer get_ptr() { - return this->item_p.get(); + assert(item_p_.has_value()); + return &item_p_.value(); } void reset(T&& item) { - item_p = std::move(item); + item_p_ = std::move(item); } explicit operator bool() const { - return static_cast(this->item_p); + return static_cast(item_p_); } }; @@ -309,25 +314,29 @@ namespace iter { using pointer = T*; private: - pointer item_p{}; + pointer item_p_{}; public: + static constexpr bool stores_value = false; + DerefHolder() = default; reference get() { - return *this->item_p; + assert(item_p_); + return *item_p_; } pointer get_ptr() { - return this->item_p; + assert(item_p_); + return item_p_; } void reset(reference item) { - this->item_p = &item; + item_p_ = &item; } explicit operator bool() const { - return this->item_p != nullptr; + return item_p_ != nullptr; } }; diff --git a/test/test_iterbase.cpp b/test/test_iterbase.cpp index 89c7fef9..c8783f32 100644 --- a/test/test_iterbase.cpp +++ b/test/test_iterbase.cpp @@ -63,6 +63,7 @@ TEST_CASE("are_same", "[iterbase]") { } TEST_CASE("DerefHolder lvalue reference", "[iterbase]") { + REQUIRE_FALSE(it::DerefHolder::stores_value); it::DerefHolder dh; int a = 2; int b = 5; @@ -78,6 +79,7 @@ TEST_CASE("DerefHolder lvalue reference", "[iterbase]") { } TEST_CASE("DerefHolder non-reference", "[iterbase]") { + REQUIRE(it::DerefHolder::stores_value); it::DerefHolder dh; int a = 2; int b = 5; @@ -85,6 +87,7 @@ TEST_CASE("DerefHolder non-reference", "[iterbase]") { dh.reset(std::move(a)); REQUIRE(dh.get() == 2); REQUIRE(&dh.get() != &a); + REQUIRE(dh.get_ptr() != &a); dh.reset(std::move(b)); REQUIRE(dh.get() == 5); From b42772dc0e35bece4eee7b30870f78013fab5703 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 7 Jun 2019 00:14:57 -0400 Subject: [PATCH 309/403] Uses shared_ptr for vector in chunked() Addresses part of #57 --- chunked.hpp | 16 +++++++++------- test/test_mixed.cpp | 33 +++++++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/chunked.hpp b/chunked.hpp index 87f0a0de..1d03b6e1 100644 --- a/chunked.hpp +++ b/chunked.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -45,20 +46,21 @@ class iter::impl::Chunker { private: template friend class Iterator; + std::shared_ptr> chunk_ = + std::make_shared>(); IteratorWrapper sub_iter_; IteratorWrapper sub_end_; - DerefVec chunk_; std::size_t chunk_size_ = 0; bool done() const { - return chunk_.empty(); + return chunk_->empty(); } void refill_chunk() { - chunk_.get().clear(); + chunk_->get().clear(); std::size_t i{0}; while (i < chunk_size_ && sub_iter_ != sub_end_) { - chunk_.get().push_back(sub_iter_); + chunk_->get().push_back(sub_iter_); ++sub_iter_; ++i; } @@ -76,7 +78,7 @@ class iter::impl::Chunker { : sub_iter_{std::move(sub_iter)}, sub_end_{std::move(sub_end)}, chunk_size_{s} { - chunk_.get().reserve(chunk_size_); + chunk_->get().reserve(chunk_size_); refill_chunk(); } @@ -103,11 +105,11 @@ class iter::impl::Chunker { } DerefVec& operator*() { - return chunk_; + return *chunk_; } DerefVec* operator->() { - return &chunk_; + return chunk_.get(); } }; diff --git a/test/test_mixed.cpp b/test/test_mixed.cpp index 46d47f03..4f5acc02 100644 --- a/test/test_mixed.cpp +++ b/test/test_mixed.cpp @@ -75,8 +75,8 @@ TEST_CASE("filtering doesn't dereference multiple times", "[imap][filter]") { } TEST_CASE("dropwhile doesn't dereference multiple times", "[imap][dropwhile]") { - using iter::imap; using iter::dropwhile; + using iter::imap; std::array arr = {{{41}, {42}, {43}}}; @@ -128,9 +128,9 @@ TEST_CASE("sorted(chain.from_iterable)", "[sorted][chain.from_iterable]") { } TEST_CASE("filter into enumerate with pipe", "[filter][enumerate]") { - using iter::imap; - using iter::filter; using iter::enumerate; + using iter::filter; + using iter::imap; std::array arr = {{{41}, {42}, {43}, {44}}}; auto seq = @@ -144,8 +144,33 @@ TEST_CASE("filter into enumerate with pipe", "[filter][enumerate]") { REQUIRE(v == vc); } +TEST_CASE("enumerate(filter(chunked()))", "[filter][enumerate][chunked]") { + using iter::chunked; + using iter::enumerate; + using iter::filter; + std::vector v(500); + auto chunks = chunked(v, 100); + auto filtered = filter([](auto&) { return true; }, chunks); + for (auto&& [i, chunk] : enumerate(filtered)) { + (void)i; + REQUIRE(chunk.size() == 100); + } +} + +TEST_CASE("zip(filter(chunked()))", "[filter][chunked][zip]") { + using iter::chunked; + using iter::filter; + using iter::zip; + std::vector v(500); + auto chunks = chunked(v, 100); + auto filtered = filter([](auto&) { return true; }, chunks); + for (auto&& [chunk] : zip(filtered)) { + REQUIRE(chunk.size() == 100); + } +} + TEST_CASE("chain.from_iterable: accept imap result that yields rvalues", - "[chain.from_iterable][imap]") { + "[chain.from_iterable][imap]") { using iter::chain; using iter::imap; const std::vector> ns = {{'a'}, {'q'}, {'x', 'z'}}; From 512dbd975af2517f894d11c2b728e3669ad5d5a8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 7 Jun 2019 00:36:00 -0400 Subject: [PATCH 310/403] Uses shared_ptr of vector in sliding_window Addresses part of #57 --- sliding_window.hpp | 14 ++++++++------ test/test_mixed.cpp | 12 ++++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/sliding_window.hpp b/sliding_window.hpp index fcb41e00..d4ab6cbc 100644 --- a/sliding_window.hpp +++ b/sliding_window.hpp @@ -7,6 +7,7 @@ #include #include +#include #include namespace iter { @@ -41,8 +42,9 @@ class iter::impl::WindowSlider { private: template friend class Iterator; + std::shared_ptr> window_ = + std::make_shared>(); IteratorWrapper sub_iter_; - DerefVec window_; public: using iterator_category = std::input_iterator_tag; @@ -56,7 +58,7 @@ class iter::impl::WindowSlider { : sub_iter_(std::move(sub_iter)) { std::size_t i{0}; while (i < window_sz && sub_iter_ != sub_end) { - window_.get().push_back(sub_iter_); + window_->get().push_back(sub_iter_); ++i; if (i != window_sz) { ++sub_iter_; @@ -75,17 +77,17 @@ class iter::impl::WindowSlider { } DerefVec& operator*() { - return window_; + return *window_; } DerefVec* operator->() { - return window_; + return window_.get(); } Iterator& operator++() { ++sub_iter_; - window_.get().pop_front(); - window_.get().push_back(sub_iter_); + window_->get().pop_front(); + window_->get().push_back(sub_iter_); return *this; } diff --git a/test/test_mixed.cpp b/test/test_mixed.cpp index 4f5acc02..a9f45e24 100644 --- a/test/test_mixed.cpp +++ b/test/test_mixed.cpp @@ -169,6 +169,18 @@ TEST_CASE("zip(filter(chunked()))", "[filter][chunked][zip]") { } } +TEST_CASE("zip(filter(sliding_window()))", "[filter][sliding_window][zip]") { + using iter::filter; + using iter::sliding_window; + using iter::zip; + std::vector v(15); + auto windows = sliding_window(v, 10); + auto filtered = filter([](auto&) { return true; }, windows); + for (auto&& [window] : zip(filtered)) { + REQUIRE(window.size() == 10); + } +} + TEST_CASE("chain.from_iterable: accept imap result that yields rvalues", "[chain.from_iterable][imap]") { using iter::chain; From a06b18af7a1ffb6a3db7c650070b1fa7c68cc9e0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Jun 2019 01:37:29 -0400 Subject: [PATCH 311/403] Tests imap(filter(groupby())) from #59 --- test/test_mixed.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/test_mixed.cpp b/test/test_mixed.cpp index a9f45e24..67ffa2ca 100644 --- a/test/test_mixed.cpp +++ b/test/test_mixed.cpp @@ -181,6 +181,22 @@ TEST_CASE("zip(filter(sliding_window()))", "[filter][sliding_window][zip]") { } } +TEST_CASE("imap(filter(groupby()))", "[filter][groupby][imap])") { + using iter::filter; + using iter::groupby; + using iter::imap; + + std::vector v{true, true, true, false, false, true, true}; + auto a = groupby(v, [](bool b) { return b; }); + auto b = filter([](auto& g) { return g.first; }, a); + auto c = imap( + [](auto& g) { return std::distance(g.second.begin(), g.second.end()); }, + b); + for (auto x : c) { + (void)x; + } +} + TEST_CASE("chain.from_iterable: accept imap result that yields rvalues", "[chain.from_iterable][imap]") { using iter::chain; From 662f7116d95cb3d17b73b73014e2e85d7ed8695a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Jun 2019 01:40:47 -0400 Subject: [PATCH 312/403] Lazily find first element of filter() I believe the right approach is to not bind any references to elements until one actually starts iterating. This way the iterator can be passed around before iteration starts without a dangling reference. This should actually fix the filter() issues of #57 and #59 --- filter.hpp | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/filter.hpp b/filter.hpp index 10a793c6..2a632be2 100644 --- a/filter.hpp +++ b/filter.hpp @@ -50,12 +50,14 @@ class iter::impl::Filtered { template friend class Iterator; using Holder = DerefHolder>; - IteratorWrapper sub_iter_; + mutable IteratorWrapper sub_iter_; IteratorWrapper sub_end_; - Holder item_; + mutable Holder item_; FilterFunc* filter_func_; - void inc_sub_iter() { + // All of these are marked const because the sub_iter_ is lazily + // initialized. The morality of this is questionable. + void inc_sub_iter() const { ++sub_iter_; if (sub_iter_ != sub_end_) { item_.reset(*sub_iter_); @@ -64,13 +66,20 @@ class iter::impl::Filtered { // increment until the iterator points to is true on the // predicate. Called by constructor and operator++ - void skip_failures() { + void skip_failures() const { while ( sub_iter_ != sub_end_ && !std::invoke(*filter_func_, item_.get())) { inc_sub_iter(); } } + void init_if_first_use() const { + if (!item_ && sub_iter_ != sub_end_) { + item_.reset(*sub_iter_); + skip_failures(); + } + } + public: using iterator_category = std::input_iterator_tag; using value_type = iterator_traits_deref; @@ -82,22 +91,20 @@ class iter::impl::Filtered { IteratorWrapper&& sub_end, FilterFunc& filter_func) : sub_iter_{std::move(sub_iter)}, sub_end_{std::move(sub_end)}, - filter_func_(&filter_func) { - if (sub_iter_ != sub_end_) { - item_.reset(*sub_iter_); - } - skip_failures(); - } + filter_func_(&filter_func) {} typename Holder::reference operator*() { + init_if_first_use(); return item_.get(); } typename Holder::pointer operator->() { + init_if_first_use(); return item_.get_ptr(); } Iterator& operator++() { + init_if_first_use(); inc_sub_iter(); skip_failures(); return *this; @@ -111,6 +118,8 @@ class iter::impl::Filtered { template bool operator!=(const Iterator& other) const { + init_if_first_use(); + other.init_if_first_use(); return sub_iter_ != other.sub_iter_; } From bacdcb2199314bc3c382190884e1d24976133c9f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Jun 2019 02:05:13 -0400 Subject: [PATCH 313/403] Adds imap(dropwhile(groupby())) like from #59 --- test/test_mixed.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/test_mixed.cpp b/test/test_mixed.cpp index 67ffa2ca..ff364271 100644 --- a/test/test_mixed.cpp +++ b/test/test_mixed.cpp @@ -197,6 +197,22 @@ TEST_CASE("imap(filter(groupby()))", "[filter][groupby][imap])") { } } +TEST_CASE("imap(dropwhile(groupby()))", "[dropwhile][groupby][imap])") { + using iter::dropwhile; + using iter::groupby; + using iter::imap; + + std::vector v{false, false, true, true, false, true, true}; + auto a = groupby(v, [](bool b) { return b; }); + auto b = dropwhile([](auto& g) { return g.first; }, a); + auto c = imap( + [](auto& g) { return std::distance(g.second.begin(), g.second.end()); }, + b); + for (auto x : c) { + (void)x; + } +} + TEST_CASE("chain.from_iterable: accept imap result that yields rvalues", "[chain.from_iterable][imap]") { using iter::chain; From 29b1e4799d45c419047a89d8d00e8a89bb8be2da Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Jun 2019 02:09:56 -0400 Subject: [PATCH 314/403] Lazily finds first element in dropwhile for #57 --- dropwhile.hpp | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/dropwhile.hpp b/dropwhile.hpp index ca190471..dc1874b0 100644 --- a/dropwhile.hpp +++ b/dropwhile.hpp @@ -39,12 +39,13 @@ class iter::impl::Dropper { template friend class Iterator; using Holder = DerefHolder>; - IteratorWrapper sub_iter_; + mutable IteratorWrapper sub_iter_; IteratorWrapper sub_end_; - Holder item_; + mutable Holder item_; FilterFunc* filter_func_; - void inc_sub_iter() { + // see comments from filter about mutability + void inc_sub_iter() const { ++sub_iter_; if (sub_iter_ != sub_end_) { item_.reset(*sub_iter_); @@ -52,12 +53,19 @@ class iter::impl::Dropper { } // skip all values for which the predicate is true - void skip_passes() { + void skip_passes() const { while (sub_iter_ != sub_end_ && std::invoke(*filter_func_, item_.get())) { inc_sub_iter(); } } + void init_if_first_use() const { + if (!item_ && sub_iter_ != sub_end_) { + item_.reset(*sub_iter_); + skip_passes(); + } + } + public: using iterator_category = std::input_iterator_tag; using value_type = iterator_traits_deref; @@ -69,22 +77,20 @@ class iter::impl::Dropper { IteratorWrapper&& sub_end, FilterFunc& filter_func) : sub_iter_{std::move(sub_iter)}, sub_end_{std::move(sub_end)}, - filter_func_(&filter_func) { - if (sub_iter_ != sub_end_) { - item_.reset(*sub_iter_); - } - skip_passes(); - } + filter_func_(&filter_func) {} typename Holder::reference operator*() { + init_if_first_use(); return item_.get(); } typename Holder::pointer operator->() { + init_if_first_use(); return item_.get_ptr(); } Iterator& operator++() { + init_if_first_use(); inc_sub_iter(); return *this; } @@ -97,6 +103,8 @@ class iter::impl::Dropper { template bool operator!=(const Iterator& other) const { + init_if_first_use(); + other.init_if_first_use(); return sub_iter_ != other.sub_iter_; } From a430b460eaa385ca911106a23ef5ee1d06371b0e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Jun 2019 02:18:40 -0400 Subject: [PATCH 315/403] Adds imap(takewhile(groupby())) test from #59 --- test/test_mixed.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/test_mixed.cpp b/test/test_mixed.cpp index ff364271..1e4ee949 100644 --- a/test/test_mixed.cpp +++ b/test/test_mixed.cpp @@ -213,6 +213,22 @@ TEST_CASE("imap(dropwhile(groupby()))", "[dropwhile][groupby][imap])") { } } +TEST_CASE("imap(takewhile(groupby()))", "[takewhile][groupby][imap])") { + using iter::groupby; + using iter::imap; + using iter::takewhile; + + std::vector v{true, true, true, false, false}; + auto a = groupby(v, [](bool b) { return b; }); + auto b = takewhile([](auto& g) { return g.first; }, a); + auto c = imap( + [](auto& g) { return std::distance(g.second.begin(), g.second.end()); }, + b); + for (auto x : c) { + (void)x; + } +} + TEST_CASE("chain.from_iterable: accept imap result that yields rvalues", "[chain.from_iterable][imap]") { using iter::chain; From fbd57d345c037f4c39720027b14901dc61f9436f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Jun 2019 02:21:19 -0400 Subject: [PATCH 316/403] Lazily checks first element under predicate for #57 --- takewhile.hpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/takewhile.hpp b/takewhile.hpp index 8e28fcf2..a04d86b2 100644 --- a/takewhile.hpp +++ b/takewhile.hpp @@ -40,11 +40,14 @@ class iter::impl::Taker { template friend class Iterator; using Holder = DerefHolder>; - IteratorWrapper sub_iter_; + // I want this mutable so I can use operator* reliably in the const + // context of init_if_first_use + mutable IteratorWrapper sub_iter_; IteratorWrapper sub_end_; - Holder item_; + mutable Holder item_; FilterFunc* filter_func_; + // see comments from filter about mutability void inc_sub_iter() { ++sub_iter_; if (sub_iter_ != sub_end_) { @@ -52,12 +55,19 @@ class iter::impl::Taker { } } - void check_current() { + void check_current() const { if (sub_iter_ != sub_end_ && !std::invoke(*filter_func_, item_.get())) { sub_iter_ = sub_end_; } } + void init_if_first_use() const { + if (!item_ && sub_iter_ != sub_end_) { + item_.reset(*sub_iter_); + check_current(); + } + } + public: using iterator_category = std::input_iterator_tag; using value_type = iterator_traits_deref; @@ -69,22 +79,20 @@ class iter::impl::Taker { IteratorWrapper&& sub_end, FilterFunc& filter_func) : sub_iter_{std::move(sub_iter)}, sub_end_{std::move(sub_end)}, - filter_func_(&filter_func) { - if (sub_iter_ != sub_end_) { - item_.reset(*sub_iter_); - } - check_current(); - } + filter_func_(&filter_func) {} typename Holder::reference operator*() { + init_if_first_use(); return item_.get(); } typename Holder::pointer operator->() { + init_if_first_use(); return item_.get_ptr(); } Iterator& operator++() { + init_if_first_use(); inc_sub_iter(); check_current(); return *this; @@ -98,6 +106,8 @@ class iter::impl::Taker { template bool operator!=(const Iterator& other) const { + init_if_first_use(); + other.init_if_first_use(); return sub_iter_ != other.sub_iter_; } From a166113a3de4f5609745f24e789a43eace914c8f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Jun 2019 02:28:31 -0400 Subject: [PATCH 317/403] Adds flipped == iterator compare for dropwhile --- test/test_dropwhile.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/test_dropwhile.cpp b/test/test_dropwhile.cpp index 55370092..2b85c607 100644 --- a/test/test_dropwhile.cpp +++ b/test/test_dropwhile.cpp @@ -105,7 +105,12 @@ TEST_CASE("dropwhile: skips all elements when all are true under predicate", "[dropwhile]") { Vec ns{3, 4, 5, 6}; auto d = dropwhile([](int i) { return i != 0; }, ns); - REQUIRE(std::begin(d) == std::end(d)); + SECTION("normal compare") { + REQUIRE(std::begin(d) == std::end(d)); + } + SECTION("reversed compare") { + REQUIRE(std::end(d) == std::begin(d)); + } } TEST_CASE("dropwhile: identity", "[dropwhile]") { @@ -119,7 +124,12 @@ TEST_CASE("dropwhile: identity", "[dropwhile]") { TEST_CASE("dropwhile: empty case is empty", "[dropwhile]") { Vec ns{}; auto d = dropwhile([](int i) { return i != 0; }, ns); - REQUIRE(std::begin(d) == std::end(d)); + SECTION("normal compare") { + REQUIRE(std::begin(d) == std::end(d)); + } + SECTION("reversed compare") { + REQUIRE(std::end(d) == std::begin(d)); + } } TEST_CASE("dropwhile: only drops from beginning", "[dropwhile]") { From 7712c2abce1a486e5ea70eb655ec8b918fb24769 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Jun 2019 02:29:18 -0400 Subject: [PATCH 318/403] Adds flipped == iterator compare for filter --- test/test_filter.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/test_filter.cpp b/test/test_filter.cpp index 73f684ee..b10dd5be 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -149,7 +149,12 @@ TEST_CASE("filter: all elements fail predicate", "[filter]") { Vec ns{10, 20, 30, 40, 50}; auto f = filter(less_than_five, ns); - REQUIRE(std::begin(f) == std::end(f)); + SECTION("normal compare") { + REQUIRE(std::begin(f) == std::end(f)); + } + SECTION("reversed compare") { + REQUIRE(std::end(f) == std::begin(f)); + } } TEST_CASE("filter: doesn't move or copy elements of iterable", "[filter]") { From 357961341543f4453ce2e5c2a85f2aa92da2ac56 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Jun 2019 02:29:32 -0400 Subject: [PATCH 319/403] Adds flipped == iterator compare for takewhile --- test/test_takewhile.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/test/test_takewhile.cpp b/test/test_takewhile.cpp index 23ad8462..903f6a9f 100644 --- a/test/test_takewhile.cpp +++ b/test/test_takewhile.cpp @@ -125,7 +125,12 @@ TEST_CASE("takewhile: everything passes predicate", "[takewhile]") { TEST_CASE("takewhile: empty iterable is empty", "[takewhile]") { Vec ns{}; auto tw = takewhile(under_ten, ns); - REQUIRE(std::begin(tw) == std::end(tw)); + SECTION("normal compare") { + REQUIRE(std::begin(tw) == std::end(tw)); + } + SECTION("reversed compare") { + REQUIRE(std::end(tw) == std::begin(tw)); + } } TEST_CASE( @@ -134,13 +139,23 @@ TEST_CASE( SECTION("First element is only element") { Vec ns = {20}; auto tw = takewhile(under_ten, ns); - REQUIRE(std::begin(tw) == std::end(tw)); + SECTION("normal compare") { + REQUIRE(std::begin(tw) == std::end(tw)); + } + SECTION("reversed compare") { + REQUIRE(std::end(tw) == std::begin(tw)); + } } SECTION("First element followed by elements that pass") { Vec ns = {20, 1, 1}; auto tw = takewhile(under_ten, ns); - REQUIRE(std::begin(tw) == std::end(tw)); + SECTION("normal compare") { + REQUIRE(std::begin(tw) == std::end(tw)); + } + SECTION("reversed compare") { + REQUIRE(std::end(tw) == std::begin(tw)); + } } } From dd34859b1cbd5fe8c7013fd0ab6888430fcaaef0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 23 Jun 2019 12:32:41 -0400 Subject: [PATCH 320/403] Replaces count's min() call with lowest() Fixes #60 --- count.hpp | 3 +-- test/test_count.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/count.hpp b/count.hpp index 1694589c..327596bf 100644 --- a/count.hpp +++ b/count.hpp @@ -8,8 +8,7 @@ namespace iter { template constexpr auto count(T start, T step) noexcept { - // if step is < 0, set the stop to numeric min, otherwise numeric max - T stop = step < T(0) ? std::numeric_limits::min() + T stop = step < T(0) ? std::numeric_limits::lowest() : std::numeric_limits::max(); return range(start, stop, step); } diff --git a/test/test_count.cpp b/test/test_count.cpp index f0f0de68..8998f1eb 100644 --- a/test/test_count.cpp +++ b/test/test_count.cpp @@ -65,6 +65,68 @@ TEST_CASE("count: with step > 1", "[count]") { REQUIRE(v == vc); } +TEST_CASE("count: with unsigned", "[count]") { + constexpr unsigned int uint_max = + static_cast(std::numeric_limits::max()); + std::vector v{}; + int steps = 0; + for (auto i : count(uint_max)) { + v.push_back(i); + if (steps == 2) { + break; + } + ++steps; + } + const std::vector vc{uint_max, uint_max + 1, uint_max + 2}; + + REQUIRE(v == vc); +} + +TEST_CASE("count: with negative step", "[count]") { + std::vector v{}; + int steps = 0; + for (auto i : count(0, -1)) { + v.push_back(i); + if (steps == 2) { + break; + } + ++steps; + } + const std::vector vc{0, -1, -2}; + + REQUIRE(v == vc); +} + +TEST_CASE("count: with double", "[count]") { + std::vector v{}; + int steps = 0; + for (auto i : count(1.0, 0.5)) { + v.push_back(i); + if (steps == 3) { + break; + } + ++steps; + } + const std::vector vc{1.0, 1.5, 2.0, 2.5}; + + REQUIRE(v == vc); +} + +TEST_CASE("count: with negative double step", "[count]") { + std::vector v{}; + int steps = 0; + for (auto i : count(1.0, -0.5)) { + v.push_back(i); + if (steps == 3) { + break; + } + ++steps; + } + const std::vector vc{1.0, 0.5, 0.0, -0.5}; + + REQUIRE(v == vc); +} + TEST_CASE("count: can bo constexpr", "[count]") { constexpr auto c = count(); constexpr auto c2 = count(5); From 93d70efe2416d05ae74dde22e0fd0d60378798e0 Mon Sep 17 00:00:00 2001 From: botelho Date: Fri, 2 Aug 2019 11:50:24 -0700 Subject: [PATCH 321/403] First rev of batched --- BUILD | 1 + batched.hpp | 141 ++++++++++++++++++++++++++++++++++ examples/SConstruct | 1 + examples/batched_examples.cpp | 23 ++++++ itertools.hpp | 1 + test/BUILD | 1 + test/SConstruct | 1 + test/test_batched.cpp | 101 ++++++++++++++++++++++++ 8 files changed, 270 insertions(+) create mode 100644 batched.hpp create mode 100644 examples/batched_examples.cpp create mode 100644 test/test_batched.cpp diff --git a/BUILD b/BUILD index 8b162b86..bab14566 100644 --- a/BUILD +++ b/BUILD @@ -2,6 +2,7 @@ cc_library( name = "cppitertools", hdrs = [ "accumulate.hpp", + "batched.hpp", "chain.hpp", "chunked.hpp", "combinations.hpp", diff --git a/batched.hpp b/batched.hpp new file mode 100644 index 00000000..b57f0e28 --- /dev/null +++ b/batched.hpp @@ -0,0 +1,141 @@ +#ifndef ITER_BATCHED_HPP_ +#define ITER_BATCHED_HPP_ + +#include "internal/iterator_wrapper.hpp" +#include "internal/iteratoriterator.hpp" +#include "internal/iterbase.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace iter { + namespace impl { + template + class Batcher; + + using BatchedFn = IterToolFnBindSizeTSecond; + } + constexpr impl::BatchedFn batched{}; +} + +template +class iter::impl::Batcher { + private: + Container container_; + std::size_t num_batches_; + + Batcher(Container&& container, std::size_t const num_batches) + : container_(std::forward(container)), num_batches_{num_batches} {} + + friend BatchedFn; + + template + using IndexVector = std::vector>; + template + using DerefVec = IterIterWrapper>; + + public: + Batcher(Batcher&&) = default; + template + class Iterator { + private: + template + friend class Iterator; + std::shared_ptr> batch_ = + std::make_shared>(); + IteratorWrapper sub_iter_; + IteratorWrapper sub_end_; + std::size_t num_batches_; + std::size_t size_; + std::size_t count_; + + bool done() const { + return batch_->empty(); + } + + void refill_batch() { + batch_->get().clear(); + if (count_ < num_batches_) { + std::size_t const batch_size(size_ / num_batches_ + std::min(1, (size_ % num_batches_) / (count_ + 1))); + batch_->get().reserve(batch_size); + for (std::size_t i = 0; i < batch_size; ++i) { + batch_->get().push_back(sub_iter_); + ++sub_iter_; + } + ++count_; + } + } + + public: + using iterator_category = std::input_iterator_tag; + using value_type = DerefVec; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + + Iterator(IteratorWrapper&& sub_iter, + IteratorWrapper&& sub_end, std::size_t num_batches) + : sub_iter_{std::move(sub_iter)}, + sub_end_{std::move(sub_end)}, + num_batches_{num_batches}, + size_{static_cast(std::distance(sub_iter_, sub_end_))}, + count_{0} { + refill_batch(); + } + + Iterator& operator++() { + refill_batch(); + return *this; + } + + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + template + bool operator!=(const Iterator& other) const { + return !(*this == other); + } + + template + bool operator==(const Iterator& other) const { + return done() == other.done() + && (done() || !(sub_iter_ != other.sub_iter_)); + } + + DerefVec& operator*() { + return *batch_; + } + + DerefVec* operator->() { + return batch_.get(); + } + }; + + Iterator begin() { + return {get_begin(container_), get_end(container_), num_batches_}; + } + + Iterator end() { + return {get_end(container_), get_end(container_), num_batches_}; + } + + Iterator> begin() const { + return {get_begin(std::as_const(container_)), + get_end(std::as_const(container_)), num_batches_}; + } + + Iterator> end() const { + return {get_end(std::as_const(container_)), + get_end(std::as_const(container_)), num_batches_}; + } +}; + +#endif diff --git a/examples/SConstruct b/examples/SConstruct index c1ed4d10..5f9110c9 100644 --- a/examples/SConstruct +++ b/examples/SConstruct @@ -15,6 +15,7 @@ env['ENV']['TERM'] = os.environ['TERM'] progs = Split( ''' accumulate + batched chain chunked combinatoric diff --git a/examples/batched_examples.cpp b/examples/batched_examples.cpp new file mode 100644 index 00000000..1d2d4a6c --- /dev/null +++ b/examples/batched_examples.cpp @@ -0,0 +1,23 @@ +#include + +#include +#include + +int main() { + std::vector v {1,2,3,4,5,6,7,8,9}; + std::cout << "num batches: 5\n"; + for (auto&& sec : iter::batched(v, 5)) { + for (auto&& i : sec) { + std::cout << i << " "; + } + std::cout << '\n'; + } + + std::cout << "num batches: 4\n"; + for (auto&& sec : iter::batched(v,4)) { + for (auto&& i : sec) { + std::cout << i << " "; + } + std::cout << '\n'; + } +} diff --git a/itertools.hpp b/itertools.hpp index 7dd9b9a8..bf824196 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -2,6 +2,7 @@ #define ITERTOOLS_ALL_HPP_ #include "accumulate.hpp" +#include "batched.hpp" #include "chain.hpp" #include "chunked.hpp" #include "combinations.hpp" diff --git a/test/BUILD b/test/BUILD index b7bdc149..9ceefecd 100644 --- a/test/BUILD +++ b/test/BUILD @@ -2,6 +2,7 @@ load(":make_tests.bzl", "itertools_tests") progs = [ "accumulate", + "batched", "chain", "chunked", "combinations", diff --git a/test/SConstruct b/test/SConstruct index e338b923..98af3051 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -23,6 +23,7 @@ if env['CXX'].startswith('clang++'): progs = Split( ''' accumulate + batched chain chunked combinations diff --git a/test/test_batched.cpp b/test/test_batched.cpp new file mode 100644 index 00000000..209edc42 --- /dev/null +++ b/test/test_batched.cpp @@ -0,0 +1,101 @@ +#include + +#include +#include +#include +#include + +#include "catch.hpp" +#include "helpers.hpp" + +using iter::batched; +using Vec = std::vector; +using ResVec = std::vector; + +TEST_CASE("batched: basic test", "[batched]") { + Vec ns = {1, 2, 3, 4, 5, 6}; + ResVec results; + SECTION("Normal call") { + for (auto&& g : batched(ns, 2)) { + results.emplace_back(std::begin(g), std::end(g)); + } + } + SECTION("Pipe") { + for (auto&& g : ns | batched(2)) { + results.emplace_back(std::begin(g), std::end(g)); + } + } + + ResVec rc = {{1, 2, 3}, {4 ,5, 6}}; + + REQUIRE(results == rc); +} + +TEST_CASE("batched: const batched", "[batched][const]") { + Vec ns = {1, 2, 3, 4, 5, 6}; + ResVec results; + SECTION("Normal call") { + const auto& ch = batched(ns, 2); + for (auto&& g : ch) { + results.emplace_back(std::begin(g), std::end(g)); + } + } + ResVec rc = {{1, 2, 3}, {4, 5, 6}}; + + REQUIRE(results == rc); +} + +TEST_CASE("batched: const iterators can be compared to non-const iterators", + "[batched][const]") { + auto c = batched(Vec{}, 1); + const auto& cc = c; + (void)(std::begin(c) == std::end(cc)); +} + +TEST_CASE("batched: len(iterable) % groupsize != 0", "[batched]") { + Vec ns = {1, 2, 3, 4, 5, 6, 7}; + ResVec results; + for (auto&& g : batched(ns, 3)) { + results.emplace_back(std::begin(g), std::end(g)); + } + + ResVec rc = {{1, 2, 3}, {4, 5}, {6, 7}}; + + REQUIRE(results == rc); +} + +TEST_CASE("batched: iterators can be compared", "[batched]") { + Vec ns = {1, 2, 3, 4, 5, 6, 7}; + auto g = batched(ns, 3); + auto it = std::begin(g); + REQUIRE(it == std::begin(g)); + REQUIRE_FALSE(it != std::begin(g)); + ++it; + REQUIRE(it != std::begin(g)); + REQUIRE_FALSE(it == std::begin(g)); +} + +TEST_CASE("batched: size 0 is empty", "[batched]") { + Vec ns{1, 2, 3}; + auto g = batched(ns, 0); + REQUIRE(std::begin(g) == std::end(g)); +} + +TEST_CASE("batched: empty iterable gives empty batched", "[batched]") { + Vec ns{}; + auto g = batched(ns, 1); + REQUIRE(std::begin(g) == std::end(g)); +} + +TEST_CASE("batched: iterator meets requirements", "[batched]") { + std::string s{}; + auto c = batched(s, 1); + REQUIRE(itertest::IsIterator::value); +} + +template +using ImpT = decltype(batched(std::declval(), 1)); +TEST_CASE("batched: has correct ctor and assign ops", "[batched]") { + REQUIRE(itertest::IsMoveConstructibleOnly>::value); + REQUIRE(itertest::IsMoveConstructibleOnly>::value); +} From 95b1d3881941c431aa389f24970db93abbee6976 Mon Sep 17 00:00:00 2001 From: botelho Date: Fri, 2 Aug 2019 15:39:18 -0700 Subject: [PATCH 322/403] Minor --- examples/batched_examples.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/batched_examples.cpp b/examples/batched_examples.cpp index 1d2d4a6c..dfe67486 100644 --- a/examples/batched_examples.cpp +++ b/examples/batched_examples.cpp @@ -14,7 +14,7 @@ int main() { } std::cout << "num batches: 4\n"; - for (auto&& sec : iter::batched(v,4)) { + for (auto&& sec : iter::batched(v, 4)) { for (auto&& i : sec) { std::cout << i << " "; } From 3e7ceca38cc17b2f6707da1615896628a47fecdb Mon Sep 17 00:00:00 2001 From: botelho Date: Fri, 2 Aug 2019 18:17:18 -0700 Subject: [PATCH 323/403] Added support for containers with different begin and end types --- batched.hpp | 24 +++++++++++++++++++++++- test/test_batched.cpp | 10 ++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/batched.hpp b/batched.hpp index b57f0e28..e5eadf13 100644 --- a/batched.hpp +++ b/batched.hpp @@ -78,12 +78,34 @@ class iter::impl::Batcher { using pointer = value_type*; using reference = value_type&; + template + struct distance_helper { + static constexpr difference_type distance(Iter1 it1, Iter2 it2) { + difference_type dist(0); + for (; it1 != it2; ++it1) + ++dist; + return dist; + } + }; + + template + struct distance_helper && std::is_arithmetic_v>> { + static constexpr difference_type distance(Iter1 it1, Iter2 it2) { + return std::distance(it1, it2); + } + }; + + template + difference_type distance(Iter1 it1, Iter2 it2) const { + return distance_helper::distance(it1, it2); + } + Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, std::size_t num_batches) : sub_iter_{std::move(sub_iter)}, sub_end_{std::move(sub_end)}, num_batches_{num_batches}, - size_{static_cast(std::distance(sub_iter_, sub_end_))}, + size_{static_cast(distance(sub_iter_, sub_end_))}, count_{0} { refill_batch(); } diff --git a/test/test_batched.cpp b/test/test_batched.cpp index 209edc42..962b77ec 100644 --- a/test/test_batched.cpp +++ b/test/test_batched.cpp @@ -81,6 +81,16 @@ TEST_CASE("batched: size 0 is empty", "[batched]") { REQUIRE(std::begin(g) == std::end(g)); } +TEST_CASE("batched: Works with different begin and end types", "[batched]") { + CharRange cr{'f'}; + std::vector> results; + for (auto&& g : batched(cr, 3)) { + results.emplace_back(std::begin(g), std::end(g)); + } + std::vector> rc = {{'a', 'b'}, {'c', 'd'}, {'e'}}; + REQUIRE(results == rc); +} + TEST_CASE("batched: empty iterable gives empty batched", "[batched]") { Vec ns{}; auto g = batched(ns, 1); From 4ba6e0469b2868fc3cf8c430b060263847236c26 Mon Sep 17 00:00:00 2001 From: ssbotelh Date: Sat, 3 Aug 2019 10:54:50 -0700 Subject: [PATCH 324/403] Added batched to README.md --- README.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c85fd38..758b6491 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Status | Compilers [slice](#slice)
[sliding\_window](#sliding_window)
[chunked](#chunked)
+[batched](#batched)
##### Combinatoric fuctions [product](#product)
@@ -168,6 +169,7 @@ would expect them to behave: - accumulate - chain.from\_iterable - chunked +- batched - combinations - combinations\_with\_replacement - cycle @@ -753,7 +755,7 @@ for (auto&& sec : sliding_window(v,4)) { chunked ------ -chunked will yield subsequent chunkes of an iterable in blocks of a specified +chunked will yield subsequent chunks of an iterable in blocks of a specified size. The final chunk may be shorter than the rest if the chunk size given does not evenly divide the length of the iterable. @@ -774,6 +776,32 @@ The above prints: 5 6 7 8 9 ``` +batched +------- + +batched will yield a given number N of batches containing subsequent elements from an iterable, +assuming the iterable contains at least N elements. +The size of each batch is immaterial, but the implementation guarantees that no two batches will +differ in size by more than 1. + +Example usage: +```c++ +vector v {1,2,3,4,5,6,7,8,9}; +for (auto&& sec : batched(v,4)) { + for (auto&& i : sec) { + cout << i << ' '; + } + cout << '\n'; +} +``` + +The above prints: +``` +1 2 3 +4 5 +6 7 +8 9 +``` product ------ From 91d091fe884a6731d3c329a4c19b8e87552afc2f Mon Sep 17 00:00:00 2001 From: botelho Date: Sun, 4 Aug 2019 23:15:02 -0700 Subject: [PATCH 325/403] Added test case --- test/test_batched.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/test_batched.cpp b/test/test_batched.cpp index 962b77ec..e32adfc1 100644 --- a/test/test_batched.cpp +++ b/test/test_batched.cpp @@ -52,7 +52,7 @@ TEST_CASE("batched: const iterators can be compared to non-const iterators", (void)(std::begin(c) == std::end(cc)); } -TEST_CASE("batched: len(iterable) % groupsize != 0", "[batched]") { +TEST_CASE("batched: len(iterable) % num_batches != 0", "[batched]") { Vec ns = {1, 2, 3, 4, 5, 6, 7}; ResVec results; for (auto&& g : batched(ns, 3)) { @@ -64,6 +64,18 @@ TEST_CASE("batched: len(iterable) % groupsize != 0", "[batched]") { REQUIRE(results == rc); } +TEST_CASE("batched: num_batches > len(iterable)", "[batched]") { + Vec ns = {1, 2, 3, 4, 5, 6, 7}; + ResVec results; + for (auto&& g : batched(ns, 9)) { + results.emplace_back(std::begin(g), std::end(g)); + } + + ResVec rc = {{1}, {2}, {3}, {4}, {5}, {6}, {7}}; + + REQUIRE(results == rc); +} + TEST_CASE("batched: iterators can be compared", "[batched]") { Vec ns = {1, 2, 3, 4, 5, 6, 7}; auto g = batched(ns, 3); From 2a5de0c2b41f33dde724cb0442d272ea620078b4 Mon Sep 17 00:00:00 2001 From: botelho Date: Mon, 5 Aug 2019 09:20:41 -0700 Subject: [PATCH 326/403] Added another example --- examples/batched_examples.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/batched_examples.cpp b/examples/batched_examples.cpp index dfe67486..c63c05b3 100644 --- a/examples/batched_examples.cpp +++ b/examples/batched_examples.cpp @@ -20,4 +20,12 @@ int main() { } std::cout << '\n'; } + + std::cout << "num batches: 6\n"; + for (auto&& sec : iter::batched(v, 6)) { + for (auto&& i : sec) { + std::cout << i << " "; + } + std::cout << '\n'; + } } From c8b32d1ff8ec4273bed2d99ec32383529ce348c9 Mon Sep 17 00:00:00 2001 From: botelho Date: Mon, 5 Aug 2019 09:34:02 -0700 Subject: [PATCH 327/403] Added test for uneven batch sizes --- test/test_batched.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/test_batched.cpp b/test/test_batched.cpp index e32adfc1..bdd5e2a3 100644 --- a/test/test_batched.cpp +++ b/test/test_batched.cpp @@ -31,6 +31,18 @@ TEST_CASE("batched: basic test", "[batched]") { REQUIRE(results == rc); } +TEST_CASE("batched: uneven batch sizes", "[batched]") { + Vec ns = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + ResVec results; + for (auto&& g : batched(ns, 6)) { + results.emplace_back(std::begin(g), std::end(g)); + } + + ResVec rc = {{1, 2}, {3, 4}, {5, 6}, {7}, {8}, {9}}; + + REQUIRE(results == rc); +} + TEST_CASE("batched: const batched", "[batched][const]") { Vec ns = {1, 2, 3, 4, 5, 6}; ResVec results; From 41f7d221fe452dfc198914560355b837423e2a1d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 25 Aug 2019 17:50:17 -0400 Subject: [PATCH 328/403] Replaces assignment with emplace in DerefHolder Fixes #62 --- internal/iterbase.hpp | 2 +- test/test_mixed.cpp | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index df1df2ba..57cc1b78 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -298,7 +298,7 @@ namespace iter { } void reset(T&& item) { - item_p_ = std::move(item); + item_p_.emplace(std::move(item)); } explicit operator bool() const { diff --git a/test/test_mixed.cpp b/test/test_mixed.cpp index 1e4ee949..e9b92d34 100644 --- a/test/test_mixed.cpp +++ b/test/test_mixed.cpp @@ -241,3 +241,18 @@ TEST_CASE("chain.from_iterable: accept imap result that yields rvalues", REQUIRE(v == vc); } + +TEST_CASE( + "filter(enumerate()), DerefHolder works correctly (see github issue #62", + "[filter][enumerate]") { + using iter::enumerate; + using iter::filter; + std::vector ns = {50, 55, 60, 65}; + auto f = + iter::filter([](auto& i) { return std::get<0>(i) > 1; }, enumerate(ns)); + const std::vector> v(std::begin(f), std::end(f)); + + const std::vector> vc = {{2, 60}, {3, 65}}; + + REQUIRE(v == vc); +} From 334c7155638a916244234678f3922bd063d68d95 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 16 Sep 2019 10:44:29 -0700 Subject: [PATCH 329/403] Adds MSVC 2019 to appveyor build status description --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 758b6491..5f473218 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Follow [@cppitertools](https://twitter.com/cppitertools) for updates. Status | Compilers ---- | ---- [![Travis Build Status](https://travis-ci.com/ryanhaining/cppitertools.svg?branch=master)](https://travis-ci.com/ryanhaining/cppitertools) | gcc-7 gcc-8 clang-5.0 clang-6.0 -[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/ryanhaining/cppitertools?svg=true)](https://ci.appveyor.com/project/ryanhaining/cppitertools) | MSVC 2017 +[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/ryanhaining/cppitertools?svg=true)](https://ci.appveyor.com/project/ryanhaining/cppitertools) | MSVC 2017 MSVC 2019 #### Table of Contents [range](#range)
From cb3635456bdb531121b82b4d2e3afc7ae1f56d47 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 22 Dec 2019 21:29:36 -0500 Subject: [PATCH 330/403] Fixes const iteration for chain() Fixes #65 --- chain.hpp | 14 ++++++++++++-- test/test_chain.cpp | 14 +++++++------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/chain.hpp b/chain.hpp index d289a6a3..23d1e054 100644 --- a/chain.hpp +++ b/chain.hpp @@ -25,6 +25,16 @@ namespace iter { // rather than a chain function, use a callable object to support // from_iterable class ChainMaker; + + template + struct AsTupleOfConstImpl; + + template + struct AsTupleOfConstImpl> + : type_is...>> {}; + + template + using AsTupleOfConst = typename AsTupleOfConstImpl::type; } } @@ -169,12 +179,12 @@ class iter::impl::Chained { {get_end(std::get(tup_))...}}; } - Iterator> begin() const { + Iterator> begin() const { return {0, {get_begin(std::as_const(std::get(tup_)))...}, {get_end(std::as_const(std::get(tup_)))...}}; } - Iterator> end() const { + Iterator> end() const { return {sizeof...(Is), {get_end(std::as_const(std::get(tup_)))...}, {get_end(std::as_const(std::get(tup_)))...}}; } diff --git a/test/test_chain.cpp b/test/test_chain.cpp index 6caabe3f..b4b77cf2 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -10,8 +10,8 @@ #include "catch.hpp" using iter::chain; -using itertest::SolidInt; using itertest::BasicIterable; +using itertest::SolidInt; using Vec = const std::vector; TEST_CASE("chain: three strings", "[chain]") { @@ -28,8 +28,8 @@ TEST_CASE("chain: three strings", "[chain]") { TEST_CASE("chain: const iteration", "[chain][const]") { std::string s1{"abc"}; - /* const */ std::string s2{"mno"}; - auto ch = chain(s1, s2, std::string{"xyz"}); + const std::string s2{"mno"}; + const auto ch = chain(s1, s2, std::string{"xyz"}); Vec v(std::begin(ch), std::end(ch)); Vec vc{'a', 'b', 'c', 'm', 'n', 'o', 'x', 'y', 'z'}; @@ -309,8 +309,8 @@ template using ImpT2 = decltype(chain.from_iterable(std::declval())); TEST_CASE("chain.from_iterable: has correct ctor and assign ops", "[chain.from_iterable]") { - REQUIRE(itertest::IsMoveConstructibleOnly>>:: - value); - REQUIRE(itertest::IsMoveConstructibleOnly&>>:: - value); + REQUIRE(itertest::IsMoveConstructibleOnly< + ImpT2>>::value); + REQUIRE(itertest::IsMoveConstructibleOnly< + ImpT2&>>::value); } From 2cc82d2be666aabd66279a8693fd2c6f196117c1 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Thu, 26 Dec 2019 15:04:25 -0800 Subject: [PATCH 331/403] Adds information to imap return type. Fixes #66 --- imap.hpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/imap.hpp b/imap.hpp index f022e6d0..1e84faf0 100644 --- a/imap.hpp +++ b/imap.hpp @@ -1,17 +1,21 @@ #ifndef ITER_IMAP_H_ #define ITER_IMAP_H_ +#include + #include "starmap.hpp" #include "zip.hpp" -#include - namespace iter { namespace impl { struct IMapFn : PipeableAndBindFirst { template - decltype(auto) operator()( - MapFunc map_func, Containers&&... containers) const { + auto operator()(MapFunc map_func, Containers&&... containers) const + // explicitly specifying type here to allow more expressions that only + // care about the type, and don't need a valid implementation. + // See #66 + -> StarMapper(containers)...))> { return starmap(map_func, zip(std::forward(containers)...)); } using PipeableAndBindFirst::operator(); From 0ebfbd60a05fe6ac2b9c39759dd91cc2cf69c136 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Thu, 26 Dec 2019 15:08:45 -0800 Subject: [PATCH 332/403] Removes trailing whitespace in README --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5f473218..bd52d172 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Follow [@cppitertools](https://twitter.com/cppitertools) for updates. #### Build and Test Status Status | Compilers ----- | ---- +---- | ---- [![Travis Build Status](https://travis-ci.com/ryanhaining/cppitertools.svg?branch=master)](https://travis-ci.com/ryanhaining/cppitertools) | gcc-7 gcc-8 clang-5.0 clang-6.0 [![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/ryanhaining/cppitertools?svg=true)](https://ci.appveyor.com/project/ryanhaining/cppitertools) | MSVC 2017 MSVC 2019 @@ -253,11 +253,11 @@ recomputed at each step to avoid accumulating floating point inaccuracies slower but more accurate. `range` also supports the following operations: - - `.size()` to get the number of elements in the range (not enabled for - floating point ranges). + - `.size()` to get the number of elements in the range (not enabled for + floating point ranges). - Accessors for `.start()`, `.stop()`, and `.step()`. - Indexing. Given a range `r`, `r[n]` is the `n`th element in the range. - + enumerate --------- @@ -782,7 +782,7 @@ batched batched will yield a given number N of batches containing subsequent elements from an iterable, assuming the iterable contains at least N elements. The size of each batch is immaterial, but the implementation guarantees that no two batches will -differ in size by more than 1. +differ in size by more than 1. Example usage: ```c++ From 342e7523e35470ce93e032e37a41eba4893c45c6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 1 Jan 2020 23:45:47 -0500 Subject: [PATCH 333/403] Travis: add gcc-9, clang-7,8,9, upgrade to xenial --- .travis.yml | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++--- README.md | 2 +- 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index d4d97a0d..349a41d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: cpp -dist: trusty +dist: xenial sudo: require matrix: @@ -10,7 +10,7 @@ matrix: apt: sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-5.0 + - llvm-toolchain-xenial packages: - clang-5.0 - clang++-5.0 @@ -18,6 +18,7 @@ matrix: - gcc-8-base - libc6 - libgcc1 + - scons env: - COMPILER=clang++-5.0 - USE_LIBCXX=1 @@ -27,7 +28,7 @@ matrix: apt: sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-6.0 + - llvm-toolchain-xenial packages: - clang-6.0 - clang++-6.0 @@ -35,9 +36,67 @@ matrix: - gcc-8-base - libc6 - libgcc1 + - scons env: - COMPILER=clang++-6.0 - USE_LIBCXX=1 + - os: linux + compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-xenial-7 + packages: + - clang-7 + - clang++-7 + - valgrind + - gcc-8-base + - libc6 + - libgcc1 + - scons + env: + - COMPILER=clang++-7 + - USE_LIBCXX=1 + - os: linux + compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-xenial-8 + packages: + - clang-8 + - clang++-8 + - valgrind + - gcc-8-base + - libc6 + - libgcc1 + - scons + env: + - COMPILER=clang++-8 + - USE_LIBCXX=1 + - os: linux + compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + # travis complains about an unlisted source here if I do it with a plain + # llvm-toolchain-xenial-9 + - sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' + packages: + - clang-9 + - clang++-9 + - valgrind + - gcc-8-base + - libc6 + - libgcc1 + - scons + env: + - COMPILER=clang++-9 + - USE_LIBCXX=1 - os: linux addons: apt: @@ -46,6 +105,7 @@ matrix: packages: - g++-7 - valgrind + - scons env: - COMPILER=g++-7 - os: linux @@ -56,8 +116,20 @@ matrix: packages: - g++-8 - valgrind + - scons env: - COMPILER=g++-8 + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-9 + - valgrind + - scons + env: + - COMPILER=g++-9 script: - ${COMPILER} --version diff --git a/README.md b/README.md index bd52d172..a7f6e5ca 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Follow [@cppitertools](https://twitter.com/cppitertools) for updates. #### Build and Test Status Status | Compilers ---- | ---- -[![Travis Build Status](https://travis-ci.com/ryanhaining/cppitertools.svg?branch=master)](https://travis-ci.com/ryanhaining/cppitertools) | gcc-7 gcc-8 clang-5.0 clang-6.0 +[![Travis Build Status](https://travis-ci.com/ryanhaining/cppitertools.svg?branch=master)](https://travis-ci.com/ryanhaining/cppitertools) | gcc-7 gcc-8 gcc-9 clang-5.0 clang-6.0 clang-7 clang-8 clang-9 [![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/ryanhaining/cppitertools?svg=true)](https://ci.appveyor.com/project/ryanhaining/cppitertools) | MSVC 2017 MSVC 2019 #### Table of Contents From 96ee0635e338a895502fe74ec1df7103ebc3e49e Mon Sep 17 00:00:00 2001 From: Alexander Bigerl Date: Fri, 17 Jan 2020 11:53:01 +0100 Subject: [PATCH 334/403] added conan build --- CMakeLists.txt | 41 +++++++++++++++++++++++++++++++++++++ cmake/dummy-config.cmake.in | 5 +++++ conanfile.py | 31 ++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 cmake/dummy-config.cmake.in create mode 100644 conanfile.py diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..59c84944 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.12) +project(cppitertools VERSION 2.0) +set(CMAKE_CXX_STANDARD 17) + + +# installation directories +set(cppitertools_INSTALL_INCLUDE_DIR "include" CACHE STRING "The installation include directory") +set(cppitertools_INSTALL_CMAKE_DIR "share/cppitertools/cmake" CACHE STRING "The installation cmake directory") + + +# define a header-only library +add_library(cppitertools INTERFACE) +add_library(cppitertools::cppitertools ALIAS cppitertools) + +target_include_directories(cppitertools INTERFACE + $ + $ + ) + + +# require C++17 +target_compile_features(cppitertools INTERFACE cxx_std_17) + +# Make package findable +configure_file(cmake/dummy-config.cmake.in cppitertools-config.cmake @ONLY) + +# Enable version checks in find_package +include(CMakePackageConfigHelpers) +write_basic_package_version_file(cppitertools-config-version.cmake COMPATIBILITY SameMajorVersion) + +# install and export target +install(TARGETS cppitertools EXPORT cppitertools-targets) + +install(EXPORT cppitertools-targets + FILE cppitertools-config.cmake + NAMESPACE cppitertools:: + DESTINATION ${cppitertools_INSTALL_CMAKE_DIR} + ) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cppitertools-config-version.cmake DESTINATION ${cppitertools_INSTALL_CMAKE_DIR}) +install(DIRECTORY . DESTINATION ${cppitertools_INSTALL_INCLUDE_DIR}) diff --git a/cmake/dummy-config.cmake.in b/cmake/dummy-config.cmake.in new file mode 100644 index 00000000..d8c788f1 --- /dev/null +++ b/cmake/dummy-config.cmake.in @@ -0,0 +1,5 @@ +# Dummy config file +# When a dependency is added with add_subdirectory, but searched with find_package + +# Redirect to the directory added with add_subdirectory +add_subdirectory(@PROJECT_SOURCE_DIR@ @PROJECT_BINARY_DIR@) \ No newline at end of file diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 00000000..4427b7a8 --- /dev/null +++ b/conanfile.py @@ -0,0 +1,31 @@ +from conans import ConanFile, CMake + +import os + + +class Tentris_Parser(ConanFile): + name = "cppitertools" + version = "1.0" + author = "Ryan Haining" + description = "Implementation of python itertools and builtin iteration functions for C++17 " + topics = ("please add topics here") + settings = "build_type", "compiler", "os", "arch" + generators = "cmake", "cmake_find_package", "cmake_paths" + + exports_sources = list() + for file in os.listdir("."): + if file.endswith(".hpp"): + exports_sources.append(str(file)) + print("found files: " + str(exports_sources)) + + exports_sources = tuple(exports_sources) + \ + ("internal/*", "CMakeLists.txt", "cmake/dummy-config.cmake.in", "LICENSE.md") + no_copy_source = True + + def package(self): + cmake = CMake(self) + cmake.configure() + cmake.install() + + def package_id(self): + self.info.header_only() From d716cf6c8281ab6383d1fbecb456e0b9d808694c Mon Sep 17 00:00:00 2001 From: Alexander Bigerl Date: Fri, 17 Jan 2020 14:08:21 +0100 Subject: [PATCH 335/403] make the headers available at cppitertools/* --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 59c84944..3caa4114 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ add_library(cppitertools::cppitertools ALIAS cppitertools) target_include_directories(cppitertools INTERFACE $ - $ + $ ) @@ -34,8 +34,8 @@ install(TARGETS cppitertools EXPORT cppitertools-targets) install(EXPORT cppitertools-targets FILE cppitertools-config.cmake NAMESPACE cppitertools:: - DESTINATION ${cppitertools_INSTALL_CMAKE_DIR} + DESTINATION ${cppitertools_INSTALL_CMAKE_DIR}/cppitertools ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cppitertools-config-version.cmake DESTINATION ${cppitertools_INSTALL_CMAKE_DIR}) -install(DIRECTORY . DESTINATION ${cppitertools_INSTALL_INCLUDE_DIR}) +install(DIRECTORY . DESTINATION ${cppitertools_INSTALL_INCLUDE_DIR}/cppitertools) From 2547739b3ca1c1f08071b4c85df57f160df1f111 Mon Sep 17 00:00:00 2001 From: Alexander Bigerl Date: Fri, 17 Jan 2020 14:24:46 +0100 Subject: [PATCH 336/403] updated conan meta data --- conanfile.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/conanfile.py b/conanfile.py index 4427b7a8..b47cbab4 100644 --- a/conanfile.py +++ b/conanfile.py @@ -3,23 +3,27 @@ import os -class Tentris_Parser(ConanFile): +class CppIterTools(ConanFile): name = "cppitertools" - version = "1.0" - author = "Ryan Haining" - description = "Implementation of python itertools and builtin iteration functions for C++17 " - topics = ("please add topics here") + version = "2.0" + author = "Ryan Haining " + homepage = "https://github.com/ryanhaining/cppitertools" + url = homepage + topics = ("conan", "itertools", "cppitertools") + license = 'BSD 2-Clause "Simplified" License' + description = "Range-based for loop add-ons inspired by the Python builtins and itertools library. " \ + "Like itertools and the Python3 builtins, this library uses lazy evaluation wherever possible." settings = "build_type", "compiler", "os", "arch" generators = "cmake", "cmake_find_package", "cmake_paths" + exports = "LICENSE.md" exports_sources = list() for file in os.listdir("."): if file.endswith(".hpp"): exports_sources.append(str(file)) print("found files: " + str(exports_sources)) - exports_sources = tuple(exports_sources) + \ - ("internal/*", "CMakeLists.txt", "cmake/dummy-config.cmake.in", "LICENSE.md") + ("internal/*", "CMakeLists.txt", "cmake/dummy-config.cmake.in") no_copy_source = True def package(self): From d245e3be3504a00acfe71fbbf153338519ea448c Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 20 Apr 2020 16:42:03 -0700 Subject: [PATCH 337/403] Fix CMakeLists.txt install paths The old code defaulted the cmake config install paths to share/cppitertools/cmake/cppitertools whereas CMake expects the config install directory to be one of (simplifying): share/cmake/cppitertools share/cppitertools share/cppitertools/cmake Unfortunately, the existing code chose to put `cppitertools` at the end of the install path unconditionally, and so we're left with either `share/cppitertools`, or `share/cmake/cppitertools` as options. Since other projects seemed to choose `share/${PROJECT_NAME}`, I figured that was a fine option, as long as the default is not broken. Therefore, this changes the default to share/cppitertools Additionally, the old code didn't unconditionally put `cppitertools` at the end of the config.version file, and so that was never being picked up. Since it was unlikely that anyone was depending on the config.version file being installed in the wrong location, we now install it at the same place as the config file. --- CMakeLists.txt | 52 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3caa4114..2bd4bc31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,22 +1,34 @@ cmake_minimum_required(VERSION 3.12) project(cppitertools VERSION 2.0) -set(CMAKE_CXX_STANDARD 17) +if(NOT DEFINED ENV{cppitertools_INSTALL_CMAKE_DIR}) + message(WARNING [[ +The default value of cppitertools_INSTALL_CMAKE_DIR changed recently, from + "share/cppitertools/cmake" +to + "share" +in order to behave better with existing CMake practice. + +In order to get the previous behavior, pass + -Dcppitertools_INSTALL_CMAKE_DIR=share/cppitertools/cmake +to the CMake invocation; in order to get the new behavior without the warning, +pass + -Dcppitertools_INSTALL_CMAKE_DIR=share +explicitly. +]]) +endif() # installation directories set(cppitertools_INSTALL_INCLUDE_DIR "include" CACHE STRING "The installation include directory") -set(cppitertools_INSTALL_CMAKE_DIR "share/cppitertools/cmake" CACHE STRING "The installation cmake directory") - +set(cppitertools_INSTALL_CMAKE_DIR "share" CACHE STRING "The installation cmake directory") # define a header-only library add_library(cppitertools INTERFACE) add_library(cppitertools::cppitertools ALIAS cppitertools) target_include_directories(cppitertools INTERFACE - $ - $ - ) - + $ + $) # require C++17 target_compile_features(cppitertools INTERFACE cxx_std_17) @@ -29,13 +41,19 @@ include(CMakePackageConfigHelpers) write_basic_package_version_file(cppitertools-config-version.cmake COMPATIBILITY SameMajorVersion) # install and export target -install(TARGETS cppitertools EXPORT cppitertools-targets) - -install(EXPORT cppitertools-targets - FILE cppitertools-config.cmake - NAMESPACE cppitertools:: - DESTINATION ${cppitertools_INSTALL_CMAKE_DIR}/cppitertools - ) - -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cppitertools-config-version.cmake DESTINATION ${cppitertools_INSTALL_CMAKE_DIR}) -install(DIRECTORY . DESTINATION ${cppitertools_INSTALL_INCLUDE_DIR}/cppitertools) +install( + TARGETS cppitertools + EXPORT cppitertools-targets) + +install( + DIRECTORY . + DESTINATION ${cppitertools_INSTALL_INCLUDE_DIR}/cppitertools) + +install( + EXPORT cppitertools-targets + FILE cppitertools-config.cmake + NAMESPACE cppitertools:: + DESTINATION ${cppitertools_INSTALL_CMAKE_DIR}/cppitertools) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/cppitertools-config-version.cmake + DESTINATION ${cppitertools_INSTALL_CMAKE_DIR}/cppitertools) From dc63b373020289012756b37f203d5cc75e355b2f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 8 Sep 2021 20:34:14 -0700 Subject: [PATCH 338/403] Replaces class with struct on tuple_(size|element) -Wmismatched-tags warns because the standard tuple_size and tuple_element are declared as struct. Fixes #82 --- enumerate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/enumerate.hpp b/enumerate.hpp index 6580b783..e2dda12b 100644 --- a/enumerate.hpp +++ b/enumerate.hpp @@ -38,11 +38,11 @@ namespace iter { namespace std { template - class tuple_size> + struct tuple_size> : public tuple_size> {}; template - class tuple_element> + struct tuple_element> : public tuple_element> {}; } From d4611ebd9664df7d92be4407d7c1c4675cd1ecd6 Mon Sep 17 00:00:00 2001 From: Patrick Fasano Date: Thu, 9 Sep 2021 04:08:30 -0400 Subject: [PATCH 339/403] cmake: Fix warning about cppitertools_INSTALL_CMAKE_DIR Fixes #76. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bd4bc31..f4f7eaeb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.12) project(cppitertools VERSION 2.0) -if(NOT DEFINED ENV{cppitertools_INSTALL_CMAKE_DIR}) +if(NOT DEFINED CACHE{cppitertools_INSTALL_CMAKE_DIR}) message(WARNING [[ The default value of cppitertools_INSTALL_CMAKE_DIR changed recently, from "share/cppitertools/cmake" From b338df3a17276f1458236a2715a7f2cd2cae9619 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Tue, 29 Mar 2022 11:18:49 -0700 Subject: [PATCH 340/403] Adds rbegin() and rend() to repeat Fixes #86 --- repeat.hpp | 8 ++++++++ test/test_mixed.cpp | 10 ++++++++++ test/test_repeat.cpp | 7 +++++++ 3 files changed, 25 insertions(+) diff --git a/repeat.hpp b/repeat.hpp index 01739c6c..7167c388 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -83,6 +83,14 @@ class iter::impl::RepeaterWithCount { constexpr Iterator end() const { return {&this->elem_, 0}; } + + constexpr Iterator rbegin() const { + return begin(); + } + + constexpr Iterator rend() const { + return end(); + } }; template diff --git a/test/test_mixed.cpp b/test/test_mixed.cpp index e9b92d34..e6b58bab 100644 --- a/test/test_mixed.cpp +++ b/test/test_mixed.cpp @@ -256,3 +256,13 @@ TEST_CASE( REQUIRE(v == vc); } + +TEST_CASE("reversed(repeat())", "[repeat][reversed]") { + using iter::reversed; + using iter::repeat; + + auto rr = reversed(repeat('x', 5)); + std::string s(rr.begin(), rr.end()); + + REQUIRE(s == "xxxxx"); +} diff --git a/test/test_repeat.cpp b/test/test_repeat.cpp index 0fc62e72..c972c4c2 100644 --- a/test/test_repeat.cpp +++ b/test/test_repeat.cpp @@ -56,6 +56,7 @@ TEST_CASE("repeat: iterators compare to const iterators", "[repeat]") { (void)(std::begin(r) == std::end(cr)); } + TEST_CASE("repeat: two argument repeats a number of times", "[repeat]") { auto r = repeat('a', 3); std::string s(std::begin(r), std::end(r)); @@ -86,6 +87,12 @@ TEST_CASE("repeat: iterator meets requirements", "[repeat]") { REQUIRE(itertest::IsIterator::value); } +TEST_CASE("repeat: is reversible", "[repeat]") { + auto r = repeat('b', 4); + std::string s(std::rbegin(r), std::rend(r)); + REQUIRE(s == "bbbb"); +} + template using ImpT = decltype(repeat(std::declval())); From fda93ac505bb29404f6704e2d616ec2cbc101395 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Tue, 29 Mar 2022 22:15:12 -0700 Subject: [PATCH 341/403] Adds rbegin() and rend() to two-argument repeat Fixes #86 --- repeat.hpp | 10 +++++++++- test/test_mixed.cpp | 21 +++++++++++++++------ test/test_repeat.cpp | 19 +++++++++++++------ 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/repeat.hpp b/repeat.hpp index 7167c388..327c21b0 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -139,7 +139,7 @@ class iter::impl::Repeater { return *this; } - constexpr Iterator operator++(int)const { + constexpr Iterator operator++(int) const { return *this; } @@ -167,6 +167,14 @@ class iter::impl::Repeater { constexpr Iterator end() const { return {nullptr}; } + + constexpr Iterator rbegin() const { + return begin(); + } + + constexpr Iterator rend() const { + return end(); + } }; template diff --git a/test/test_mixed.cpp b/test/test_mixed.cpp index e6b58bab..9c4c3ed6 100644 --- a/test/test_mixed.cpp +++ b/test/test_mixed.cpp @@ -1,12 +1,11 @@ // mixing different itertools, there is nothing called iter::mixed() -#include "itertools.hpp" - -#include "catch.hpp" - #include #include +#include "catch.hpp" +#include "itertools.hpp" + class MyUnMovable { int val; @@ -257,12 +256,22 @@ TEST_CASE( REQUIRE(v == vc); } -TEST_CASE("reversed(repeat())", "[repeat][reversed]") { - using iter::reversed; +TEST_CASE("reversed(repeat(v, n))", "[repeat][reversed]") { using iter::repeat; + using iter::reversed; auto rr = reversed(repeat('x', 5)); std::string s(rr.begin(), rr.end()); REQUIRE(s == "xxxxx"); } + +TEST_CASE("reversed(repeat(v))", "[repeat][reversed]") { + using iter::repeat; + using iter::reversed; + + auto rr = reversed(repeat('x')); + auto it = rr.begin(); + + REQUIRE(*it == 'x'); +} diff --git a/test/test_repeat.cpp b/test/test_repeat.cpp index c972c4c2..ab92cbc1 100644 --- a/test/test_repeat.cpp +++ b/test/test_repeat.cpp @@ -1,12 +1,10 @@ -#include - -#include "helpers.hpp" - #include +#include #include #include #include "catch.hpp" +#include "helpers.hpp" using iter::repeat; @@ -56,7 +54,6 @@ TEST_CASE("repeat: iterators compare to const iterators", "[repeat]") { (void)(std::begin(r) == std::end(cr)); } - TEST_CASE("repeat: two argument repeats a number of times", "[repeat]") { auto r = repeat('a', 3); std::string s(std::begin(r), std::end(r)); @@ -87,7 +84,17 @@ TEST_CASE("repeat: iterator meets requirements", "[repeat]") { REQUIRE(itertest::IsIterator::value); } -TEST_CASE("repeat: is reversible", "[repeat]") { +TEST_CASE("repeat: one-argument is reversible", "[repeat]") { + auto r = repeat('c'); + auto it = std::rbegin(r); + (void)(it != std::rend(r)); + + REQUIRE(*it == 'c'); + ++it; + REQUIRE(*it == 'c'); +} + +TEST_CASE("repeat: two-argument is reversible", "[repeat]") { auto r = repeat('b', 4); std::string s(std::rbegin(r), std::rend(r)); REQUIRE(s == "bbbb"); From affe89e17d8121e3c26391b7e8a63de0e8e4a78d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 19 Jul 2022 09:51:47 -0700 Subject: [PATCH 342/403] Removes note on (discouraged) .index and .element in enumerate --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a7f6e5ca..107ca507 100644 --- a/README.md +++ b/README.md @@ -262,7 +262,8 @@ enumerate --------- Continually "yields" containers similar to pairs. They are basic structs with a -.index and a .element, and also work with structured binding declarations. +an index in .first, and the element in .second, and also work with structured +binding declarations. Usage appears as: ```c++ From c703a135d6bec700a5e687b60e834d05f0915894 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 19 Jul 2022 09:52:57 -0700 Subject: [PATCH 343/403] fixes enumerate typos --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 107ca507..66f48aae 100644 --- a/README.md +++ b/README.md @@ -261,8 +261,8 @@ slower but more accurate. enumerate --------- -Continually "yields" containers similar to pairs. They are basic structs with a -an index in .first, and the element in .second, and also work with structured +Continually "yields" containers similar to pairs. They are structs with +the index in `.first`, and the element in `.second`, and also work with structured binding declarations. Usage appears as: From ad94c5a89a89bff8b2168b03a7d1442e2f768552 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Wed, 17 Aug 2022 14:08:35 -0700 Subject: [PATCH 344/403] Updates starmap ::reference to match * Updates the Iterator::reference type to match the type of operator*() --- starmap.hpp | 21 +++++++++++------ test/test_starmap.cpp | 53 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index d3fb678b..fbeaad68 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -34,8 +34,10 @@ class iter::impl::StarMapper { mutable Func func_; Container container_; - using StarIterDeref = std::remove_reference_t>()))>; + using StarIterDeref = + decltype(std::apply(func_, std::declval>())); + using StarIterDerefValue = + std::remove_cv_t>; StarMapper(Func f, Container&& c) : func_(std::move(f)), container_(std::forward(c)) {} @@ -53,10 +55,10 @@ class iter::impl::StarMapper { public: using iterator_category = std::input_iterator_tag; - using value_type = StarIterDeref; + using value_type = StarIterDerefValue; using difference_type = std::ptrdiff_t; using pointer = value_type*; - using reference = value_type&; + using reference = StarIterDeref; Iterator(Func& f, IteratorWrapper&& sub_iter) : func_(&f), sub_iter_(std::move(sub_iter)) {} @@ -86,7 +88,7 @@ class iter::impl::StarMapper { return std::apply(*func_, *sub_iter_); } - auto operator-> () -> ArrowProxy { + auto operator->() -> ArrowProxy { return {**this}; } }; @@ -130,7 +132,12 @@ class iter::impl::TupleStarMapper { class IteratorData { public: template - static auto get_and_call_with_tuple(Func& f, TupTypeT& t) -> decltype(std::apply(f, std::get(t))) { //TODO: Remove duplicated expression in decltype, using decltype(auto) as return type, when all compilers correctly deduce type (i.e. MSVC cl 19.15 does not do it). + static auto get_and_call_with_tuple(Func& f, TupTypeT& t) + -> decltype(std::apply(f, + std::get(t))) { // TODO: Remove duplicated expression in + // decltype, using decltype(auto) as return + // type, when all compilers correctly deduce + // type (i.e. MSVC cl 19.15 does not do it). return std::apply(f, std::get(t)); } @@ -169,7 +176,7 @@ class iter::impl::TupleStarMapper { return IteratorData::callers[index_](*func_, *tup_); } - auto operator-> () { + auto operator->() { return ArrowProxy{**this}; } diff --git a/test/test_starmap.cpp b/test/test_starmap.cpp index 4c12b7c1..528d5f0f 100644 --- a/test/test_starmap.cpp +++ b/test/test_starmap.cpp @@ -1,10 +1,10 @@ #include - #include "helpers.hpp" #include #include #include +#include #include #include "catch.hpp" @@ -16,6 +16,18 @@ namespace { return d * i; } + int& larger_ref(int& a, int& b) { + return a > b ? a : b; + } + + const int& larger_const_ref(const int& a, const int& b) { + return a > b ? a : b; + } + + int larger(int a, int b) { + return a > b ? a : b; + } + std::string g(const std::string& s, int i, char c) { std::stringstream ss; ss << s << ' ' << i << ' ' << c; @@ -74,7 +86,8 @@ TEST_CASE("starmap: works with pointer to member function", "[starmap]") { TEST_CASE("starmap: vector of pairs const iteration", "[starmap][const]") { using Vec = const std::vector; - const std::vector> v1 = {{1.0, 2}, {3.0, 11}, {6.0, 7}}; + const std::vector> v1 = { + {1.0, 2}, {3.0, 11}, {6.0, 7}}; const auto sm = starmap(Callable{}, v1); std::vector v(std::begin(sm), std::end(sm)); @@ -182,3 +195,39 @@ TEST_CASE( auto sm = starmap(Callable{}, tup); REQUIRE(itertest::IsIterator::value); } + +TEST_CASE("starmap: iterator dereference type matches 'reference' type alias", + "[starmap]") { + std::vector> input; + SECTION("with reference return type") { + auto sm = iter::starmap(larger_ref, input); + REQUIRE( + std::is_same_v); + } + SECTION("with const reference return type") { + auto sm = iter::starmap(larger_const_ref, input); + REQUIRE( + std::is_same_v); + } + SECTION("with value return type") { + auto sm = iter::starmap(larger, input); + REQUIRE( + std::is_same_v); + } +} + +TEST_CASE("starmap: iterator has correct 'value' type alias", "[starmap]") { + std::vector> input; + SECTION("with reference return type") { + auto sm = iter::starmap(larger_ref, input); + REQUIRE(std::is_same_v); + } + SECTION("with const reference return type") { + auto sm = iter::starmap(larger_const_ref, input); + REQUIRE(std::is_same_v); + } + SECTION("with value return type") { + auto sm = iter::starmap(larger, input); + REQUIRE(std::is_same_v); + } +} From e4fb18534092ae001f4af47b5a3420beba4c4390 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Thu, 18 Aug 2022 16:23:55 -0700 Subject: [PATCH 345/403] Adds test helper for reference correctness operator* needs to match Iterator::reference Issue #88 --- test/helpers.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/helpers.hpp b/test/helpers.hpp index aa80cd3c..93112519 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -2,7 +2,6 @@ #define TEST_HELPER_H_ #include - #include #include #include @@ -208,6 +207,10 @@ namespace itertest { template struct IsIterator : std::false_type {}; + template + struct ReferenceMatchesDeref + : std::is_same())> {}; + template struct IsIterator())), // copyctor @@ -216,8 +219,8 @@ namespace itertest { decltype(std::declval().operator->()), // operator-> decltype(++std::declval()), // prefix ++ decltype(std::declval()++), // postfix ++ - decltype( - std::declval() != std::declval()), // != + decltype(std::declval() + != std::declval()), // != decltype(std::declval() == std::declval()) // == >> : std::true_type {}; From d70c2b1a7f478ce1d6d6eddfe49ea273c0e34c71 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Thu, 18 Aug 2022 16:31:40 -0700 Subject: [PATCH 346/403] Uses ReferenceMatchesDeref in starmap test Issue #88 --- test/test_starmap.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/test_starmap.cpp b/test/test_starmap.cpp index 528d5f0f..feae8da9 100644 --- a/test/test_starmap.cpp +++ b/test/test_starmap.cpp @@ -201,18 +201,15 @@ TEST_CASE("starmap: iterator dereference type matches 'reference' type alias", std::vector> input; SECTION("with reference return type") { auto sm = iter::starmap(larger_ref, input); - REQUIRE( - std::is_same_v); + REQUIRE(itertest::ReferenceMatchesDeref::value); } SECTION("with const reference return type") { auto sm = iter::starmap(larger_const_ref, input); - REQUIRE( - std::is_same_v); + REQUIRE(itertest::ReferenceMatchesDeref::value); } SECTION("with value return type") { auto sm = iter::starmap(larger, input); - REQUIRE( - std::is_same_v); + REQUIRE(itertest::ReferenceMatchesDeref::value); } } From 5e8ddb3f13a2f1974a3b01137f68d4e4896a1ede Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Thu, 18 Aug 2022 16:34:45 -0700 Subject: [PATCH 347/403] Fixes reference type in accumulate Issue #88 --- accumulate.hpp | 13 +++++++------ test/test_accumulate.cpp | 23 ++++++++++++++++++----- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 0d43a20e..94c0c369 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -28,8 +28,9 @@ class iter::impl::Accumulator { friend AccumulateFn; - using AccumVal = std::remove_reference_t, iterator_deref>>; + using AccumVal = std::remove_cv_t< + std::remove_reference_t, iterator_deref>>>; Accumulator(Container&& container, AccumulateFunc accumulate_func) : container_(std::forward(container)), @@ -52,8 +53,8 @@ class iter::impl::Accumulator { using iterator_category = std::input_iterator_tag; using value_type = AccumVal; using difference_type = std::ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; + using pointer = const value_type*; + using reference = const value_type&; Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, AccumulateFunc& accumulate_fun) @@ -65,11 +66,11 @@ class iter::impl::Accumulator { ? std::nullopt : std::make_optional(*sub_iter_)} {} - const AccumVal& operator*() const { + reference operator*() const { return *acc_val_; } - const AccumVal* operator->() const { + pointer operator->() const { return &*acc_val_; } diff --git a/test/test_accumulate.cpp b/test/test_accumulate.cpp index 02467fb2..f91f32b6 100644 --- a/test/test_accumulate.cpp +++ b/test/test_accumulate.cpp @@ -131,11 +131,24 @@ TEST_CASE("accumulate: operator->", "[accumulate]") { } TEST_CASE("accumulate: iterator meets requirements", "[accumulate]") { - Vec ns{}; - auto a = accumulate(ns, [](int a, int b) { return a + b; }); - auto it = std::begin(a); - it = std::begin(a); - REQUIRE(itertest::IsIterator::value); + std::vector ns{}; + SECTION("with reference return type") { + auto acc = accumulate(ns, [](int& a, int&) -> int& { return a; }); + REQUIRE(itertest::IsIterator::value); + REQUIRE(itertest::ReferenceMatchesDeref::value); + } + + SECTION("with const reference return type") { + auto acc = accumulate(ns, [](int& a, int&) -> const int& { return a; }); + REQUIRE(itertest::IsIterator::value); + REQUIRE(itertest::ReferenceMatchesDeref::value); + } + + SECTION("with value return type") { + auto acc = accumulate(ns, [](int a, int) -> int { return a; }); + REQUIRE(itertest::IsIterator::value); + REQUIRE(itertest::ReferenceMatchesDeref::value); + } } TEST_CASE( From 038a4363a1bc8c9af4edc73b0d825256241aa2d8 Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Thu, 18 Aug 2022 16:35:44 -0700 Subject: [PATCH 348/403] Fixes reference type in product Issue #88 --- product.hpp | 4 ++-- test/test_product.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/product.hpp b/product.hpp index d7bc61e9..7de5727a 100644 --- a/product.hpp +++ b/product.hpp @@ -98,7 +98,7 @@ class iter::impl::Productor { using value_type = TupleDeref; using difference_type = std::ptrdiff_t; using pointer = value_type*; - using reference = value_type&; + using reference = value_type; IteratorTempl(IteratorTuple&& iters, IteratorTuple&& end_iters) @@ -148,7 +148,7 @@ class iter::impl::Productor { return {(*std::get(iters_))...}; } - auto operator-> () -> ArrowProxy { + auto operator->() -> ArrowProxy { return {**this}; } }; diff --git a/test/test_product.cpp b/test/test_product.cpp index aa7ed1bb..6a580bc9 100644 --- a/test/test_product.cpp +++ b/test/test_product.cpp @@ -221,6 +221,7 @@ TEST_CASE("product: iterator meets requirements", "[product]") { std::string s{"abc"}; auto c = product(s, s); REQUIRE(itertest::IsIterator::value); + REQUIRE(itertest::ReferenceMatchesDeref::value); } template From 86e8a0cdd30a00152ff82633ace8e86386c9cd2c Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Thu, 18 Aug 2022 16:37:26 -0700 Subject: [PATCH 349/403] Fixes reference type in zip Issue #88 --- test/test_zip.cpp | 2 ++ zip.hpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/test_zip.cpp b/test/test_zip.cpp index 7bf8ff96..cb49981c 100644 --- a/test/test_zip.cpp +++ b/test/test_zip.cpp @@ -140,8 +140,10 @@ TEST_CASE("zip: iterator meets requirements", "[zip]") { std::string s{}; auto c = zip(s); REQUIRE(itertest::IsIterator::value); + REQUIRE(itertest::ReferenceMatchesDeref::value); auto c2 = zip(s, s); REQUIRE(itertest::IsIterator::value); + REQUIRE(itertest::ReferenceMatchesDeref::value); } template diff --git a/zip.hpp b/zip.hpp index abadf45c..98bfd3c4 100644 --- a/zip.hpp +++ b/zip.hpp @@ -56,7 +56,7 @@ class iter::impl::Zipped { using value_type = TupleDeref; using difference_type = std::ptrdiff_t; using pointer = value_type*; - using reference = value_type&; + using reference = value_type; Iterator(IteratorTuple&& iters) : iters_(std::move(iters)) {} @@ -91,7 +91,7 @@ class iter::impl::Zipped { return {(*std::get(iters_))...}; } - auto operator-> () -> ArrowProxy { + auto operator->() -> ArrowProxy { return {**this}; } }; From cc5f11f9311d8670b50d52ccb08eb1c984f8294c Mon Sep 17 00:00:00 2001 From: ryanhaining Date: Thu, 18 Aug 2022 16:38:21 -0700 Subject: [PATCH 350/403] Fixes reference type in slice Issue #88 --- slice.hpp | 13 ++++++------- test/test_slice.cpp | 15 ++++++++++++--- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/slice.hpp b/slice.hpp index 22855645..a926ecbb 100644 --- a/slice.hpp +++ b/slice.hpp @@ -51,7 +51,7 @@ class iter::impl::Sliced { using value_type = iterator_traits_deref; using difference_type = std::ptrdiff_t; using pointer = value_type*; - using reference = value_type&; + using reference = iterator_deref; Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, DifferenceType start, @@ -131,10 +131,9 @@ struct iter::impl::SliceFn { private: friend SliceFn; - constexpr FnPartial(DifferenceType start, DifferenceType stop, - DifferenceType step) noexcept : start_{start}, - stop_{stop}, - step_{step} {} + constexpr FnPartial( + DifferenceType start, DifferenceType stop, DifferenceType step) noexcept + : start_{start}, stop_{stop}, step_{step} {} DifferenceType start_; DifferenceType stop_; DifferenceType step_; @@ -159,8 +158,8 @@ struct iter::impl::SliceFn { template >> - constexpr FnPartial operator()(DifferenceType stop) const - noexcept { + constexpr FnPartial operator()( + DifferenceType stop) const noexcept { return {0, stop, 1}; } diff --git a/test/test_slice.cpp b/test/test_slice.cpp index 38386b73..5fae78f4 100644 --- a/test/test_slice.cpp +++ b/test/test_slice.cpp @@ -148,9 +148,18 @@ TEST_CASE("slice: with iterable doesn't move or copy elems", "[slice]") { } TEST_CASE("slice: iterator meets requirements", "[slice]") { - std::string s{"abcdef"}; - auto c = slice(s, 1, 3); - REQUIRE(itertest::IsIterator::value); + SECTION("with iterable yielding references") { + std::string s{"abcdef"}; + auto c = slice(s, 1, 3); + REQUIRE(itertest::IsIterator::value); + REQUIRE(itertest::ReferenceMatchesDeref::value); + } + SECTION("with iterable yielding values") { + itertest::InputIterable it{}; + auto c = slice(it, 1, 3); + REQUIRE(itertest::IsIterator::value); + REQUIRE(itertest::ReferenceMatchesDeref::value); + } } template From 6f7a3d042da474126f519fd4e70d0db06e28a82c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Dec 2022 18:30:02 -0800 Subject: [PATCH 351/403] Updates catch.hpp version --- test/download_catch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/download_catch.sh b/test/download_catch.sh index 487e1233..4f1ed06b 100755 --- a/test/download_catch.sh +++ b/test/download_catch.sh @@ -1,2 +1,2 @@ #!/usr/bin/env sh -wget -c https://github.com/catchorg/Catch2/releases/download/v2.6.0/catch.hpp +wget -c https://github.com/catchorg/Catch2/releases/download/v2.13.10/catch.hpp From 09e472243bdaf81c11ebeb9806092037c35253f1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Dec 2022 18:36:21 -0800 Subject: [PATCH 352/403] Adds unique_everseen taking hash and eq functions Fixes #90 --- test/test_unique_everseen.cpp | 30 ++++++++++++++++++++++++++++++ unique_everseen.hpp | 32 ++++++++++++++++++++++++++------ 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/test/test_unique_everseen.cpp b/test/test_unique_everseen.cpp index d70de075..68cb319a 100644 --- a/test/test_unique_everseen.cpp +++ b/test/test_unique_everseen.cpp @@ -85,3 +85,33 @@ TEST_CASE( REQUIRE(itertest::IsMoveConstructibleOnly>::value); REQUIRE(itertest::IsMoveConstructibleOnly>::value); } + +struct IntWrapper { + int n; +}; + +struct IntWrapperHash { + int operator()(const IntWrapper& iw) const { + return iw.n % 10; + } +}; + +struct IntWrapperEq { + int operator()(const IntWrapper& lhs, const IntWrapper& rhs) const { + return lhs.n == rhs.n; + } +}; + +TEST_CASE("unique_everseen: works with custom hash and equality functions", + "[unique_everseen]") { + std::vector iwv = { + {2}, {3}, {4}, {2}, {10}, {2}, {2}, {12}, {10}}; + Vec vc{2, 3, 4, 10, 12}; + + std::vector v; + for (auto&& iw : unique_everseen(iwv, IntWrapperHash{}, IntWrapperEq{})) { + v.push_back(iw.n); + } + + REQUIRE(v == vc); +} diff --git a/unique_everseen.hpp b/unique_everseen.hpp index 35322ca8..1e138d63 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -13,15 +13,35 @@ namespace iter { namespace impl { struct UniqueEverseenFn : Pipeable { + private: template - auto operator()(Container&& container) const { - using elem_type = impl::iterator_deref; - auto func = [elem_seen = std::unordered_set>()]( - const std::remove_reference_t& e) mutable { - return elem_seen.insert(e).second; - }; + using Key = std::decay_t>; + + public: + template + auto operator()(Container&& container, const Hash& hash, + const KeyEqual& key_equal) const { + // You can't pass a hash function or an equality function without + // passing a bucket_count as well. We get the default bucket count here + // the first time this function runs. + static auto default_bucket_count = + std::unordered_set{}.bucket_count(); + using elem_type = iterator_deref; + auto func = + [elem_seen = + std::unordered_set, Hash, KeyEqual>( + default_bucket_count, hash, key_equal)]( + const std::remove_reference_t& e) mutable { + return elem_seen.insert(e).second; + }; return filter(func, std::forward(container)); } + + template + auto operator()(Container&& container) const { + return (*this)(std::forward(container), + std::hash>{}, std::equal_to>{}); + } }; } From a788a37bcf4a1f996181e7639efbf506484c0d1e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 26 Dec 2022 18:52:12 -0800 Subject: [PATCH 353/403] Describes unique_everseen with hash and eq functions Issue #90 --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 66f48aae..c405d760 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,7 @@ would expect them to behave: - sorted - starmap - takewhile -- unique\_everseen +- unique\_everseen (\*only without custom hash and equality callables) - unique\_justseen I don't personally care for the piping style, but it seemed to be desired by @@ -323,7 +323,7 @@ unique\_everseen *Additional Requirements*: Underlying values must be copy-constructible. This is a filter adaptor that only generates values that have never been seen -before. For this to work your object must be specialized for `std::hash`. +before. Prints `1 2 3 4 5 6 7 8 9` ```c++ @@ -333,6 +333,18 @@ for (auto&& i : unique_everseen(v)) { } ``` +`unique_everseen` uses an `undordered_set` so it needs hashable elements. For +types that don't work with `std::hash` or `std::equal_to`, `unique_everseen` +also provides an overload taking a hash callable and an equality callable. +This **does not** work with the pipe syntax. + +```c++ +vector v { /* ... */ }; +for (auto&& w : unique_everseen(v, WidgetHash{}, WidgetEq{})) { + cout << w.name() << ' '; +} +``` + unique\_justseen -------------- Another filter adaptor that only omits consecutive duplicates. From 57e5494a22a06757059f8d6b12f41d80abe778b3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 30 Dec 2022 10:34:21 -0800 Subject: [PATCH 354/403] Moves Identity function from groupby to iterbase. Issue #90 --- groupby.hpp | 7 ------- internal/iterbase.hpp | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 4f2fffb5..cac82426 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -18,13 +18,6 @@ namespace iter { template class GroupProducer; - struct Identity { - template - const T& operator()(const T& t) const { - return t; - } - }; - using GroupByFn = IterToolFnOptionalBindSecond; } constexpr impl::GroupByFn groupby{}; diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 57cc1b78..69db7599 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -129,6 +129,13 @@ namespace iter { template constexpr bool is_iterable = IsIterable::value; + struct Identity { + template + const T& operator()(const T& t) const { + return t; + } + }; + namespace detail { template struct ArrowHelper { From 22be440497442098015cab4d5403628df2e7e8fa Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 30 Dec 2022 10:41:17 -0800 Subject: [PATCH 355/403] Adds overload taking KeyFunc for types without == Issue #90 --- test/test_unique_justseen.cpp | 24 ++++++++++++++++++++++++ unique_justseen.hpp | 16 ++++++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/test/test_unique_justseen.cpp b/test/test_unique_justseen.cpp index c6671e5f..455ac927 100644 --- a/test/test_unique_justseen.cpp +++ b/test/test_unique_justseen.cpp @@ -91,3 +91,27 @@ TEST_CASE( REQUIRE(itertest::IsMoveConstructibleOnly>::value); REQUIRE(itertest::IsMoveConstructibleOnly>::value); } + +struct IntWrapper { + int n; +}; + +struct IntWrapperKey { + int operator()(const IntWrapper& iw) const { + return iw.n; + } +}; + +TEST_CASE("unique_justseen: works with key function", + "[unique_justseen]") { + std::vector iwv = { + {2}, {3}, {4}, {2}, {10}, {2}, {2}, {12}, {10}}; + Vec vc{2, 3, 4, 2, 10, 2, 12, 10}; + + std::vector v; + for (auto&& iw : unique_justseen(iwv, IntWrapperKey{})) { + v.push_back(iw.n); + } + + REQUIRE(v == vc); +} diff --git a/unique_justseen.hpp b/unique_justseen.hpp index 2d63b7ea..b717392f 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -10,12 +10,20 @@ namespace iter { namespace impl { struct UniqueJustseenFn : Pipeable { + public: + template + auto operator()(Container&& container, KeyFunc key_fn) const { + // decltype(auto) return type in lambda so reference types are preserved + return imap( + [](auto&& group) -> decltype(auto) { + return *get_begin(group.second); + }, + groupby(std::forward(container), key_fn)); + } + template auto operator()(Container&& container) const { - // decltype(auto) return type in lambda so reference types are preserved - return imap([](auto&& group) -> decltype( - auto) { return *get_begin(group.second); }, - groupby(std::forward(container))); + return (*this)(std::forward(container), Identity{}); } }; } From 2584f419309e785290036666036e34e73c64690f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 30 Dec 2022 11:27:32 -0800 Subject: [PATCH 356/403] Adds PipeableAndBindOptionalSecond --- internal/iterbase.hpp | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index 69db7599..6f654828 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -95,8 +95,8 @@ namespace iter { // iterator_type is the type of C's iterator template - using const_iterator_type = decltype( - get_begin(std::declval&>())); + using const_iterator_type = decltype(get_begin( + std::declval&>())); // iterator_deref is the type obtained by dereferencing an iterator // to an object of type C @@ -391,6 +391,37 @@ namespace iter { } }; + // Pipeable callable which allows binding of the second argument + // f(a, b) is the same as a | f(b) + // f(a) with an iterable is the same as f(a, DefaultT{}) + template + struct PipeableAndBindOptionalSecond : Pipeable { + protected: + template + struct FnPartial : Pipeable> { + mutable T stored_arg; + constexpr FnPartial(T in_t) : stored_arg(in_t) {} + + template + auto operator()(Container&& container) const { + return F{}(std::forward(container), stored_arg); + } + }; + + public: + template >> + FnPartial> operator()(T&& t) const { + return {std::forward(t)}; + } + + template >> + auto operator()(Container&& container) const { + return static_cast(*this)( + std::forward(container), DefaultT{}); + } + }; + // This is a complicated class to generate a callable that can work: // (1) with just a single (iterable) passed, and DefaultT substituted // (2) with an iterable and a callable From 06cc4fe4479b8e51a1bd08115ca370cbee5771ff Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 30 Dec 2022 11:28:03 -0800 Subject: [PATCH 357/403] Updates unique_justseen overload to be pipeable Issue #90 --- test/test_unique_justseen.cpp | 11 +++++++++-- unique_justseen.hpp | 8 ++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/test/test_unique_justseen.cpp b/test/test_unique_justseen.cpp index 455ac927..72af19b8 100644 --- a/test/test_unique_justseen.cpp +++ b/test/test_unique_justseen.cpp @@ -109,8 +109,15 @@ TEST_CASE("unique_justseen: works with key function", Vec vc{2, 3, 4, 2, 10, 2, 12, 10}; std::vector v; - for (auto&& iw : unique_justseen(iwv, IntWrapperKey{})) { - v.push_back(iw.n); + SECTION("Normal call") { + for (auto&& iw : unique_justseen(iwv, IntWrapperKey{})) { + v.push_back(iw.n); + } + } + SECTION("Pipe") { + for (auto&& iw : iwv | unique_justseen(IntWrapperKey{})) { + v.push_back(iw.n); + } } REQUIRE(v == vc); diff --git a/unique_justseen.hpp b/unique_justseen.hpp index b717392f..5a566e78 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -9,8 +9,9 @@ namespace iter { namespace impl { - struct UniqueJustseenFn : Pipeable { + struct UniqueJustseenFn : PipeableAndBindOptionalSecond { public: + using PipeableAndBindOptionalSecond::operator(); template auto operator()(Container&& container, KeyFunc key_fn) const { // decltype(auto) return type in lambda so reference types are preserved @@ -20,11 +21,6 @@ namespace iter { }, groupby(std::forward(container), key_fn)); } - - template - auto operator()(Container&& container) const { - return (*this)(std::forward(container), Identity{}); - } }; } constexpr impl::UniqueJustseenFn unique_justseen{}; From 8a8b6d0f12e9b5a1fe505820ba81d787b8c610c5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 30 Dec 2022 11:32:33 -0800 Subject: [PATCH 358/403] Adds unique_justseen with key to README Issue #90 --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index c405d760..c9d99d3a 100644 --- a/README.md +++ b/README.md @@ -358,6 +358,15 @@ for (auto&& i : unique_justseen(v)) { } ``` +If elements cannot be directly compared with equality, you can pass in a key +callable. +```c++ +vector v { /* ... */ }; +for (auto&& p : unique_justseen(v, [] (const Person& p) { return p.name; })) + cout << p.name() << ' ' << p.age() << '\n'; +} +``` + takewhile --------- Yields elements from an iterable until the first element that is false under From add5acc932dea2c78acd80747bab71ec0b5bce27 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 30 Dec 2022 11:39:31 -0800 Subject: [PATCH 359/403] Switches flag from c++1z to c++17 --- examples/SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/SConstruct b/examples/SConstruct index 5f9110c9..cb5c373c 100644 --- a/examples/SConstruct +++ b/examples/SConstruct @@ -3,7 +3,7 @@ import os env = Environment( ENV=os.environ, CXXFLAGS= ['-g', '-Wall', '-Wextra', - '-pedantic', '-std=c++1z', + '-pedantic', '-std=c++17', '-I/usr/local/include' ], CPPPATH='..', From eecaaf71ee2103f2afef0567bc22ce1502cc1f0a Mon Sep 17 00:00:00 2001 From: Pedro Kaj Kjellerup Nacht Date: Tue, 6 Jun 2023 14:20:58 +0000 Subject: [PATCH 360/403] Add security policy Signed-off-by: Pedro Kaj Kjellerup Nacht --- SECURITY.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..201281d4 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,19 @@ +# Security Policy + +If you have discovered a security vulnerability in this project, please report it +privately. **Do not disclose it as a public issue.** This gives me time to work with you +to fix the issue before public exposure, reducing the chance that the exploit will be +used before a patch is released. + +You may submit the report in the following ways: + +- send an email to haining.cpp@gmail.com; and/or +- send me a [private vulnerability report](https://github.com/ryanhaining/cppitertools/security/advisories/new) + +Please provide the following information in your report: + +- A description of the vulnerability and its impact +- How to reproduce the issue + +This project is maintained by a single maintainer on a reasonable-effort basis. As such, +I ask that you give me 90 days to work on a fix before public exposure. From 492c15aab96f4ca3938a6b734d6a08cb7feea75a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 3 Jul 2023 20:37:50 -0700 Subject: [PATCH 361/403] Update travis-ci link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c9d99d3a..64c1430f 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Follow [@cppitertools](https://twitter.com/cppitertools) for updates. #### Build and Test Status Status | Compilers ---- | ---- -[![Travis Build Status](https://travis-ci.com/ryanhaining/cppitertools.svg?branch=master)](https://travis-ci.com/ryanhaining/cppitertools) | gcc-7 gcc-8 gcc-9 clang-5.0 clang-6.0 clang-7 clang-8 clang-9 +[![Travis Build Status](https://travis-ci.com/ryanhaining/cppitertools.svg?branch=master)](https://app.travis-ci.com/github/ryanhaining/cppitertools) | gcc-7 gcc-8 gcc-9 clang-5.0 clang-6.0 clang-7 clang-8 clang-9 [![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/ryanhaining/cppitertools?svg=true)](https://ci.appveyor.com/project/ryanhaining/cppitertools) | MSVC 2017 MSVC 2019 #### Table of Contents From 556fca33235b6ad1fba6e37df104ca23a01a5b45 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 20 Sep 2023 23:38:56 -0700 Subject: [PATCH 362/403] Removes "recently changed" cmake warning fixes #97 --- CMakeLists.txt | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f4f7eaeb..32d26fde 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,23 +1,6 @@ cmake_minimum_required(VERSION 3.12) project(cppitertools VERSION 2.0) -if(NOT DEFINED CACHE{cppitertools_INSTALL_CMAKE_DIR}) - message(WARNING [[ -The default value of cppitertools_INSTALL_CMAKE_DIR changed recently, from - "share/cppitertools/cmake" -to - "share" -in order to behave better with existing CMake practice. - -In order to get the previous behavior, pass - -Dcppitertools_INSTALL_CMAKE_DIR=share/cppitertools/cmake -to the CMake invocation; in order to get the new behavior without the warning, -pass - -Dcppitertools_INSTALL_CMAKE_DIR=share -explicitly. -]]) -endif() - # installation directories set(cppitertools_INSTALL_INCLUDE_DIR "include" CACHE STRING "The installation include directory") set(cppitertools_INSTALL_CMAKE_DIR "share" CACHE STRING "The installation cmake directory") From 9b2cee49f4ce9725513e9a12d303de9471078e89 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 16 Jan 2024 23:53:55 -0800 Subject: [PATCH 363/403] Modifies combinations(c, 0) to produce {{}} Instead of no elements, a sequence of a single empty iterable, to match python's behavior. Issue #101 --- combinations.hpp | 22 +++++++++++++++++++--- test/test_combinations.cpp | 28 ++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/combinations.hpp b/combinations.hpp index 7572142c..7aca3115 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -73,6 +73,12 @@ class iter::impl::Combinator { } } + static Iterator zero_length_end(ContainerT& container) { + Iterator it{container, 0}; + it.steps_ = 0; + return it; + } + CombIteratorDeref& operator*() { return indices_; } @@ -82,6 +88,11 @@ class iter::impl::Combinator { } Iterator& operator++() { + if (indices_.get().empty()) { + // zero-length case. + ++steps_; + return *this; + } for (auto iter = indices_.get().rbegin(); iter != indices_.get().rend(); ++iter) { ++(*iter); @@ -94,11 +105,10 @@ class iter::impl::Combinator { if (!(dumb_next(*iter, dist) != get_end(*container_p_))) { if ((iter + 1) != indices_.get().rend()) { size_t inc = 1; - for (auto down = iter; ; --down) { + for (auto down = iter;; --down) { (*down) = dumb_next(*(iter + 1), 1 + inc); ++inc; - if (down == indices_.get().rbegin()) - break; + if (down == indices_.get().rbegin()) break; } } else { steps_ = COMPLETE; @@ -138,6 +148,9 @@ class iter::impl::Combinator { } Iterator end() { + if (length_ == 0) { + return Iterator::zero_length_end(container_); + } return {container_, 0}; } @@ -146,6 +159,9 @@ class iter::impl::Combinator { } Iterator> end() const { + if (length_ == 0) { + return Iterator>::zero_length_end(container_); + } return {std::as_const(container_), 0}; } }; diff --git a/test/test_combinations.cpp b/test/test_combinations.cpp index f5c153cf..6d9718dc 100644 --- a/test/test_combinations.cpp +++ b/test/test_combinations.cpp @@ -5,7 +5,6 @@ #undef DEFINE_DEFAULT_ITERATOR_CTOR #include - #include #include #include @@ -95,10 +94,31 @@ TEST_CASE("combinations: size too large gives no results", "[combinations]") { REQUIRE(std::begin(c) == std::end(c)); } -TEST_CASE("combinations: size 0 gives nothing", "[combinations]") { +TEST_CASE("combinations: size 0 gives one empty result", "[combinations]") { std::string s{"ABCD"}; - auto c = combinations(s, 0); - REQUIRE(std::begin(c) == std::end(c)); + + CharCombSet ans = {{}}; + + CharCombSet sc; + for (auto&& v : combinations(s, 0)) { + sc.emplace_back(std::begin(v), std::end(v)); + } + + REQUIRE(ans == sc); +} + +TEST_CASE("combinations: size 0 gives one empty result for empty input", + "[combinations]") { + std::string s{}; + + CharCombSet ans = {{}}; + + CharCombSet sc; + for (auto&& v : combinations(s, 0)) { + sc.emplace_back(std::begin(v), std::end(v)); + } + + REQUIRE(ans == sc); } TEST_CASE( From 60171c0c987f98751f9b06a5e44b3e3733f429bd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 16 Jan 2024 23:56:25 -0800 Subject: [PATCH 364/403] Modifies combinations_with_replacement(c, 0) to produce {{}} Issue #101 --- combinations_with_replacement.hpp | 22 ++++++++++++++++++--- test/test_combinations_with_replacement.cpp | 20 ++++++++++++++++--- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index b7e20d7d..d501c6e1 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -60,6 +60,12 @@ class iter::impl::CombinatorWithReplacement { ? 0 : COMPLETE} {} + static Iterator zero_length_end(ContainerT& container) { + Iterator it{container, 0}; + it.steps_ = 0; + return it; + } + CombIteratorDeref& operator*() { return indices_; } @@ -69,15 +75,19 @@ class iter::impl::CombinatorWithReplacement { } Iterator& operator++() { + if (indices_.get().empty()) { + // zero-length case. + ++steps_; + return *this; + } for (auto iter = indices_.get().rbegin(); iter != indices_.get().rend(); ++iter) { ++(*iter); if (!(*iter != get_end(*container_p_))) { if ((iter + 1) != indices_.get().rend()) { - for (auto down = iter; ; --down) { + for (auto down = iter;; --down) { (*down) = dumb_next(*(iter + 1)); - if (down == indices_.get().rbegin()) - break; + if (down == indices_.get().rbegin()) break; } } else { steps_ = COMPLETE; @@ -117,6 +127,9 @@ class iter::impl::CombinatorWithReplacement { } Iterator end() { + if (length_ == 0) { + return Iterator::zero_length_end(container_); + } return {container_, 0}; } @@ -125,6 +138,9 @@ class iter::impl::CombinatorWithReplacement { } Iterator> end() const { + if (length_ == 0) { + return Iterator>::zero_length_end(container_); + } return {std::as_const(container_), 0}; } }; diff --git a/test/test_combinations_with_replacement.cpp b/test/test_combinations_with_replacement.cpp index 61f30120..536780ac 100644 --- a/test/test_combinations_with_replacement.cpp +++ b/test/test_combinations_with_replacement.cpp @@ -1,5 +1,4 @@ #include - #include #include #include @@ -96,8 +95,23 @@ TEST_CASE("combinations_with_replacement: big size is no problem", TEST_CASE("combinations_with_replacement: 0 size is empty", "[combinations_with_replacement]") { std::string s{"A"}; - auto cwr = combinations_with_replacement(s, 0); - REQUIRE(std::begin(cwr) == std::end(cwr)); + CharCombSet sc; + for (auto v : combinations_with_replacement(s, 0)) { + sc.emplace_back(std::begin(v), std::end(v)); + } + CharCombSet ans = {{}}; + REQUIRE(ans == sc); +} + +TEST_CASE("combinations_with_replacement: 0 size is empty with empty container", + "[combinations_with_replacement]") { + std::string s{}; + CharCombSet sc; + for (auto v : combinations_with_replacement(s, 0)) { + sc.emplace_back(std::begin(v), std::end(v)); + } + CharCombSet ans = {{}}; + REQUIRE(ans == sc); } TEST_CASE("combinations_with_replacement: operator->", From d26742747b4ba4e1dff0b078382b00a36676dcba Mon Sep 17 00:00:00 2001 From: Sayan Date: Tue, 16 Apr 2024 20:56:20 -0400 Subject: [PATCH 365/403] compare const and non-const chained iterators; all tests pass --- chain.hpp | 55 +++++++++++++++++++++++++++++---------------- test/test_chain.cpp | 9 +++----- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/chain.hpp b/chain.hpp index 23d1e054..55338c9d 100644 --- a/chain.hpp +++ b/chain.hpp @@ -1,10 +1,6 @@ #ifndef ITER_CHAIN_HPP_ #define ITER_CHAIN_HPP_ -#include "internal/iter_tuples.hpp" -#include "internal/iterator_wrapper.hpp" -#include "internal/iterbase.hpp" - #include #include #include @@ -12,6 +8,10 @@ #include #include +#include "internal/iter_tuples.hpp" +#include "internal/iterator_wrapper.hpp" +#include "internal/iterbase.hpp" + namespace iter { namespace impl { template @@ -43,6 +43,26 @@ class iter::impl::Chained { private: friend ChainMaker; + template + class IteratorDataPair { + IteratorDataPair() = delete; + + public: + using IterTupTypeA = iterator_tuple_type; + using IterTupTypeB = iterator_tuple_type; + + template + static bool get_and_check_not_equal( + const IterTupTypeA& lhs, const IterTupTypeB& rhs) { + return std::get(lhs) != std::get(rhs); + } + + using NeqFunc = bool (*)(const IterTupTypeA&, const IterTupTypeB&); + + constexpr static std::array neq_comparers{ + {get_and_check_not_equal...}}; + }; + template class IteratorData { IteratorData() = delete; @@ -76,16 +96,9 @@ class iter::impl::Chained { ++std::get(iters); } - template - static bool get_and_check_not_equal( - const IterTupType& lhs, const IterTupType& rhs) { - return std::get(lhs) != std::get(rhs); - } - using DerefFunc = DerefType (*)(IterTupType&); using ArrowFunc = ArrowType (*)(IterTupType&); using IncFunc = void (*)(IterTupType&); - using NeqFunc = bool (*)(const IterTupType&, const IterTupType&); constexpr static std::array derefers{ {get_and_deref...}}; @@ -96,9 +109,6 @@ class iter::impl::Chained { constexpr static std::array incrementers{ {get_and_increment...}}; - constexpr static std::array neq_comparers{ - {get_and_check_not_equal...}}; - using TraitsValue = iterator_traits_deref>; }; @@ -119,12 +129,16 @@ class iter::impl::Chained { void check_for_end_and_adjust() { while (index_ < sizeof...(Is) - && !(IterData::neq_comparers[index_](iters_, ends_))) { + && !(IteratorDataPair::neq_comparers[index_]( + iters_, ends_))) { ++index_; } } public: + template + friend class Iterator; + using iterator_category = std::input_iterator_tag; using value_type = typename IteratorData::TraitsValue; using difference_type = std::ptrdiff_t; @@ -141,7 +155,7 @@ class iter::impl::Chained { return IterData::derefers[index_](iters_); } - decltype(auto) operator-> () { + decltype(auto) operator->() { return IterData::arrowers[index_](iters_); } @@ -158,13 +172,16 @@ class iter::impl::Chained { } // TODO make const and non-const iterators comparable - bool operator!=(const Iterator& other) const { + template + bool operator!=(const Iterator& other) const { return index_ != other.index_ || (index_ != sizeof...(Is) - && IterData::neq_comparers[index_](iters_, other.iters_)); + && IteratorDataPair::neq_comparers[index_]( + iters_, other.iters_)); } - bool operator==(const Iterator& other) const { + template + bool operator==(const Iterator& other) const { return !(*this != other); } }; diff --git a/test/test_chain.cpp b/test/test_chain.cpp index b4b77cf2..5ad9c361 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -1,6 +1,4 @@ #include -#include "helpers.hpp" - #include #include #include @@ -8,6 +6,7 @@ #include #include "catch.hpp" +#include "helpers.hpp" using iter::chain; using itertest::BasicIterable; @@ -37,14 +36,12 @@ TEST_CASE("chain: const iteration", "[chain][const]") { REQUIRE(v == vc); } -// TODO make this work -#if 0 -TEST_CASE("chain: const iterators can be compared to non-const itertors", "[chain][const]") { +TEST_CASE("chain: const iterators can be compared to non-const itertors", + "[chain][const]") { auto ch = chain(std::string{}, std::string{}); const auto& cch = ch; (void)(std::begin(ch) == std::end(cch)); } -#endif TEST_CASE("chain: with different container types", "[chain]") { std::string s1{"abc"}; From 7119a5d7b00228130a47b7554c515bd5b403774f Mon Sep 17 00:00:00 2001 From: maxmarsc Date: Fri, 26 Apr 2024 13:15:11 +0200 Subject: [PATCH 366/403] Moved all headers into a cppitertools directory Removed test build files from git tracking --- CMakeLists.txt | 6 +++--- accumulate.hpp => cppitertools/accumulate.hpp | 0 batched.hpp => cppitertools/batched.hpp | 0 chain.hpp => cppitertools/chain.hpp | 0 chunked.hpp => cppitertools/chunked.hpp | 0 combinations.hpp => cppitertools/combinations.hpp | 0 .../combinations_with_replacement.hpp | 0 compress.hpp => cppitertools/compress.hpp | 0 count.hpp => cppitertools/count.hpp | 0 cycle.hpp => cppitertools/cycle.hpp | 0 dropwhile.hpp => cppitertools/dropwhile.hpp | 0 enumerate.hpp => cppitertools/enumerate.hpp | 0 filter.hpp => cppitertools/filter.hpp | 0 filterfalse.hpp => cppitertools/filterfalse.hpp | 0 groupby.hpp => cppitertools/groupby.hpp | 0 imap.hpp => cppitertools/imap.hpp | 0 {internal => cppitertools/internal}/iter_tuples.hpp | 0 .../internal}/iterator_wrapper.hpp | 0 .../internal}/iteratoriterator.hpp | 0 {internal => cppitertools/internal}/iterbase.hpp | 0 itertools.hpp => cppitertools/itertools.hpp | 0 permutations.hpp => cppitertools/permutations.hpp | 0 powerset.hpp => cppitertools/powerset.hpp | 0 product.hpp => cppitertools/product.hpp | 0 range.hpp => cppitertools/range.hpp | 0 repeat.hpp => cppitertools/repeat.hpp | 0 reversed.hpp => cppitertools/reversed.hpp | 0 slice.hpp => cppitertools/slice.hpp | 0 sliding_window.hpp => cppitertools/sliding_window.hpp | 0 sorted.hpp => cppitertools/sorted.hpp | 0 starmap.hpp => cppitertools/starmap.hpp | 0 takewhile.hpp => cppitertools/takewhile.hpp | 0 .../unique_everseen.hpp | 0 .../unique_justseen.hpp | 0 zip.hpp => cppitertools/zip.hpp | 0 zip_longest.hpp => cppitertools/zip_longest.hpp | 0 examples/accumulate_examples.cpp | 4 ++-- examples/batched_examples.cpp | 2 +- examples/chain_examples.cpp | 2 +- examples/chunked_examples.cpp | 2 +- examples/combinatoric_examples.cpp | 10 +++++----- examples/compress_examples.cpp | 2 +- examples/count_examples.cpp | 2 +- examples/cycle_examples.cpp | 2 +- examples/dropwhile_examples.cpp | 2 +- examples/enumerate_examples.cpp | 2 +- examples/filter_examples.cpp | 2 +- examples/filterfalse_examples.cpp | 2 +- examples/groupby_examples.cpp | 2 +- examples/imap_examples.cpp | 2 +- examples/mixed_examples.cpp | 4 ++-- examples/range_examples.cpp | 2 +- examples/repeat_examples.cpp | 2 +- examples/reversed_examples.cpp | 2 +- examples/slice_examples.cpp | 4 ++-- examples/sliding_window_examples.cpp | 2 +- examples/sorted_examples.cpp | 2 +- examples/starmap_examples.cpp | 2 +- examples/takewhile_examples.cpp | 2 +- examples/unique_everseen_examples.cpp | 2 +- examples/unique_justseen_examples.cpp | 2 +- examples/zip_examples.cpp | 2 +- examples/zip_longest_examples.cpp | 2 +- test/helpers.hpp | 2 +- test/test_accumulate.cpp | 2 +- test/test_batched.cpp | 2 +- test/test_chain.cpp | 2 +- test/test_chunked.cpp | 2 +- test/test_combinations.cpp | 2 +- test/test_combinations_with_replacement.cpp | 2 +- test/test_compress.cpp | 2 +- test/test_count.cpp | 2 +- test/test_cycle.cpp | 2 +- test/test_dropwhile.cpp | 2 +- test/test_enumerate.cpp | 2 +- test/test_filter.cpp | 2 +- test/test_filterfalse.cpp | 2 +- test/test_groupby.cpp | 2 +- test/test_imap.cpp | 2 +- test/test_iterator_wrapper.cpp | 2 +- test/test_iteratoriterator.cpp | 2 +- test/test_iterbase.cpp | 4 ++-- test/test_mixed.cpp | 2 +- test/test_permutations.cpp | 2 +- test/test_powerset.cpp | 2 +- test/test_product.cpp | 2 +- test/test_range.cpp | 2 +- test/test_repeat.cpp | 2 +- test/test_reversed.cpp | 2 +- test/test_slice.cpp | 2 +- test/test_sliding_window.cpp | 2 +- test/test_sorted.cpp | 4 ++-- test/test_starmap.cpp | 2 +- test/test_takewhile.cpp | 2 +- test/test_unique_everseen.cpp | 2 +- test/test_unique_justseen.cpp | 2 +- test/test_zip.cpp | 2 +- test/test_zip_longest.cpp | 2 +- 98 files changed, 74 insertions(+), 74 deletions(-) rename accumulate.hpp => cppitertools/accumulate.hpp (100%) rename batched.hpp => cppitertools/batched.hpp (100%) rename chain.hpp => cppitertools/chain.hpp (100%) rename chunked.hpp => cppitertools/chunked.hpp (100%) rename combinations.hpp => cppitertools/combinations.hpp (100%) rename combinations_with_replacement.hpp => cppitertools/combinations_with_replacement.hpp (100%) rename compress.hpp => cppitertools/compress.hpp (100%) rename count.hpp => cppitertools/count.hpp (100%) rename cycle.hpp => cppitertools/cycle.hpp (100%) rename dropwhile.hpp => cppitertools/dropwhile.hpp (100%) rename enumerate.hpp => cppitertools/enumerate.hpp (100%) rename filter.hpp => cppitertools/filter.hpp (100%) rename filterfalse.hpp => cppitertools/filterfalse.hpp (100%) rename groupby.hpp => cppitertools/groupby.hpp (100%) rename imap.hpp => cppitertools/imap.hpp (100%) rename {internal => cppitertools/internal}/iter_tuples.hpp (100%) rename {internal => cppitertools/internal}/iterator_wrapper.hpp (100%) rename {internal => cppitertools/internal}/iteratoriterator.hpp (100%) rename {internal => cppitertools/internal}/iterbase.hpp (100%) rename itertools.hpp => cppitertools/itertools.hpp (100%) rename permutations.hpp => cppitertools/permutations.hpp (100%) rename powerset.hpp => cppitertools/powerset.hpp (100%) rename product.hpp => cppitertools/product.hpp (100%) rename range.hpp => cppitertools/range.hpp (100%) rename repeat.hpp => cppitertools/repeat.hpp (100%) rename reversed.hpp => cppitertools/reversed.hpp (100%) rename slice.hpp => cppitertools/slice.hpp (100%) rename sliding_window.hpp => cppitertools/sliding_window.hpp (100%) rename sorted.hpp => cppitertools/sorted.hpp (100%) rename starmap.hpp => cppitertools/starmap.hpp (100%) rename takewhile.hpp => cppitertools/takewhile.hpp (100%) rename unique_everseen.hpp => cppitertools/unique_everseen.hpp (100%) rename unique_justseen.hpp => cppitertools/unique_justseen.hpp (100%) rename zip.hpp => cppitertools/zip.hpp (100%) rename zip_longest.hpp => cppitertools/zip_longest.hpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 32d26fde..c7eb98ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ add_library(cppitertools::cppitertools ALIAS cppitertools) target_include_directories(cppitertools INTERFACE $ - $) + $) # require C++17 target_compile_features(cppitertools INTERFACE cxx_std_17) @@ -29,8 +29,8 @@ install( EXPORT cppitertools-targets) install( - DIRECTORY . - DESTINATION ${cppitertools_INSTALL_INCLUDE_DIR}/cppitertools) + DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cppitertools + DESTINATION ${cppitertools_INSTALL_INCLUDE_DIR}) install( EXPORT cppitertools-targets diff --git a/accumulate.hpp b/cppitertools/accumulate.hpp similarity index 100% rename from accumulate.hpp rename to cppitertools/accumulate.hpp diff --git a/batched.hpp b/cppitertools/batched.hpp similarity index 100% rename from batched.hpp rename to cppitertools/batched.hpp diff --git a/chain.hpp b/cppitertools/chain.hpp similarity index 100% rename from chain.hpp rename to cppitertools/chain.hpp diff --git a/chunked.hpp b/cppitertools/chunked.hpp similarity index 100% rename from chunked.hpp rename to cppitertools/chunked.hpp diff --git a/combinations.hpp b/cppitertools/combinations.hpp similarity index 100% rename from combinations.hpp rename to cppitertools/combinations.hpp diff --git a/combinations_with_replacement.hpp b/cppitertools/combinations_with_replacement.hpp similarity index 100% rename from combinations_with_replacement.hpp rename to cppitertools/combinations_with_replacement.hpp diff --git a/compress.hpp b/cppitertools/compress.hpp similarity index 100% rename from compress.hpp rename to cppitertools/compress.hpp diff --git a/count.hpp b/cppitertools/count.hpp similarity index 100% rename from count.hpp rename to cppitertools/count.hpp diff --git a/cycle.hpp b/cppitertools/cycle.hpp similarity index 100% rename from cycle.hpp rename to cppitertools/cycle.hpp diff --git a/dropwhile.hpp b/cppitertools/dropwhile.hpp similarity index 100% rename from dropwhile.hpp rename to cppitertools/dropwhile.hpp diff --git a/enumerate.hpp b/cppitertools/enumerate.hpp similarity index 100% rename from enumerate.hpp rename to cppitertools/enumerate.hpp diff --git a/filter.hpp b/cppitertools/filter.hpp similarity index 100% rename from filter.hpp rename to cppitertools/filter.hpp diff --git a/filterfalse.hpp b/cppitertools/filterfalse.hpp similarity index 100% rename from filterfalse.hpp rename to cppitertools/filterfalse.hpp diff --git a/groupby.hpp b/cppitertools/groupby.hpp similarity index 100% rename from groupby.hpp rename to cppitertools/groupby.hpp diff --git a/imap.hpp b/cppitertools/imap.hpp similarity index 100% rename from imap.hpp rename to cppitertools/imap.hpp diff --git a/internal/iter_tuples.hpp b/cppitertools/internal/iter_tuples.hpp similarity index 100% rename from internal/iter_tuples.hpp rename to cppitertools/internal/iter_tuples.hpp diff --git a/internal/iterator_wrapper.hpp b/cppitertools/internal/iterator_wrapper.hpp similarity index 100% rename from internal/iterator_wrapper.hpp rename to cppitertools/internal/iterator_wrapper.hpp diff --git a/internal/iteratoriterator.hpp b/cppitertools/internal/iteratoriterator.hpp similarity index 100% rename from internal/iteratoriterator.hpp rename to cppitertools/internal/iteratoriterator.hpp diff --git a/internal/iterbase.hpp b/cppitertools/internal/iterbase.hpp similarity index 100% rename from internal/iterbase.hpp rename to cppitertools/internal/iterbase.hpp diff --git a/itertools.hpp b/cppitertools/itertools.hpp similarity index 100% rename from itertools.hpp rename to cppitertools/itertools.hpp diff --git a/permutations.hpp b/cppitertools/permutations.hpp similarity index 100% rename from permutations.hpp rename to cppitertools/permutations.hpp diff --git a/powerset.hpp b/cppitertools/powerset.hpp similarity index 100% rename from powerset.hpp rename to cppitertools/powerset.hpp diff --git a/product.hpp b/cppitertools/product.hpp similarity index 100% rename from product.hpp rename to cppitertools/product.hpp diff --git a/range.hpp b/cppitertools/range.hpp similarity index 100% rename from range.hpp rename to cppitertools/range.hpp diff --git a/repeat.hpp b/cppitertools/repeat.hpp similarity index 100% rename from repeat.hpp rename to cppitertools/repeat.hpp diff --git a/reversed.hpp b/cppitertools/reversed.hpp similarity index 100% rename from reversed.hpp rename to cppitertools/reversed.hpp diff --git a/slice.hpp b/cppitertools/slice.hpp similarity index 100% rename from slice.hpp rename to cppitertools/slice.hpp diff --git a/sliding_window.hpp b/cppitertools/sliding_window.hpp similarity index 100% rename from sliding_window.hpp rename to cppitertools/sliding_window.hpp diff --git a/sorted.hpp b/cppitertools/sorted.hpp similarity index 100% rename from sorted.hpp rename to cppitertools/sorted.hpp diff --git a/starmap.hpp b/cppitertools/starmap.hpp similarity index 100% rename from starmap.hpp rename to cppitertools/starmap.hpp diff --git a/takewhile.hpp b/cppitertools/takewhile.hpp similarity index 100% rename from takewhile.hpp rename to cppitertools/takewhile.hpp diff --git a/unique_everseen.hpp b/cppitertools/unique_everseen.hpp similarity index 100% rename from unique_everseen.hpp rename to cppitertools/unique_everseen.hpp diff --git a/unique_justseen.hpp b/cppitertools/unique_justseen.hpp similarity index 100% rename from unique_justseen.hpp rename to cppitertools/unique_justseen.hpp diff --git a/zip.hpp b/cppitertools/zip.hpp similarity index 100% rename from zip.hpp rename to cppitertools/zip.hpp diff --git a/zip_longest.hpp b/cppitertools/zip_longest.hpp similarity index 100% rename from zip_longest.hpp rename to cppitertools/zip_longest.hpp diff --git a/examples/accumulate_examples.cpp b/examples/accumulate_examples.cpp index 9d9a2f67..4d8569d2 100644 --- a/examples/accumulate_examples.cpp +++ b/examples/accumulate_examples.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include #include diff --git a/examples/batched_examples.cpp b/examples/batched_examples.cpp index c63c05b3..1dfa6abf 100644 --- a/examples/batched_examples.cpp +++ b/examples/batched_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/chain_examples.cpp b/examples/chain_examples.cpp index 607fa040..cdcd7fed 100644 --- a/examples/chain_examples.cpp +++ b/examples/chain_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/chunked_examples.cpp b/examples/chunked_examples.cpp index 9c3046f5..c3325df1 100644 --- a/examples/chunked_examples.cpp +++ b/examples/chunked_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/combinatoric_examples.cpp b/examples/combinatoric_examples.cpp index 653d428c..0915f985 100644 --- a/examples/combinatoric_examples.cpp +++ b/examples/combinatoric_examples.cpp @@ -1,8 +1,8 @@ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/examples/compress_examples.cpp b/examples/compress_examples.cpp index b60197a9..dbabbbb9 100644 --- a/examples/compress_examples.cpp +++ b/examples/compress_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/count_examples.cpp b/examples/count_examples.cpp index 10ac8a72..70b876cc 100644 --- a/examples/count_examples.cpp +++ b/examples/count_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/examples/cycle_examples.cpp b/examples/cycle_examples.cpp index 7f973d66..0598431a 100644 --- a/examples/cycle_examples.cpp +++ b/examples/cycle_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/dropwhile_examples.cpp b/examples/dropwhile_examples.cpp index 8c628f1a..c8f993c0 100644 --- a/examples/dropwhile_examples.cpp +++ b/examples/dropwhile_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/enumerate_examples.cpp b/examples/enumerate_examples.cpp index 899c3b39..822abbbf 100644 --- a/examples/enumerate_examples.cpp +++ b/examples/enumerate_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/filter_examples.cpp b/examples/filter_examples.cpp index d28c443a..5ce16af2 100644 --- a/examples/filter_examples.cpp +++ b/examples/filter_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/filterfalse_examples.cpp b/examples/filterfalse_examples.cpp index dd937cee..0edc004a 100644 --- a/examples/filterfalse_examples.cpp +++ b/examples/filterfalse_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/groupby_examples.cpp b/examples/groupby_examples.cpp index 8d4a9918..5525f9ff 100644 --- a/examples/groupby_examples.cpp +++ b/examples/groupby_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/imap_examples.cpp b/examples/imap_examples.cpp index 812281b6..95fee802 100644 --- a/examples/imap_examples.cpp +++ b/examples/imap_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/mixed_examples.cpp b/examples/mixed_examples.cpp index 08ff774b..9f1ba056 100644 --- a/examples/mixed_examples.cpp +++ b/examples/mixed_examples.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include #include diff --git a/examples/range_examples.cpp b/examples/range_examples.cpp index 1dd03199..ff328ee7 100644 --- a/examples/range_examples.cpp +++ b/examples/range_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/examples/repeat_examples.cpp b/examples/repeat_examples.cpp index 24d37a8d..2dceaf98 100644 --- a/examples/repeat_examples.cpp +++ b/examples/repeat_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/examples/reversed_examples.cpp b/examples/reversed_examples.cpp index d4d804d9..1bb8dbed 100644 --- a/examples/reversed_examples.cpp +++ b/examples/reversed_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/slice_examples.cpp b/examples/slice_examples.cpp index 42a16e33..d9f2501a 100644 --- a/examples/slice_examples.cpp +++ b/examples/slice_examples.cpp @@ -1,7 +1,7 @@ #include -#include -#include +#include +#include #include #include diff --git a/examples/sliding_window_examples.cpp b/examples/sliding_window_examples.cpp index ff286202..7658182d 100644 --- a/examples/sliding_window_examples.cpp +++ b/examples/sliding_window_examples.cpp @@ -1,4 +1,4 @@ -#include "sliding_window.hpp" +#include "cppitertools/sliding_window.hpp" #include #include diff --git a/examples/sorted_examples.cpp b/examples/sorted_examples.cpp index 109d137d..4e6b5a22 100644 --- a/examples/sorted_examples.cpp +++ b/examples/sorted_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/starmap_examples.cpp b/examples/starmap_examples.cpp index 9797756c..b375ef3e 100644 --- a/examples/starmap_examples.cpp +++ b/examples/starmap_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/takewhile_examples.cpp b/examples/takewhile_examples.cpp index 3062a141..d86d6442 100644 --- a/examples/takewhile_examples.cpp +++ b/examples/takewhile_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/unique_everseen_examples.cpp b/examples/unique_everseen_examples.cpp index a670f0b1..52dc02fa 100644 --- a/examples/unique_everseen_examples.cpp +++ b/examples/unique_everseen_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/unique_justseen_examples.cpp b/examples/unique_justseen_examples.cpp index 878cd4f8..7c8cd9aa 100644 --- a/examples/unique_justseen_examples.cpp +++ b/examples/unique_justseen_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/zip_examples.cpp b/examples/zip_examples.cpp index d35dd0cf..51febf13 100644 --- a/examples/zip_examples.cpp +++ b/examples/zip_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/examples/zip_longest_examples.cpp b/examples/zip_longest_examples.cpp index 5f8dc9e7..d3c80173 100644 --- a/examples/zip_longest_examples.cpp +++ b/examples/zip_longest_examples.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/test/helpers.hpp b/test/helpers.hpp index 93112519..80167980 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -1,7 +1,7 @@ #ifndef TEST_HELPER_H_ #define TEST_HELPER_H_ -#include +#include #include #include #include diff --git a/test/test_accumulate.cpp b/test/test_accumulate.cpp index f91f32b6..c868f0c5 100644 --- a/test/test_accumulate.cpp +++ b/test/test_accumulate.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" #include diff --git a/test/test_batched.cpp b/test/test_batched.cpp index bdd5e2a3..098acecc 100644 --- a/test/test_batched.cpp +++ b/test/test_batched.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/test/test_chain.cpp b/test/test_chain.cpp index b4b77cf2..9196ef72 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" #include diff --git a/test/test_chunked.cpp b/test/test_chunked.cpp index 7e3165a0..3aaca797 100644 --- a/test/test_chunked.cpp +++ b/test/test_chunked.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/test/test_combinations.cpp b/test/test_combinations.cpp index 6d9718dc..14548240 100644 --- a/test/test_combinations.cpp +++ b/test/test_combinations.cpp @@ -4,7 +4,7 @@ #undef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE #undef DEFINE_DEFAULT_ITERATOR_CTOR -#include +#include #include #include #include diff --git a/test/test_combinations_with_replacement.cpp b/test/test_combinations_with_replacement.cpp index 536780ac..2c3ee0f6 100644 --- a/test/test_combinations_with_replacement.cpp +++ b/test/test_combinations_with_replacement.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/test/test_compress.cpp b/test/test_compress.cpp index 1330e9c2..70aa3f89 100644 --- a/test/test_compress.cpp +++ b/test/test_compress.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" #include diff --git a/test/test_count.cpp b/test/test_count.cpp index 8998f1eb..d5248ac2 100644 --- a/test/test_count.cpp +++ b/test/test_count.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" #include diff --git a/test/test_cycle.cpp b/test/test_cycle.cpp index 84981878..0974a87c 100644 --- a/test/test_cycle.cpp +++ b/test/test_cycle.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" diff --git a/test/test_dropwhile.cpp b/test/test_dropwhile.cpp index 2b85c607..2a41a671 100644 --- a/test/test_dropwhile.cpp +++ b/test/test_dropwhile.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" diff --git a/test/test_enumerate.cpp b/test/test_enumerate.cpp index d5fb4238..777146e6 100644 --- a/test/test_enumerate.cpp +++ b/test/test_enumerate.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" diff --git a/test/test_filter.cpp b/test/test_filter.cpp index b10dd5be..f160785b 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" diff --git a/test/test_filterfalse.cpp b/test/test_filterfalse.cpp index 7a74a0df..93d50d6a 100644 --- a/test/test_filterfalse.cpp +++ b/test/test_filterfalse.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" diff --git a/test/test_groupby.cpp b/test/test_groupby.cpp index 0069da14..6ce9d479 100644 --- a/test/test_groupby.cpp +++ b/test/test_groupby.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" diff --git a/test/test_imap.cpp b/test/test_imap.cpp index b2be404d..40a9d3e3 100644 --- a/test/test_imap.cpp +++ b/test/test_imap.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" diff --git a/test/test_iterator_wrapper.cpp b/test/test_iterator_wrapper.cpp index 6c79a278..e5b0238a 100644 --- a/test/test_iterator_wrapper.cpp +++ b/test/test_iterator_wrapper.cpp @@ -1,7 +1,7 @@ // NOTE this header tests implementation details #include "catch.hpp" -#include "internal/iterator_wrapper.hpp" +#include "cppitertools/internal/iterator_wrapper.hpp" // I'm using a std::vector of 1 int instead of just an int in order to give // the iterator types non-trivial constructors, destructors, and assignment. diff --git a/test/test_iteratoriterator.cpp b/test/test_iteratoriterator.cpp index dd2c4987..11c1b16c 100644 --- a/test/test_iteratoriterator.cpp +++ b/test/test_iteratoriterator.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/test/test_iterbase.cpp b/test/test_iterbase.cpp index c8783f32..c904b841 100644 --- a/test/test_iterbase.cpp +++ b/test/test_iterbase.cpp @@ -2,8 +2,8 @@ // on any of this. Users of the library must consider all of this undocumented // -#include -#include +#include +#include #include #include #include diff --git a/test/test_mixed.cpp b/test/test_mixed.cpp index 9c4c3ed6..b190adf6 100644 --- a/test/test_mixed.cpp +++ b/test/test_mixed.cpp @@ -4,7 +4,7 @@ #include #include "catch.hpp" -#include "itertools.hpp" +#include "cppitertools/itertools.hpp" class MyUnMovable { int val; diff --git a/test/test_permutations.cpp b/test/test_permutations.cpp index 5da85fc8..8d77d2f2 100644 --- a/test/test_permutations.cpp +++ b/test/test_permutations.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" diff --git a/test/test_powerset.cpp b/test/test_powerset.cpp index c18dd1f7..44a7d8b5 100644 --- a/test/test_powerset.cpp +++ b/test/test_powerset.cpp @@ -1,4 +1,4 @@ -#include +#include #define CHAR_RANGE_DEFAULT_CONSTRUCTIBLE #include "helpers.hpp" diff --git a/test/test_product.cpp b/test/test_product.cpp index 6a580bc9..a453da99 100644 --- a/test/test_product.cpp +++ b/test/test_product.cpp @@ -1,4 +1,4 @@ -#include +#include #define DEFINE_BASIC_ITERABLE_COPY_CTOR #define DEFINE_BASIC_ITERABLE_CONST_BEGIN_AND_END diff --git a/test/test_range.cpp b/test/test_range.cpp index 4a25211a..b2b15f98 100644 --- a/test/test_range.cpp +++ b/test/test_range.cpp @@ -1,4 +1,4 @@ -#include "range.hpp" +#include "cppitertools/range.hpp" #include #include diff --git a/test/test_repeat.cpp b/test/test_repeat.cpp index ab92cbc1..5427909a 100644 --- a/test/test_repeat.cpp +++ b/test/test_repeat.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include diff --git a/test/test_reversed.cpp b/test/test_reversed.cpp index 530a17fc..10dfe4d9 100644 --- a/test/test_reversed.cpp +++ b/test/test_reversed.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/test/test_slice.cpp b/test/test_slice.cpp index 5fae78f4..fc5b42fe 100644 --- a/test/test_slice.cpp +++ b/test/test_slice.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/test/test_sliding_window.cpp b/test/test_sliding_window.cpp index a302e1dc..e031ce75 100644 --- a/test/test_sliding_window.cpp +++ b/test/test_sliding_window.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/test/test_sorted.cpp b/test/test_sorted.cpp index ff151576..ea80decf 100644 --- a/test/test_sorted.cpp +++ b/test/test_sorted.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -46,7 +46,7 @@ TEST_CASE("sorted: const iteration", "[sorted][const]") { REQUIRE(v == vc); } -//FIXME: This test currently fails (STL assertion fails on MSVC with debug library, simple test failure on gcc). The problem is 'sorted' will sort twice, once for non-const and once for const container; the resulting iterators are thus not on the same container (violating domain of == as specified in C++17 [forward.iterators]¶2). Remove [!hide] tag when fixed. +//FIXME: This test currently fails (STL assertion fails on MSVC with debug library, simple test failure on gcc). The problem is 'sorted' will sort twice, once for non-const and once for const container; the resulting iterators are thus not on the same container (violating domain of == as specified in C++17 [forward.iterators]�2). Remove [!hide] tag when fixed. TEST_CASE("sorted: const iterators can be compared to non-const iterators", "[sorted][const][!hide]") { auto s = sorted(Vec{1}); diff --git a/test/test_starmap.cpp b/test/test_starmap.cpp index feae8da9..e3958c84 100644 --- a/test/test_starmap.cpp +++ b/test/test_starmap.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" #include diff --git a/test/test_takewhile.cpp b/test/test_takewhile.cpp index 903f6a9f..e3dade73 100644 --- a/test/test_takewhile.cpp +++ b/test/test_takewhile.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/test/test_unique_everseen.cpp b/test/test_unique_everseen.cpp index 68cb319a..c5fedad3 100644 --- a/test/test_unique_everseen.cpp +++ b/test/test_unique_everseen.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" diff --git a/test/test_unique_justseen.cpp b/test/test_unique_justseen.cpp index 72af19b8..6147b477 100644 --- a/test/test_unique_justseen.cpp +++ b/test/test_unique_justseen.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" diff --git a/test/test_zip.cpp b/test/test_zip.cpp index cb49981c..87c927f8 100644 --- a/test/test_zip.cpp +++ b/test/test_zip.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" diff --git a/test/test_zip_longest.cpp b/test/test_zip_longest.cpp index 4759a412..cdf29269 100644 --- a/test/test_zip_longest.cpp +++ b/test/test_zip_longest.cpp @@ -1,4 +1,4 @@ -#include +#include #include "helpers.hpp" From 02f1457e23e277db646c6fe4cc519f5b1e9cc314 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 3 May 2024 17:02:49 -0700 Subject: [PATCH 367/403] Fixes BUILD for cppitertools/ prefix users will need to prefix includes with "cppitertools/" Issue #100 --- BUILD | 70 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/BUILD b/BUILD index bab14566..f2fab7df 100644 --- a/BUILD +++ b/BUILD @@ -1,43 +1,43 @@ cc_library( name = "cppitertools", hdrs = [ - "accumulate.hpp", - "batched.hpp", - "chain.hpp", - "chunked.hpp", - "combinations.hpp", - "combinations_with_replacement.hpp", - "compress.hpp", - "count.hpp", - "cycle.hpp", - "dropwhile.hpp", - "enumerate.hpp", - "filter.hpp", - "filterfalse.hpp", - "groupby.hpp", - "imap.hpp", - "itertools.hpp", - "permutations.hpp", - "powerset.hpp", - "product.hpp", - "range.hpp", - "repeat.hpp", - "reversed.hpp", - "slice.hpp", - "sliding_window.hpp", - "sorted.hpp", - "starmap.hpp", - "takewhile.hpp", - "unique_everseen.hpp", - "unique_justseen.hpp", - "zip.hpp", - "zip_longest.hpp", + "cppitertools/accumulate.hpp", + "cppitertools/batched.hpp", + "cppitertools/chain.hpp", + "cppitertools/chunked.hpp", + "cppitertools/combinations.hpp", + "cppitertools/combinations_with_replacement.hpp", + "cppitertools/compress.hpp", + "cppitertools/count.hpp", + "cppitertools/cycle.hpp", + "cppitertools/dropwhile.hpp", + "cppitertools/enumerate.hpp", + "cppitertools/filter.hpp", + "cppitertools/filterfalse.hpp", + "cppitertools/groupby.hpp", + "cppitertools/imap.hpp", + "cppitertools/itertools.hpp", + "cppitertools/permutations.hpp", + "cppitertools/powerset.hpp", + "cppitertools/product.hpp", + "cppitertools/range.hpp", + "cppitertools/repeat.hpp", + "cppitertools/reversed.hpp", + "cppitertools/slice.hpp", + "cppitertools/sliding_window.hpp", + "cppitertools/sorted.hpp", + "cppitertools/starmap.hpp", + "cppitertools/takewhile.hpp", + "cppitertools/unique_everseen.hpp", + "cppitertools/unique_justseen.hpp", + "cppitertools/zip.hpp", + "cppitertools/zip_longest.hpp", ], srcs = [ - "internal/iter_tuples.hpp", - "internal/iterator_wrapper.hpp", - "internal/iteratoriterator.hpp", - "internal/iterbase.hpp", + "cppitertools/internal/iter_tuples.hpp", + "cppitertools/internal/iterator_wrapper.hpp", + "cppitertools/internal/iteratoriterator.hpp", + "cppitertools/internal/iterbase.hpp", ], visibility = ["//visibility:public"], ) From f857d4ad101b5635842e6216e4d962c71da41cec Mon Sep 17 00:00:00 2001 From: Sayan Date: Sun, 5 May 2024 09:28:10 -0400 Subject: [PATCH 368/403] remove stale comments; improve tests for const non-const comparisons [chain] --- chain.hpp | 1 - test/test_chain.cpp | 54 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/chain.hpp b/chain.hpp index 55338c9d..85dd6555 100644 --- a/chain.hpp +++ b/chain.hpp @@ -171,7 +171,6 @@ class iter::impl::Chained { return ret; } - // TODO make const and non-const iterators comparable template bool operator!=(const Iterator& other) const { return index_ != other.index_ diff --git a/test/test_chain.cpp b/test/test_chain.cpp index 5ad9c361..47360d97 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -38,9 +38,31 @@ TEST_CASE("chain: const iteration", "[chain][const]") { TEST_CASE("chain: const iterators can be compared to non-const itertors", "[chain][const]") { - auto ch = chain(std::string{}, std::string{}); - const auto& cch = ch; - (void)(std::begin(ch) == std::end(cch)); + std::string s1{"abc"}; + std::list li{'m', 'n', 'o'}; + auto ch = chain(s1, li); + + const auto cch = chain(s1, li); + SECTION("begin and const begin compare equal") { + REQUIRE(std::begin(ch) == std::begin(cch)); + } + SECTION("begin and const end compare not-equal") { + REQUIRE_FALSE(std::begin(ch) == std::end(cch)); + } + SECTION("end and const end compare equal") { + REQUIRE(std::end(ch) == std::end(cch)); + } + SECTION( + "const and non-const iterator compare equal/not-equal at appropriate " + "pos.") { + auto iter = ch.begin(); + iter++; + auto citer = cch.begin(); + citer++; + REQUIRE(iter == citer); + citer++; + REQUIRE_FALSE(iter == citer); + } } TEST_CASE("chain: with different container types", "[chain]") { @@ -215,10 +237,32 @@ TEST_CASE( "chain.from_iterable: const iterators can be compared to non-const " "iterators", "[chain.from_iterable][const]") { - std::vector> v{}; + std::vector> v{{1, 2}, {4, 6}}; auto ch = chain.from_iterable(v); const auto& cch = ch; - (void)(std::begin(ch) == std::end(cch)); + + SECTION("begin and const end compare not-equal") { + REQUIRE_FALSE(std::begin(ch) == std::end(cch)); + } + SECTION("begin and const begin compare equal") { + REQUIRE(std::begin(ch) == std::begin(cch)); + } + SECTION("end and const end compare not-equal") { + REQUIRE(std::end(ch) == std::end(cch)); + } + SECTION( + "const and non-const iterator compare equal/not-equal at appropriate " + "pos.") { + auto iter = ch.begin(); + iter++; + auto citer = cch.begin(); + citer++; + REQUIRE(iter == citer); + citer++; + REQUIRE_FALSE(iter == citer); + iter++; + REQUIRE(iter == citer); + } } TEST_CASE("chain.fromm_iterable: Works with different begin and end types", From 7abcb2d8da270544df3b41bf623d50f3357f7d28 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 6 May 2024 12:49:22 -0700 Subject: [PATCH 369/403] Updates conanfile for cppitertools subdirectory/ And conan2 I think? I am not really sure what I'm doing here. Issue #100 --- conanfile.py | 61 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/conanfile.py b/conanfile.py index b47cbab4..114b620f 100644 --- a/conanfile.py +++ b/conanfile.py @@ -1,35 +1,44 @@ -from conans import ConanFile, CMake - -import os +from conan import ConanFile +from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps class CppIterTools(ConanFile): - name = "cppitertools" - version = "2.0" - author = "Ryan Haining " - homepage = "https://github.com/ryanhaining/cppitertools" + name = 'cppitertools' + version = '3.0' + author = 'Ryan Haining ' + homepage = 'https://github.com/ryanhaining/cppitertools' url = homepage - topics = ("conan", "itertools", "cppitertools") - license = 'BSD 2-Clause "Simplified" License' - description = "Range-based for loop add-ons inspired by the Python builtins and itertools library. " \ - "Like itertools and the Python3 builtins, this library uses lazy evaluation wherever possible." - settings = "build_type", "compiler", "os", "arch" - generators = "cmake", "cmake_find_package", "cmake_paths" - exports = "LICENSE.md" - - exports_sources = list() - for file in os.listdir("."): - if file.endswith(".hpp"): - exports_sources.append(str(file)) - print("found files: " + str(exports_sources)) - exports_sources = tuple(exports_sources) + \ - ("internal/*", "CMakeLists.txt", "cmake/dummy-config.cmake.in") - no_copy_source = True + topics = ('itertools', 'cppitertools') + license = "BSD 2-Clause 'Simplified' License" + description = 'Range-based for loop add-ons inspired by the Python builtins and itertools library. ' \ + 'Like itertools and the Python3 builtins, this library uses lazy evaluation wherever possible.' + settings = 'build_type', 'compiler', 'os', 'arch' + exports = 'LICENSE.md' - def package(self): + exports_sources = ( + 'cppitertools/*', + 'cppitertools/internal/*', + 'CMakeLists.txt', + 'cmake/dummy-config.cmake.in') + + def layout(self): + cmake_layout(self) + + def generate(self): + deps = CMakeDeps(self) + deps.generate() + tc = CMakeToolchain(self) + tc.generate() + + def build(self): cmake = CMake(self) cmake.configure() + cmake.build() + + def package(self): + cmake = CMake(self) cmake.install() - def package_id(self): - self.info.header_only() + def package_info(self): + self.cpp_info.bindirs = [] + self.cpp_info.libdirs = [] From 87ad8a0b3de4a10cf475c01e0ccdf517529b4142 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 21 Jun 2024 11:46:33 -0700 Subject: [PATCH 370/403] Adds bazel lockfiles to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index ac51a054..553aa4a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ bazel-* +MODULE.bazel +MODULE.bazel.lock From 69d3b3f510847bdb953894f81cf6f52b9b533b8f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 21 Jun 2024 11:53:32 -0700 Subject: [PATCH 371/403] Removes anonymous namespace around chain definition Fixes #104 --- cppitertools/chain.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cppitertools/chain.hpp b/cppitertools/chain.hpp index 85dd6555..76759eeb 100644 --- a/cppitertools/chain.hpp +++ b/cppitertools/chain.hpp @@ -343,9 +343,7 @@ class iter::impl::ChainMaker { }; namespace iter { - namespace { - constexpr auto chain = iter::impl::ChainMaker{}; - } + inline constexpr auto chain = iter::impl::ChainMaker{}; } #endif From ab4999407f73ca09cc2e5efff2b8724ac40b071a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 21 Jun 2024 11:54:29 -0700 Subject: [PATCH 372/403] Adds inline specifier to itertools callable objects in headers Related to issue #104 --- cppitertools/accumulate.hpp | 2 +- cppitertools/batched.hpp | 2 +- cppitertools/chunked.hpp | 2 +- cppitertools/combinations.hpp | 2 +- cppitertools/combinations_with_replacement.hpp | 2 +- cppitertools/cycle.hpp | 2 +- cppitertools/dropwhile.hpp | 2 +- cppitertools/enumerate.hpp | 2 +- cppitertools/filter.hpp | 2 +- cppitertools/filterfalse.hpp | 2 +- cppitertools/groupby.hpp | 2 +- cppitertools/imap.hpp | 2 +- cppitertools/permutations.hpp | 2 +- cppitertools/powerset.hpp | 2 +- cppitertools/reversed.hpp | 2 +- cppitertools/slice.hpp | 2 +- cppitertools/sliding_window.hpp | 2 +- cppitertools/sorted.hpp | 2 +- cppitertools/starmap.hpp | 2 +- cppitertools/takewhile.hpp | 2 +- cppitertools/unique_everseen.hpp | 2 +- cppitertools/unique_justseen.hpp | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/cppitertools/accumulate.hpp b/cppitertools/accumulate.hpp index 94c0c369..2c5bc54e 100644 --- a/cppitertools/accumulate.hpp +++ b/cppitertools/accumulate.hpp @@ -17,7 +17,7 @@ namespace iter { using AccumulateFn = IterToolFnOptionalBindSecond>; } - constexpr impl::AccumulateFn accumulate{}; + inline constexpr impl::AccumulateFn accumulate{}; } template diff --git a/cppitertools/batched.hpp b/cppitertools/batched.hpp index e5eadf13..f3d00ece 100644 --- a/cppitertools/batched.hpp +++ b/cppitertools/batched.hpp @@ -20,7 +20,7 @@ namespace iter { using BatchedFn = IterToolFnBindSizeTSecond; } - constexpr impl::BatchedFn batched{}; + inline constexpr impl::BatchedFn batched{}; } template diff --git a/cppitertools/chunked.hpp b/cppitertools/chunked.hpp index 1d03b6e1..13fa652f 100644 --- a/cppitertools/chunked.hpp +++ b/cppitertools/chunked.hpp @@ -20,7 +20,7 @@ namespace iter { using ChunkedFn = IterToolFnBindSizeTSecond; } - constexpr impl::ChunkedFn chunked{}; + inline constexpr impl::ChunkedFn chunked{}; } template diff --git a/cppitertools/combinations.hpp b/cppitertools/combinations.hpp index 7aca3115..cdee9cdd 100644 --- a/cppitertools/combinations.hpp +++ b/cppitertools/combinations.hpp @@ -15,7 +15,7 @@ namespace iter { using CombinationsFn = IterToolFnBindSizeTSecond; } - constexpr impl::CombinationsFn combinations{}; + inline constexpr impl::CombinationsFn combinations{}; } template diff --git a/cppitertools/combinations_with_replacement.hpp b/cppitertools/combinations_with_replacement.hpp index d501c6e1..39db37bd 100644 --- a/cppitertools/combinations_with_replacement.hpp +++ b/cppitertools/combinations_with_replacement.hpp @@ -15,7 +15,7 @@ namespace iter { using CombinationsWithReplacementFn = IterToolFnBindSizeTSecond; } - constexpr impl::CombinationsWithReplacementFn combinations_with_replacement{}; + inline constexpr impl::CombinationsWithReplacementFn combinations_with_replacement{}; } template diff --git a/cppitertools/cycle.hpp b/cppitertools/cycle.hpp index 1d3ecaef..fb3ca9c7 100644 --- a/cppitertools/cycle.hpp +++ b/cppitertools/cycle.hpp @@ -15,7 +15,7 @@ namespace iter { using CycleFn = IterToolFn; } - constexpr impl::CycleFn cycle{}; + inline constexpr impl::CycleFn cycle{}; } template diff --git a/cppitertools/dropwhile.hpp b/cppitertools/dropwhile.hpp index dc1874b0..e751bfe3 100644 --- a/cppitertools/dropwhile.hpp +++ b/cppitertools/dropwhile.hpp @@ -16,7 +16,7 @@ namespace iter { using DropWhileFn = IterToolFnOptionalBindFirst; } - constexpr impl::DropWhileFn dropwhile{}; + inline constexpr impl::DropWhileFn dropwhile{}; } template diff --git a/cppitertools/enumerate.hpp b/cppitertools/enumerate.hpp index e2dda12b..5d59feab 100644 --- a/cppitertools/enumerate.hpp +++ b/cppitertools/enumerate.hpp @@ -33,7 +33,7 @@ namespace iter { using EnumerateFn = IterToolFnOptionalBindSecond; } - constexpr impl::EnumerateFn enumerate{}; + inline constexpr impl::EnumerateFn enumerate{}; } namespace std { diff --git a/cppitertools/filter.hpp b/cppitertools/filter.hpp index 2a632be2..1e069070 100644 --- a/cppitertools/filter.hpp +++ b/cppitertools/filter.hpp @@ -24,7 +24,7 @@ namespace iter { using FilterFn = IterToolFnOptionalBindFirst; } - constexpr impl::FilterFn filter{}; + inline constexpr impl::FilterFn filter{}; } template diff --git a/cppitertools/filterfalse.hpp b/cppitertools/filterfalse.hpp index f0f22628..4056c402 100644 --- a/cppitertools/filterfalse.hpp +++ b/cppitertools/filterfalse.hpp @@ -38,7 +38,7 @@ namespace iter { using FilterFalseFn = IterToolFnOptionalBindFirst; } - constexpr impl::FilterFalseFn filterfalse{}; + inline constexpr impl::FilterFalseFn filterfalse{}; } // Delegates to Filtered with PredicateFlipper diff --git a/cppitertools/groupby.hpp b/cppitertools/groupby.hpp index cac82426..6d7453f9 100644 --- a/cppitertools/groupby.hpp +++ b/cppitertools/groupby.hpp @@ -20,7 +20,7 @@ namespace iter { using GroupByFn = IterToolFnOptionalBindSecond; } - constexpr impl::GroupByFn groupby{}; + inline constexpr impl::GroupByFn groupby{}; } template diff --git a/cppitertools/imap.hpp b/cppitertools/imap.hpp index 1e84faf0..80b8cc3d 100644 --- a/cppitertools/imap.hpp +++ b/cppitertools/imap.hpp @@ -21,7 +21,7 @@ namespace iter { using PipeableAndBindFirst::operator(); }; } - constexpr impl::IMapFn imap{}; + inline constexpr impl::IMapFn imap{}; } #endif diff --git a/cppitertools/permutations.hpp b/cppitertools/permutations.hpp index e10872d4..f567bc68 100644 --- a/cppitertools/permutations.hpp +++ b/cppitertools/permutations.hpp @@ -17,7 +17,7 @@ namespace iter { class Permuter; using PermutationsFn = IterToolFn; } - constexpr impl::PermutationsFn permutations{}; + inline constexpr impl::PermutationsFn permutations{}; } template diff --git a/cppitertools/powerset.hpp b/cppitertools/powerset.hpp index 3439069d..d6131ca8 100644 --- a/cppitertools/powerset.hpp +++ b/cppitertools/powerset.hpp @@ -18,7 +18,7 @@ namespace iter { using PowersetFn = IterToolFn; } - constexpr impl::PowersetFn powerset{}; + inline constexpr impl::PowersetFn powerset{}; } template diff --git a/cppitertools/reversed.hpp b/cppitertools/reversed.hpp index 3b914bb1..022088f6 100644 --- a/cppitertools/reversed.hpp +++ b/cppitertools/reversed.hpp @@ -45,7 +45,7 @@ namespace iter { using ReversedFn = IterToolFn; } - constexpr impl::ReversedFn reversed{}; + inline constexpr impl::ReversedFn reversed{}; } template diff --git a/cppitertools/slice.hpp b/cppitertools/slice.hpp index a926ecbb..38557016 100644 --- a/cppitertools/slice.hpp +++ b/cppitertools/slice.hpp @@ -172,7 +172,7 @@ struct iter::impl::SliceFn { }; namespace iter { - constexpr impl::SliceFn slice{}; + inline constexpr impl::SliceFn slice{}; } #endif diff --git a/cppitertools/sliding_window.hpp b/cppitertools/sliding_window.hpp index d4ab6cbc..01c348ba 100644 --- a/cppitertools/sliding_window.hpp +++ b/cppitertools/sliding_window.hpp @@ -16,7 +16,7 @@ namespace iter { class WindowSlider; using SlidingWindowFn = IterToolFnBindSizeTSecond; } - constexpr impl::SlidingWindowFn sliding_window{}; + inline constexpr impl::SlidingWindowFn sliding_window{}; } template diff --git a/cppitertools/sorted.hpp b/cppitertools/sorted.hpp index 4e963228..a704af3f 100644 --- a/cppitertools/sorted.hpp +++ b/cppitertools/sorted.hpp @@ -15,7 +15,7 @@ namespace iter { class SortedView; using SortedFn = IterToolFnOptionalBindSecond>; } - constexpr impl::SortedFn sorted{}; + inline constexpr impl::SortedFn sorted{}; } template diff --git a/cppitertools/starmap.hpp b/cppitertools/starmap.hpp index fbeaad68..f9c2d260 100644 --- a/cppitertools/starmap.hpp +++ b/cppitertools/starmap.hpp @@ -252,7 +252,7 @@ struct iter::impl::StarMapFn : PipeableAndBindFirst { }; namespace iter { - constexpr impl::StarMapFn starmap{}; + inline constexpr impl::StarMapFn starmap{}; } #endif diff --git a/cppitertools/takewhile.hpp b/cppitertools/takewhile.hpp index a04d86b2..338e43aa 100644 --- a/cppitertools/takewhile.hpp +++ b/cppitertools/takewhile.hpp @@ -16,7 +16,7 @@ namespace iter { using TakeWhileFn = IterToolFnOptionalBindFirst; } - constexpr impl::TakeWhileFn takewhile{}; + inline constexpr impl::TakeWhileFn takewhile{}; } template diff --git a/cppitertools/unique_everseen.hpp b/cppitertools/unique_everseen.hpp index 1e138d63..2195a4bd 100644 --- a/cppitertools/unique_everseen.hpp +++ b/cppitertools/unique_everseen.hpp @@ -45,7 +45,7 @@ namespace iter { }; } - constexpr impl::UniqueEverseenFn unique_everseen{}; + inline constexpr impl::UniqueEverseenFn unique_everseen{}; } #endif diff --git a/cppitertools/unique_justseen.hpp b/cppitertools/unique_justseen.hpp index 5a566e78..c4ca47f5 100644 --- a/cppitertools/unique_justseen.hpp +++ b/cppitertools/unique_justseen.hpp @@ -23,7 +23,7 @@ namespace iter { } }; } - constexpr impl::UniqueJustseenFn unique_justseen{}; + inline constexpr impl::UniqueJustseenFn unique_justseen{}; } #endif From 78a4eaa8a3b3b45aeea1022fd8a9402321729358 Mon Sep 17 00:00:00 2001 From: Udaya Prakash Date: Wed, 21 Aug 2024 16:33:29 +0000 Subject: [PATCH 373/403] Add bzlmod support to cppitertools --- .bazelrc | 2 ++ .bazelversion | 1 + .gitignore | 1 - MODULE.bazel | 3 +++ 4 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .bazelrc create mode 100644 .bazelversion create mode 100644 MODULE.bazel diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 00000000..cbb8025a --- /dev/null +++ b/.bazelrc @@ -0,0 +1,2 @@ +# workspace support is deprecated in Bazel 7 +common --enable_bzlmod \ No newline at end of file diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 00000000..34a8f745 --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +7.3.1 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 553aa4a3..0d4fed27 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ bazel-* -MODULE.bazel MODULE.bazel.lock diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 00000000..d8dc8f72 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,3 @@ +module( + name = "cppitertools" +) \ No newline at end of file From 88de5d7cb3316231fce6e2a87e904cf3077a3def Mon Sep 17 00:00:00 2001 From: Udaya Prakash Date: Wed, 21 Aug 2024 16:36:26 +0000 Subject: [PATCH 374/403] add new line --- .bazelversion | 2 +- MODULE.bazel | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bazelversion b/.bazelversion index 34a8f745..643916c0 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -7.3.1 \ No newline at end of file +7.3.1 diff --git a/MODULE.bazel b/MODULE.bazel index d8dc8f72..b4a4568e 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,3 +1,3 @@ module( name = "cppitertools" -) \ No newline at end of file +) From e06f15357cc9ca78029e4158bee67da9f110e34f Mon Sep 17 00:00:00 2001 From: Udaya Prakash Date: Wed, 21 Aug 2024 16:37:36 +0000 Subject: [PATCH 375/403] remove bazelrc file --- .bazelrc | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .bazelrc diff --git a/.bazelrc b/.bazelrc deleted file mode 100644 index cbb8025a..00000000 --- a/.bazelrc +++ /dev/null @@ -1,2 +0,0 @@ -# workspace support is deprecated in Bazel 7 -common --enable_bzlmod \ No newline at end of file From 5a7f4aa357ed9b0ad59823e3d2acd57217d5beaf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 18 Oct 2024 09:55:13 -0700 Subject: [PATCH 376/403] Escapes '<' and '>' in zip_longest description --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 64c1430f..7b43c218 100644 --- a/README.md +++ b/README.md @@ -579,7 +579,7 @@ Repeatedly yields a tuple of `boost::optional`s where `T` is the type yielded by the sequences' respective iterators. Because of its boost dependency, `zip_longest` is not in `itertools.hpp` and must be included separately. -The following loop prints either "Just " or "Nothing" for each +The following loop prints either "Just \" or "Nothing" for each element in each tuple yielded. ```c++ From 516115a959c92f5b7f133e4f52bcd7e701c46069 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 5 Feb 2025 16:48:51 -0800 Subject: [PATCH 377/403] Updates .bazelversion to 8.0.1 --- .bazelversion | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bazelversion b/.bazelversion index 643916c0..cd1d2e94 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -7.3.1 +8.0.1 From 371888d0f9c1ee687c8c1241c8c86ebed26929d6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 6 Feb 2025 16:41:33 -0800 Subject: [PATCH 378/403] Adds undefinide and address sanitizer to tests --- test/BUILD | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/BUILD b/test/BUILD index 9ceefecd..cc9aefe6 100644 --- a/test/BUILD +++ b/test/BUILD @@ -37,10 +37,13 @@ progs = [ "helpers", ] +SANITIZE = "-fsanitize=address,undefined" + cc_library( name = "test_main", srcs = ["test_main.cpp", "catch.hpp"], - copts = ["-std=c++17", "-g"] + copts = [SANITIZE, "-Wall", "-Wextra", "-std=c++17", "-g"], + linkopts = [SANITIZE], ) itertools_tests(progs) From d4c7340b44e141874b749a2c08489cb3ae180a71 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 6 Feb 2025 16:42:19 -0800 Subject: [PATCH 379/403] Suppresses bad dangling reference warning Fixes #108 --- cppitertools/internal/iterbase.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cppitertools/internal/iterbase.hpp b/cppitertools/internal/iterbase.hpp index 6f654828..9a8b33ba 100644 --- a/cppitertools/internal/iterbase.hpp +++ b/cppitertools/internal/iterbase.hpp @@ -353,6 +353,9 @@ namespace iter { template struct Pipeable { template +#if defined(__GNUC__) && !defined(__clang__) + [[gnu::no_dangling]] +#endif friend decltype(auto) operator|(T&& x, const Pipeable& p) { return static_cast(p)(std::forward(x)); } From fa6ee1a8b93c374185abd69e374ce9f4fd054cb4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 10 Feb 2025 12:44:31 -0800 Subject: [PATCH 380/403] Moves utility callables into helpers.hpp Cleanup while doing #89 --- test/helpers.hpp | 16 +++++++++++++++ test/test_dropwhile.cpp | 24 +--------------------- test/test_filter.cpp | 22 +------------------- test/test_filterfalse.cpp | 22 +------------------- test/test_takewhile.cpp | 43 +++++++++++++-------------------------- 5 files changed, 33 insertions(+), 94 deletions(-) diff --git a/test/helpers.hpp b/test/helpers.hpp index 80167980..57f8a372 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -414,4 +414,20 @@ class IntCharPairRange : DiffEndRange, IncIntCharPair>({0, 'a'}, stop) {} }; +inline bool less_than_five(int i) { + return i < 5; +} + +class LessThanValue { + private: + int compare_val; + + public: + LessThanValue(int v) : compare_val(v) {} + + bool operator()(int i) { + return i < this->compare_val; + } +}; + #endif diff --git a/test/test_dropwhile.cpp b/test/test_dropwhile.cpp index 2a41a671..97c947f4 100644 --- a/test/test_dropwhile.cpp +++ b/test/test_dropwhile.cpp @@ -1,31 +1,15 @@ #include - -#include "helpers.hpp" - #include #include #include #include "catch.hpp" +#include "helpers.hpp" using iter::dropwhile; using Vec = const std::vector; -namespace { - class LessThanValue { - private: - int compare_val; - - public: - LessThanValue(int v) : compare_val(v) {} - - bool operator()(int i) { - return i < this->compare_val; - } - }; -} - TEST_CASE("dropwhile: skips initial elements", "[dropwhile]") { Vec ns{1, 2, 3, 4, 5, 6, 7, 8}; std::vector v; @@ -147,12 +131,6 @@ TEST_CASE("dropwhile: operator->", "[dropwhile]") { REQUIRE(it->size() == 6); } -namespace { - int less_than_five(int i) { - return i < 5; - } -} - TEST_CASE("dropwhile: works with function pointer", "[dropwhile]") { Vec ns{1, 2, 3, 4, 5, 6, 7, 8}; auto d = dropwhile(less_than_five, ns); diff --git a/test/test_filter.cpp b/test/test_filter.cpp index f160785b..a990844a 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -1,35 +1,15 @@ #include - -#include "helpers.hpp" - #include #include #include #include "catch.hpp" +#include "helpers.hpp" using iter::filter; using Vec = const std::vector; -namespace { - bool less_than_five(int i) { - return i < 5; - } - - class LessThanValue { - private: - int compare_val; - - public: - LessThanValue(int v) : compare_val(v) {} - - bool operator()(int i) { - return i < this->compare_val; - } - }; -} - TEST_CASE("filter: handles different callable types", "[filter]") { Vec ns = {1, 2, 5, 6, 3, 1, 7, -1, 5}; Vec vc = {1, 2, 3, 1, -1}; diff --git a/test/test_filterfalse.cpp b/test/test_filterfalse.cpp index 93d50d6a..9a1dd4bc 100644 --- a/test/test_filterfalse.cpp +++ b/test/test_filterfalse.cpp @@ -1,35 +1,15 @@ #include - -#include "helpers.hpp" - #include #include #include #include "catch.hpp" +#include "helpers.hpp" using iter::filterfalse; using Vec = const std::vector; -namespace { - bool less_than_five(int i) { - return i < 5; - } - - class LessThanValue { - private: - int compare_val; - - public: - LessThanValue(int v) : compare_val(v) {} - - bool operator()(int i) { - return i < this->compare_val; - } - }; -} - TEST_CASE("filterfalse: handles different callable types", "[filterfalse]") { Vec ns = {1, 2, 5, 6, 3, 1, 7, -1, 5}; Vec vc = {5, 6, 7, 5}; diff --git a/test/test_takewhile.cpp b/test/test_takewhile.cpp index e3dade73..0be43f84 100644 --- a/test/test_takewhile.cpp +++ b/test/test_takewhile.cpp @@ -1,6 +1,5 @@ -#include - #include +#include #include #include #include @@ -11,48 +10,34 @@ using iter::takewhile; using Vec = const std::vector; -namespace { - bool under_ten(int i) { - return i < 10; - } - - struct UnderTen { - bool operator()(int i) { - return i < 10; - } - }; -} - TEST_CASE("takewhile: works with lambda, callable, and function pointer", "[takewhile]") { - Vec ns = {1, 3, 5, 20, 2, 4, 6, 8}; + Vec ns = {1, 3, 4, 20, 2, 4, 6, 8}; + const Vec vc = {1, 3, 4}; SECTION("function pointer") { - auto tw = takewhile(under_ten, ns); + auto tw = takewhile(less_than_five, ns); Vec v(std::begin(tw), std::end(tw)); - Vec vc = {1, 3, 5}; REQUIRE(v == vc); } SECTION("callable object") { std::vector v; SECTION("Normal call") { - auto tw = takewhile(UnderTen{}, ns); + auto tw = takewhile(LessThanValue{10}, ns); v.assign(std::begin(tw), std::end(tw)); } SECTION("Pipe") { - auto tw = ns | takewhile(UnderTen{}); + auto tw = ns | takewhile(LessThanValue{10}); v.assign(std::begin(tw), std::end(tw)); } - Vec vc = {1, 3, 5}; REQUIRE(v == vc); } SECTION("lambda") { auto tw = takewhile([](int i) { return i < 10; }, ns); Vec v(std::begin(tw), std::end(tw)); - Vec vc = {1, 3, 5}; REQUIRE(v == vc); } } @@ -78,7 +63,7 @@ TEST_CASE("takewhile: handles pointer to member", "[takewhile]") { TEST_CASE("takewhile: supports const iteration", "[takewhile][const]") { Vec ns = {1, 3, 5, 20, 2, 4, 6, 8}; - const auto tw = takewhile(UnderTen{}, ns); + const auto tw = takewhile(LessThanValue{10}, ns); Vec v(std::begin(tw), std::end(tw)); Vec vc = {1, 3, 5}; REQUIRE(v == vc); @@ -86,7 +71,7 @@ TEST_CASE("takewhile: supports const iteration", "[takewhile][const]") { TEST_CASE("takewhile: const iterator and non-const iterator are comparable", "[takewhile][const]") { - auto tw = takewhile(UnderTen{}, Vec{}); + auto tw = takewhile(LessThanValue{10}, Vec{}); const auto& ctw = tw; (void)(std::begin(tw) == std::end(ctw)); } @@ -117,14 +102,14 @@ TEST_CASE("takewhile: identity", "[takewhile]") { TEST_CASE("takewhile: everything passes predicate", "[takewhile]") { Vec ns{1, 2, 3}; - auto tw = takewhile(under_ten, ns); + auto tw = takewhile(less_than_five, ns); Vec v(std::begin(tw), std::end(tw)); Vec vc = {1, 2, 3}; } TEST_CASE("takewhile: empty iterable is empty", "[takewhile]") { Vec ns{}; - auto tw = takewhile(under_ten, ns); + auto tw = takewhile(less_than_five, ns); SECTION("normal compare") { REQUIRE(std::begin(tw) == std::end(tw)); } @@ -138,7 +123,7 @@ TEST_CASE( "[takewhile]") { SECTION("First element is only element") { Vec ns = {20}; - auto tw = takewhile(under_ten, ns); + auto tw = takewhile(less_than_five, ns); SECTION("normal compare") { REQUIRE(std::begin(tw) == std::end(tw)); } @@ -149,7 +134,7 @@ TEST_CASE( SECTION("First element followed by elements that pass") { Vec ns = {20, 1, 1}; - auto tw = takewhile(under_ten, ns); + auto tw = takewhile(less_than_five, ns); SECTION("normal compare") { REQUIRE(std::begin(tw) == std::end(tw)); } @@ -161,10 +146,10 @@ TEST_CASE( TEST_CASE("takewhile: moves rvalues, binds to lvalues", "[takewhile]") { itertest::BasicIterable bi{1, 2}; - takewhile(under_ten, bi); + takewhile(less_than_five, bi); REQUIRE_FALSE(bi.was_moved_from()); - takewhile(under_ten, std::move(bi)); + takewhile(less_than_five, std::move(bi)); REQUIRE(bi.was_moved_from()); } From f9ce3d8d4eff145061df406f14265a4cc8946d6f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 10 Feb 2025 13:03:10 -0800 Subject: [PATCH 381/403] Adds MoveOnlyLessThanValue for testing For #89 --- test/helpers.hpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/helpers.hpp b/test/helpers.hpp index 57f8a372..94fd08f1 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -430,4 +430,22 @@ class LessThanValue { } }; +class MoveOnlyLessThanValue { + private: + int compare_val; + + public: + MoveOnlyLessThanValue(int v) : compare_val(v) {} + + MoveOnlyLessThanValue(const MoveOnlyLessThanValue&) = delete; + MoveOnlyLessThanValue& operator=(const MoveOnlyLessThanValue&) = delete; + + MoveOnlyLessThanValue(MoveOnlyLessThanValue&&) = default; + MoveOnlyLessThanValue& operator=(MoveOnlyLessThanValue&&) = default; + + bool operator()(int i) { + return i < this->compare_val; + } +}; + #endif From 420583c1df803566942e1c70c61ef5986d85006e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 10 Feb 2025 13:10:55 -0800 Subject: [PATCH 382/403] IncludeBlocks: Preserve in clang-format --- .clang-format | 1 + 1 file changed, 1 insertion(+) diff --git a/.clang-format b/.clang-format index 650739d3..d9d9622a 100644 --- a/.clang-format +++ b/.clang-format @@ -8,5 +8,6 @@ BreakBeforeBinaryOperators: NonAssignment DerivePointerAlignment: false NamespaceIndentation: All FixNamespaceComments: false +IncludeBlocks: Preserve ... From 1c828d06d73d6bdd1ee6649619ef61b459d0957a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 10 Feb 2025 13:11:58 -0800 Subject: [PATCH 383/403] Adds move-only callable support to filter Issue #89 --- cppitertools/filter.hpp | 4 +++- test/test_filter.cpp | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cppitertools/filter.hpp b/cppitertools/filter.hpp index 1e069070..53ed15cc 100644 --- a/cppitertools/filter.hpp +++ b/cppitertools/filter.hpp @@ -29,6 +29,8 @@ namespace iter { template class iter::impl::Filtered { + static_assert(!std::is_reference_v); + private: Container container_; mutable FilterFunc filter_func_; @@ -39,7 +41,7 @@ class iter::impl::Filtered { // Value constructor for use only in the filter function Filtered(FilterFunc filter_func, Container&& container) : container_(std::forward(container)), - filter_func_(filter_func) {} + filter_func_(std::move(filter_func)) {} public: Filtered(Filtered&&) = default; diff --git a/test/test_filter.cpp b/test/test_filter.cpp index a990844a..a0f5db96 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -25,6 +25,12 @@ TEST_CASE("filter: handles different callable types", "[filter]") { REQUIRE(v == vc); } + SECTION("with move-only callable object") { + auto f = filter(MoveOnlyLessThanValue{5}, ns); + Vec v(std::begin(f), std::end(f)); + REQUIRE(v == vc); + } + SECTION("with lambda") { auto ltf = [](int i) { return i < 5; }; auto f = filter(ltf, ns); From d45c47b75f28c976ae06cb472fcd29905b1bc207 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Feb 2025 16:30:40 -0800 Subject: [PATCH 384/403] Updates FnPartials to move stored_arg when rvalue Overloads `operator|` for rvalue and lvalue `Pipeable`s and downcasts accordingly. Adds rvalue-reference qualified overloads to FnPartial `operator|` that calls `std::move(stored_arg)` when creating the actual iterable object. This allows a move-only callable to get passed by value, but only moves, all the way into the itertool. ``` // both should work iter::some_itertool(sequence, MoveOnlyCallable{}); sequence | iter::some_itertool(MoveOnlyCallable{}); ``` I did attempt passing a `std::reference_wrapper` from the `FnPartial` but the iteration happens after the `FnPartial` is destroyed, So the following is unsafe: ``` // unsafe, wrong template auto operator()(Container&& container) const { if constexpr (std::is_copy_constructible_v) { return F{}(stored_arg, std::forward(container)); } else { return F{}(std::ref(stored_arg), std::forward(container)); } } ``` Setting the stage to fix #89 --- cppitertools/internal/iterbase.hpp | 38 +++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/cppitertools/internal/iterbase.hpp b/cppitertools/internal/iterbase.hpp index 9a8b33ba..9cb97442 100644 --- a/cppitertools/internal/iterbase.hpp +++ b/cppitertools/internal/iterbase.hpp @@ -353,9 +353,14 @@ namespace iter { template struct Pipeable { template -#if defined(__GNUC__) && !defined(__clang__) - [[gnu::no_dangling]] +#if defined(__GNUC__) && !defined(__clang__) + [[gnu::no_dangling]] #endif + friend decltype(auto) operator|(T&& x, Pipeable&& p) { + return static_cast(p)(std::forward(x)); + } + + template friend decltype(auto) operator|(T&& x, const Pipeable& p) { return static_cast(p)(std::forward(x)); } @@ -378,11 +383,17 @@ namespace iter { protected: template struct FnPartial : Pipeable> { + static_assert(!std::is_reference_v); mutable T stored_arg; - constexpr FnPartial(T in_t) : stored_arg(in_t) {} + constexpr FnPartial(T in_t) : stored_arg(std::move(in_t)) {} template - auto operator()(Container&& container) const { + auto operator()(Container&& container) && { + return F{}(std::move(stored_arg), std::forward(container)); + } + + template + auto operator()(Container&& container) const& { return F{}(stored_arg, std::forward(container)); } }; @@ -403,10 +414,15 @@ namespace iter { template struct FnPartial : Pipeable> { mutable T stored_arg; - constexpr FnPartial(T in_t) : stored_arg(in_t) {} + constexpr FnPartial(T in_t) : stored_arg(std::move(in_t)) {} template - auto operator()(Container&& container) const { + auto operator()(Container&& container) && { + return F{}(std::forward(container), std::move(stored_arg)); + } + + template + auto operator()(Container&& container) const& { return F{}(std::forward(container), stored_arg); } }; @@ -469,10 +485,16 @@ namespace iter { template struct FnPartial : Pipeable> { mutable T stored_arg; - constexpr FnPartial(T in_t) : stored_arg(in_t) {} + constexpr FnPartial(T in_t) : stored_arg(std::move(in_t)) {} template - auto operator()(Container&& container) const { + auto operator()(Container&& container) && { + return IterToolFnOptionalBindSecond{}( + std::forward(container), std::move(stored_arg)); + } + + template + auto operator()(Container&& container) const& { return IterToolFnOptionalBindSecond{}( std::forward(container), stored_arg); } From dcc59d65c5036693c114f5a03b611b900180c83e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Feb 2025 16:52:11 -0800 Subject: [PATCH 385/403] Uses unique_ptr in move-only callable for louder error Issue #89 --- test/helpers.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/helpers.hpp b/test/helpers.hpp index 94fd08f1..f94250f3 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -432,10 +433,12 @@ class LessThanValue { class MoveOnlyLessThanValue { private: - int compare_val; + // unique_ptr is better for triggering asan than an int if there's a dangling + // reference to the callable + std::unique_ptr compare_val; public: - MoveOnlyLessThanValue(int v) : compare_val(v) {} + MoveOnlyLessThanValue(int v) : compare_val{std::make_unique(v)} {} MoveOnlyLessThanValue(const MoveOnlyLessThanValue&) = delete; MoveOnlyLessThanValue& operator=(const MoveOnlyLessThanValue&) = delete; @@ -444,7 +447,7 @@ class MoveOnlyLessThanValue { MoveOnlyLessThanValue& operator=(MoveOnlyLessThanValue&&) = default; bool operator()(int i) { - return i < this->compare_val; + return i < *compare_val; } }; From 0fc1cf1a3d889da8a8d390faedf4e4dcfc68e437 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Feb 2025 16:53:13 -0800 Subject: [PATCH 386/403] Adds filter tests with pipe and move-only Issue #89 --- test/test_filter.cpp | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/test/test_filter.cpp b/test/test_filter.cpp index a0f5db96..445476c8 100644 --- a/test/test_filter.cpp +++ b/test/test_filter.cpp @@ -13,30 +13,46 @@ using Vec = const std::vector; TEST_CASE("filter: handles different callable types", "[filter]") { Vec ns = {1, 2, 5, 6, 3, 1, 7, -1, 5}; Vec vc = {1, 2, 3, 1, -1}; + std::vector v; SECTION("with function pointer") { auto f = filter(less_than_five, ns); - Vec v(std::begin(f), std::end(f)); - REQUIRE(v == vc); + v = Vec(std::begin(f), std::end(f)); } SECTION("with callable object") { auto f = filter(LessThanValue{5}, ns); - Vec v(std::begin(f), std::end(f)); - REQUIRE(v == vc); + v = Vec(std::begin(f), std::end(f)); + } + + SECTION("with lvalue callable object") { + auto lt = LessThanValue{5}; + SECTION("normal call") { + auto f = filter(lt, ns); + v = Vec(std::begin(f), std::end(f)); + } + SECTION("pipe") { + auto f = ns | filter(lt); + v = Vec(std::begin(f), std::end(f)); + } } SECTION("with move-only callable object") { - auto f = filter(MoveOnlyLessThanValue{5}, ns); - Vec v(std::begin(f), std::end(f)); - REQUIRE(v == vc); + SECTION("normal call") { + auto f = filter(MoveOnlyLessThanValue{5}, ns); + v = Vec(std::begin(f), std::end(f)); + } + SECTION("pipe") { + auto f = ns | filter(MoveOnlyLessThanValue{5}); + v = Vec(std::begin(f), std::end(f)); + } } SECTION("with lambda") { auto ltf = [](int i) { return i < 5; }; auto f = filter(ltf, ns); - Vec v(std::begin(f), std::end(f)); - REQUIRE(v == vc); + v = Vec(std::begin(f), std::end(f)); } + REQUIRE(v == vc); } TEST_CASE("filter: handles pointer to member", "[filter]") { From 020f99db7570a39f281fcde6e59da154de58995d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Feb 2025 17:04:21 -0800 Subject: [PATCH 387/403] Adds support for move-only callables in filterfalse Issue #89 --- cppitertools/filterfalse.hpp | 3 ++- test/test_filterfalse.cpp | 39 +++++++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/cppitertools/filterfalse.hpp b/cppitertools/filterfalse.hpp index 4056c402..269724dd 100644 --- a/cppitertools/filterfalse.hpp +++ b/cppitertools/filterfalse.hpp @@ -48,7 +48,8 @@ class iter::impl::FilterFalsed friend FilterFalseFn; FilterFalsed(FilterFunc in_filter_func, Container&& in_container) : Filtered, Container>( - {in_filter_func}, std::forward(in_container)) {} + {std::move(in_filter_func)}, + std::forward(in_container)) {} }; #endif diff --git a/test/test_filterfalse.cpp b/test/test_filterfalse.cpp index 9a1dd4bc..ad79646a 100644 --- a/test/test_filterfalse.cpp +++ b/test/test_filterfalse.cpp @@ -13,31 +13,46 @@ using Vec = const std::vector; TEST_CASE("filterfalse: handles different callable types", "[filterfalse]") { Vec ns = {1, 2, 5, 6, 3, 1, 7, -1, 5}; Vec vc = {5, 6, 7, 5}; + std::vector v; SECTION("with function pointer") { auto f = filterfalse(less_than_five, ns); - Vec v(std::begin(f), std::end(f)); - REQUIRE(v == vc); + v = Vec(std::begin(f), std::end(f)); } SECTION("with callable object") { - std::vector v; - SECTION("Normal call") { - auto f = filterfalse(LessThanValue{5}, ns); - v.assign(std::begin(f), std::end(f)); + auto f = filterfalse(LessThanValue{5}, ns); + v = Vec(std::begin(f), std::end(f)); + } + + SECTION("with lvalue callable object") { + auto lt = LessThanValue{5}; + SECTION("normal call") { + auto f = filterfalse(lt, ns); + v = Vec(std::begin(f), std::end(f)); + } + SECTION("pipe") { + auto f = ns | filterfalse(lt); + v = Vec(std::begin(f), std::end(f)); } - SECTION("Pipe") { - auto f = ns | filterfalse(LessThanValue{5}); - v.assign(std::begin(f), std::end(f)); + } + + SECTION("with move-only callable object") { + SECTION("normal call") { + auto f = filterfalse(MoveOnlyLessThanValue{5}, ns); + v = Vec(std::begin(f), std::end(f)); + } + SECTION("pipe") { + auto f = ns | filterfalse(MoveOnlyLessThanValue{5}); + v = Vec(std::begin(f), std::end(f)); } - REQUIRE(v == vc); } SECTION("with lambda") { auto ltf = [](int i) { return i < 5; }; auto f = filterfalse(ltf, ns); - Vec v(std::begin(f), std::end(f)); - REQUIRE(v == vc); + v = Vec(std::begin(f), std::end(f)); } + REQUIRE(v == vc); } TEST_CASE("filterfalse: handles pointer to member", "[filterfalse]") { From f9f7de419c7360c97281cc35db02c3d689aa005b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Feb 2025 17:04:52 -0800 Subject: [PATCH 388/403] Adds support for move-only callables in dropwhile Issue #89 --- cppitertools/dropwhile.hpp | 2 +- test/test_dropwhile.cpp | 45 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/cppitertools/dropwhile.hpp b/cppitertools/dropwhile.hpp index e751bfe3..86942826 100644 --- a/cppitertools/dropwhile.hpp +++ b/cppitertools/dropwhile.hpp @@ -29,7 +29,7 @@ class iter::impl::Dropper { Dropper(FilterFunc filter_func, Container&& container) : container_(std::forward(container)), - filter_func_(filter_func) {} + filter_func_(std::move(filter_func)) {} public: Dropper(Dropper&&) = default; diff --git a/test/test_dropwhile.cpp b/test/test_dropwhile.cpp index 97c947f4..077bfd73 100644 --- a/test/test_dropwhile.cpp +++ b/test/test_dropwhile.cpp @@ -10,6 +10,51 @@ using iter::dropwhile; using Vec = const std::vector; +TEST_CASE("dropwhile: handles different callable types", "[dropwhile]") { + Vec ns = {1, 3, 4, 20, 2, 4, 6, 8}; + Vec vc = {20, 2, 4, 6, 8}; + std::vector v; + SECTION("with function pointer") { + auto d = dropwhile(less_than_five, ns); + v = Vec(std::begin(d), std::end(d)); + } + + SECTION("with callable object") { + auto d = dropwhile(LessThanValue{5}, ns); + v = Vec(std::begin(d), std::end(d)); + } + + SECTION("with lvalue callable object") { + auto lt = LessThanValue{5}; + SECTION("normal call") { + auto d = dropwhile(lt, ns); + v = Vec(std::begin(d), std::end(d)); + } + SECTION("pipe") { + auto d = ns | dropwhile(lt); + v = Vec(std::begin(d), std::end(d)); + } + } + + SECTION("with move-only callable object") { + SECTION("normal call") { + auto d = dropwhile(MoveOnlyLessThanValue{5}, ns); + v = Vec(std::begin(d), std::end(d)); + } + SECTION("pipe") { + auto d = ns | dropwhile(MoveOnlyLessThanValue{5}); + v = Vec(std::begin(d), std::end(d)); + } + } + + SECTION("with lambda") { + auto ltf = [](int i) { return i < 5; }; + auto d = dropwhile(ltf, ns); + v = Vec(std::begin(d), std::end(d)); + } + REQUIRE(v == vc); +} + TEST_CASE("dropwhile: skips initial elements", "[dropwhile]") { Vec ns{1, 2, 3, 4, 5, 6, 7, 8}; std::vector v; From 35fdf0c9fba07476d4d07f608396640d6d6d2c47 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Feb 2025 17:05:23 -0800 Subject: [PATCH 389/403] Adds support for move-only callables to groupby Issue #89 --- cppitertools/groupby.hpp | 3 +- test/test_groupby.cpp | 74 +++++++++++++++++++++++++++++++++++----- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/cppitertools/groupby.hpp b/cppitertools/groupby.hpp index 6d7453f9..313f088a 100644 --- a/cppitertools/groupby.hpp +++ b/cppitertools/groupby.hpp @@ -35,7 +35,8 @@ class iter::impl::GroupProducer { using key_func_ret = std::invoke_result_t>; GroupProducer(Container&& container, KeyFunc key_func) - : container_(std::forward(container)), key_func_(key_func) {} + : container_(std::forward(container)), + key_func_(std::move(key_func)) {} public: GroupProducer(GroupProducer&&) = default; diff --git a/test/test_groupby.cpp b/test/test_groupby.cpp index 6ce9d479..5904c78d 100644 --- a/test/test_groupby.cpp +++ b/test/test_groupby.cpp @@ -3,6 +3,7 @@ #include "helpers.hpp" #include +#include #include #include @@ -21,22 +22,38 @@ namespace { } }; + struct MoveOnlySizer { + // here to trigger asan if a dangling reference gets used + std::unique_ptr counter_ = std::make_unique(); + + MoveOnlySizer(const MoveOnlySizer&) = delete; + MoveOnlySizer& operator=(const MoveOnlySizer&) = delete; + + MoveOnlySizer(MoveOnlySizer&&) = default; + MoveOnlySizer& operator=(MoveOnlySizer&&) = default; + + int operator()(const std::string& s) { + ++*counter_; + return s.size(); + } + }; + const std::vector vec = { "hi", "ab", "ho", "abc", "def", "abcde", "efghi"}; } -TEST_CASE("groupby: works with lambda, callable, and function pointer") { +TEST_CASE("groupby: handles different callable types", "[groupby]") { std::vector keys; std::vector> groups; - SECTION("Function pointer") { - SECTION("Normal call") { + SECTION("with function pointer") { + SECTION("normal call") { for (auto&& gb : groupby(vec, length)) { keys.push_back(gb.first); groups.emplace_back(std::begin(gb.second), std::end(gb.second)); } } - SECTION("Pipe") { + SECTION("pipe") { for (auto&& gb : vec | groupby(length)) { keys.push_back(gb.first); groups.emplace_back(std::begin(gb.second), std::end(gb.second)); @@ -44,14 +61,53 @@ TEST_CASE("groupby: works with lambda, callable, and function pointer") { } } - SECTION("Callable object") { - for (auto&& gb : groupby(vec, Sizer{})) { - keys.push_back(gb.first); - groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + SECTION("with callable object") { + SECTION("normal call") { + for (auto&& gb : groupby(vec, Sizer{})) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + SECTION("pipe") { + for (auto&& gb : vec | groupby(Sizer{})) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } } } - SECTION("lambda function") { + SECTION("with lvalue callable object") { + auto sizer = Sizer{}; + SECTION("normal call") { + for (auto&& gb : groupby(vec, sizer)) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + SECTION("pipe") { + for (auto&& gb : vec | groupby(sizer)) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + } + + SECTION("with move-only callable object") { + SECTION("normal call") { + for (auto&& gb : groupby(vec, MoveOnlySizer{})) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + SECTION("pipe") { + for (auto&& gb : vec | groupby(MoveOnlySizer{})) { + keys.push_back(gb.first); + groups.emplace_back(std::begin(gb.second), std::end(gb.second)); + } + } + } + + SECTION("with lambda") { for (auto&& gb : groupby(vec, [](const std::string& s) { return s.size(); })) { keys.push_back(gb.first); From 417b1ebe067a381585def401c2f94a8c1ae20476 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Feb 2025 17:06:29 -0800 Subject: [PATCH 390/403] Adds support for move-only callables to imap Issue #89 --- cppitertools/imap.hpp | 3 +- test/test_imap.cpp | 72 ++++++++++++++++++++++++++++++++----------- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/cppitertools/imap.hpp b/cppitertools/imap.hpp index 80b8cc3d..21ca2e81 100644 --- a/cppitertools/imap.hpp +++ b/cppitertools/imap.hpp @@ -16,7 +16,8 @@ namespace iter { // See #66 -> StarMapper(containers)...))> { - return starmap(map_func, zip(std::forward(containers)...)); + return starmap( + std::move(map_func), zip(std::forward(containers)...)); } using PipeableAndBindFirst::operator(); }; diff --git a/test/test_imap.cpp b/test/test_imap.cpp index 40a9d3e3..cfda992b 100644 --- a/test/test_imap.cpp +++ b/test/test_imap.cpp @@ -17,10 +17,29 @@ namespace { return i + 1; } - class PlusOner { + struct PlusOner { + int operator()(int i) const { + return i + 1; + } + }; + + class MoveOnlyAdder { + private: + // unique_ptr is better for triggering asan than an int if there's a + // dangling reference to the callable + std::unique_ptr add_amount_; + public: + MoveOnlyAdder(int v) : add_amount_{std::make_unique(v)} {} + + MoveOnlyAdder(const MoveOnlyAdder&) = delete; + MoveOnlyAdder& operator=(const MoveOnlyAdder&) = delete; + + MoveOnlyAdder(MoveOnlyAdder&&) = default; + MoveOnlyAdder& operator=(MoveOnlyAdder&&) = default; + int operator()(int i) { - return i + 1; + return i + *add_amount_; } }; @@ -33,31 +52,48 @@ namespace { } } -TEST_CASE("imap: works with lambda, callable, and function", "[imap]") { - Vec ns = {10, 20, 30}; +TEST_CASE("imap: handles different callable types", "[imap]") { + Vec ns = {10, 15, 300}; + Vec vc = {11, 16, 301}; std::vector v; - SECTION("with lambda") { - auto im = imap([](int i) { return i + 1; }, ns); - v.assign(std::begin(im), std::end(im)); + SECTION("with function pointer") { + auto m = imap(plusone, ns); + v = Vec(std::begin(m), std::end(m)); } - SECTION("with callable") { - SECTION("Normal call") { - auto im = imap(PlusOner{}, ns); - v.assign(std::begin(im), std::end(im)); + SECTION("with callable object") { + auto m = imap(PlusOner{}, ns); + v = Vec(std::begin(m), std::end(m)); + } + + SECTION("with lvalue callable object") { + auto lt = PlusOner{}; + SECTION("normal call") { + auto m = imap(lt, ns); + v = Vec(std::begin(m), std::end(m)); } - SECTION("Pipe") { - auto im = ns | imap(PlusOner{}); - v.assign(std::begin(im), std::end(im)); + SECTION("pipe") { + auto m = ns | imap(lt); + v = Vec(std::begin(m), std::end(m)); } } - SECTION("with function") { - auto im = imap(PlusOner{}, ns); - v.assign(std::begin(im), std::end(im)); + SECTION("with move-only callable object") { + SECTION("normal call") { + auto m = imap(MoveOnlyAdder{1}, ns); + v = Vec(std::begin(m), std::end(m)); + } + SECTION("pipe") { + auto m = ns | imap(MoveOnlyAdder{1}); + v = Vec(std::begin(m), std::end(m)); + } } - Vec vc = {11, 21, 31}; + SECTION("with lambda") { + auto ltf = [](int i) { return i + 1; }; + auto m = imap(ltf, ns); + v = Vec(std::begin(m), std::end(m)); + } REQUIRE(v == vc); } From 6a23fdae0ac40524a53ffa3d6a72689fb60aa990 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Feb 2025 17:07:08 -0800 Subject: [PATCH 391/403] Adds tests for move-only callables to starmap Issue #89 --- test/test_starmap.cpp | 81 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/test/test_starmap.cpp b/test/test_starmap.cpp index e3958c84..c8758669 100644 --- a/test/test_starmap.cpp +++ b/test/test_starmap.cpp @@ -47,16 +47,42 @@ namespace { return a; } }; + + struct Adder { + long operator()(long a, int b) { + return a + b; + } + }; + + struct MoveOnlyAddAndPlus { + private: + // unique_ptr is better for triggering asan than an int if there's a + // dangling reference to the callable + std::unique_ptr add_amount_; + + public: + MoveOnlyAddAndPlus(int v) : add_amount_{std::make_unique(v)} {} + + MoveOnlyAddAndPlus(const MoveOnlyAddAndPlus&) = delete; + MoveOnlyAddAndPlus& operator=(const MoveOnlyAddAndPlus&) = delete; + + MoveOnlyAddAndPlus(MoveOnlyAddAndPlus&&) = default; + MoveOnlyAddAndPlus& operator=(MoveOnlyAddAndPlus&&) = default; + + int operator()(long a, int b) { + return a + b + *add_amount_; + } + }; } TEST_CASE("starmap: works with function pointer and lambda", "[starmap]") { - using Vec = const std::vector; const std::vector> v1 = {{1l, 2}, {3l, 11}, {6l, 7}}; - Vec vc = {2l, 33l, 42l}; + const std::vector greater_vc = {2l, 33l, 42l}; + const std::vector added_vc = {3l, 14l, 13l}; - std::vector v; - SECTION("with function") { - SECTION("Normal call") { + SECTION("with function pointer") { + std::vector v; + SECTION("normal call") { auto sm = starmap(f, v1); v.assign(std::begin(sm), std::end(sm)); } @@ -64,13 +90,54 @@ TEST_CASE("starmap: works with function pointer and lambda", "[starmap]") { auto sm = v1 | starmap(f); v.assign(std::begin(sm), std::end(sm)); } + REQUIRE(v == greater_vc); + } + + SECTION("with callable object") { + std::vector v; + SECTION("normal call") { + auto sm = starmap(Adder{}, v1); + v.assign(std::begin(sm), std::end(sm)); + } + SECTION("pipe") { + auto sm = v1 | starmap(Adder{}); + v.assign(std::begin(sm), std::end(sm)); + } + REQUIRE(v == added_vc); + } + + SECTION("with lvalue callable object") { + std::vector v; + auto adder = Adder{}; + SECTION("normal call") { + auto sm = starmap(adder, v1); + v.assign(std::begin(sm), std::end(sm)); + } + SECTION("pipe") { + auto sm = v1 | starmap(adder); + v.assign(std::begin(sm), std::end(sm)); + } + REQUIRE(v == std::vector{3l, 14l, 13l}); + } + + SECTION("with move-only callable object") { + const std::vector sum_plus_one_vc = {4l, 14l, 13l}; + std::vector v; + SECTION("normal call") { + auto m = starmap(MoveOnlyAddAndPlus{1}, v1); + v.assign(std::begin(m), std::end(m)); + } + SECTION("pipe") { + auto m = v1 | starmap(MoveOnlyAddAndPlus{1}); + v.assign(std::begin(m), std::end(m)); + } } SECTION("with lambda") { auto sm = starmap([](long a, int b) { return a * b; }, v1); - v.assign(std::begin(sm), std::end(sm)); + std::vector v(std::begin(sm), std::end(sm)); + REQUIRE(v == greater_vc); } - REQUIRE(v == vc); } TEST_CASE("starmap: works with pointer to member function", "[starmap]") { From 7242a9aadbbd70026a5e3b4059df9075fe465a7f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Feb 2025 17:07:54 -0800 Subject: [PATCH 392/403] Adds support for move-only callables to takewhile Issue #89 --- cppitertools/takewhile.hpp | 2 +- test/test_takewhile.cpp | 53 ++++++++++++++++++++++++-------------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/cppitertools/takewhile.hpp b/cppitertools/takewhile.hpp index 338e43aa..3a351d0c 100644 --- a/cppitertools/takewhile.hpp +++ b/cppitertools/takewhile.hpp @@ -29,7 +29,7 @@ class iter::impl::Taker { Taker(FilterFunc filter_func, Container&& container) : container_(std::forward(container)), - filter_func_(filter_func) {} + filter_func_(std::move(filter_func)) {} public: Taker(Taker&&) = default; diff --git a/test/test_takewhile.cpp b/test/test_takewhile.cpp index 0be43f84..f562b438 100644 --- a/test/test_takewhile.cpp +++ b/test/test_takewhile.cpp @@ -10,36 +10,49 @@ using iter::takewhile; using Vec = const std::vector; -TEST_CASE("takewhile: works with lambda, callable, and function pointer", - "[takewhile]") { +TEST_CASE("takewhile: handles different callable types", "[takewhile]") { Vec ns = {1, 3, 4, 20, 2, 4, 6, 8}; - const Vec vc = {1, 3, 4}; - SECTION("function pointer") { + Vec vc = {1, 3, 4}; + std::vector v; + SECTION("with function pointer") { auto tw = takewhile(less_than_five, ns); - Vec v(std::begin(tw), std::end(tw)); - REQUIRE(v == vc); + v = Vec(std::begin(tw), std::end(tw)); } - SECTION("callable object") { - std::vector v; - SECTION("Normal call") { - auto tw = takewhile(LessThanValue{10}, ns); - v.assign(std::begin(tw), std::end(tw)); - } + SECTION("with callable object") { + auto tw = takewhile(LessThanValue{5}, ns); + v = Vec(std::begin(tw), std::end(tw)); + } - SECTION("Pipe") { - auto tw = ns | takewhile(LessThanValue{10}); - v.assign(std::begin(tw), std::end(tw)); + SECTION("with lvalue callable object") { + auto lt = LessThanValue{5}; + SECTION("normal call") { + auto tw = takewhile(lt, ns); + v = Vec(std::begin(tw), std::end(tw)); + } + SECTION("pipe") { + auto tw = ns | takewhile(lt); + v = Vec(std::begin(tw), std::end(tw)); } + } - REQUIRE(v == vc); + SECTION("with move-only callable object") { + SECTION("normal call") { + auto tw = takewhile(MoveOnlyLessThanValue{5}, ns); + v = Vec(std::begin(tw), std::end(tw)); + } + SECTION("pipe") { + auto tw = ns | takewhile(MoveOnlyLessThanValue{5}); + v = Vec(std::begin(tw), std::end(tw)); + } } - SECTION("lambda") { - auto tw = takewhile([](int i) { return i < 10; }, ns); - Vec v(std::begin(tw), std::end(tw)); - REQUIRE(v == vc); + SECTION("with lambda") { + auto ltf = [](int i) { return i < 5; }; + auto tw = takewhile(ltf, ns); + v = Vec(std::begin(tw), std::end(tw)); } + REQUIRE(v == vc); } TEST_CASE("takewhile: handles pointer to member", "[takewhile]") { From 051d8f9830c401697213dc538477d41c5709b213 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Feb 2025 17:08:09 -0800 Subject: [PATCH 393/403] Adds support for move-only callables to unique_justseen Issue #89 --- cppitertools/unique_justseen.hpp | 8 ++++--- test/test_unique_justseen.cpp | 40 +++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/cppitertools/unique_justseen.hpp b/cppitertools/unique_justseen.hpp index c4ca47f5..e86d20ba 100644 --- a/cppitertools/unique_justseen.hpp +++ b/cppitertools/unique_justseen.hpp @@ -9,9 +9,11 @@ namespace iter { namespace impl { - struct UniqueJustseenFn : PipeableAndBindOptionalSecond { + struct UniqueJustseenFn + : PipeableAndBindOptionalSecond { public: - using PipeableAndBindOptionalSecond::operator(); + using PipeableAndBindOptionalSecond:: + operator(); template auto operator()(Container&& container, KeyFunc key_fn) const { // decltype(auto) return type in lambda so reference types are preserved @@ -19,7 +21,7 @@ namespace iter { [](auto&& group) -> decltype(auto) { return *get_begin(group.second); }, - groupby(std::forward(container), key_fn)); + groupby(std::forward(container), std::move(key_fn))); } }; } diff --git a/test/test_unique_justseen.cpp b/test/test_unique_justseen.cpp index 6147b477..530ab869 100644 --- a/test/test_unique_justseen.cpp +++ b/test/test_unique_justseen.cpp @@ -102,21 +102,45 @@ struct IntWrapperKey { } }; -TEST_CASE("unique_justseen: works with key function", - "[unique_justseen]") { +struct MoveOnlyIntWrapperKey { + MoveOnlyIntWrapperKey(const MoveOnlyIntWrapperKey&) = delete; + MoveOnlyIntWrapperKey& operator=(const MoveOnlyIntWrapperKey&) = delete; + + MoveOnlyIntWrapperKey(MoveOnlyIntWrapperKey&&) = default; + MoveOnlyIntWrapperKey& operator=(MoveOnlyIntWrapperKey&&) = default; + int operator()(const IntWrapper& iw) const { + return iw.n; + } +}; + +TEST_CASE("unique_justseen: works with key function", "[unique_justseen]") { std::vector iwv = { {2}, {3}, {4}, {2}, {10}, {2}, {2}, {12}, {10}}; Vec vc{2, 3, 4, 2, 10, 2, 12, 10}; std::vector v; - SECTION("Normal call") { - for (auto&& iw : unique_justseen(iwv, IntWrapperKey{})) { - v.push_back(iw.n); + SECTION("with callable") { + SECTION("Normal call") { + for (auto&& iw : unique_justseen(iwv, IntWrapperKey{})) { + v.push_back(iw.n); + } + } + SECTION("Pipe") { + for (auto&& iw : iwv | unique_justseen(IntWrapperKey{})) { + v.push_back(iw.n); + } } } - SECTION("Pipe") { - for (auto&& iw : iwv | unique_justseen(IntWrapperKey{})) { - v.push_back(iw.n); + SECTION("with move-only callable") { + SECTION("Normal call") { + for (auto&& iw : unique_justseen(iwv, MoveOnlyIntWrapperKey{})) { + v.push_back(iw.n); + } + } + SECTION("Pipe") { + for (auto&& iw : iwv | unique_justseen(MoveOnlyIntWrapperKey{})) { + v.push_back(iw.n); + } } } From 7ce67a6e4602651130bab0b71bb31d877c5a66f4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Feb 2025 17:48:27 -0800 Subject: [PATCH 394/403] Replaces true/false tag dispatches with if constexpr --- cppitertools/internal/iterbase.hpp | 48 ++++++++++-------------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/cppitertools/internal/iterbase.hpp b/cppitertools/internal/iterbase.hpp index 9cb97442..34abd934 100644 --- a/cppitertools/internal/iterbase.hpp +++ b/cppitertools/internal/iterbase.hpp @@ -214,28 +214,20 @@ namespace iter { } } - template - void dumb_advance_impl( - Iter& iter, const EndIter& end, Distance distance, std::false_type) { - for (Distance i(0); i < distance && iter != end; ++i) { - ++iter; - } - } - - template - void dumb_advance_impl( - Iter& iter, const EndIter& end, Distance distance, std::true_type) { - if (static_cast(end - iter) < distance) { - iter = end; - } else { - iter += distance; - } - } - // iter will not be incremented past end template void dumb_advance(Iter& iter, const EndIter& end, Distance distance) { - dumb_advance_impl(iter, end, distance, is_random_access_iter{}); + if constexpr (is_random_access_iter{}) { + if (static_cast(end - iter) < distance) { + iter = end; + } else { + iter += distance; + } + } else { + for (Distance i(0); i < distance && iter != end; ++i) { + ++iter; + } + } } template @@ -452,22 +444,14 @@ namespace iter { using Base = PipeableAndBindFirst>; - protected: - template - auto operator()(Container&& container, std::false_type) const { - return static_cast(*this)( - std::forward(container)); - } - - template - auto operator()(Container&& container, std::true_type) const { - return (*this)(DefaultT{}, std::forward(container)); - } - public: template auto operator()(T&& t) const { - return (*this)(std::forward(t), IsIterable{}); + if constexpr (IsIterable{}) { + return (*this)(DefaultT{}, std::forward(t)); + } else { + return static_cast(*this)(std::forward(t)); + } } template Date: Thu, 13 Feb 2025 16:36:06 -0800 Subject: [PATCH 395/403] Sets bazelversion to 8.* --- .bazelversion | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bazelversion b/.bazelversion index cd1d2e94..f4abeaad 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -8.0.1 +8.* From da33b531264fe1604871c8a2765f2ef3dcd98d99 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 14 Feb 2025 14:39:17 -0800 Subject: [PATCH 396/403] Forwards key to `Group` If we knew the key type was not a reference, we could just call std::move, but there might be an lvalue reference hiding in there. --- cppitertools/groupby.hpp | 8 ++++++-- test/test_groupby.cpp | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/cppitertools/groupby.hpp b/cppitertools/groupby.hpp index 313f088a..1c73f9f6 100644 --- a/cppitertools/groupby.hpp +++ b/cppitertools/groupby.hpp @@ -178,6 +178,8 @@ class iter::impl::GroupProducer { friend class Iterator; friend class GroupIterator; Iterator& owner_; + // The key function may return a reference, so we need to call forward, not + // move, when going for efficiency. key_func_ret key_; // completed is set if a Group is iterated through @@ -192,7 +194,7 @@ class iter::impl::GroupProducer { bool completed = false; Group(Iterator& owner, key_func_ret key) - : owner_(owner), key_(key) {} + : owner_(owner), key_(std::forward>(key)) {} public: ~Group() { @@ -204,7 +206,9 @@ class iter::impl::GroupProducer { // move-constructible, non-copy-constructible, non-assignable Group(Group&& other) noexcept - : owner_(other.owner_), key_{other.key_}, completed{other.completed} { + : owner_(other.owner_), + key_{std::forward>(other.key_)}, + completed{other.completed} { other.completed = true; } diff --git a/test/test_groupby.cpp b/test/test_groupby.cpp index 5904c78d..02798f39 100644 --- a/test/test_groupby.cpp +++ b/test/test_groupby.cpp @@ -40,6 +40,43 @@ namespace { const std::vector vec = { "hi", "ab", "ho", "abc", "def", "abcde", "efghi"}; + + struct Person { + std::string name; + int id; + bool operator==(const Person& other) const { + return id == other.id; + } + }; + + std::string& get_name(Person& p) { + return p.name; + } + + template + std::vector extract_person_group(G g) { + return {std::begin(g), std::end(g)}; + } +} + +TEST_CASE("groupby: handle key function that returns reference", "[groupby]") { + std::vector people = {{"first", 1}, {"first", 2}, {"first", 3}}; + std::vector keys; + std::vector> groups; + + for (auto&& gb : groupby(people, get_name)) { + groups.push_back(extract_person_group(std::move(gb.second))); + keys.push_back(gb.first); + } + + const std::vector kc = {"first"}; + const std::vector> gc = { + {{"first", 1}, {"first", 2}, {"first", 3}}}; + + REQUIRE(people[0].name == "first"); + REQUIRE(gc[0][0].name == "first"); + REQUIRE(keys == kc); + REQUIRE(groups == gc); } TEST_CASE("groupby: handles different callable types", "[groupby]") { From cf16b06cee79c7216233448cd25e4cb925efd7d2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 14 Feb 2025 14:47:19 -0800 Subject: [PATCH 397/403] Only uses gnu::nodangling when it's available in gcc --- cppitertools/internal/iterbase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cppitertools/internal/iterbase.hpp b/cppitertools/internal/iterbase.hpp index 34abd934..a21489dc 100644 --- a/cppitertools/internal/iterbase.hpp +++ b/cppitertools/internal/iterbase.hpp @@ -345,7 +345,7 @@ namespace iter { template struct Pipeable { template -#if defined(__GNUC__) && !defined(__clang__) +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 14 [[gnu::no_dangling]] #endif friend decltype(auto) operator|(T&& x, Pipeable&& p) { From 5bc867a1ee8fbcee322f072d700171e1901214dc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 18 Feb 2025 14:02:50 -0800 Subject: [PATCH 398/403] Removes cv qualifiers from value_type --- cppitertools/internal/iterbase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cppitertools/internal/iterbase.hpp b/cppitertools/internal/iterbase.hpp index a21489dc..f4d8792e 100644 --- a/cppitertools/internal/iterbase.hpp +++ b/cppitertools/internal/iterbase.hpp @@ -117,7 +117,7 @@ namespace iter { template using iterator_traits_deref = - std::remove_reference_t>; + std::remove_cv_t>>; template struct IsIterable : std::false_type {}; From 392734a2991980f25fe18c91d8bee05c99477d0f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 18 Feb 2025 17:03:48 -0800 Subject: [PATCH 399/403] Removes cv qualifiers from iterator iterator value_type --- cppitertools/internal/iteratoriterator.hpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/cppitertools/internal/iteratoriterator.hpp b/cppitertools/internal/iteratoriterator.hpp index 3993a4d0..0ab23bad 100644 --- a/cppitertools/internal/iteratoriterator.hpp +++ b/cppitertools/internal/iteratoriterator.hpp @@ -24,7 +24,8 @@ namespace iter { template class IteratorIterator { - template friend class IteratorIterator; + template + friend class IteratorIterator; using Diff = std::ptrdiff_t; static_assert( std::is_same< @@ -37,10 +38,14 @@ namespace iter { public: using iterator_category = std::random_access_iterator_tag; - using value_type = std::remove_reference_t())>; + using value_type = std::remove_cv_t< + std::remove_reference_t())>>; using difference_type = std::ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; + using pointer = + std::remove_reference_t())>*; + using reference = std::add_lvalue_reference_t< + std::remove_reference_t())>>; + IteratorIterator() = default; IteratorIterator(const TopIter& it) : sub_iter{it} {} @@ -84,7 +89,7 @@ namespace iter { return **this->sub_iter; } - auto operator-> () const -> decltype(*sub_iter) { + auto operator->() const -> decltype(*sub_iter) { return *this->sub_iter; } From 1bbe5a437f5039d242b0fb6983faa2a3f005edc5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 18 Feb 2025 17:10:03 -0800 Subject: [PATCH 400/403] Removes cv qualifiers from DerefHolder when storing value --- cppitertools/internal/iterbase.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cppitertools/internal/iterbase.hpp b/cppitertools/internal/iterbase.hpp index f4d8792e..e9627079 100644 --- a/cppitertools/internal/iterbase.hpp +++ b/cppitertools/internal/iterbase.hpp @@ -262,9 +262,8 @@ namespace iter { std::is_same::value && are_same::value> {}; // DerefHolder holds the value gotten from an iterator dereference - // if the iterate dereferences to an lvalue references, a pointer to the - // element is stored - // if it does not, a value is stored instead + // if the iterator dereferences to an lvalue references, a pointer to the + // element is stored. if it does not, a value is stored instead // get() returns a reference to the held item // get_ptr() returns a pointer to the held item // reset() replaces the currently held item @@ -274,7 +273,7 @@ namespace iter { static_assert(!std::is_lvalue_reference::value, "Non-lvalue-ref specialization used for lvalue ref type"); // it could still be an rvalue reference - using TPlain = std::remove_reference_t; + using TPlain = std::remove_cv_t>; std::optional item_p_; From 674e8b9a6d2f2319ea38312b6ada073937843e70 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 18 Feb 2025 17:10:52 -0800 Subject: [PATCH 401/403] Specifies pointer and reference to match operators exactly --- cppitertools/filter.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cppitertools/filter.hpp b/cppitertools/filter.hpp index 53ed15cc..d743d8b1 100644 --- a/cppitertools/filter.hpp +++ b/cppitertools/filter.hpp @@ -86,8 +86,8 @@ class iter::impl::Filtered { using iterator_category = std::input_iterator_tag; using value_type = iterator_traits_deref; using difference_type = std::ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; + using pointer = typename Holder::pointer; + using reference = typename Holder::reference; Iterator(IteratorWrapper&& sub_iter, IteratorWrapper&& sub_end, FilterFunc& filter_func) From 13947eb68f464cb014343de7a155016290655d1a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 18 Feb 2025 17:13:09 -0800 Subject: [PATCH 402/403] Specifies chain pointer and reference to match calls exactly --- cppitertools/chain.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cppitertools/chain.hpp b/cppitertools/chain.hpp index 76759eeb..05557387 100644 --- a/cppitertools/chain.hpp +++ b/cppitertools/chain.hpp @@ -142,8 +142,8 @@ class iter::impl::Chained { using iterator_category = std::input_iterator_tag; using value_type = typename IteratorData::TraitsValue; using difference_type = std::ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; + using pointer = typename IteratorData::ArrowType; + using reference = typename IteratorData::DerefType; Iterator(std::size_t i, typename IterData::IterTupType&& iters, typename IterData::IterTupType&& ends) From bb59879a7dbea29cc70d204b8c4889e35bb1110e Mon Sep 17 00:00:00 2001 From: Cristi Popa Date: Sat, 6 Dec 2025 15:55:05 +0100 Subject: [PATCH 403/403] Update readme to use google style markdown rendering --- README.md | 382 +++++++++++++++++++++++++++++------------------------- 1 file changed, 206 insertions(+), 176 deletions(-) diff --git a/README.md b/README.md index 7b43c218..740dacbd 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,7 @@ - - CPPItertools ============ Range-based for loop add-ons inspired by the Python builtins and itertools -library. Like itertools and the Python3 builtins, this library uses lazy +library. Like itertools and the Python3 builtins, this library uses lazy evaluation wherever possible. *Note*: Everything is inside the `iter` namespace. @@ -44,7 +42,7 @@ Status | Compilers [chunked](#chunked)
[batched](#batched)
-##### Combinatoric fuctions +##### Combinatorial functions [product](#product)
[combinations](#combinations)
[combinations\_with\_replacement](#combinations_with_replacement)
@@ -55,11 +53,10 @@ Status | Compilers This library is **header-only** and relies only on the C++ standard library. The only exception is `zip_longest` which uses `boost::optional`. `#include ` will include all of the provided -tools except for `zip_longest` which must be included separately. You may +tools except for `zip_longest` which must be included separately. You may also include individual pieces with the relevant header (`#include ` for example). - ### Running tests You may use either `scons` or `bazel` to build the tests. `scons` seems to work better with viewing the test output, but the same `bazel` command @@ -86,7 +83,7 @@ $ bazel test //test:test_enumerate # runs a specific test #### Requirements of passed objects Most itertools will work with iterables using InputIterators and not copy -or move any underlying elements. The itertools that need ForwardIterators or +or move any underlying elements. The itertools that need ForwardIterators or have additional requirements are noted in this document. However, the cases should be fairly obvious: any time an element needs to appear multiple times (as in `combinations` or `cycle`) or be looked at more than once (specifically, @@ -110,7 +107,7 @@ appropriate as a GitHub issue (or you just don't want to open one), you can email me directly with whatever code you have that describes the problem; I've been pretty responsive in the past. If I believe you are "misusing" the library, I'll try to put the blame on myself for being unclear -in this document and take the steps to clarify it. So please, contact me with +in this document and take the steps to clarify it. So please, contact me with any concerns, I'm open to feedback. #### How (not) to use this library @@ -125,41 +122,42 @@ know. #### Handling of rvalues vs lvalues The rules are pretty simple, and the library can be largely used without -knowledge of them. -Let's take an example +knowledge of them. Let's take an example + ```c++ std::vector vec{2,4,6,8}; for (auto&& p : enumerate(vec)) { /* ... */ } ``` + In this case, `enumerate` will return an object that has bound a reference to `vec`. No copies are produced here, neither of `vec` nor of the elements it holds. If an rvalue was passed to enumerate, binding a reference would be unsafe. Consider: + ```c++ for (auto&& p : enumerate(std::vector{2,4,6,8})) { /* ... */ } ``` + Instead, `enumerate` will return an object that has the temporary *moved* into -it. That is, the returned object will contain a `std::vector` rather than +it. That is, the returned object will contain a `std::vector` rather than just a reference to one. This may seem like a contrived example, but it matters when `enumerate` is passed the result of a function call like `enumerate(f())`, -or, more obviously, something like `enumerate(zip(a, b))`. The object returned +or, more obviously, something like `enumerate(zip(a, b))`. The object returned from `zip` must be moved into the `enumerate` object. As a more specific result, itertools can be mixed and nested. - - #### Pipe syntax Wherever it makes sense, I've implemented the "pipe" operator that has become common in similar libraries. When the syntax is available, it is done by pulling out the iterable from the call and placing it before the tool. For example: ```c++ -filter(pred, seq); // regular call -seq | filter(pred); // pipe-style -enumerate(seq); // regular call -seq | enumerate; // pipe-style. +filter(pred, seq); // regular call +seq | filter(pred); // pipe-style +enumerate(seq); // regular call +seq | enumerate; // pipe-style. ``` The following tools support pipe. The remaining I left out because although @@ -193,46 +191,50 @@ would expect them to behave: I don't personally care for the piping style, but it seemed to be desired by the users. - range ----- Uses an underlying iterator to achieve the same effect of the python range -function. `range` can be used in three different ways: +function. `range` can be used in three different ways: + +Only the stopping point is provided. Prints `0 1 2 3 4 5 6 7 8 9` -Only the stopping point is provided. Prints `0 1 2 3 4 5 6 7 8 9` ```c++ for (auto i : range(10)) { - cout << i << '\n'; + cout << i << '\n'; } ``` -The start and stop are both provided. Prints `10 11 12 13 14` +The start and stop are both provided. Prints `10 11 12 13 14` + ```c++ for (auto i : range(10, 15)) { - cout << i << '\n'; + cout << i << '\n'; } ``` -The start, stop, and step are all provided. Prints `20 22 24 26 28` +The start, stop, and step are all provided. Prints `20 22 24 26 28` + ```c++ for (auto i : range(20, 30, 2)) { - cout << i << '\n'; + cout << i << '\n'; } ``` -Negative values are allowed as well. Prints `2 1 0 -1 -2` +Negative values are allowed as well. Prints `2 1 0 -1 -2` + ```c++ for (auto i : range(2, -3, -1)) { - cout << i << '\n'; + cout << i << '\n'; } ``` A step size of 0 results in an empty range (Python's raises an exception). The following prints nothing + ```c++ for (auto i : range(0, 10, 0)) { - cout << i << '\n'; + cout << i << '\n'; } ``` @@ -240,9 +242,10 @@ In addition to normal integer range operations, doubles and other numeric types are supported through the template Prints: `5.0 5.5 6.0` ... `9.5` + ```c++ for(auto i : range(5.0, 10.0, 0.5)) { - cout << i << '\n'; + cout << i << '\n'; } ``` @@ -253,46 +256,45 @@ recomputed at each step to avoid accumulating floating point inaccuracies slower but more accurate. `range` also supports the following operations: - - `.size()` to get the number of elements in the range (not enabled for - floating point ranges). - - Accessors for `.start()`, `.stop()`, and `.step()`. - - Indexing. Given a range `r`, `r[n]` is the `n`th element in the range. + - `.size()` to get the number of elements in the range (not enabled for + floating point ranges). + - Accessors for `.start()`, `.stop()`, and `.step()`. + - Indexing. Given a range `r`, `r[n]` is the `n`th element in the range. enumerate --------- - -Continually "yields" containers similar to pairs. They are structs with -the index in `.first`, and the element in `.second`, and also work with structured -binding declarations. -Usage appears as: +Continually "yields" containers similar to pairs. They are structs with the +index in `.first`, and the element in `.second`, and also work with structured +binding declarations. Usage appears as: ```c++ vector vec{2, 4, 6, 8}; for (auto&& [i, e] : enumerate(vec)) { - cout << i << ": " << e << '\n'; + cout << i << ": " << e << '\n'; } ``` filter ------ -Called as `filter(predicate, iterable)`. The predicate can be any callable. +Called as `filter(predicate, iterable)`. The predicate can be any callable. `filter` will only yield values that are true under the predicate. -Prints values greater than 4: `5 6 7 8` +Prints values greater than 4: `5 6 7 8` + ```c++ vector vec{1, 5, 4, 0, 6, 7, 3, 0, 2, 8, 3, 2, 1}; for (auto&& i : filter([] (int i) { return i > 4; }, vec)) { - cout << i <<'\n'; + cout << i <<'\n'; } - ``` If no predicate is passed, the elements themselves are tested for truth Prints only non-zero values. + ```c++ for(auto&& i : filter(vec)) { - cout << i << '\n'; + cout << i << '\n'; } ``` @@ -300,36 +302,38 @@ filterfalse ----------- Similar to filter, but only prints values that are false under the predicate. -Prints values not greater than 4: `1 4 3 2 3 2 1 ` +Prints values not greater than 4: `1 4 3 2 3 2 1` + ```c++ vector vec{1, 5, 4, 0, 6, 7, 3, 0, 2, 8, 3, 2, 1}; for (auto&& i : filterfalse([] (int i) { return i > 4; }, vec)) { - cout << i <<'\n'; + cout << i <<'\n'; } - ``` If no predicate is passed, the elements themselves are tested for truth. Prints only zero values. + ```c++ for(auto&& i : filterfalse(vec)) { - cout << i << '\n'; + cout << i << '\n'; } - ``` + unique\_everseen ---------------- +---------------- *Additional Requirements*: Underlying values must be copy-constructible. This is a filter adaptor that only generates values that have never been seen before. Prints `1 2 3 4 5 6 7 8 9` + ```c++ vector v {1,2,3,4,3,2,1,5,6,7,7,8,9,8,9,6}; for (auto&& i : unique_everseen(v)) { - cout << i << ' '; + cout << i << ' '; } ``` @@ -341,29 +345,30 @@ This **does not** work with the pipe syntax. ```c++ vector v { /* ... */ }; for (auto&& w : unique_everseen(v, WidgetHash{}, WidgetEq{})) { - cout << w.name() << ' '; + cout << w.name() << ' '; } ``` unique\_justseen --------------- +---------------- Another filter adaptor that only omits consecutive duplicates. Prints `1 2 3 4 3 2 1` -Example Usage: + ```c++ vector v {1,1,1,2,2,3,3,3,4,3,2,1,1,1}; for (auto&& i : unique_justseen(v)) { - cout << i << ' '; + cout << i << ' '; } ``` If elements cannot be directly compared with equality, you can pass in a key callable. + ```c++ vector v { /* ... */ }; -for (auto&& p : unique_justseen(v, [] (const Person& p) { return p.name; })) - cout << p.name() << ' ' << p.age() << '\n'; +for (auto&& p : unique_justseen(v, [] (const Person& p) { return p.name; })) { + cout << p.name() << ' ' << p.age() << '\n'; } ``` @@ -372,11 +377,12 @@ takewhile Yields elements from an iterable until the first element that is false under the predicate is encountered. -Prints `1 2 3 4`. (5 is false under the predicate) +Prints `1 2 3 4`. (5 is false under the predicate) + ```c++ vector ivec{1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1}; for (auto&& i : takewhile([] (int i) {return i < 5;}, ivec)) { - cout << i << '\n'; + cout << i << '\n'; } ``` @@ -386,10 +392,11 @@ Yields all elements after and including the first element that is true under the predicate. Prints `5 6 7 1 2` + ```c++ vector ivec{1, 2, 3, 4, 5, 6, 7, 1, 2}; for (auto&& i : dropwhile([] (int i) {return i < 5;}, ivec)) { - cout << i << '\n'; + cout << i << '\n'; } ``` @@ -397,18 +404,18 @@ cycle ----- *Additional Requirements*: Input must have a ForwardIterator - -Repeatedly produces all values of an iterable. The loop will be infinite, so a +Repeatedly produces all values of an iterable. The loop will be infinite, so a `break` or other control flow structure is necessary to exit. Prints `1 2 3` repeatedly until `some_condition` is true + ```c++ vector vec{1, 2, 3}; for (auto&& i : cycle(vec)) { - cout << i << '\n'; - if (some_condition) { - break; - } + cout << i << '\n'; + if (some_condition) { + break; + } } ``` @@ -416,19 +423,21 @@ repeat ------ Repeatedly produces a single argument forever, or a given number of times. `repeat` will bind a reference when passed an lvalue and move when given -an rvalue. It will then yield a reference to the same item until completion. +an rvalue. It will then yield a reference to the same item until completion. The below prints `1` five times. + ```c++ for (auto&& e : repeat(1, 5)) { - cout << e << '\n'; + cout << e << '\n'; } ``` The below prints `2` forever + ```c++ for (auto&& e : repeat(2)) { - cout << e << '\n'; + cout << e << '\n'; } ``` @@ -448,9 +457,10 @@ being the `std::numeric_limits::max()` for the integral type (`long` by default) The below will print `0 1 2` ... etc + ```c++ for (auto&& i : count()) { - cout << i << '\n'; + cout << i << '\n'; } ``` @@ -460,31 +470,32 @@ groupby a reference, the reference must remain valid after the iterator is incremented. Roughly equivalent to requiring the Input have a ForwardIterator. -Separate an iterable into groups sharing a common key. The following example +Separate an iterable into groups sharing a common key. The following example creates a new group whenever a string of a different length is encountered. + ```c++ vector vec = { - "hi", "ab", "ho", - "abc", "def", - "abcde", "efghi" + "hi", "ab", "ho", + "abc", "def", + "abcde", "efghi" }; for (auto&& gb : groupby(vec, [] (const string &s) {return s.length(); })) { - cout << "key: " << gb.first << '\n'; - cout << "content: "; - for (auto&& s : gb.second) { - cout << s << " "; - } - cout << '\n'; + cout << "key: " << gb.first << '\n'; + cout << "content: "; + for (auto&& s : gb.second) { + cout << s << " "; + } + cout << '\n'; } ``` + *Note*: Just like Python's `itertools.groupby`, this doesn't do any sorting. It just iterates through, making a new group each time there is a key change. Thus, if the group is unsorted, the same key may appear multiple times. starmap ------- - Takes a sequence of tuple-like objects (anything that works with `std::get`) and unpacks each object into individual arguments for each function call. The below example takes a `vector` of `pairs` of ints, and passes them @@ -494,21 +505,21 @@ the first and second arguments to the function. ```c++ vector> v = {{2, 3}, {5, 2}, {3, 4}}; // {base, exponent} for (auto&& i : starmap([](int b, int e){return pow(b, e);}, v)) { - // ... + // ... } ``` `starmap` can also work over a tuple-like object of tuple-like objects even when the contained objects are different as long as the functor works with -multiple types of calls. For example, a `Callable` struct with overloads +multiple types of calls. For example, a `Callable` struct with overloads for its `operator()` will work as long as all overloads have the same return type ```c++ struct Callable { - int operator()(int i) const; - int operator()(int i, char c) const; - int operator()(double d, int i, char c) const; + int operator()(int i) const; + int operator()(int i, char c) const; + int operator()(double d, int i, char c) const; }; ``` @@ -516,36 +527,40 @@ This will work with a tuple of mixed types ```c++ auto t = make_tuple( - make_tuple(5), // first form - make_pair(3, 'c'), // second - make_tuple(1.0, 1, '1')); // third + make_tuple(5), // first form + make_pair(3, 'c'), // second + make_tuple(1.0, 1, '1')); // third for (auto&& i : starmap(Callable{}, t)) { - // ... + // ... } ``` accumulate -------- +---------- *Additional Requirements*: Type return from functor (with reference removed) must be assignable. Differs from `std::accumulate` (which in my humble opinion should be named -`std::reduce` or `std::foldl`). It is similar to a functional reduce where one -can see all of the intermediate results. By default, it keeps a running sum. +`std::reduce` or `std::foldl`). It is similar to a functional reduce where one +can see all of the intermediate results. By default, it keeps a running sum. + Prints: `1 3 6 10 15` + ```c++ for (auto&& i : accumulate(range(1, 6))) { - cout << i << '\n'; + cout << i << '\n'; } ``` + A second, optional argument may provide an alternative binary function -to compute results. The following example multiplies the numbers, rather +to compute results. The following example multiplies the numbers, rather than adding them. + Prints: `1 2 6 24 120` ```c++ for (auto&& i : accumulate(range(1, 6), std::multiplies{})) { - cout << i << '\n'; + cout << i << '\n'; } ``` @@ -556,10 +571,11 @@ zip --- Takes an arbitrary number of ranges of different types and efficiently iterates over them in parallel (so an iterator to each container is incremented -simultaneously). When you dereference an iterator to "zipped" range you get a +simultaneously). When you dereference an iterator to "zipped" range you get a tuple of the elements the iterators were holding. Example usage: + ```c++ array iseq{{1,2,3,4}}; vector fseq{1.2,1.4,12.3,4.5,9.9}; @@ -567,16 +583,16 @@ vector sseq{"i","like","apples","a lot","dude"}; array dseq{{1.2,1.2,1.2,1.2,1.2}}; for (auto&& [i, f, s, d] : zip(iseq, fseq, sseq, dseq)) { - cout << i << ' ' << f << ' ' << s << ' ' << d << '\n'; - f = 2.2f; // modifies the underlying 'fseq' sequence + cout << i << ' ' << f << ' ' << s << ' ' << d << '\n'; + f = 2.2f; // modifies the underlying 'fseq' sequence } ``` zip\_longest ------------ +------------ Terminates on the longest sequence instead of the shortest. Repeatedly yields a tuple of `boost::optional`s where `T` is the type -yielded by the sequences' respective iterators. Because of its boost +yielded by the sequences' respective iterators. Because of its boost dependency, `zip_longest` is not in `itertools.hpp` and must be included separately. The following loop prints either "Just \" or "Nothing" for each @@ -586,23 +602,24 @@ element in each tuple yielded. vector v1 = {0, 1, 2, 3}; vector v2 = {10, 11}; for (auto&& [x, y] : zip_longest(v1, v2)) { - cout << '{'; - if (x) { - cout << "Just " << *x; - } else { - cout << "Nothing"; - } - cout << ", "; - if (y) { - cout << "Just " << *y; - } else { - cout << "Nothing"; - } - cout << "}\n"; + cout << '{'; + if (x) { + cout << "Just " << *x; + } else { + cout << "Nothing"; + } + cout << ", "; + if (y) { + cout << "Just " << *y; + } else { + cout << "Nothing"; + } + cout << "}\n"; } ``` The output is: + ``` {Just 0, Just 10} {Just 1, Just 11} @@ -612,27 +629,27 @@ The output is: imap ---- - -Takes a function and one or more iterables. The number of iterables must -match the number of arguments to the function. Applies the function to -each element (or elements) in the iterable(s). Terminates on the shortest +Takes a function and one or more iterables. The number of iterables must +match the number of arguments to the function. Applies the function to +each element (or elements) in the iterable(s). Terminates on the shortest sequence. Prints the squares of the numbers in vec: `1 4 9 16 25` ```c++ vector vec{1, 2, 3, 4, 5}; for (auto&& i : imap([] (int x) {return x * x;}, vec)) { - cout << i << '\n'; + cout << i << '\n'; } ``` With more than one sequence, the below adds corresponding elements from each vector together, printing `11 23 35 47 59 71` + ```c++ vector vec1{1, 3, 5, 7, 9, 11}; vector vec2{10, 20, 30, 40, 50, 60}; for (auto&& i : imap([] (int x, int y) { return x + y; }, vec1, vec2)) { - cout << i << '\n'; + cout << i << '\n'; } ``` @@ -640,10 +657,8 @@ for (auto&& i : imap([] (int x, int y) { return x + y; }, vec1, vec2)) { `std::map`, and because it is more related to `itertools.imap` than the python builtin `map`. - compress -------- - Yields only the values corresponding to true in the selectors iterable. Terminates on the shortest sequence. @@ -652,7 +667,7 @@ Prints `2 6` vector ivec{1, 2, 3, 4, 5, 6}; vector bvec{false, true, false, false, false, true}; for (auto&& i : compress(ivec, bvec) { - cout << i << '\n'; + cout << i << '\n'; } ``` @@ -662,10 +677,10 @@ sorted Allows iteration over a sequence in sorted order. `sorted` does **not** produce a new sequence, copy elements, or modify the original -sequence. It only provides a way to iterate over existing elements. +sequence. It only provides a way to iterate over existing elements. `sorted` also takes an optional second [comparator](http://en.cppreference.com/w/cpp/concept/Compare) -argument. If not provided, defaults to `std::less`.
+argument. If not provided, defaults to `std::less`.
Iterables passed to sorted are required to have an iterator with an `operator*() const` member. @@ -674,7 +689,7 @@ The below outputs `0 1 2 3 4`. ```c++ unordered_set nums{4, 0, 2, 1, 3}; for (auto&& i : sorted(nums)) { - cout << i << '\n'; + cout << i << '\n'; } ``` @@ -692,31 +707,31 @@ vector vec1{1,2,3,4,5,6}; array arr1{{7,8,9,10}}; for (auto&& i : chain(empty,vec1,arr1)) { - cout << i << '\n'; + cout << i << '\n'; } ``` chain.from\_iterable -------------------- - +-------------------- Similar to chain, but rather than taking a variadic number of iterables, it takes an iterable of iterables and chains the contained iterables together. A simple example is shown below using a vector of vectors to represent a 2d ragged array, and prints it in row-major order. + ```c++ vector> matrix = { - {1, 2, 3}, - {4, 5}, - {6, 8, 9, 10, 11, 12} + {1, 2, 3}, + {4, 5}, + {6, 8, 9, 10, 11, 12} }; for (auto&& i : chain.from_iterable(matrix)) { - cout << i << '\n'; + cout << i << '\n'; } ``` reversed -------- +-------- *Additional Requirements*: Input must be compatible with `std::rbegin()` and `std::rend()` @@ -724,7 +739,7 @@ Iterates over elements of a sequence in reverse order. ```c++ for (auto&& i : reversed(a)) { - cout << i << '\n'; + cout << i << '\n'; } ``` @@ -735,18 +750,19 @@ Returns selected elements from a range, parameters are start, stop and step. the range returned is [start,stop) where you only take every step element This outputs `0 3 6 9 12` + ```c++ vector a{0,1,2,3,4,5,6,7,8,9,10,11,12,13}; for (auto&& i : slice(a,0,15,3)) { - cout << i << '\n'; + cout << i << '\n'; } ``` sliding\_window -------------- +--------------- *Additional Requirements*: Input must have a ForwardIterator -Takes a section from a range and increments the whole section. If the +Takes a section from a range and increments the whole section. If the window size is larger than the length of the input, the `sliding_window` will yield nothing (begin == end). @@ -764,60 +780,65 @@ take a section of size 4, output is: ``` Example Usage: + ```c++ vector v = {1,2,3,4,5,6,7,8,9}; for (auto&& sec : sliding_window(v,4)) { - for (auto&& i : sec) { - cout << i << ' '; - i.get() = 90; - } - cout << '\n'; + for (auto&& i : sec) { + cout << i << ' '; + i.get() = 90; + } + cout << '\n'; } ``` -chunked ------- +chunked +------- chunked will yield subsequent chunks of an iterable in blocks of a specified size. The final chunk may be shorter than the rest if the chunk size given does not evenly divide the length of the iterable. Example usage: + ```c++ vector v {1,2,3,4,5,6,7,8,9}; for (auto&& sec : chunked(v,4)) { - for (auto&& i : sec) { - cout << i << ' '; - } - cout << '\n'; + for (auto&& i : sec) { + cout << i << ' '; + } + cout << '\n'; } ``` The above prints: + ``` 1 2 3 4 5 6 7 8 9 ``` + batched ------- - batched will yield a given number N of batches containing subsequent elements from an iterable, assuming the iterable contains at least N elements. The size of each batch is immaterial, but the implementation guarantees that no two batches will differ in size by more than 1. Example usage: + ```c++ vector v {1,2,3,4,5,6,7,8,9}; for (auto&& sec : batched(v,4)) { - for (auto&& i : sec) { - cout << i << ' '; - } - cout << '\n'; + for (auto&& i : sec) { + cout << i << ' '; + } + cout << '\n'; } ``` The above prints: + ``` 1 2 3 4 5 @@ -826,54 +847,60 @@ The above prints: ``` product ------- +------- *Additional Requirements*: Input must have a ForwardIterator Generates the cartesian product of the given ranges put together. Example usage: + ```c++ vector v1{1,2,3}; vector v2{7,8}; vector v3{"the","cat"}; vector v4{"hi","what's","up","dude"}; for (auto&& [a, b, c, d] : product(v1,v2,v3,v4)) { - cout << a << ", " << b << ", " << c << ", " << d << '\n'; + cout << a << ", " << b << ", " << c << ", " << d << '\n'; } ``` -Product also accepts a "repeat" as a template argument. Currently this is the only way to do repeats. **If you are reading this and need `product(seq, 3)` instead of `product<3>(seq)` please open an issue**. +Product also accepts a "repeat" as a template argument. Currently this is the +only way to do repeats. **If you are reading this and need `product(seq, 3)` +instead of `product<3>(seq)` please open an issue**. Example usage: + ```c++ std::string s = "abc"; // equivalent of product(s, s, s); for (auto&& t : product<3>(s)) { - // ... + // ... } ``` combinations ------------ +------------ *Additional Requirements*: Input must have a ForwardIterator Generates n length unique sequences of the input range. Example usage: + ```c++ vector v = {1,2,3,4,5}; for (auto&& i : combinations(v,3)) { - for (auto&& j : i ) cout << j << " "; - cout << '\n'; + for (auto&& j : i ) cout << j << " "; + cout << '\n'; } ``` combinations\_with\_replacement ------------------------------ +------------------------------- *Additional Requirements*: Input must have a ForwardIterator -Like combinations, but with replacement of each element. The +Like combinations, but with replacement of each element. The below is printed by the loop that follows: + ``` {A, A} {A, B} @@ -882,43 +909,46 @@ below is printed by the loop that follows: {B, C} {C, C} ``` + ```c++ for (auto&& v : combinations_with_replacement(s, 2)) { - cout << '{' << v[0] << ", " << v[1] << "}\n"; + cout << '{' << v[0] << ", " << v[1] << "}\n"; } ``` permutations ------------ -*Additional Requirements*: Input must have a ForwardIterator. Iterator must +------------ +*Additional Requirements*: Input must have a ForwardIterator. Iterator must have an `operator*() const`. Generates all the permutations of a range using `std::next_permutation`. Example usage: + ```c++ vector v = {1,2,3,4,5}; for (auto&& vec : permutations(v)) { - for (auto&& i : vec) { - cout << i << ' '; - } - cout << '\n'; + for (auto&& i : vec) { + cout << i << ' '; + } + cout << '\n'; } ``` powerset -------- +-------- *Additional Requirements*: Input must have a ForwardIterator Generates every possible subset of a set, runs in O(2^n). Example usage: + ```c++ vector vec {1,2,3,4,5,6,7,8,9}; for (auto&& v : powerset(vec)) { - for (auto&& i : v) { - cout << i << " "; - } - cout << '\n'; + for (auto&& i : v) { + cout << i << " "; + } + cout << '\n'; } ```