From fce71b6e7623b29349f9a6be2ffd82167b73c887 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 28 Sep 2014 20:41:00 -0400 Subject: [PATCH 01/90] uses -std=c++14 in SConstruct --- tests/SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/SConstruct b/tests/SConstruct index eb1c70a7..7a4abeec 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -4,7 +4,7 @@ import os env = Environment( CXX='c++', CXXFLAGS= ['-g', '-Wall', '-Wextra', - '-pedantic', '-std=c++11', + '-pedantic', '-std=c++14', '-fdiagnostics-color=always', '-I/usr/local/include'], CPPPATH='..', From 84d382bda543af17f30371ca53cc5a3730dace8e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 28 Sep 2014 20:41:07 -0400 Subject: [PATCH 02/90] Flattens zip implementation No recursive template. Using std::index_sequence everywhere now. --- zip.hpp | 137 ++++++++++++++++++++++++-------------------------------- 1 file changed, 58 insertions(+), 79 deletions(-) diff --git a/zip.hpp b/zip.hpp index 08d2ec1a..d5066b7a 100644 --- a/zip.hpp +++ b/zip.hpp @@ -6,9 +6,14 @@ #include #include #include +#include namespace iter { + + template + void absorb(Ts&&...) { } + template class Zipped; @@ -16,114 +21,88 @@ namespace iter { Zipped zip(Containers&&...); // specialization for at least 1 template argument - template - class Zipped { - static_assert(!std::is_rvalue_reference::value, - "Itertools cannot be templated with rvalue references"); - - friend Zipped zip( - Container&&, RestContainers&&...); - - template - friend class Zipped; - + template + class Zipped { private: - Container container; - Zipped rest_zipped; - Zipped(Container container, RestContainers&&... rest) - : container(std::forward(container)), - rest_zipped{std::forward(rest)...} + std::tuple containers; + std::make_index_sequence indices; + + public: + Zipped(Containers... in_containers) + : containers{std::forward(in_containers)...} { } - public: class Iterator { private: - using RestIter = - typename Zipped::Iterator; + std::tuple...> iters; + std::make_index_sequence indices; + + template + bool not_equal(const Iterator& other, + std::index_sequence) const { + if (sizeof...(Is) == 0) { + // empty zip() case, return false right away + return false; + } + bool results[] = { true, + (std::get(this->iters) != + std::get(other.iters))... + }; + return std::all_of( + std::begin(results), std::end(results), + [](bool b){ return b; } ); + } + + template + void increment(std::index_sequence) { + absorb(++std::get(this->iters)...); + } + + template + auto deref(std::index_sequence) { + return std::tuple...>{ + (*std::get(this->iters))...}; + } - iterator_type iter; - RestIter rest_iter; public: - constexpr static const bool is_base_iter = false; - Iterator(iterator_type it, const RestIter& rest) - : iter{it}, - rest_iter{rest} + Iterator(iterator_type... its) + : iters{its...} { } Iterator& operator++() { - ++this->iter; - ++this->rest_iter; + this->increment(this->indices); return *this; } bool operator!=(const Iterator& other) const { - return this->iter != other.iter && - (RestIter::is_base_iter || - this->rest_iter != other.rest_iter); + return this->not_equal(other, this->indices); } - auto operator*() -> - decltype(std::tuple_cat( - std::tuple>{ - *this->iter}, - *this->rest_iter)) - { - return std::tuple_cat( - std::tuple>{ - *this->iter}, - *this->rest_iter); + auto operator*() { + return this->deref(this->indices); } }; - - Iterator begin() { - return {std::begin(this->container), - std::begin(this->rest_zipped)}; + private: + template + Iterator make_begin(std::index_sequence) { + return {std::begin(std::get(this->containers))...}; } - Iterator end() { - return {std::end(this->container), - std::end(this->rest_zipped)}; + template + Iterator make_end(std::index_sequence) { + return {std::end(std::get(this->containers))...}; } - }; - - template <> - class Zipped<> { public: - class Iterator { - public: - constexpr static const bool is_base_iter = true; - - Iterator() { } - Iterator(const Iterator&) { } - Iterator& operator=(const Iterator&) { return *this; } - - Iterator& operator++() { - return *this; - } - - // if this were to return true, there would be no need - // for the is_base_iter static class attribute. - // However, returning false causes an empty zip() call - // to reach the "end" immediately. Returning true here - // instead results in an infinite loop in the zip() case - bool operator!=(const Iterator&) const { - return false; - } - - std::tuple<> operator*() { - return std::tuple<>{}; - } - }; Iterator begin() { - return {}; + return this->make_begin(this->indices); } Iterator end() { - return {}; + return this->make_end(this->indices); } - }; + }; template Zipped zip(Containers&&... containers) { From 528836d57f2485b2857e18ba75cf449e40cdb34b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 28 Sep 2014 22:20:06 -0400 Subject: [PATCH 03/90] replaces empty zip if check with overload --- zip.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/zip.hpp b/zip.hpp index d5066b7a..1a449dac 100644 --- a/zip.hpp +++ b/zip.hpp @@ -37,13 +37,14 @@ namespace iter { std::tuple...> iters; std::make_index_sequence indices; + bool not_equal( + const Iterator&, std::index_sequence<>) const { + return false; + } + template bool not_equal(const Iterator& other, std::index_sequence) const { - if (sizeof...(Is) == 0) { - // empty zip() case, return false right away - return false; - } bool results[] = { true, (std::get(this->iters) != std::get(other.iters))... From f7b5c3028321bd73338c525b6312b2d61614d1cc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Sep 2014 00:32:57 -0400 Subject: [PATCH 04/90] Simplifies by templating on tuple and Is rather than repeating the deduction all over the place. --- zip.hpp | 103 +++++++++++++++++++++++++------------------------------- 1 file changed, 45 insertions(+), 58 deletions(-) diff --git a/zip.hpp b/zip.hpp index 1a449dac..cc8c58ab 100644 --- a/zip.hpp +++ b/zip.hpp @@ -8,106 +8,93 @@ #include #include - namespace iter { template void absorb(Ts&&...) { } +#if 0 template class Zipped; template Zipped zip(Containers&&...); +#endif // specialization for at least 1 template argument - template + template class Zipped { private: - std::tuple containers; - std::make_index_sequence indices; - + TupType containers; + using iters_tuple = + std::tuple(std::declval()))>...>; public: - Zipped(Containers... in_containers) - : containers{std::forward(in_containers)...} + Zipped(TupType&& in_containers) + : containers(std::move(in_containers)) { } class Iterator { private: - std::tuple...> iters; - std::make_index_sequence indices; + using iters_tuple = + std::tuple(std::declval()))>...>; + using iters_deref_tuple = + std::tuple(std::declval()))>...>; - bool not_equal( - const Iterator&, std::index_sequence<>) const { - return false; - } - - template - bool not_equal(const Iterator& other, - std::index_sequence) const { - bool results[] = { true, - (std::get(this->iters) != - std::get(other.iters))... - }; - return std::all_of( - std::begin(results), std::end(results), - [](bool b){ return b; } ); - } - - template - void increment(std::index_sequence) { - absorb(++std::get(this->iters)...); - } - - template - auto deref(std::index_sequence) { - return std::tuple...>{ - (*std::get(this->iters))...}; - } + iters_tuple iters; public: - Iterator(iterator_type... its) - : iters{its...} + Iterator(iters_tuple&& its) + : iters(std::move(its)) { } Iterator& operator++() { - this->increment(this->indices); + absorb(++std::get(this->iters)...); return *this; } bool operator!=(const Iterator& other) const { - return this->not_equal(other, this->indices); + if (sizeof...(Is) == 0) return false; + + bool results[] = { true, + (std::get(this->iters) != + std::get(other.iters))... + }; + return std::all_of( + std::begin(results), std::end(results), + [](bool b){ return b; } ); } auto operator*() { - return this->deref(this->indices); + return iters_deref_tuple{ + (*std::get(this->iters))...}; } }; - private: - template - Iterator make_begin(std::index_sequence) { - return {std::begin(std::get(this->containers))...}; - } - - template - Iterator make_end(std::index_sequence) { - return {std::end(std::get(this->containers))...}; - } - - public: Iterator begin() { - return this->make_begin(this->indices); + return iters_tuple{ + std::begin(std::get(this->containers))...}; } Iterator end() { - return this->make_end(this->indices); + return iters_tuple{ + std::end(std::get(this->containers))...}; } - }; + }; + + template + Zipped zip_impl( + TupType&& in_containers, std::index_sequence) { + return {std::move(in_containers)}; + } template - Zipped zip(Containers&&... containers) { - return {std::forward(containers)...}; + auto zip(Containers&&... containers) { + return zip_impl(std::tuple{ + std::forward(containers)...}, + std::index_sequence_for{}); } } From 77fc126990b5b7bcebab9009103990c6f3938a7b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Sep 2014 20:42:00 -0400 Subject: [PATCH 05/90] makes Zipped constructor private again --- zip.hpp | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/zip.hpp b/zip.hpp index cc8c58ab..fb49ecac 100644 --- a/zip.hpp +++ b/zip.hpp @@ -13,36 +13,35 @@ namespace iter { template void absorb(Ts&&...) { } -#if 0 - template + template class Zipped; - template - Zipped zip(Containers&&...); -#endif + template + Zipped zip_impl(TupleType&&, std::index_sequence); - // specialization for at least 1 template argument - template + template class Zipped { private: - TupType containers; + TupleType containers; using iters_tuple = std::tuple(std::declval()))>...>; - public: - Zipped(TupType&& in_containers) + std::get(std::declval()))>...>; + friend Zipped zip_impl( + TupleType&&, std::index_sequence); + + Zipped(TupleType&& in_containers) : containers(std::move(in_containers)) { } + public: class Iterator { private: using iters_tuple = std::tuple(std::declval()))>...>; + std::get(std::declval()))>...>; using iters_deref_tuple = std::tuple(std::declval()))>...>; - + std::get(std::declval()))>...>; iters_tuple iters; public: @@ -84,9 +83,9 @@ namespace iter { } }; - template - Zipped zip_impl( - TupType&& in_containers, std::index_sequence) { + template + Zipped zip_impl( + TupleType&& in_containers, std::index_sequence) { return {std::move(in_containers)}; } From dee21e2f69b5713246d86159284312d50d8fb119 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Sep 2014 21:16:15 -0400 Subject: [PATCH 06/90] refactors type aliases --- iterbase.hpp | 34 ++++++++++++++++++++++++++++++++++ zip.hpp | 26 +++++++------------------- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 15f0a0a0..63bd142c 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -9,6 +9,7 @@ // this file directly. #include +#include #include #include #include @@ -79,6 +80,39 @@ namespace iter { typename std::remove_const< iterator_deref>::type>::type; + + 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())); + + namespace detail { + template + std::tuple...> iterator_tuple_deref_helper( + const std::tuple&); + } + + // 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())); + + // 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&&...) { } + } #endif // #ifndef ITERBASE_HPP_ diff --git a/zip.hpp b/zip.hpp index fb49ecac..f8622553 100644 --- a/zip.hpp +++ b/zip.hpp @@ -10,9 +10,6 @@ namespace iter { - template - void absorb(Ts&&...) { } - template class Zipped; @@ -23,9 +20,6 @@ namespace iter { class Zipped { private: TupleType containers; - using iters_tuple = - std::tuple(std::declval()))>...>; friend Zipped zip_impl( TupleType&&, std::index_sequence); @@ -36,16 +30,10 @@ namespace iter { class Iterator { private: - using iters_tuple = - std::tuple(std::declval()))>...>; - using iters_deref_tuple = - std::tuple(std::declval()))>...>; - iters_tuple iters; + iterator_tuple_type iters; public: - Iterator(iters_tuple&& its) + Iterator(iterator_tuple_type&& its) : iters(std::move(its)) { } @@ -67,19 +55,19 @@ namespace iter { } auto operator*() { - return iters_deref_tuple{ + return iterator_deref_tuple{ (*std::get(this->iters))...}; } }; Iterator begin() { - return iters_tuple{ - std::begin(std::get(this->containers))...}; + return {iterator_tuple_type{ + std::begin(std::get(this->containers))...}}; } Iterator end() { - return iters_tuple{ - std::end(std::get(this->containers))...}; + return {iterator_tuple_type{ + std::end(std::get(this->containers))...}}; } }; From dc7fcd67a40cc9b6ec2464175b8d24ecdb946f97 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Sep 2014 21:21:21 -0400 Subject: [PATCH 07/90] removes mutable (idk why it was ever there) --- imap.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imap.hpp b/imap.hpp index 74e316a7..2418b149 100644 --- a/imap.hpp +++ b/imap.hpp @@ -94,7 +94,7 @@ namespace iter { class Iterator { private: MapFunc map_func; - mutable ZippedIterType zipiter; + ZippedIterType zipiter; public: Iterator(MapFunc map_func, ZippedIterType zipiter) : From 034681307b09c4dd74282dd8428378dbdc2c3f89 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 29 Sep 2014 23:12:05 -0400 Subject: [PATCH 08/90] Cuts down unique_justseen with a lambda This was my original intention, but since lambdas can't appear in an unevaluated context, it didn't work with a trailing return type. With an inferred return type, however, it's fine. --- unique_justseen.hpp | 48 ++++++++++++--------------------------------- 1 file changed, 13 insertions(+), 35 deletions(-) diff --git a/unique_justseen.hpp b/unique_justseen.hpp index eaf81747..366e747e 100644 --- a/unique_justseen.hpp +++ b/unique_justseen.hpp @@ -1,7 +1,6 @@ -#ifndef UNIQUE_JUSTSEEN_HPP -#define UNIQUE_JUSTSEEN_HPP +#ifndef ITER_UNIQUE_JUSTSEEN_H_ +#define ITER_UNIQUE_JUSTSEEN_H_ -#include "iterbase.hpp" #include "groupby.hpp" #include "imap.hpp" @@ -9,44 +8,23 @@ #include #include -namespace iter -{ - template - struct GroupFrontGetter{ - auto operator()(iterator_deref&& gb) -> - decltype(*std::begin(gb.second)) { - return *std::begin(gb.second); - } +namespace iter { - auto operator()(iterator_deref& gb) -> - decltype(*std::begin(gb.second)) { - return *std::begin(gb.second); - } - }; - - - // gets first of each group. since each group is decided based on equality - // with the previous item, this results in each item only appearing once template - auto unique_justseen(Container&& container) -> - decltype(imap(GroupFrontGetter(container)))>{}, - groupby(std::forward(container)))) { - return imap(GroupFrontGetter(container)))>{}, + auto unique_justseen(Container&& container) { + // explicit return type in lambda so reference types are preserved + return imap([] (auto&& group) -> iterator_deref { + return *std::begin(group.second); }, groupby(std::forward(container))); } template - auto unique_justseen(std::initializer_list il) -> - decltype(imap(GroupFrontGetter>(il)))>{}, - groupby(std::forward>(il)))) { - return imap(GroupFrontGetter>(il)))>{}, - groupby(std::forward>(il))); + auto unique_justseen(std::initializer_list il) { + return imap( + [](auto&& group) -> iterator_deref> { + return *std::begin(group.second); }, + groupby(il)); } } - -#endif //UNIQUE_JUSTSEEN_HPP +#endif // #ifndef ITER_UNIQUE_JUSTSEEN_H_ From 327db3415b486176f7889ecd630791d54b944979 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 12 Oct 2014 19:41:08 -0400 Subject: [PATCH 09/90] Replaces complex call_with_tuple With std::get and an integer_sequence --- imap.hpp | 61 +++++++++----------------------------------------------- 1 file changed, 9 insertions(+), 52 deletions(-) diff --git a/imap.hpp b/imap.hpp index fd6f0ecc..a88ea5fb 100644 --- a/imap.hpp +++ b/imap.hpp @@ -4,63 +4,23 @@ #include "zip.hpp" #include -#include namespace iter { namespace detail { - - template - struct Expander { - template - static auto call(Functor&& f, Tup&& tup, Ts&&... args) - -> decltype(Expander::call( - std::forward(f), - std::forward(tup), - std::get(tup), - std::forward(args)...)) - { - // recurse - return Expander::call( - std::forward(f), - std::forward(tup), - std::get(tup), // pull out one element - std::forward(args)...); // everything already expanded + template + auto call_with_tuple_impl(MapFunc&& mf, TupleType&& tup, + std::index_sequence) { + return mf(std::get(tup)...); } - }; - template - struct Expander<0, Functor, Tup> { - template - static auto call(Functor&& f, Tup&&, Ts&&... args) - -> decltype(f(std::forward(args)...)) - { - static_assert( - std::tuple_size< - typename std::remove_reference::type>::value - == sizeof...(Ts), - "tuple has not been fully expanded"); - return f(std::forward(args)...); // the actual call + template + auto call_with_tuple(MapFunc&& mf, std::tuple&& tup){ + return call_with_tuple_impl( + mf, tup, std::index_sequence_for{}); } - }; - - template - auto call_with_tuple(Functor&& f, Tup&& tup) - -> decltype(Expander::type>::value, - Functor, Tup>::call( - std::forward(f), - std::forward(tup))) - { - return Expander::type>::value, - Functor, Tup>::call( - std::forward(f), - std::forward(tup)); } - } // end detail - //Forward declarations of IMap and imap template class IMap; @@ -102,10 +62,7 @@ namespace iter { zipiter(zipiter) { } - auto operator*() -> - decltype(detail::call_with_tuple( - this->map_func, *(this->zipiter))) - { + auto operator*() { return detail::call_with_tuple( this->map_func, *(this->zipiter)); } From 2f3df24376ce6304d92ba46ce98674052f6971b1 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 15 Oct 2014 10:29:30 -0400 Subject: [PATCH 10/90] Moves call_with_tuple into iterbase and makes it more flexible --- imap.hpp | 16 +--------------- iterbase.hpp | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/imap.hpp b/imap.hpp index a88ea5fb..38d7241a 100644 --- a/imap.hpp +++ b/imap.hpp @@ -7,20 +7,6 @@ namespace iter { - namespace detail { - template - auto call_with_tuple_impl(MapFunc&& mf, TupleType&& tup, - std::index_sequence) { - return mf(std::get(tup)...); - } - - template - auto call_with_tuple(MapFunc&& mf, std::tuple&& tup){ - return call_with_tuple_impl( - mf, tup, std::index_sequence_for{}); - } - } - //Forward declarations of IMap and imap template class IMap; @@ -63,7 +49,7 @@ namespace iter { { } auto operator*() { - return detail::call_with_tuple( + return call_with_tuple( this->map_func, *(this->zipiter)); } diff --git a/iterbase.hpp b/iterbase.hpp index 63bd142c..da6e703e 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -107,12 +107,33 @@ namespace iter { 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 + auto call_with_tuple_impl(Func&& mf, TupleType&& tup, + std::index_sequence) { + return mf(std::get(tup)...); + } + } + + // expand a TupleType into individual arguments when calling a Func + template + auto call_with_tuple(Func&& mf, TupleType&& tup) { + constexpr auto TUP_SIZE = std::tuple_size< + typename std::remove_reference::type>::value; + return detail::call_with_tuple_impl( + std::forward(mf), + std::forward(tup), + std::make_index_sequence{}); + } + } #endif // #ifndef ITERBASE_HPP_ From e23c73d54fe75e78dafb300fdefd4fa5f97a63f0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 17 Oct 2014 14:12:29 -0400 Subject: [PATCH 11/90] describes purpose of c++14 branch --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d44c246..81cd774c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,12 @@ -CPPItertools +CPPItertools C++14 development Branch ============ +**NOTE**: this branch is for refining and moving forward with the C++14 +standard. It will be merged into master when compiler and library +support for the standard approaches completion in common compilers. +Specifically I'm considering clang and gcc, along with libstdc++ +and libc++ + 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. From f3e78488bc30b0fe763d0e1a135d09d1b221e498 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 18 Oct 2014 15:10:43 -0400 Subject: [PATCH 12/90] relaced decay with decay_t --- iterbase.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index da6e703e..d0eade82 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -117,7 +117,7 @@ namespace iter { namespace detail { template - auto call_with_tuple_impl(Func&& mf, TupleType&& tup, + decltype(auto) call_with_tuple_impl(Func&& mf, TupleType&& tup, std::index_sequence) { return mf(std::get(tup)...); } @@ -125,9 +125,9 @@ namespace iter { // expand a TupleType into individual arguments when calling a Func template - auto call_with_tuple(Func&& mf, TupleType&& tup) { + decltype(auto) call_with_tuple(Func&& mf, TupleType&& tup) { constexpr auto TUP_SIZE = std::tuple_size< - typename std::remove_reference::type>::value; + std::decay_t>::value; return detail::call_with_tuple_impl( std::forward(mf), std::forward(tup), From 26755551c32b956cfa40811199fbe6eee5853348 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 18 Oct 2014 17:35:09 -0400 Subject: [PATCH 13/90] marks operator* as decltype(auto) in imap iterator --- imap.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imap.hpp b/imap.hpp index 38d7241a..e39a468c 100644 --- a/imap.hpp +++ b/imap.hpp @@ -48,7 +48,7 @@ namespace iter { zipiter(zipiter) { } - auto operator*() { + decltype(auto) operator*() { return call_with_tuple( this->map_func, *(this->zipiter)); } From c250beb3a3a63335ceedfe2b1c9e8592e80ea48b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 18 Oct 2014 20:09:54 -0400 Subject: [PATCH 14/90] adds test for starmap --- tests/teststarmap.cpp | 75 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 tests/teststarmap.cpp diff --git a/tests/teststarmap.cpp b/tests/teststarmap.cpp new file mode 100644 index 00000000..0d293abc --- /dev/null +++ b/tests/teststarmap.cpp @@ -0,0 +1,75 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using iter::starmap; + +double f(double d, int i) { + return d * i; +} + +std::string g(const std::string& s, int i, double d) { + std::stringstream ss; + ss << s << ' ' << i << ' ' << d; + return ss.str(); +} + +void test_normal() { + std::cout << "vector>\n"; + std::vector> v1 = {{1.0, 2}, {3.2, 42}, {6.9, 7}}; + for (auto&& i : starmap(f, v1)) { + std::cout << i << '\n'; + } + std::cout << '\n'; + + std::cout << "list\n"; + { + using T = std::tuple; + std::list li = + {T{"hey", 42, 6.9}, T{"there", 3, 4.0}, T{"yall", 5, 3.1}}; + for (auto&& s : starmap(g, li)) { + std::cout << s << '\n'; + } + } + std::cout << '\n'; +} + +struct Callable { + int operator()(int a, int b, int c) { + return a + b + c; + } + + int operator()(int a) { + return a; + } +}; + +void test_tuple_of_tuples() { + auto tup = std::make_tuple(std::make_tuple(10, 19, 60),std::make_tuple(7)); + Callable c; + std::cout << "tuple, tuple>\n"; + for (auto&& i : starmap(c, tup)) { + std::cout << i << '\n'; + } + + auto tup2 = std::make_tuple(std::array{15, 100, 2000}, + std::make_tuple(16)); + std::cout << "tuple, tuple>\n"; + for (auto&& i : starmap(c, tup2)) { + std::cout << i << '\n'; + } + std::cout << '\n'; +} + +int main() { + test_normal(); + test_tuple_of_tuples(); + +} From adbf9ece561b3b7ab60501255080c4c20b71a50e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 18 Oct 2014 20:10:21 -0400 Subject: [PATCH 15/90] adds starmap --- starmap.hpp | 160 +++++++++++++++++++++++++++++++++++++++++++++++ tests/.gitignore | 1 + tests/SConstruct | 1 + 3 files changed, 162 insertions(+) create mode 100644 starmap.hpp diff --git a/starmap.hpp b/starmap.hpp new file mode 100644 index 00000000..165cc363 --- /dev/null +++ b/starmap.hpp @@ -0,0 +1,160 @@ +#ifndef ITER_STARMAP_H_ +#define ITER_STARMAP_H_ + +#include "iterbase.hpp" + +#include +#include + +namespace iter { + template + class StarMapper { + private: + Func func; + Container container; + public: + StarMapper(Func f, Container c) + : func(f), + container(std::forward(c)) + { } + + class Iterator { + private: + Func func; + iterator_type sub_iter; + public: + Iterator(Func f, iterator_type iter) + : func(f), + sub_iter(iter) + { } + + bool operator!=(const Iterator& other) const { + return this->sub_iter != other.sub_iter; + } + + Iterator operator++() { + ++this->sub_iter; + return *this; + } + + decltype(auto) operator*() { + return call_with_tuple(this->func, *this->sub_iter); + } + }; + + Iterator begin() { + return {this->func, std::begin(this->container)}; + } + + Iterator end() { + return {this->func, std::end(this->container)}; + } + }; + + template + StarMapper starmap(Func func, Container&& container) { + return {func, std::forward(container)}; + } + + template >::value> + class TupleStarMapper { + private: + Func func; + TupleType tup; + public: + TupleStarMapper(Func f, TupleType t) + : func(f), + tup(std::forward(t)) + { } + + template + class Iterator { + private: + Func func; + TupleType& tup; + bool passed; + Iterator<0, Idx + 1> next_level; + + public: + Iterator(Func f, TupleType& t, bool done) + : func(f), + tup(t), + passed{done}, + next_level(f, t, done) + { } + + decltype(auto) operator*() { + if (this->passed) { + return *this->next_level; + } else { + return call_with_tuple( + this->func, std::get(this->tup)); + } + } + + Iterator operator++() { + if (!this->passed) { + this->passed = true; + } else { + ++this->next_level; + } + return *this; + } + + bool operator!=(const Iterator& other) const { + return this->passed != other.passed + || this->next_level != other.next_level; + } + }; + + template + class Iterator { + private: + // data members unused since this should never get + // dereferenced, but are needed to compile + Func func; + TupleType& tup; + public: + Iterator(Func f, TupleType& t, bool) + : func(f), + tup(t) + { } + + decltype(auto) operator*() { + assert(false && "deref of last level in starmap"); + return call_with_tuple(func, std::get<0>(tup)); + } + + Iterator operator++() { + assert(false && "++ on last level of starmap"); + return *this; + } + + bool operator!=(const Iterator&) const { + return false; + } + }; + + Iterator<0, 0> begin() { + return {this->func, this->tup, false}; + } + + Iterator<0, 0> end() { + return {this->func, this->tup, true}; + } + }; + + template + TupleStarMapper> starmap( + Func func, std::tuple tup) { + return {func, tup}; + } + + +} + + + + +#endif // #ifndef ITER_STARMAP_H_ diff --git a/tests/.gitignore b/tests/.gitignore index 7daa7f9d..a72824de 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -28,6 +28,7 @@ testgrouper testcommand_chains testgroupby testsorted +teststarmap testunique_justseen testunique_everseen .sconsign.dblite diff --git a/tests/SConstruct b/tests/SConstruct index 7a4abeec..d1271d7d 100644 --- a/tests/SConstruct +++ b/tests/SConstruct @@ -34,6 +34,7 @@ progs = Split(''' powerset sliding_window imap + starmap count filterfalse grouper From ba4c3b940664855ebbcf4aea64cc3043d375a2c2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 18 Oct 2014 20:10:58 -0400 Subject: [PATCH 16/90] adds starmap to itertools.hpp --- itertools.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/itertools.hpp b/itertools.hpp index 55039902..3ef9dd1e 100644 --- a/itertools.hpp +++ b/itertools.hpp @@ -1,5 +1,5 @@ -#ifndef ITERTOOLS_HPP -#define ITERTOOLS_HPP +#ifndef ITERTOOLS_HPP_ +#define ITERTOOLS_HPP_ #include "accumulate.hpp" #include "chain.hpp" @@ -24,6 +24,7 @@ #include "reversed.hpp" #include "slice.hpp" #include "sorted.hpp" +#include "starmap.hpp" #include "takewhile.hpp" #include "unique_everseen.hpp" #include "unique_justseen.hpp" From bc9b13799fc96452f7a5fcaef3181cef97f29a9c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 19 Oct 2014 12:32:22 -0400 Subject: [PATCH 17/90] Replaces recursive iterators with flat array Because TupleStarMapper::Iterator::operator* causes a recursive call, it gets slower as one goes further along, the cost of longer tuples is unexpectedly high. This new scheme uses a set of classes templated on the index they use in std::get, all inheriting from a common base. An array of base class pointers can then be indexed into. It incurs a virtual function call but that's worth it. The dynamic allocation seems to be the bigger cost, but it's possible that can be alleviated as well. --- starmap.hpp | 123 +++++++++++++++++++++++++++------------------------- 1 file changed, 65 insertions(+), 58 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index 165cc363..14f14108 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -4,9 +4,13 @@ #include "iterbase.hpp" #include +#include +#include #include +#include namespace iter { + // starmap with a container where T is one of tuple, pair, array template class StarMapper { private: @@ -56,101 +60,104 @@ namespace iter { return {func, std::forward(container)}; } + + // starmap for a tuple or pair of tuples or pairs template >::value> class TupleStarMapper { private: - Func func; - TupleType tup; - public: - TupleStarMapper(Func f, TupleType t) - : func(f), - tup(std::forward(t)) - { } + class TupleExpanderBase { + protected: + // deduced return type to return of Func when called with + // one of TupleType + using ResultType = + decltype(call_with_tuple( + std::declval(), + std::get<0>(std::declval()))); + public: + virtual ResultType call() = 0; - template - class Iterator { + virtual ~TupleExpanderBase() { } + }; + + template + class TupleExpander : public TupleExpanderBase { private: Func func; TupleType& tup; - bool passed; - Iterator<0, Idx + 1> next_level; - public: - Iterator(Func f, TupleType& t, bool done) + TupleExpander(Func f, TupleType& t) : func(f), - tup(t), - passed{done}, - next_level(f, t, done) + tup(t) { } - decltype(auto) operator*() { - if (this->passed) { - return *this->next_level; - } else { - return call_with_tuple( - this->func, std::get(this->tup)); - } + typename TupleExpanderBase::ResultType call() override { + return call_with_tuple( + this->func, std::get(this->tup)); } + }; - Iterator operator++() { - if (!this->passed) { - this->passed = true; - } else { - ++this->next_level; - } - return *this; - } + private: + Func func; + TupleType tup; + std::array, Size> tuple_getters; - bool operator!=(const Iterator& other) const { - return this->passed != other.passed - || this->next_level != other.next_level; - } - }; + template + TupleStarMapper(Func f, TupleType t, std::index_sequence) + : func(f), + tup(std::forward(t)), + tuple_getters( + {std::make_unique>(func, tup)...}) + { } + + public: + TupleStarMapper(Func f, TupleType t) + : TupleStarMapper(f, std::forward(t), + std::make_index_sequence{}) + { } - template - class Iterator { + class Iterator { private: - // data members unused since this should never get - // dereferenced, but are needed to compile - Func func; - TupleType& tup; + std::array, Size>& + tuple_getters; + std::size_t index; + public: - Iterator(Func f, TupleType& t, bool) - : func(f), - tup(t) + Iterator(std::array< + std::unique_ptr, Size>& tg, + std::size_t i) + : tuple_getters(tg), + index{i} { } - + decltype(auto) operator*() { - assert(false && "deref of last level in starmap"); - return call_with_tuple(func, std::get<0>(tup)); + return this->tuple_getters[this->index]->call(); } Iterator operator++() { - assert(false && "++ on last level of starmap"); + ++this->index; return *this; } - bool operator!=(const Iterator&) const { - return false; + bool operator!=(const Iterator& other) const { + return this->index != other.index; } }; - Iterator<0, 0> begin() { - return {this->func, this->tup, false}; + Iterator begin() { + return {this->tuple_getters, 0}; } - Iterator<0, 0> end() { - return {this->func, this->tup, true}; + Iterator end() { + return {this->tuple_getters, Size}; } }; template - TupleStarMapper> starmap( - Func func, std::tuple tup) { + TupleStarMapper&> starmap( + Func func, std::tuple& tup) { return {func, tup}; } - } From 917ad43c328e8720d58fe796209fd381e755694e Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Oct 2014 00:07:13 -0400 Subject: [PATCH 18/90] adds starmap test with pair of tuples --- tests/teststarmap.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/teststarmap.cpp b/tests/teststarmap.cpp index 0d293abc..992c7ce3 100644 --- a/tests/teststarmap.cpp +++ b/tests/teststarmap.cpp @@ -66,6 +66,14 @@ void test_tuple_of_tuples() { std::cout << i << '\n'; } std::cout << '\n'; + + std::cout << "pair, tuple>\n"; + auto p = std::make_pair(std::array{15, 100, 2000}, + std::make_tuple(16)); + for (auto&& i : starmap(c, p)) { + std::cout << i << '\n'; + } + std::cout << '\n'; } int main() { From 7350d07421db5c3be58b8563bf9565775da036a3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Oct 2014 00:08:27 -0400 Subject: [PATCH 19/90] supports starmap over a pair --- starmap.hpp | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index 14f14108..920825ec 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -55,12 +55,14 @@ namespace iter { } }; + + template - StarMapper starmap(Func func, Container&& container) { + StarMapper starmap_helper( + Func func, Container&& container, std::false_type) { return {func, std::forward(container)}; } - // starmap for a tuple or pair of tuples or pairs template >::value> @@ -153,12 +155,27 @@ namespace iter { } }; - template - TupleStarMapper&> starmap( - Func func, std::tuple& tup) { - return {func, tup}; + template + TupleStarMapper starmap_helper( + Func func, TupleType&& tup, std::true_type) { + return {func, std::forward(tup)}; } + // "tag dispatch" to differentiate between normal containers and + // tuple-like containers, things that work with std::get + template + struct is_tuple_like : public std::false_type { }; + + template + struct is_tuple_like(std::declval()), void())> + : public std::true_type { }; + + template + auto starmap(Func func, Seq&& sequence) { + return starmap_helper( + func, std::forward(sequence), + is_tuple_like{}); + } } From f9209106698999a3ea0b363054acbf4e30d64876 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 20 Oct 2014 00:11:45 -0400 Subject: [PATCH 20/90] implements imap in terms of starmap and gets rid of nearly the entire imap.hpp in the process --- imap.hpp | 75 +++----------------------------------------------------- 1 file changed, 3 insertions(+), 72 deletions(-) diff --git a/imap.hpp b/imap.hpp index e39a468c..8c5721aa 100644 --- a/imap.hpp +++ b/imap.hpp @@ -2,84 +2,15 @@ #define ITER_IMAP_H_ #include "zip.hpp" +#include "starmap.hpp" #include namespace iter { - - //Forward declarations of IMap and imap - template - class IMap; - - template - IMap imap(MapFunc, Containers&&...); - - template - class IMap { - // The imap function is the only thing allowed to create a IMap - friend IMap imap(MapFunc, Containers&& ...); - - using ZippedType = decltype(zip(std::declval()...)); - using ZippedIterType = iterator_type; - private: - MapFunc map_func; - ZippedType zipped; - - // Value constructor for use only in the imap function - IMap(MapFunc map_func, Containers&& ... containers) : - map_func(map_func), - zipped(zip(std::forward(containers)...)) - { } - IMap() = delete; - IMap& operator=(const IMap&) = delete; - - public: - IMap(const IMap&) = default; - IMap(IMap&&) = default; - - class Iterator { - private: - MapFunc map_func; - ZippedIterType zipiter; - - public: - Iterator(MapFunc map_func, ZippedIterType zipiter) : - map_func(map_func), - zipiter(zipiter) - { } - - decltype(auto) operator*() { - return call_with_tuple( - this->map_func, *(this->zipiter)); - } - - Iterator& operator++() { - ++this->zipiter; - return *this; - } - - bool operator!=(const Iterator& other) const { - return this->zipiter != other.zipiter; - } - }; - - Iterator begin() { - return {this->map_func, this->zipped.begin()}; - } - - Iterator end() { - return {this->map_func, this->zipped.end()}; - } - - }; - - // Helper function to instantiate a IMap template - IMap imap( - MapFunc map_func, Containers&& ... containers) { - return {map_func, std::forward(containers)...}; + auto imap(MapFunc map_func, Containers&& ... containers) { + return starmap(map_func, zip(std::forward(containers)...)); } - } #endif // #ifndef ITER_IMAP_H_ From c413262eea9329ed534062f7f83ec54459daa3dc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 23 Oct 2014 11:13:49 -0400 Subject: [PATCH 21/90] Adds braces around array initliazation --- starmap.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starmap.hpp b/starmap.hpp index 920825ec..dadc5884 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -109,7 +109,7 @@ namespace iter { : func(f), tup(std::forward(t)), tuple_getters( - {std::make_unique>(func, tup)...}) + {{std::make_unique>(func, tup)...}}) { } public: From 0d6811c0a1deeb2329830f6bd1efd47f674d8c38 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 23 Oct 2014 11:14:07 -0400 Subject: [PATCH 22/90] Adds braces around array initializations --- tests/teststarmap.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/teststarmap.cpp b/tests/teststarmap.cpp index 992c7ce3..f85bd40d 100644 --- a/tests/teststarmap.cpp +++ b/tests/teststarmap.cpp @@ -59,7 +59,7 @@ void test_tuple_of_tuples() { std::cout << i << '\n'; } - auto tup2 = std::make_tuple(std::array{15, 100, 2000}, + auto tup2 = std::make_tuple(std::array{{15, 100, 2000}}, std::make_tuple(16)); std::cout << "tuple, tuple>\n"; for (auto&& i : starmap(c, tup2)) { @@ -68,7 +68,7 @@ void test_tuple_of_tuples() { std::cout << '\n'; std::cout << "pair, tuple>\n"; - auto p = std::make_pair(std::array{15, 100, 2000}, + auto p = std::make_pair(std::array{{15, 100, 2000}}, std::make_tuple(16)); for (auto&& i : starmap(c, p)) { std::cout << i << '\n'; From 6dc80a1ef247f0cb78206b50822e75de0ae893fa Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 23 Oct 2014 11:16:12 -0400 Subject: [PATCH 23/90] makes absorb() non-templated --- iterbase.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index d0eade82..c60713df 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -112,8 +112,7 @@ namespace iter { // 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&&...) { } + void absorb(...) { } namespace detail { template From 0ce44f35f578feef8536ac5829cf65969c9e80b9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Fri, 24 Oct 2014 10:53:17 -0400 Subject: [PATCH 24/90] uses anonymous template parm in is_tuple_like --- starmap.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starmap.hpp b/starmap.hpp index 920825ec..34b91737 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -163,7 +163,7 @@ namespace iter { // "tag dispatch" to differentiate between normal containers and // tuple-like containers, things that work with std::get - template + template struct is_tuple_like : public std::false_type { }; template From 5fe7c0f381d5e1d1fcd7e4f16f1a7fe772404873 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 28 Oct 2014 16:36:15 -0400 Subject: [PATCH 25/90] Flattens chain Chain is flattened using a similar approach to starmap. A different instantiation of each ChainIterWrapper for each index. This avoids having a nested class structure, and the time to perform operator* doesn't increase as one gets further into the chain. An index keeps track of which iterator we're on each step of the way. It's not very pretty though. --- chain.hpp | 182 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 102 insertions(+), 80 deletions(-) diff --git a/chain.hpp b/chain.hpp index e5df892d..0c75c4c5 100644 --- a/chain.hpp +++ b/chain.hpp @@ -8,128 +8,140 @@ #include #include #include +#include +#include namespace iter { // rather than a chain function, use a callable object to support // from_iterable class ChainMaker; - template + template class Chained { friend class ChainMaker; - template - friend class Chained; private: - Container container; - Chained rest_chained; - Chained(Container container, RestContainers&&... rest) - : container(std::forward(container)), - rest_chained{std::forward(rest)...} - { } + class ChainIterWrapperBase { + protected: + using ResultType = + iterator_deref>; + public: + virtual ~ChainIterWrapperBase() { } + virtual bool operator!=( + const ChainIterWrapperBase&) const = 0; + virtual bool operator==( + const ChainIterWrapperBase&) const = 0; + virtual ResultType operator*() = 0; + virtual ChainIterWrapperBase& operator++() = 0; + }; - public: - class Iterator { + template + class ChainIterWrapper : public ChainIterWrapperBase { private: - using RestIter = - typename Chained::Iterator; iterator_type sub_iter; - const iterator_type sub_end; - RestIter rest_iter; - bool at_end; public: - Iterator(const iterator_type& s_begin, - const iterator_type& s_end, - RestIter rest_iter) - : sub_iter{s_begin}, - sub_end{s_end}, - rest_iter{rest_iter}, - at_end{!(sub_iter != sub_end)} + ChainIterWrapper(const iterator_type& iter) + : sub_iter{iter} { } - - Iterator& operator++() { - if (this->at_end) { - ++this->rest_iter; - } else { - ++this->sub_iter; - if (!(this->sub_iter != this->sub_end)) { - this->at_end = true; - } - } - return *this; + + bool operator!=(const ChainIterWrapperBase& other) + const override { + return this->sub_iter != + static_cast( + other).sub_iter; } - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter || - this->rest_iter != other.rest_iter; + bool operator==(const ChainIterWrapperBase& other) + const override { + return !(*this != + static_cast(other)); } - iterator_deref operator*() { - return this->at_end ? - *this->rest_iter : *this->sub_iter; + typename ChainIterWrapper::ResultType operator*() { + return *this->sub_iter; } - }; - Iterator begin() { - return {std::begin(this->container), - std::end(this->container), - std::begin(this->rest_chained)}; - } + ChainIterWrapper& operator++() override { + ++this->sub_iter; + return *this; + } + }; - Iterator end() { - return {std::end(this->container), - std::end(this->container), - std::end(this->rest_chained)}; - } - }; - template - class Chained { - friend class ChainMaker; - template - friend class Chained; private: - Container container; - Chained(Container container) - : container(std::forward(container)) + using ArrayType = + std::array, + sizeof...(Is)>; + TupleType containers; + ArrayType end_iter_wrappers; + + Chained(TupleType&& tup_containers) + : containers(std::move(tup_containers)), + end_iter_wrappers{{std::make_unique< + ChainIterWrapper>>( + std::end(std::get(this->containers)))...}} { } public: class Iterator { private: - iterator_type sub_iter; - const iterator_type sub_end; + using ArrayType = + std::array, + sizeof...(Is)>; + + ArrayType iter_wrappers; + const ArrayType& end_iter_wrappers; + std::size_t index; + + void check_index() { + while (this->index < iter_wrappers.size() + && *this->iter_wrappers[this->index] + == *this->end_iter_wrappers[this->index]) { + ++this->index; + } + } + public: - Iterator(const iterator_type& s_begin, - const iterator_type& s_end) - : sub_iter{s_begin}, - sub_end{s_end} - { } - + Iterator(ArrayType&& iters, ArrayType& ends, std::size_t i) + : iter_wrappers(std::move(iters)), + end_iter_wrappers(ends), + index{i} + { + this->check_index(); + } + Iterator& operator++() { - ++this->sub_iter; + ++*this->iter_wrappers[this->index]; + this->check_index(); return *this; } - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; + decltype(auto) operator*() { + return **this->iter_wrappers[this->index]; } - iterator_deref operator*() { - return *this->sub_iter; + bool operator!=(const Iterator& other) const { + return this->index != other.index; } }; + Iterator begin() { - return {std::begin(this->container), - std::end(this->container)}; + ArrayType a{{ + std::make_unique< + ChainIterWrapper>>( + std::begin(std::get(this->containers)) + )...}}; + return {std::move(a), end_iter_wrappers, 0}; } Iterator end() { - return {std::end(this->container), - std::end(this->container)}; + ArrayType a{{std::unique_ptr< + ChainIterWrapper>>{ + nullptr}...}}; + return {std::move(a), end_iter_wrappers, sizeof...(Is)}; } }; @@ -179,7 +191,6 @@ namespace iter { } return *this; } - bool operator!=(const Iterator& other) const { return this->top_level_iter != other.top_level_iter && @@ -203,11 +214,22 @@ namespace iter { class ChainMaker { + private: + template + Chained chain_impl( + TupleType&& in_containers, + std::index_sequence) const { + return {std::move(in_containers)}; + } + public: // expose regular call operator to provide usual chain() template - Chained operator()(Containers&&... cs) const { - return {std::forward(cs)...}; + auto operator()(Containers&&... cs) const { + return this->chain_impl( + std::tuple{ + std::forward(cs)...}, + std::index_sequence_for{}); } // chain.from_iterable From 0305423f4079880456fc66a0d78d538bcaaac6a3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 9 Nov 2014 23:46:20 -0500 Subject: [PATCH 26/90] adds chain iterator copy ctor --- chain.hpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/chain.hpp b/chain.hpp index d116fcd4..70e1b2f7 100644 --- a/chain.hpp +++ b/chain.hpp @@ -106,12 +106,21 @@ namespace iter { public: Iterator(ArrayType&& iters, ArrayType& ends, std::size_t i) : iter_wrappers(std::move(iters)), - end_iter_wrappers(ends), + end_iter_wrappers{ends}, index{i} { this->check_index(); } + Iterator(const Iterator& other) + : iter_wrappers{{ + // make this not so awful. + std::unique_ptr{new ChainIterWrapper>(dynamic_cast>&>(*std::get(other.iter_wrappers)))}... + }}, + end_iter_wrappers{other.end_iter_wrappers}, + index{other.index} + { } + Iterator& operator++() { ++*this->iter_wrappers[this->index]; this->check_index(); From 300caf936f7ded86b6a3d5579c1942e7dfbee60d Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 11 Nov 2014 23:55:01 -0500 Subject: [PATCH 27/90] Replaces polymorphic solution with std::functions ..which are also polymorphic, but it allows for a single const static array per instatiation of TupleStarMapper --- iterbase.hpp | 4 ++ starmap.hpp | 115 +++++++++++++++++++++++++-------------------------- 2 files changed, 60 insertions(+), 59 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index d0eade82..5564bcb8 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -134,6 +134,10 @@ namespace iter { std::make_index_sequence{}); } + // this will eventually make it into the standard, but for now: + template + using void_t = void; + } #endif // #ifndef ITERBASE_HPP_ diff --git a/starmap.hpp b/starmap.hpp index 34b91737..272753e6 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -59,81 +59,56 @@ namespace iter { template StarMapper starmap_helper( - Func func, Container&& container, std::false_type) { - return {func, std::forward(container)}; + Func&& func, Container&& container, std::false_type) { + return {std::forward(func), std::forward(container)}; } // starmap for a tuple or pair of tuples or pairs - template >::value> + template class TupleStarMapper { private: - class TupleExpanderBase { - protected: - // deduced return type to return of Func when called with - // one of TupleType - using ResultType = - decltype(call_with_tuple( - std::declval(), - std::get<0>(std::declval()))); - public: - virtual ResultType call() = 0; + Func func; + TupType tup; - virtual ~TupleExpanderBase() { } - }; + private: + static_assert(sizeof...(Is) + == std::tuple_size>::value, + "tuple size doesn't match size of Is"); template - class TupleExpander : public TupleExpanderBase { - private: - Func func; - TupleType& tup; - public: - TupleExpander(Func f, TupleType& t) - : func(f), - tup(t) - { } + static decltype(auto) get_and_call_with_tuple(Func& f, TupType &t){ + return call_with_tuple(f, std::get(t)); + } - typename TupleExpanderBase::ResultType call() override { - return call_with_tuple( - this->func, std::get(this->tup)); - } - }; + using v = + void_t(func, tup))...>; - private: - Func func; - TupleType tup; - std::array, Size> tuple_getters; + using ResultType = decltype(get_and_call_with_tuple<0>(func, tup)); + using CallerFunc = std::function; - template - TupleStarMapper(Func f, TupleType t, std::index_sequence) - : func(f), - tup(std::forward(t)), - tuple_getters( - {std::make_unique>(func, tup)...}) - { } + const static std::array callers; public: - TupleStarMapper(Func f, TupleType t) - : TupleStarMapper(f, std::forward(t), - std::make_index_sequence{}) + TupleStarMapper(Func f, TupType t) + : func(std::forward(f)), + tup(std::forward(t)) { } class Iterator { private: - std::array, Size>& - tuple_getters; + Func& func; + TupType& tup; std::size_t index; public: - Iterator(std::array< - std::unique_ptr, Size>& tg, - std::size_t i) - : tuple_getters(tg), + Iterator(Func& f, TupType& t, std::size_t i) + : func{f}, + tup{t}, index{i} { } decltype(auto) operator*() { - return this->tuple_getters[this->index]->call(); + return callers[this->index](this->func, this->tup); } Iterator operator++() { @@ -147,20 +122,41 @@ namespace iter { }; Iterator begin() { - return {this->tuple_getters, 0}; + return {this->func, this->tup, 0}; } Iterator end() { - return {this->tuple_getters, Size}; + return {this->func, this->tup, sizeof...(Is)}; } }; + // initialize array with a caller function for each index + template + const std::array< + typename TupleStarMapper::CallerFunc, + sizeof...(Is)> + TupleStarMapper::callers{{ + get_and_call_with_tuple...}}; - template - TupleStarMapper starmap_helper( - Func func, TupleType&& tup, std::true_type) { - return {func, std::forward(tup)}; + + + template + TupleStarMapper starmap_helper_impl( + Func&& func, TupType&& tup, std::index_sequence) + { + return {std::forward(func), std::forward(tup)}; } + template + auto starmap_helper( + Func&& func, TupType&& tup, std::true_type) { + return starmap_helper_impl( + std::forward(func), + std::forward(tup), + std::make_index_sequence< + std::tuple_size>::value>{}); + } + + // "tag dispatch" to differentiate between normal containers and // tuple-like containers, things that work with std::get template @@ -171,9 +167,10 @@ namespace iter { : public std::true_type { }; template - auto starmap(Func func, Seq&& sequence) { + auto starmap(Func&& func, Seq&& sequence) { return starmap_helper( - func, std::forward(sequence), + std::forward(func), + std::forward(sequence), is_tuple_like{}); } } From 7d878e57fd1521a7ea29bd6f0d6d077d3a61e893 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Nov 2014 00:08:51 -0500 Subject: [PATCH 28/90] Computes callers as constexpr I did it constexpr. I'm pretty happy with this, I can't see it getting much better outside of not writing the code at all. --- iterbase.hpp | 4 ---- starmap.hpp | 14 +++++--------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 5564bcb8..d0eade82 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -134,10 +134,6 @@ namespace iter { std::make_index_sequence{}); } - // this will eventually make it into the standard, but for now: - template - using void_t = void; - } #endif // #ifndef ITERBASE_HPP_ diff --git a/starmap.hpp b/starmap.hpp index 272753e6..4a41cba9 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -80,13 +80,11 @@ namespace iter { return call_with_tuple(f, std::get(t)); } - using v = - void_t(func, tup))...>; - using ResultType = decltype(get_and_call_with_tuple<0>(func, tup)); - using CallerFunc = std::function; + using CallerFunc = ResultType (*)(Func&, TupType&); - const static std::array callers; + constexpr static std::array callers{{ + get_and_call_with_tuple...}}; public: TupleStarMapper(Func f, TupType t) @@ -129,13 +127,11 @@ namespace iter { return {this->func, this->tup, sizeof...(Is)}; } }; - // initialize array with a caller function for each index template - const std::array< + constexpr std::array< typename TupleStarMapper::CallerFunc, sizeof...(Is)> - TupleStarMapper::callers{{ - get_and_call_with_tuple...}}; + TupleStarMapper::callers; From 56b5a6498b9d430d65bb2507be62faa971be9cef Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Nov 2014 21:08:58 -0500 Subject: [PATCH 29/90] adds test for iterator assignment to chain --- tests/testchain.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/testchain.cpp b/tests/testchain.cpp index 19ab374d..3dfde3d1 100644 --- a/tests/testchain.cpp +++ b/tests/testchain.cpp @@ -19,6 +19,11 @@ int main() { for (auto e : chain(ivec, lvec)) { std::cout << e << std::endl; } + + auto c = chain(ivec, lvec); + auto it = std::begin(c); + auto it2 = std::begin(c); + it = it2; } { std::vector empty{}; @@ -58,4 +63,5 @@ int main() { std::cout << i << '\n'; } } + } From 3dabc8757c0865cc3824f13534e4356f8a734daf Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Nov 2014 21:10:37 -0500 Subject: [PATCH 30/90] Uses constexpr array of funcion pointers for chain Instead of the polymorphism and the base class, I was able to use a similar approach as in starmap to get chain to act more dynamic than it really is. Starmap needed only one set of function pointers, for the dereferencing, chain is admittedly more complicated because it needs one for each operation that must be performed per iterator. --- chain.hpp | 259 ++++++++++++++++++++++++++---------------------------- 1 file changed, 124 insertions(+), 135 deletions(-) diff --git a/chain.hpp b/chain.hpp index 70e1b2f7..f73db8e3 100644 --- a/chain.hpp +++ b/chain.hpp @@ -3,156 +3,145 @@ #include "iterbase.hpp" -#include +#include +#include #include #include -#include -#include #include -#include +#include +#include namespace iter { // rather than a chain function, use a callable object to support // from_iterable class ChainMaker; - template - class Chained { +template +class Chained { + private: friend class ChainMaker; - private: - class ChainIterWrapperBase { - protected: - using ResultType = - iterator_deref>; - public: - virtual ~ChainIterWrapperBase() { } - virtual bool operator!=( - const ChainIterWrapperBase&) const = 0; - virtual bool operator==( - const ChainIterWrapperBase&) const = 0; - virtual ResultType operator*() = 0; - virtual ChainIterWrapperBase& operator++() = 0; - }; - - template - class ChainIterWrapper : public ChainIterWrapperBase { - private: - iterator_type sub_iter; - - public: - ChainIterWrapper(const iterator_type& iter) - : sub_iter{iter} - { } - - bool operator!=(const ChainIterWrapperBase& other) - const override { - return this->sub_iter != - static_cast( - other).sub_iter; - } - - bool operator==(const ChainIterWrapperBase& other) - const override { - return !(*this != - static_cast(other)); - } - - typename ChainIterWrapper::ResultType operator*() { - return *this->sub_iter; - } - - ChainIterWrapper& operator++() override { - ++this->sub_iter; - return *this; + static_assert(std::tuple_size>::value + == sizeof...(Is), + "tuple size != sizeof Is"); + + using IterTupType = iterator_tuple_type; + + using DerefType = + iterator_deref>; + + template + static DerefType get_and_deref(IterTupType& iters) { + return *std::get(iters); + } + + template + static void get_and_increment(IterTupType& iters) { + ++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 IncFunc = void (*)(IterTupType&); + using NeqFunc = bool (*)(const IterTupType&, const IterTupType&); + + + constexpr static std::array derefers{{ + get_and_deref...}}; + + constexpr static std::array incrementers{{ + get_and_increment...}}; + + constexpr static std::array neq_comparers{{ + get_and_check_not_equal...}}; + + private: + TupType tup; + public: + Chained(TupType t) + : tup(t) + { } + + class Iterator { + private: + 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; } + } + 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(); + } + + decltype(auto) operator*() { + return derefers[this->index](this->iters); + } + + Iterator& operator++() { + incrementers[this->index](this->iters); + this->check_for_end_and_adjust(); + return *this; + } + + bool operator!=(const Iterator& other) const { + return this->index != other.index + || (this->index != sizeof...(Is) + && neq_comparers.at(this->index)( + this->iters,other.iters)); + } + + + }; + + Iterator begin() { + return { + 0, + IterTupType{std::begin(std::get(this->tup))...}, + IterTupType{std::end(std::get(this->tup))...} }; + } - - private: - using ArrayType = - std::array, - sizeof...(Is)>; - TupleType containers; - ArrayType end_iter_wrappers; - - Chained(TupleType&& tup_containers) - : containers(std::move(tup_containers)), - end_iter_wrappers{{std::make_unique< - ChainIterWrapper>>( - std::end(std::get(this->containers)))...}} - { } - - public: - class Iterator { - private: - using ArrayType = - std::array, - sizeof...(Is)>; - - ArrayType iter_wrappers; - const ArrayType& end_iter_wrappers; - std::size_t index; - - void check_index() { - while (this->index < iter_wrappers.size() - && *this->iter_wrappers[this->index] - == *this->end_iter_wrappers[this->index]) { - ++this->index; - } - } - - - public: - Iterator(ArrayType&& iters, ArrayType& ends, std::size_t i) - : iter_wrappers(std::move(iters)), - end_iter_wrappers{ends}, - index{i} - { - this->check_index(); - } - - Iterator(const Iterator& other) - : iter_wrappers{{ - // make this not so awful. - std::unique_ptr{new ChainIterWrapper>(dynamic_cast>&>(*std::get(other.iter_wrappers)))}... - }}, - end_iter_wrappers{other.end_iter_wrappers}, - index{other.index} - { } - - Iterator& operator++() { - ++*this->iter_wrappers[this->index]; - this->check_index(); - return *this; - } - - decltype(auto) operator*() { - return **this->iter_wrappers[this->index]; - } - - bool operator!=(const Iterator& other) const { - return this->index != other.index; - } + Iterator end() { + return { + sizeof...(Is), + IterTupType{std::end(std::get(this->tup))...}, + IterTupType{std::end(std::get(this->tup))...} }; - - - Iterator begin() { - ArrayType a{{ - std::make_unique< - ChainIterWrapper>>( - std::begin(std::get(this->containers)) - )...}}; - return {std::move(a), end_iter_wrappers, 0}; - } - - Iterator end() { - ArrayType a{{std::unique_ptr< - ChainIterWrapper>>{ - nullptr}...}}; - return {std::move(a), end_iter_wrappers, sizeof...(Is)}; - } - }; + } +}; + +template +constexpr std::array< + typename Chained::DerefFunc, sizeof...(Is)> + Chained::derefers; + +template +constexpr std::array< + typename Chained::IncFunc, sizeof...(Is)> + Chained::incrementers; + +template +constexpr std::array< + typename Chained::NeqFunc, sizeof...(Is)> + Chained::neq_comparers; template class ChainedFromIterable { From fbaab61bfeb222cad67b6956a8a35a02a54f2c07 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Nov 2014 21:19:45 -0500 Subject: [PATCH 31/90] Makes absorb take universal refs again Because with just absorb(...) it tries to make copies, which makes sense. --- iterbase.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iterbase.hpp b/iterbase.hpp index c60713df..d0eade82 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -112,7 +112,8 @@ namespace iter { // function absorbing all arguments passed to it. used when // applying a function to a parameter pack but not passing the evaluated // results anywhere - void absorb(...) { } + template + void absorb(Ts&&...) { } namespace detail { template From b312fa0e4e54d3fa0d333b4f71b72c5f91fa6660 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 12 Nov 2014 21:30:38 -0500 Subject: [PATCH 32/90] replaces only .at() with [] --- chain.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain.hpp b/chain.hpp index f73db8e3..50299693 100644 --- a/chain.hpp +++ b/chain.hpp @@ -104,7 +104,7 @@ class Chained { bool operator!=(const Iterator& other) const { return this->index != other.index || (this->index != sizeof...(Is) - && neq_comparers.at(this->index)( + && neq_comparers[this->index]( this->iters,other.iters)); } From 13924b0724677e4af38a03d86272172d31244a79 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 17:03:19 -0500 Subject: [PATCH 33/90] uses -std=c++14 --- catchtest/SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index 0a8c1e35..cd23626e 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -4,7 +4,7 @@ env = Environment( ENV = os.environ, CXX='c++', CXXFLAGS= ['-g', '-Wall', '-Wextra', - '-pedantic', '-std=c++11', + '-pedantic', '-std=c++14', '-fdiagnostics-color=always', '-I/usr/local/include'], CPPPATH='..', From 79b89521e50e2b1ca1f0d681c1c6f5efd1b47743 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 17:03:46 -0500 Subject: [PATCH 34/90] corrects error in section description --- catchtest/test_imap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catchtest/test_imap.cpp b/catchtest/test_imap.cpp index ba9ae171..9f7b8e4d 100644 --- a/catchtest/test_imap.cpp +++ b/catchtest/test_imap.cpp @@ -48,7 +48,7 @@ TEST_CASE("imap: works with lambda, callable, and function", "[imap]") { REQUIRE( v == vc ); } - SECTION("with function") { + SECTION("with callable") { auto im = imap(PlusOner{}, ns); Vec v(std::begin(im), std::end(im)); Vec vc = {11, 21, 31}; From bb76192dafeb4555f1937b326c779e7a13d7bbbe Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 17:08:08 -0500 Subject: [PATCH 35/90] drops references to functions, derives stditerator --- starmap.hpp | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index 4a41cba9..8ff04994 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -4,30 +4,39 @@ #include "iterbase.hpp" #include +#include #include #include #include #include namespace iter { + // starmap with a container where T is one of tuple, pair, array template class StarMapper { private: Func func; Container container; + + using StarIterDeref = + std::remove_reference_t>()))>; + public: - StarMapper(Func f, Container c) - : func(f), + StarMapper(Func f, Container&& c) + : func(std::forward(f)), container(std::forward(c)) { } - class Iterator { + class Iterator + : public std::iterator + { private: Func func; iterator_type sub_iter; public: - Iterator(Func f, iterator_type iter) + Iterator(Func& f, iterator_type iter) : func(f), sub_iter(iter) { } @@ -36,11 +45,21 @@ namespace iter { return this->sub_iter != other.sub_iter; } + bool operator==(const Iterator& other) const { + return !(*this != other); + } + Iterator operator++() { ++this->sub_iter; return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + decltype(auto) operator*() { return call_with_tuple(this->func, *this->sub_iter); } @@ -59,7 +78,7 @@ namespace iter { template StarMapper starmap_helper( - Func&& func, Container&& container, std::false_type) { + Func func, Container&& container, std::false_type) { return {std::forward(func), std::forward(container)}; } @@ -92,6 +111,7 @@ namespace iter { tup(std::forward(t)) { } + // TODO inherit from std::iterator class Iterator { private: Func& func; @@ -137,14 +157,14 @@ namespace iter { template TupleStarMapper starmap_helper_impl( - Func&& func, TupType&& tup, std::index_sequence) + Func func, TupType&& tup, std::index_sequence) { return {std::forward(func), std::forward(tup)}; } template auto starmap_helper( - Func&& func, TupType&& tup, std::true_type) { + Func func, TupType&& tup, std::true_type) { return starmap_helper_impl( std::forward(func), std::forward(tup), @@ -163,7 +183,7 @@ namespace iter { : public std::true_type { }; template - auto starmap(Func&& func, Seq&& sequence) { + auto starmap(Func func, Seq&& sequence) { return starmap_helper( std::forward(func), std::forward(sequence), @@ -171,7 +191,4 @@ namespace iter { } } - - - -#endif // #ifndef ITER_STARMAP_H_ +#endif From b9c5e27e62b263405dd610282f409f0bc1191376 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 17:24:57 -0500 Subject: [PATCH 36/90] adds basic starmap test --- catchtest/test_starmap.cpp | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 catchtest/test_starmap.cpp diff --git a/catchtest/test_starmap.cpp b/catchtest/test_starmap.cpp new file mode 100644 index 00000000..015b966e --- /dev/null +++ b/catchtest/test_starmap.cpp @@ -0,0 +1,42 @@ +#include + +#include "helpers.hpp" + +#include +#include +#include + +#include "catch.hpp" + +using iter::starmap; + +namespace { + long f(long d, int i) { + return d * i; + } + + std::string g(const std::string& s, int i, double d) { + std::stringstream ss; + ss << s << ' ' << i << ' ' << d; + return ss.str(); + } +} + +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}; + + SECTION("with function") { + auto sm = starmap(f, v1); + Vec v(std::begin(sm), std::end(sm)); + REQUIRE( v == vc ); + } + + SECTION("with lambda") { + auto sm = starmap([](long a, int b) { return a * b; }, v1); + Vec v(std::begin(sm), std::end(sm)); + REQUIRE( v == vc ); + } +} From 0a408fecc5900cfe6b09694d69ad0e4791cfb29f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 17:32:55 -0500 Subject: [PATCH 37/90] builds starmap test --- catchtest/SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/catchtest/SConstruct b/catchtest/SConstruct index cd23626e..36e14df3 100644 --- a/catchtest/SConstruct +++ b/catchtest/SConstruct @@ -38,6 +38,7 @@ progs = Split( slice sliding_window + starmap takewhile unique_everseen unique_justseen From d248ba210a63182f0b60553750ec529a2d2c1591 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 17:33:04 -0500 Subject: [PATCH 38/90] tests starmap a bit harder --- catchtest/test_starmap.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/catchtest/test_starmap.cpp b/catchtest/test_starmap.cpp index 015b966e..e3e091a0 100644 --- a/catchtest/test_starmap.cpp +++ b/catchtest/test_starmap.cpp @@ -3,6 +3,7 @@ #include "helpers.hpp" #include +#include #include #include @@ -15,9 +16,9 @@ namespace { return d * i; } - std::string g(const std::string& s, int i, double d) { + std::string g(const std::string& s, int i, char c) { std::stringstream ss; - ss << s << ' ' << i << ' ' << d; + ss << s << ' ' << i << ' ' << c; return ss.str(); } } @@ -40,3 +41,16 @@ TEST_CASE("starmap: works with function pointer and lambda", "[starmap]") { REQUIRE( v == vc ); } } + +TEST_CASE("starmap: list of tuples", "[starmap]") { + using Vec = const std::vector; + using T = std::tuple; + std::list li = + {T{"hey", 42, 'a'}, T{"there", 3, 'b'}, T{"yall", 5, 'c'}}; + + auto sm = starmap(g, li); + Vec v(std::begin(sm), std::end(sm)); + Vec vc = {"hey 42 a", "there 3 b", "yall 5 c"}; + + REQUIRE( v == vc ); +} From d567e4513cfbd59c9b4428c9d938d161a7fd0401 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 17:47:27 -0500 Subject: [PATCH 39/90] tests starmap with a tuple of tuples --- catchtest/test_starmap.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/catchtest/test_starmap.cpp b/catchtest/test_starmap.cpp index e3e091a0..378a8286 100644 --- a/catchtest/test_starmap.cpp +++ b/catchtest/test_starmap.cpp @@ -21,6 +21,16 @@ namespace { ss << s << ' ' << i << ' ' << c; return ss.str(); } + + struct Callable { + int operator()(int a, int b, int c) { + return a + b + c; + } + + int operator()(int a) { + return a; + } + }; } TEST_CASE("starmap: works with function pointer and lambda", "[starmap]") { @@ -54,3 +64,13 @@ TEST_CASE("starmap: list of tuples", "[starmap]") { REQUIRE( v == vc ); } + +TEST_CASE("starmap: tuple of tuples", "[starmap]") { + using Vec = const std::vector; + auto tup = std::make_tuple(std::make_tuple(10, 19, 60),std::make_tuple(7)); + auto sm = starmap(Callable{}, tup); + Vec v(std::begin(sm), std::end(sm)); + Vec vc = {89, 7}; + + REQUIRE( v == vc ); +} From a39975c5334e809178205e03a1ac8f979d12bdcc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 17:47:41 -0500 Subject: [PATCH 40/90] TupleStarMapper iter derives std::iterator --- starmap.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index 8ff04994..3f8a64e2 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -105,14 +105,16 @@ namespace iter { constexpr static std::array callers{{ get_and_call_with_tuple...}}; + using TraitsValue = std::remove_reference_t; public: TupleStarMapper(Func f, TupType t) : func(std::forward(f)), tup(std::forward(t)) { } - // TODO inherit from std::iterator - class Iterator { + class Iterator + : public std::iterator + { private: Func& func; TupType& tup; From c7a08e30eb52d37bed0fee2e0c4dd2e3a2bb523b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 18:52:17 -0500 Subject: [PATCH 41/90] tests starmap with pair of array and tuple --- catchtest/test_starmap.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/catchtest/test_starmap.cpp b/catchtest/test_starmap.cpp index 378a8286..fc59fd18 100644 --- a/catchtest/test_starmap.cpp +++ b/catchtest/test_starmap.cpp @@ -74,3 +74,16 @@ TEST_CASE("starmap: tuple of tuples", "[starmap]") { REQUIRE( v == vc ); } + +TEST_CASE("starmap: tuple of pairs", "[starmap]") { + using Vec = const std::vector; + auto p = std::make_pair(std::array{{15, 100, 2000}}, + std::make_tuple(16)); + Callable c; + auto sm = starmap(c, p); + + Vec v(std::begin(sm), std::end(sm)); + Vec vc = {2115, 16}; + + REQUIRE( v == vc ); +} From 1c63201569b195f3f3b05247444ac7c3f44cbae3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 20:21:13 -0500 Subject: [PATCH 42/90] flattens zip longest --- zip_longest.hpp | 161 +++++++++++++++++++----------------------------- 1 file changed, 62 insertions(+), 99 deletions(-) diff --git a/zip_longest.hpp b/zip_longest.hpp index cc6705b9..98b20ec4 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -11,65 +11,51 @@ namespace iter { - template - using OptIterDeref = boost::optional>; - - template + template class ZippedLongest; - template - ZippedLongest zip_longest(Containers&&...); + template + ZippedLongest + zip_longest_impl(TupleType&&, std::index_sequence); - template - class ZippedLongest { - static_assert(!std::is_rvalue_reference::value, - "Itertools cannot be templated with rvalue references"); + template + class ZippedLongest { + private: + TupleType containers; + friend ZippedLongest zip_longest_impl( + TupleType&&, std::index_sequence); - friend ZippedLongest zip_longest( - Container&&, RestContainers&&...); + template + using OptType = boost::optional>>; - template - friend class ZippedLongest; + using ZipIterDeref = std::tuple...>; - private: - using OptType = OptIterDeref; - using ZipIterDeref = - std::tuple...>; - - Container container; - ZippedLongest rest_zipped; - ZippedLongest(Container&& container, RestContainers&&... rest) - : container(std::forward(container)), - rest_zipped{std::forward(rest)...} + ZippedLongest(TupleType&& in_containers) + : containers(std::move(in_containers)) { } - public: class Iterator : public std::iterator { private: - using RestIter = - typename ZippedLongest::Iterator; - - iterator_type iter; - iterator_type end; - RestIter rest_iter; + iterator_tuple_type iters; + iterator_tuple_type ends; public: - Iterator( - iterator_type it, - iterator_type in_end, - const RestIter& rest) - : iter{it}, - end{in_end}, - rest_iter{rest} + Iterator(iterator_tuple_type&& in_iters, + iterator_tuple_type&& in_ends) + : iters(std::move(in_iters)), + ends(std::move(in_ends)) { } Iterator& operator++() { - if (this->iter != this->end) { - ++this->iter; - } - ++this->rest_iter; + // increment every iterator that's not already at + // the end + absorb( + ((std::get(this->iters) != + std::get(this->ends)) ? + (++std::get(this->iters), 0) : 0)...); return *this; } @@ -80,8 +66,15 @@ namespace iter { } bool operator!=(const Iterator& other) const { - return this->iter != other.iter || - this->rest_iter != other.rest_iter; + if (sizeof...(Is) == 0) return false; + + bool results[] = { false, + (std::get(this->iters) != + std::get(other.iters))... + }; + return std::any_of( + std::begin(results), std::end(results), + [](bool b){ return b; } ); } bool operator==(const Iterator& other) const { @@ -89,72 +82,42 @@ namespace iter { } ZipIterDeref operator*() { - if (this->iter != this->end) { - return std::tuple_cat( - std::tuple{{*this->iter}}, - *this->rest_iter); - } else { - return std::tuple_cat( - std::tuple{{}}, - *this->rest_iter); - } + return ZipIterDeref{ + ((std::get(this->iters) != + std::get(this->ends)) + ? OptType{*std::get(this->iters)} + : OptType{})...}; } }; Iterator begin() { - return {std::begin(this->container), - std::end(this->container), - std::begin(this->rest_zipped)}; + return { + iterator_tuple_type{ + std::begin(std::get(this->containers))...}, + iterator_tuple_type{ + std::end(std::get(this->containers))...}}; } Iterator end() { - return {std::end(this->container), - std::end(this->container), - std::end(this->rest_zipped)}; + return { + iterator_tuple_type{ + std::end(std::get(this->containers))...}, + iterator_tuple_type{ + std::end(std::get(this->containers))...}}; } - }; - - - template <> - class ZippedLongest<> { - public: - class Iterator - : public std::iterator> - { - public: - Iterator& operator++() { - return *this; - } +}; - constexpr Iterator operator++(int) { - return *this; - } - - constexpr bool operator!=(const Iterator&) const { - return false; - } - - constexpr bool operator==(const Iterator&) const { - return true; - } - - constexpr std::tuple<> operator*() { - return {}; - } - }; - - constexpr Iterator begin() { - return {}; - } - - constexpr Iterator end() { - return {}; - } - }; + template + ZippedLongest zip_longest_impl( + TupleType&& in_containers, std::index_sequence) { + return {std::move(in_containers)}; + } template - ZippedLongest zip_longest(Containers&&... containers) { - return {std::forward(containers)...}; + auto zip_longest(Containers&&... containers) { + return zip_longest_impl(std::tuple{ + std::forward(containers)...}, + std::index_sequence_for{}); } } From f95dba8572ec2600b1b83b95f5b39d415be45822 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 20:40:05 -0500 Subject: [PATCH 43/90] uses c++14 type aliases --- accumulate.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index 8df2e409..c57d177c 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -38,10 +38,10 @@ namespace iter { // AccumVal must be default constructible using AccumVal = - typename std::remove_reference< - typename std::result_of, - iterator_deref)>::type>::type; + iterator_deref)>>; static_assert( std::is_default_constructible::value, "Cannot accumulate a non-default constructible type"); @@ -125,12 +125,12 @@ namespace iter { template auto accumulate(Container&& container) -> decltype(accumulate(std::forward(container), - std::plus>::type>{})) + std::plus>>{})) { return accumulate(std::forward(container), - std::plus>::type>{}); + std::plus>>{}); } template From 0fd65dfc500c654823c977f0261fa456fab9c67b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 20:41:09 -0500 Subject: [PATCH 44/90] uses c++14 type aliases --- combinations.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/combinations.hpp b/combinations.hpp index a2cfeda2..6f8b3dd9 100644 --- a/combinations.hpp +++ b/combinations.hpp @@ -46,7 +46,7 @@ namespace iter { { private: constexpr static const int COMPLETE = -1; - typename std::remove_reference::type *container_p; + std::remove_reference_t *container_p; CombIteratorDeref indices; int steps{}; From 36f8e3856c71cb044bbe95e4a0f56dd15aacc6be Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 20:41:58 -0500 Subject: [PATCH 45/90] uses c++14 type aliases --- combinations_with_replacement.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/combinations_with_replacement.hpp b/combinations_with_replacement.hpp index bfb8a9b1..96ea9af0 100644 --- a/combinations_with_replacement.hpp +++ b/combinations_with_replacement.hpp @@ -52,7 +52,7 @@ namespace iter { { private: constexpr static const int COMPLETE = -1; - typename std::remove_reference::type *container_p; + std::remove_reference_t *container_p; CombIteratorDeref indices; int steps; From 516e707db264ee6544cab39e0a539547bc661bf0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 20:43:10 -0500 Subject: [PATCH 46/90] uses c++14 type aliases --- groupby.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index 42768202..dcda1fda 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -32,8 +32,8 @@ namespace iter { friend GroupBy, KF> groupby( std::initializer_list, KF); - using key_func_ret = typename - std::result_of)>::type; + using key_func_ret = + std::result_of_t)>; GroupBy(Container&& container, KeyFunc key_func) : container(std::forward(container)), From e31a0db04317d4328fabd796f00c632e9a768648 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 20:47:45 -0500 Subject: [PATCH 47/90] uses c++14 type aliases --- iterbase.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 52f5d807..95f369ef 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -30,7 +30,7 @@ namespace iter { template using iterator_traits_deref = - typename std::remove_reference>::type; + std::remove_reference_t>; // iterator_type is the type of C's iterator template @@ -48,11 +48,11 @@ namespace iter { template struct is_random_access_iter::iterator_category, - std::random_access_iterator_tag>::value, - void>::type> : std::true_type { }; + std::random_access_iterator_tag>::value + >> : std::true_type { }; template using has_random_access_iter = is_random_access_iter>; From 3d3a0ec9767059ed8854d79f854cfe66b5032517 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 20:49:55 -0500 Subject: [PATCH 48/90] uses c++14 type aliases --- powerset.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerset.hpp b/powerset.hpp index 964b0651..eb58f909 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -29,7 +29,7 @@ namespace iter { std::input_iterator_tag, CombinatorType> { private: - typename std::remove_reference::type *container_p; + std::remove_reference_t *container_p; std::size_t set_size; std::unique_ptr comb; iterator_type comb_iter; From 2651b6603849b7d64e5ddbe930cc82f4fccdd617 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 20:53:23 -0500 Subject: [PATCH 49/90] shortens tag dispatch --- range.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/range.hpp b/range.hpp index f0e7048c..9ce252b8 100644 --- a/range.hpp +++ b/range.hpp @@ -121,7 +121,7 @@ namespace iter { // So, if an iterator is not equal to that, it is valid bool operator!=(const Iterator& other) const { return not_equal_to( - other, typename std::is_unsigned::type()); + other, std::is_unsigned{}); } bool operator==(const Iterator& other) const { From ead0e699bc642348372395485ae29f835b004094 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 20:54:21 -0500 Subject: [PATCH 50/90] uses c++14 type aliases --- repeat.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repeat.hpp b/repeat.hpp index 03ecadce..7a9c6adc 100644 --- a/repeat.hpp +++ b/repeat.hpp @@ -24,7 +24,7 @@ namespace iter { friend Repeater repeat(T&&); friend Repeater repeat(T&&, int); private: - using TPlain = typename std::remove_reference::type; + using TPlain = std::remove_reference_t; T elem; int count; From 816e70054fbcd3ae8692eed087ffa46d4b9755dc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sun, 8 Feb 2015 21:22:03 -0500 Subject: [PATCH 51/90] uses auto funcs and init capture --- unique_everseen.hpp | 47 ++++++++++++++------------------------------- 1 file changed, 14 insertions(+), 33 deletions(-) diff --git a/unique_everseen.hpp b/unique_everseen.hpp index ec95eb34..6a095fe6 100644 --- a/unique_everseen.hpp +++ b/unique_everseen.hpp @@ -10,45 +10,26 @@ #include #include -namespace iter -{ - //the container type must be usable in an unordered_map to achieve constant - //performance checking if it has ever been seen +namespace iter { template - auto unique_everseen(Container&& container) - -> Filter)>,Container> - { - using elem_t = iterator_deref; - std::unordered_set::type> elem_seen; - - std::function func = - //has to be captured by value because it goes out of scope when the - //function returns - [elem_seen](elem_t e) mutable - { - if (elem_seen.find(e) == std::end(elem_seen)){ - elem_seen.insert(e); - return true; - } else { - return false; - } + auto unique_everseen(Container&& container) { + using elem_type = iterator_deref; + auto func = + [ + elem_seen = std::unordered_set>() + ] (const elem_type& e) mutable { + return elem_seen.insert(e).second; }; return filter(func, std::forward(container)); } template - auto unique_everseen(std::initializer_list il) - -> Filter, std::initializer_list> - { - std::unordered_set elem_seen; - std::function func = [elem_seen](const T& e) mutable - { - if (elem_seen.find(e) == std::end(elem_seen)){ - elem_seen.insert(e); - return true; - } else { - return false; - } + auto unique_everseen(std::initializer_list il) { + auto func = + [ + elem_seen = std::unordered_set() + ] (const T& e) mutable { + return elem_seen.insert(e).second; }; return filter(func, il); } From eba0d63f1522ce107608cdfaf861919f7dfb6edb Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 9 Feb 2015 15:28:19 -0500 Subject: [PATCH 52/90] return type deduction --- accumulate.hpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/accumulate.hpp b/accumulate.hpp index c57d177c..6186d869 100644 --- a/accumulate.hpp +++ b/accumulate.hpp @@ -123,11 +123,7 @@ namespace iter { } template - auto accumulate(Container&& container) -> - decltype(accumulate(std::forward(container), - std::plus>>{})) - { + auto accumulate(Container&& container) { return accumulate(std::forward(container), std::plus>>{}); @@ -142,9 +138,7 @@ namespace iter { } template - auto accumulate(std::initializer_list il) -> - decltype(accumulate(std::move(il), std::plus{})) - { + auto accumulate(std::initializer_list il) { return accumulate(std::move(il), std::plus{}); } From f5c4cf055b7540f30c500bf140b7f290315d9b85 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 9 Feb 2015 15:29:49 -0500 Subject: [PATCH 53/90] uses return type deduction --- count.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/count.hpp b/count.hpp index e0bc7cd0..4ef0a3be 100644 --- a/count.hpp +++ b/count.hpp @@ -9,13 +9,13 @@ namespace iter { using DefaultRangeType = long; - auto count() -> decltype(range(DefaultRangeType(0), DefaultRangeType(0))) { + auto count() { return range(DefaultRangeType(0), std::numeric_limits::max()); } template - auto count(T start, T step) -> decltype(range(start, start, start)) { + auto count(T start, T step) { // if step is < 0, set the stop to numeric min, otherwise numeric max T stop = step < T(0) ? std::numeric_limits::min() : std::numeric_limits::max(); @@ -23,7 +23,7 @@ namespace iter { } template - auto count(T start) -> decltype(range(start, start)) { + auto count(T start) { return count(start, T(1)); } } From 16a88e32c99d2ccfb3a2b7a7f2ba5d631bcfa163 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 9 Feb 2015 15:31:52 -0500 Subject: [PATCH 54/90] uses return type deduction --- filter.hpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/filter.hpp b/filter.hpp index fdefe612..b66da5fe 100644 --- a/filter.hpp +++ b/filter.hpp @@ -143,20 +143,14 @@ namespace iter { template - auto filter(Container&& container) -> - decltype(filter( - detail::BoolTester(), - std::forward(container))) { + auto filter(Container&& container) { return filter( detail::BoolTester(), std::forward(container)); } template - auto filter(std::initializer_list il) -> - decltype(filter( - detail::BoolTester>(), - std::move(il))) { + auto filter(std::initializer_list il) { return filter( detail::BoolTester>(), std::move(il)); From f3e0f261b5f1d7a56813371e8e07ca9ddd426c78 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 9 Feb 2015 15:35:16 -0500 Subject: [PATCH 55/90] uses return type deduction --- filterfalse.hpp | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/filterfalse.hpp b/filterfalse.hpp index 3bad5fa0..f7530ab9 100644 --- a/filterfalse.hpp +++ b/filterfalse.hpp @@ -53,11 +53,7 @@ namespace iter { // the bool result of the function. The PredicateFlipper is then passed // to the normal filter() function template - auto filterfalse(FilterFunc filter_func, Container&& container) -> - decltype(filter( - detail::PredicateFlipper( - filter_func), - std::forward(container))) { + auto filterfalse(FilterFunc filter_func, Container&& container) { return filter( detail::PredicateFlipper(filter_func), std::forward(container)); @@ -66,10 +62,7 @@ namespace iter { // Single argument version, uses a BoolFlipper to reverse the truthiness // of an object template - auto filterfalse(Container&& container) -> - decltype(filter( - detail::BoolFlipper(), - std::forward(container))) { + auto filterfalse(Container&& container) { return filter( detail::BoolFlipper(), std::forward(container)); @@ -79,23 +72,18 @@ namespace iter { //specializations for initializer_lists template - auto filterfalse(FilterFunc filter_func, std::initializer_list container) -> - decltype(filter( - detail::PredicateFlipper>( - filter_func), - std::move(container))) { + auto filterfalse(FilterFunc filter_func, + std::initializer_list container) { return filter( - detail::PredicateFlipper>(filter_func), + detail::PredicateFlipper>( + filter_func), std::move(container)); } // Single argument version, uses a BoolFlipper to reverse the truthiness // of an object template - auto filterfalse(std::initializer_list container) -> - decltype(filter( - detail::BoolFlipper>(), - std::move(container))) { + auto filterfalse(std::initializer_list container) { return filter( detail::BoolFlipper>(), std::move(container)); From 944d74cc45069157044fc61ffc0b9e14d8181de3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 9 Feb 2015 15:36:51 -0500 Subject: [PATCH 56/90] uses return type deduction --- groupby.hpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/groupby.hpp b/groupby.hpp index dcda1fda..f4a59e64 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -258,9 +258,7 @@ namespace iter { template - auto groupby(Container&& container) -> - decltype(groupby(std::forward(container), - ItemReturner())) { + auto groupby(Container&& container) { return groupby(std::forward(container), ItemReturner()); } @@ -274,9 +272,7 @@ namespace iter { template - auto groupby(std::initializer_list il) -> - decltype(groupby(std::move(il), - ItemReturner>())) { + auto groupby(std::initializer_list il) { return groupby( std::move(il), ItemReturner>()); From 9b120bb1b4d8010ec4dbf4ea5baa9e35ad1d487f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 9 Feb 2015 15:39:29 -0500 Subject: [PATCH 57/90] uses return type deduction --- sorted.hpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sorted.hpp b/sorted.hpp index 5dbbdc9b..7caa2731 100644 --- a/sorted.hpp +++ b/sorted.hpp @@ -66,13 +66,10 @@ namespace iter { } template - auto sorted(Container&& container) -> - decltype(sorted(std::forward(container), - std::less>())) - { - return sorted(std::forward(container), - std::less>()); - } + auto sorted(Container&& container) { + return sorted(std::forward(container), + std::less>()); + } } From 2e119bec14cee30d9bdfde1c78298e4db1046554 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 9 Feb 2015 16:08:08 -0500 Subject: [PATCH 58/90] uses return type deduction --- iteratoriterator.hpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/iteratoriterator.hpp b/iteratoriterator.hpp index 5bd807bc..10faa0ee 100644 --- a/iteratoriterator.hpp +++ b/iteratoriterator.hpp @@ -67,11 +67,11 @@ namespace iter { return ret; } - auto operator*() -> decltype(**sub_iter) { + decltype(auto) operator*() { return **this->sub_iter; } - auto operator->() -> decltype(*sub_iter) { + decltype(auto) operator->() { return *this->sub_iter; } @@ -112,7 +112,7 @@ namespace iter { return this->sub_iter - rhs.sub_iter; } - auto operator[](Diff idx) -> decltype(*sub_iter[idx]) { + decltype(auto) operator[](Diff idx) { return *sub_iter[idx]; } @@ -156,24 +156,22 @@ namespace iter { : container(sz, val) { } - auto at(size_type pos) -> decltype(*container.at(pos)) { + decltype(auto) at(size_type pos) { return *container.at(pos); } - auto at(size_type pos) const -> decltype(*container.at(pos)) { + decltype(auto) at(size_type pos) const { return *container.at(pos); } - auto operator[](size_type pos) + decltype(auto) operator[](size_type pos) noexcept(noexcept(*container[pos])) - -> decltype(*container[pos]) { return *container[pos]; } - auto operator[](size_type pos) const + decltype(auto) operator[](size_type pos) const noexcept(noexcept(*container[pos])) - -> decltype(*container[pos]) { return *container[pos]; } From bbcb5cd06134163d2d57588e7b90c2344a36fbd3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 9 Feb 2015 16:30:35 -0500 Subject: [PATCH 59/90] tests that starmap moves and binds correctly --- catchtest/test_starmap.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/catchtest/test_starmap.cpp b/catchtest/test_starmap.cpp index fc59fd18..ce8d40c6 100644 --- a/catchtest/test_starmap.cpp +++ b/catchtest/test_starmap.cpp @@ -87,3 +87,11 @@ TEST_CASE("starmap: tuple of pairs", "[starmap]") { REQUIRE( v == vc ); } + +TEST_CASE("starmap: moves rvalues, binds to lvalues", "[starmap]") { + itertest::BasicIterable> bi{}; + starmap(Callable{}, bi); + REQUIRE_FALSE( bi.was_moved_from() ); + starmap(Callable{}, std::move(bi)); + REQUIRE( bi.was_moved_from() ); +} From 8161f3902519486b5c116bb96e31cca8f56279e4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 18 Feb 2015 00:23:11 -0500 Subject: [PATCH 60/90] uses Func* in starmap iterator --- starmap.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index 3f8a64e2..15119dc2 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -33,11 +33,11 @@ namespace iter { : public std::iterator { private: - Func func; + Func *func; iterator_type sub_iter; public: Iterator(Func& f, iterator_type iter) - : func(f), + : func(&f), sub_iter(iter) { } @@ -61,7 +61,7 @@ namespace iter { } decltype(auto) operator*() { - return call_with_tuple(this->func, *this->sub_iter); + return call_with_tuple(*this->func, *this->sub_iter); } }; From ec1d73153b09ccd342f9eb5a9bced3d91548f7e0 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 18 Feb 2015 00:24:14 -0500 Subject: [PATCH 61/90] eliminates extra copy of iterator --- starmap.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index 15119dc2..3e1ec9fc 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -36,9 +36,9 @@ namespace iter { Func *func; iterator_type sub_iter; public: - Iterator(Func& f, iterator_type iter) + Iterator(Func& f, iterator_type&& iter) : func(&f), - sub_iter(iter) + sub_iter(std::move(iter)) { } bool operator!=(const Iterator& other) const { From 7c096f05f4a918eeadbb16d44f99f0a8b64a9599 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 18 Feb 2015 00:37:52 -0500 Subject: [PATCH 62/90] corrects ++ and == in starmap iterators prefix ++ was returning Iterator instead of Iterator& --- starmap.hpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index 3e1ec9fc..138dba75 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -49,7 +49,7 @@ namespace iter { return !(*this != other); } - Iterator operator++() { + Iterator& operator++() { ++this->sub_iter; return *this; } @@ -131,14 +131,24 @@ namespace iter { return callers[this->index](this->func, this->tup); } - Iterator operator++() { + Iterator& operator++() { ++this->index; return *this; } + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + bool operator!=(const Iterator& other) const { return this->index != other.index; } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } }; Iterator begin() { From 2d6a5aa2991d83bd8bcc56a2a0a35219f75d3aa2 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 18 Feb 2015 00:40:28 -0500 Subject: [PATCH 63/90] explicitly defaults default ctors for DerefHolder --- iterbase.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iterbase.hpp b/iterbase.hpp index 6ab8958a..48c987fd 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -198,6 +198,7 @@ namespace iter { std::unique_ptr item_p; public: + DerefHolder() = default; DerefHolder(const DerefHolder& other) : item_p{other.item_p ? new TPlain(*other.item_p) : nullptr} { } @@ -244,6 +245,7 @@ namespace iter { typename std::remove_reference::type *item_p =nullptr; public: + DerefHolder() = default; T get() { return *this->item_p; } From 5a11a2c5c5310cf2a75d9bc4ea70dbe6e57c9de4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 18 Feb 2015 11:01:22 -0500 Subject: [PATCH 64/90] forwards the tuple elements to the called function --- iterbase.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/iterbase.hpp b/iterbase.hpp index 48c987fd..7a354802 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -162,7 +162,10 @@ namespace iter { template decltype(auto) call_with_tuple_impl(Func&& mf, TupleType&& tup, std::index_sequence) { - return mf(std::get(tup)...); + return mf(std::forward< + std::tuple_element_t< + Is, std::remove_reference_t> + >(std::get(tup))...); } } From a755f8b906372b9557d369481802635120ea5fe4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 10:35:16 -0500 Subject: [PATCH 65/90] tests normal starmap iterator requirements --- catchtest/test_starmap.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_starmap.cpp b/catchtest/test_starmap.cpp index ce8d40c6..b26de6c5 100644 --- a/catchtest/test_starmap.cpp +++ b/catchtest/test_starmap.cpp @@ -95,3 +95,10 @@ TEST_CASE("starmap: moves rvalues, binds to lvalues", "[starmap]") { starmap(Callable{}, std::move(bi)); REQUIRE( bi.was_moved_from() ); } + +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); + REQUIRE( itertest::IsIterator::value ); +} From 57ef52338ca340ace4b778ebf45347e3a865b4cc Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 10:41:54 -0500 Subject: [PATCH 66/90] tests TupleStarMapper's iterator requirements --- catchtest/test_starmap.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/catchtest/test_starmap.cpp b/catchtest/test_starmap.cpp index b26de6c5..994f96b7 100644 --- a/catchtest/test_starmap.cpp +++ b/catchtest/test_starmap.cpp @@ -102,3 +102,10 @@ TEST_CASE("starmap: iterator meets requirements", "[starmap]") { auto sm = starmap([](long a, int b) { return a * b; }, v1); REQUIRE( itertest::IsIterator::value ); } + +TEST_CASE("starmap: tuple of tuples iterator meets requirements", + "[starmap]") { + auto tup = std::make_tuple(std::make_tuple(10, 19, 60),std::make_tuple(7)); + auto sm = starmap(Callable{}, tup); + REQUIRE( itertest::IsIterator::value ); +} From 8f284acb26acbe0b4747b9ceffea80b9b93e1933 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 11:20:24 -0500 Subject: [PATCH 67/90] replaces references with pointers in starmap iter to make the iterator assignable --- starmap.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/starmap.hpp b/starmap.hpp index 138dba75..978fab23 100644 --- a/starmap.hpp +++ b/starmap.hpp @@ -116,19 +116,19 @@ namespace iter { : public std::iterator { private: - Func& func; - TupType& tup; + 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}, + : func{&f}, + tup{&t}, index{i} { } decltype(auto) operator*() { - return callers[this->index](this->func, this->tup); + return callers[this->index](*this->func, *this->tup); } Iterator& operator++() { From 46c5c68c9cd670d2ded40ffa495bd7e7009c6601 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 11:24:20 -0500 Subject: [PATCH 68/90] uses c++14 aliases --- groupby.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/groupby.hpp b/groupby.hpp index a50730bc..b81e1eeb 100644 --- a/groupby.hpp +++ b/groupby.hpp @@ -179,7 +179,7 @@ namespace iter { iterator_traits_deref> { private: - typename std::remove_reference::type *key; + std::remove_reference_t *key; Group *group_p; bool not_at_end() { From 203e881080143f35b0fae9ebf3289066ad3a81ee Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 23 Feb 2015 11:24:36 -0500 Subject: [PATCH 69/90] uses c++14 aliases --- iterbase.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 42efd0b7..ce97260d 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -196,7 +196,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 = typename std::remove_reference::type; + using TPlain = std::remove_reference_t; std::unique_ptr item_p; @@ -247,7 +247,7 @@ namespace iter { static_assert(std::is_lvalue_reference::value, "lvalue specialization handling non-lvalue-ref type"); - typename std::remove_reference::type *item_p =nullptr; + std::remove_reference_t *item_p =nullptr; public: DerefHolder() = default; From dfee40438f886f7a8f067873b5c0a54eed88bf06 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 18:25:12 -0700 Subject: [PATCH 70/90] adds starmap to the docs --- README.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/README.md b/README.md index a0623a8b..9cd3a1f4 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ evaluation wherever possible. [repeat](#repeat)
[count](#count)
[groupby](#groupby)
+[starmap](#starmap)
[accumulate](#accumulate)
[compress](#compress)
[sorted](#sorted)
@@ -287,6 +288,48 @@ for (auto&& gb : groupby(vec, [] (const string &s) {return s.length(); })) { It just iterates through, making a new group each time there is a key change. Thus, if the 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 +to a function expecting two ints, with the elements of the `pair` being +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 +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; +}; +``` + +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 +for (auto&& i : starmap(Callable{}, t)) { + // ... +} +``` + accumulate ------- Differs from `std::accumulate` (which in my humble opinion should be named From ef1ae7513b98dd57e090667d1e8ed9eab9b6ac3b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Sat, 4 Apr 2015 19:00:02 -0700 Subject: [PATCH 71/90] tests that sorted iter meets requirements --- catchtest/test_sorted.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/catchtest/test_sorted.cpp b/catchtest/test_sorted.cpp index 918dec7d..843501b7 100644 --- a/catchtest/test_sorted.cpp +++ b/catchtest/test_sorted.cpp @@ -171,3 +171,9 @@ TEST_CASE("sorted: doesn't move or copy elements of iterable", "[sorted]") { (void)i; } } + +TEST_CASE("sorted: iterator meets requirements", "[sorted]") { + Vec v; + auto r = sorted(v); + REQUIRE( itertest::IsIterator::value ); +} From 8b58b1d86762729126e5b2cc7c7a27c172e1475c Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 20 May 2015 00:06:49 -0700 Subject: [PATCH 72/90] removes old tests --- tests/.gitignore | 5 - tests/SConstruct | 52 --------- tests/samples.hpp | 98 ---------------- tests/testaccumulate.cpp | 33 ------ tests/testchain.cpp | 67 ----------- tests/testchainfromiterable.cpp | 28 ----- tests/testcombinations.cpp | 75 ------------- tests/testcombinations_with_replacement.cpp | 55 --------- tests/testcommand_chains.cpp | 78 ------------- tests/testcompress.cpp | 67 ----------- tests/testcount.cpp | 38 ------- tests/testcycle.cpp | 70 ------------ tests/testdropwhile.cpp | 35 ------ tests/testenumerate.cpp | 60 ---------- tests/testfilter.cpp | 83 -------------- tests/testfilterfalse.cpp | 93 --------------- tests/testgroupby.cpp | 109 ------------------ tests/testgrouper.cpp | 51 --------- tests/testimap.cpp | 45 -------- tests/testpermutations.cpp | 60 ---------- tests/testpowerset.cpp | 44 -------- tests/testproduct.cpp | 77 ------------- tests/testrange.cpp | 83 -------------- tests/testrepeat.cpp | 31 ----- tests/testreversed.cpp | 43 ------- tests/testslice.cpp | 81 -------------- tests/testsliding_window.cpp | 53 --------- tests/testsorted.cpp | 36 ------ tests/teststarmap.cpp | 83 -------------- tests/testtakewhile.cpp | 32 ------ tests/testunique_everseen.cpp | 41 ------- tests/testunique_justseen.cpp | 35 ------ tests/testzip.cpp | 118 -------------------- tests/testzip_longest.cpp | 96 ---------------- 34 files changed, 2055 deletions(-) delete mode 100644 tests/.gitignore delete mode 100644 tests/SConstruct delete mode 100644 tests/samples.hpp delete mode 100644 tests/testaccumulate.cpp delete mode 100644 tests/testchain.cpp delete mode 100644 tests/testchainfromiterable.cpp delete mode 100644 tests/testcombinations.cpp delete mode 100644 tests/testcombinations_with_replacement.cpp delete mode 100644 tests/testcommand_chains.cpp delete mode 100644 tests/testcompress.cpp delete mode 100644 tests/testcount.cpp delete mode 100644 tests/testcycle.cpp delete mode 100644 tests/testdropwhile.cpp delete mode 100644 tests/testenumerate.cpp delete mode 100644 tests/testfilter.cpp delete mode 100644 tests/testfilterfalse.cpp delete mode 100644 tests/testgroupby.cpp delete mode 100644 tests/testgrouper.cpp delete mode 100644 tests/testimap.cpp delete mode 100644 tests/testpermutations.cpp delete mode 100644 tests/testpowerset.cpp delete mode 100644 tests/testproduct.cpp delete mode 100644 tests/testrange.cpp delete mode 100644 tests/testrepeat.cpp delete mode 100644 tests/testreversed.cpp delete mode 100644 tests/testslice.cpp delete mode 100644 tests/testsliding_window.cpp delete mode 100644 tests/testsorted.cpp delete mode 100644 tests/teststarmap.cpp delete mode 100644 tests/testtakewhile.cpp delete mode 100644 tests/testunique_everseen.cpp delete mode 100644 tests/testunique_justseen.cpp delete mode 100644 tests/testzip.cpp delete mode 100644 tests/testzip_longest.cpp diff --git a/tests/.gitignore b/tests/.gitignore deleted file mode 100644 index a77d502e..00000000 --- a/tests/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.o -*.swp -test* -!test*.cpp -.sconsign.dblite diff --git a/tests/SConstruct b/tests/SConstruct deleted file mode 100644 index 8e344b2b..00000000 --- a/tests/SConstruct +++ /dev/null @@ -1,52 +0,0 @@ -import os - -env = Environment( - ENV = {'PATH' : os.environ['PATH']}, - CXX='c++', - CXXFLAGS= ['-g', '-Wall', '-Wextra', - '-pedantic', '-std=c++14', - '-fdiagnostics-color=always', - '-I/usr/local/include'], - CPPPATH='..', - LINKFLAGS='-L/usr/local/lib') - -# allows highighting to print to terminal from compiler output -env['ENV']['TERM'] = os.environ['TERM'] - -progs = Split(''' - accumulate - cycle - enumerate - range - zip - slice - reversed - filter - repeat - takewhile - dropwhile - zip_longest - product - permutations - compress - combinations_with_replacement - combinations - powerset - sliding_window - imap - starmap - count - filterfalse - grouper - chain - chainfromiterable - groupby - sorted - unique_justseen - unique_everseen - command_chains - ''') - - -for p in progs: - env.Program('test{0}.cpp'.format(p)) diff --git a/tests/samples.hpp b/tests/samples.hpp deleted file mode 100644 index 820d2c1e..00000000 --- a/tests/samples.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef ITERTOOLS_SAMPLE_CLASSES_HPP -#define ITERTOOLS_SAMPLE_CLASSES_HPP - -#include -#include -#include - -namespace itertest { - class MoveOnly { - private: - int i; // not an aggregate - public: - MoveOnly(int v) - : i{v} - { } - - MoveOnly(const MoveOnly&) = delete; - MoveOnly& operator=(const MoveOnly&) = delete; - - MoveOnly(MoveOnly&& other) noexcept - : i{other.i} - { } - - MoveOnly& operator=(MoveOnly&& other) noexcept { - this->i = other.i; - return *this; - } - - // for std::next_permutation compatibility - friend bool operator<(const MoveOnly& lhs, const MoveOnly& rhs) { - return lhs.i < rhs.i; - } - - friend std::ostream& operator<<( - std::ostream& out, const MoveOnly& self) { - return out << self.i; - } - - }; - - class DerefByValue { - private: - static constexpr std::size_t N = 3; - int array[N] = {0, 1, 2}; - public: - DerefByValue() = default; - - class Iterator { - private: - int *current; - public: - Iterator() = default; - Iterator(int *p) - : current{p} - { } - - bool operator!=(const Iterator& other) const { - return this->current != other.current; - } - - // for testing, iterator derefences to an int instead of - // an int& - int operator*() { - return *this->current; - } - - Iterator& operator++() { - ++this->current; - return *this; - } - }; - - Iterator begin() { - return {this->array}; - } - - Iterator end() { - return {this->array + N}; - } - }; - - class DerefByValueFancy { - private: - static constexpr std::size_t N = 3; - int array[N] = {0, 1, 2}; - public: - DerefByValueFancy() = default; - - int *begin() { - return this->array; - } - - int *end() { - return this->array + N; - } - }; -} -#endif // #ifndef ITERTOOLS_SAMPLE_CLASSES_HPP diff --git a/tests/testaccumulate.cpp b/tests/testaccumulate.cpp deleted file mode 100644 index 2321ffca..00000000 --- a/tests/testaccumulate.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include - -#include -#include - -int main() { - std::vector vec = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - for (auto v : iter::accumulate(vec, [](int a, int b){return a - b;})) { - std::cout << v << '\n'; - } - for (auto v : iter::accumulate(iter::range(10), - [](int a, int b){return a - b;})) { - std::cout << v << '\n'; - } - for (auto v : iter::accumulate({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - [](int a, int b){return a - b;})) { - std::cout << v << '\n'; - } - - for (auto v : iter::accumulate(iter::range(10))) { - std::cout << v << '\n'; - } - for (auto v : iter::accumulate({0, 1, 2, 3, 4, 5, 6, 7, 8, 9})) { - std::cout << v << '\n'; - } - - for (auto v : iter::accumulate(std::vector{1,2,3,4,5,6,7,8,9})) { - std::cout << v << '\n'; - } - - return 0; -} diff --git a/tests/testchain.cpp b/tests/testchain.cpp deleted file mode 100644 index 3dfde3d1..00000000 --- a/tests/testchain.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include - -using iter::chain; -using il = std::initializer_list; - -int main() { - - { - std::vector ivec{1, 4, 7, 9}; - std::vector lvec{100, 200, 300, 400, 500, 600}; - - for (auto e : chain(ivec, lvec)) { - std::cout << e << std::endl; - } - - auto c = chain(ivec, lvec); - auto it = std::begin(c); - auto it2 = std::begin(c); - it = it2; - } - { - std::vector empty{}; - std::vector vec1{1,2,3,4,5,6}; - std::array arr1{{7,8,9,10}}; - std::array arr2{{11,12,13}}; - std::cout << std::endl << "Chain iter test" << std::endl; - for (auto i : iter::chain(empty,vec1,arr1)) { - std::cout << i << std::endl; - } - std::cout<{1,2,3,4}, - std::array{{5,6,7,8}})) { - std::cout << i << '\n'; - } - } - -} diff --git a/tests/testchainfromiterable.cpp b/tests/testchainfromiterable.cpp deleted file mode 100644 index f4b6d599..00000000 --- a/tests/testchainfromiterable.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include - -#include -#include - -using iter::chain; - -int main() { - std::vector> matrix = { - {1, 2, 3}, - {4, 5}, - {6, 8, 9, 10, 11, 12} - }; - for (auto i : chain.from_iterable(matrix)) { - std::cout << i << '\n'; - } - - std::cout << "with temporary\n"; - for (auto i : chain.from_iterable(std::vector>{ - {1, 2, 3}, - {4, 5}, - {6, 8, 9, 10, 11, 12} - })) { - std::cout << i << '\n'; - } - - return 0; -} diff --git a/tests/testcombinations.cpp b/tests/testcombinations.cpp deleted file mode 100644 index 4dce1139..00000000 --- a/tests/testcombinations.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "samples.hpp" -#include -#include - -#include -#include -#include -#include - -using iter::combinations; -int main() { - itertest::DerefByValue dbv; - std::vector mv; - for (auto i : iter::range(3)) { - mv.emplace_back(i); - } - std::vector v = {1,2,3,4,5}; - - for (auto i : combinations(mv,2)) { - for (auto j : i ) std::cout << j << " "; - std::cout<{1,2,3,4,5}, 3)) { - for (auto j : i ) std::cout << j << " "; - std::cout< -#include - -#include -#include -#include -#include - -using iter::combinations_with_replacement; - -int main() { - std::vector mv; - for (auto i : iter::range(3)) { - mv.emplace_back(i); - } - - std::vector v = {1,2,3,}; - for (auto i : combinations_with_replacement(v,4)) { - for (auto j : i ) std::cout << j << " "; - std::cout<{1,2,3},4)) { - for (auto j : i ) std::cout << j << " "; - std::cout< - -#include -#include -#include -#include -#include - -using namespace iter; - -template -std::ostream & operator<<(std::ostream & out, const boost::optional& opt) { - if (opt) { - out << "Just " << *opt; - } else { - out << "Nothing"; - } - return out; -} -int main() { - { - std::vector vec1{1,2,3,4,5,6}; - std::vector vec2{1,2,3,4,5}; - std::vector strvec - {"his","name","was","robert","paulson","his","name","was","robert","paulson"}; - for (auto t : zip_longest(chain(vec1,vec2),strvec)) { - std::cout << std::get<0>(t) << " " - << std::get<1>(t) << std::endl; - } - } - - std::string str = "hello world"; - std::vector vec = {6, 9, 6, 9}; - for (auto p : enumerate(enumerate(str))) { (void)p; } - for (auto p : enumerate(zip(str, vec))) { (void)p; } - - std::cout << std::endl; - { - std::vector vec1{1,2,3,4,5,6}; - std::vector vec2{7,8,9,10}; - std::vector strvec - {"We're","done","when","I","say","we're","done"}; - for (auto t : zip(strvec,chain(slice(vec1,2,6),slice(vec2,1,4)))) { - std::cout << std::get<0>(t) << " " - << std::get<1>(t) << std::endl; - } - } - std::cout << std::endl; - { - std::vector vec1{1,2,3,4,5,6}; - std::vector vec2{7,8,9,10}; - for (auto s : sliding_window(chain(vec1,vec2),4)) { - for (auto i : s) std::cout << i << " "; - std::cout< vec1{1,2,3,4,5,6}; - std::vector vec2{7,8,9,10}; - for (auto s : grouper(chain(vec1,vec2),3)) { - for (auto i : s) std::cout << i << " "; - std::cout< const& c) - {return std::get<0>(c) >= std::get<1>(c);}, - prod_range)) { - std::cout << std::get<0>(ij) << "," << std::get<1>(ij) << std::endl; - } - return 0; -} diff --git a/tests/testcompress.cpp b/tests/testcompress.cpp deleted file mode 100644 index 5197f3e2..00000000 --- a/tests/testcompress.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include - -#include -#include - -using iter::compress; -using iter::range; - -template -void testcase(std::vector data_vec, - std::vector sel_vec) -{ - - for (auto e : compress(data_vec, sel_vec)) { - std::cout << e << '\n'; - } -} - -int main(void) -{ - std::vector ivec{1, 2, 3, 4, 5, 6}; - std::vector bvec{true, false, true, false, true, false}; - std::cout << "Should print 1 3 5\n"; - testcase(ivec, bvec); - - std::vector bvec2{false, true, false, false, false, true}; - std::cout << "Should print 2 6\n"; - testcase(ivec, bvec2); - - std::vector bvec3{false, true}; - std::cout << "Should print 2\n"; - testcase(ivec, bvec3); - - std::cout << "Should print 0 2 4\n"; - for (auto i : compress(range(10), bvec)) { - std::cout << i << '\n'; - } - - std::cout << "Should print 0 2 4\n"; - for (auto i : compress({0,1,2,3,4,5}, bvec)) { - std::cout << i << '\n'; - } - - std::cout << "Should print 0 2 4\n"; - for (auto i : compress(range(10), {true, false, true, false, true})) { - std::cout << i << '\n'; - } - - std::cout << "Should print 0 2 4\n"; - for (auto i : compress({0, 1, 2, 3, 4, 5}, - {true, false, true, false, true})) - { - std::cout << i << '\n'; - } - - std::cout << "Should print 0 2 4\n"; - for (auto i : compress(std::vector{0, 1, 2, 3, 4, 5}, - std::vector{true, false, true, false, true})) - { - std::cout << i << '\n'; - } - - - - return 0; -} diff --git a/tests/testcount.cpp b/tests/testcount.cpp deleted file mode 100644 index 946d6841..00000000 --- a/tests/testcount.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include - -#include - -using iter::count; - -int main() { - for (auto i : count()) { - std::cout << i << '\n'; - if (i == 100) { - break; - } - } - - for (auto i : count(5.0, 0.5)){ - std::cout << i << '\n'; - if (i > 100) { - break; - } - } - - for (auto i : count(0, -1)) { - std::cout << i << '\n'; - if (i < -100) { - break; - } - } - - for (auto i : count()) { - std::cout << i << '\n'; - if (i > 10000) { - break; - } - } - - - return 0; -} diff --git a/tests/testcycle.cpp b/tests/testcycle.cpp deleted file mode 100644 index 138692cc..00000000 --- a/tests/testcycle.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include -#include - -#include -#include - -using iter::cycle; -using iter::range; - -int main() { - std::vector vec = {2, 4, 6}; - - size_t count = 0; - for (auto i : cycle(vec)) { - std::cout << i << '\n'; - if (count == 100) { - break; - } - ++count; - } - - count = 0; - int array[] = {68, 69, 70}; - for (auto i : cycle(array)) { - std::cout << i << '\n'; - if (count == 20) { - break; - } - ++count; - } - - count = 0; - for (auto i : cycle({7, 8, 9})) { - std::cout << i << '\n'; - if (count == 20) { - break; - } - ++count; - } - - count = 0; - for (auto i : cycle(range(3))) { - std::cout << i << '\n'; - if (count == 20) { - break; - } - ++count; - } - - count = 0; - const std::string s("hello"); - for (auto c : cycle(s)) { - std::cout << c << '\n'; - if (count == 20) { - break; - } - ++count; - } - - count = 0; - for (auto i : std::vector{1,2,3,4,5}) { - std::cout << i << '\n'; - if (count == 20) { - break; - } - ++count; - } - - return 0; -} diff --git a/tests/testdropwhile.cpp b/tests/testdropwhile.cpp deleted file mode 100644 index 3140f81a..00000000 --- a/tests/testdropwhile.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -#include -#include -#include - -using iter::dropwhile; -using iter::range; - -int main() { - std::vector ivec{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4}; - for (auto& i : dropwhile([] (int i) {return i < 5;}, ivec)) { - std::cout << i << '\n'; - i = 69; - } - assert(ivec.at(0) == 1); - assert(ivec.at(4) == 69); - - for (auto i : dropwhile([] (int i) {return i < 5;}, range(10))) { - std::cout << i << '\n'; - } - - for (auto i : dropwhile([] (int i) {return i < 5;}, - {1, 2, 3, 4, 5, 6, 7, 8, 9})) { - std::cout << i << '\n'; - } - - for (auto i : dropwhile([] (int i) {return i < 5;}, - std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9})) { - std::cout << i << '\n'; - } - - return 0; -} diff --git a/tests/testenumerate.cpp b/tests/testenumerate.cpp deleted file mode 100644 index fcc1745c..00000000 --- a/tests/testenumerate.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include - -#include -#include -#include - -using iter::enumerate; -using iter::range; - -int main() { - std::cout << "const std::string\n"; - const std::string const_string("goodbye world"); - for (auto e : enumerate(const_string)) { - std::cout << e.index << ": " << e.element << std::endl; - } - - - std::vector vec; - for(int i = 0; i < 12; ++i) { - vec.push_back(i * i); - } - - - std::cout << "print vector element, set it to zero, then print it again\n"; - for (auto e : enumerate(vec)) { - std::cout << e.index << ": " << e.element << std::endl; - e.element = 0; - // tests to make sure vector can be edited - std::cout << e.index << ": " << e.element << std::endl; - } - - std::cout << "static array\n"; - int array[] = {1, 9, 8, 11}; - for (auto e : enumerate(array)) { - std::cout << e.index << ": " << e.element << '\n'; - } - - std::cout << "initializer list\n"; - for (auto e : enumerate({0, 1, 4, 9, 16, 25})) { - std::cout << e.index << "^2 = " << e.element << '\n'; - } - - std::cout << "range(10, 20, 2)\n"; - for (auto e : enumerate(range(10, 20, 2))) { - std::cout << e.index << ": " << e.element << '\n'; - } - - std::cout << "range(10, 20, 2)\n"; - for (auto e : enumerate(enumerate(range(10, 20, 2)))) { - std::cout << e.index << ": " << e.element.element << '\n'; - } - - std::cout << "vector temporary\n"; - for (auto e : enumerate(std::vector(5,2))) { - std::cout << e.index << ": " << e.element << '\n'; - } - - return 0; -} diff --git a/tests/testfilter.cpp b/tests/testfilter.cpp deleted file mode 100644 index e8af2aab..00000000 --- a/tests/testfilter.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include -#include - -#include -#include - -using iter::filter; - -bool greater_than_four(int i) { - return i > 4; -} - -class LessThanValue { - private: - int compare_val; - - public: - LessThanValue() = delete; - LessThanValue(int v) : compare_val(v) { } - - bool operator() (int i) { - return i < this->compare_val; - } -}; - - -int main() { - std::vector vec{1, 5, 6, 7, 2, 3, 8, 3, 2, 1}; - - std::cout << "Greater than 4 (function pointer)\n"; - for (auto i : filter(greater_than_four, vec)) { - std::cout << i << '\n'; - } - - std::cout << "Less than 4 (lambda)\n"; - for (auto i : filter([] (const int i) { return i < 4; }, vec)) { - std::cout << i << '\n'; - } - - LessThanValue lv(4); - std::cout << "Less than 4 (callable object)\n"; - for (auto i : filter(lv, vec)) { - std::cout << i << '\n'; - } - - std::cout << "Nonzero ints filter(vec2)\n"; - std::vector vec2 {0, 1, 2, 0, 3, 0, 0, 0, 4, 5, 0}; - for (auto i : filter(vec2)) { - std::cout << i << '\n'; - } - - std::cout << "odd numbers in range(10) temp\n"; - for (auto i : filter([] (const int i) {return i % 2;}, iter::range(10))) { - std::cout << i << '\n'; - } - - std::cout << "range(-1, 2)\n"; - for (auto i : filter(iter::range(-1, 2))) { - std::cout << i << '\n'; - } - - - std::cout << "ever numbers in initializer_list\n"; - for (auto i : filter([] (const int i) {return i % 2 == 0;}, - {1, 2, 3, 4, 5, 6, 7})) - { - std::cout << i << '\n'; - } - - std::cout << "default in initialization_list\n"; - for (auto i : filter({-2, -1, 0, 0, 0, 1, 2})) { - std::cout << i << '\n'; - } - - std::cout << "ever numbers in vector temporary\n"; - for (auto i : filter([] (const int i) {return i % 2 == 0;}, - std::vector{1, 2, 3, 4, 5, 6, 7})) - { - std::cout << i << '\n'; - } - - return 0; -} diff --git a/tests/testfilterfalse.cpp b/tests/testfilterfalse.cpp deleted file mode 100644 index 9063d0bf..00000000 --- a/tests/testfilterfalse.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include -#include - -#include -#include - -using iter::filterfalse; -using iter::range; - -bool greater_than_four(int i) { - return i > 4; -} - -class LessThanValue { - private: - int compare_val; - - public: - LessThanValue() = delete; - LessThanValue(int v) : compare_val(v) { } - - bool operator() (int i) const { - return i < this->compare_val; - } -}; - - -int main() { - std::vector vec{1, 5, 6, 7, 2, 3, 8, 3, 2, 1}; - - std::cout << "Greater than 4 (function pointer)\n"; - for (auto i : filterfalse(greater_than_four, vec)) { - std::cout << i << '\n'; - } - - std::cout << "Less than 4 (lambda)\n"; - for (auto i : filterfalse([] (const int i) { return i < 4; }, vec)) { - std::cout << i << '\n'; - } - - LessThanValue lv(4); - std::cout << "Less than 4 (callable object)\n"; - for (auto i : filterfalse(lv, vec)) { - std::cout << i << '\n'; - } - - std::cout << "zero ints filter(vec2)\n"; - std::vector vec2 {0, 1, 2, 0, 3, 0, 0, 0, 4, 5, 0}; - for (auto i : filterfalse(vec2)) { - std::cout << i << '\n'; - } - - std::cout << "Constness tests\n"; - const std::vector cvec(vec); - for (auto i : filterfalse(greater_than_four, cvec)) { - std::cout << i << '\n'; - } - - for (auto i : filterfalse([] (const int & i) { return i < 4; }, cvec)) { - std::cout << i << '\n'; - } - - - std::cout << "i%2 with range(10), should print even numbers\n"; - for (auto i : filterfalse([] (const int i) { return i % 2; }, range(10))) { - std::cout << i << '\n'; - } - - std::cout << "range(-1, 2)\n"; - for (auto i : filterfalse(range(-1, 2))) { - std::cout << i << '\n'; - } - - std::cout << "initializer_list\n"; - for (auto i : filterfalse([] (const int i) { return i % 2; }, - {10, 11, 12, 13, 14, 15, 16})) - { - std::cout << i << '\n'; - } - - std::cout << "initializer_list with default\n"; - for (auto i : filterfalse({-1, -2, 0, 0, 0, 0, 1, 2, 3})) { - std::cout << i << '\n'; - } - - std::cout << "vector temporary with default\n"; - for (auto i : filterfalse( - std::vector{-1, -2, 0, 0, 0, 0, 1, 2, 3})) { - std::cout << i << '\n'; - } - - return 0; -} diff --git a/tests/testgroupby.cpp b/tests/testgroupby.cpp deleted file mode 100644 index 9fc03ee3..00000000 --- a/tests/testgroupby.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include - -#include -#include -#include - -using iter::groupby; - - -int length(std::string s) -{ - return s.length(); -} - -int main() -{ - std::vector vec = { - "hi", "ab", "ho", - "abc", "def", - "abcde", "efghi" - }; - - for (auto gb : groupby(vec, &length)) { - std::cout << "key: " << gb.first << '\n'; - std::cout << "content: "; - for (auto s : gb.second) { - std::cout << s << " "; - } - std::cout << '\n'; - } - - for (auto gb : groupby(vec, [] (const std::string &s) {return s.length(); })) { - std::cout << "key: " << gb.first << '\n'; - std::cout << "content: "; - for (auto s : gb.second) { - std::cout << s << " "; - } - std::cout << '\n'; - } - - std::cout << "skipping length of 3\n"; - for (auto gb : groupby(vec, &length)) { - if (gb.first == 3) { - continue; - } - std::cout << "key: " << gb.first << '\n'; - std::cout << "content: "; - for (auto s : gb.second) { - std::cout << s << " "; - } - std::cout << '\n'; - } - - - std::vector ivec = {5, 5, 6, 6, 19, 19, 19, 19, 69, 0, 10, 10}; - for (auto gb : groupby(ivec)) { - std::cout << "key: " << gb.first << '\n'; - std::cout << "content: "; - for (auto s : gb.second) { - std::cout << s << " "; - } - std::cout << '\n'; - } - - for (auto gb : groupby("aabbccccdd", [] (const char c) {return c < 'c';})){ - std::cout << "key: " << gb.first << '\n'; - std::cout << "content: "; - for (auto s : gb.second) { - std::cout << s << " "; - } - std::cout << '\n'; - } - - for (auto gb : groupby({'a', 'a', 'b', 'b', 'c'})) { - std::cout << "key: " << gb.first << '\n'; - std::cout << "content: "; - for (auto s : gb.second) { - std::cout << s << " "; - } - std::cout << '\n'; - } - - for (auto gb : groupby({'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'}, - [] (const char c) {return c < 'c'; })) { - std::cout << "key: " << gb.first << '\n'; - std::cout << "content: "; - for (auto s : gb.second) { - std::cout << s << " "; - } - std::cout << '\n'; - } - - std::cout << "with vector temporary:\n"; - for (auto gb : groupby( - std::vector{'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'}, - [] (const char c) {return c < 'c'; })) { - std::cout << "key: " << gb.first << '\n'; - std::cout << "content: "; - for (auto s : gb.second) { - std::cout << s << " "; - } - std::cout << '\n'; - } - - - return 0; -} - - diff --git a/tests/testgrouper.cpp b/tests/testgrouper.cpp deleted file mode 100644 index b16ebc98..00000000 --- a/tests/testgrouper.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "grouper.hpp" -#include -#include -using iter::grouper; -int main() { - std::vector v {1,2,3,4,5,6,7,8,9}; - for (auto sec : grouper(v,4)) { - for (auto i : sec) { - std::cout << i << " "; - i.get() *= 2; - } - std::cout << '\n'; - } - - for (auto sec : grouper(std::vector{1,2,3,4,5,6,7,8,9}, 4)) { - for (auto i : sec) { - std::cout << i << " "; - i.get() *= 2; - } - std::cout << '\n'; - } - - for (auto sec : grouper(v,3)) { - for (auto i : sec) { - std::cout << i << " "; - } - std::cout << '\n'; - } - std::vector empty {}; - for (auto sec : grouper(empty,3)) { - std::cout << "Shouldn't print\n"; - for (auto i : sec) { - std::cout << i << " Shouldn't print\n"; - } - } - - int arr[] = {1,2,3,4,5,6,7}; - for (auto sec : grouper(arr, 2)) { - for (auto i : sec) { - std::cout << i << ' '; - } - std::cout << '\n'; - } - - for (auto sec : grouper({1,2,3,4,5,6,7}, 2)) { - for (auto i : sec) { - std::cout << i << ' '; - } - std::cout << '\n'; - } -} diff --git a/tests/testimap.cpp b/tests/testimap.cpp deleted file mode 100644 index 3d6f38ca..00000000 --- a/tests/testimap.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include - -#include -#include - -using iter::imap; - -int main() { - std::vector vec1 = {1, 2, 3, 4, 5, 6}; - std::vector vec2 = {10, 20, 30, 40, 50, 60}; - for (auto i : imap([] (int x, int y) { return x + y; }, vec1, vec2)) { - std::cout << i << '\n'; - } - - std::vector vec3 = {100, 200, 300, 400, 500, 600}; - for (auto i : imap([] (int a, int b, int c) { return a + b + c; }, - vec1, vec2, vec3)) { - std::cout << i << '\n'; - } - - for (auto i : imap([] (int i) {return i * i; }, vec1)) { - std::cout << i << '\n'; - } - - std::vector vec{1, 2, 3, 4, 5}; - for (auto i : imap([] (int x) {return x * x;}, vec)) { - std::cout << i << '\n'; - } - - std::vector vec4{1, 2, 3}; - for (auto i : imap([] (int a, int b) { return a + b; }, vec, vec4)) { - std::cout << i << '\n'; - } - - for (auto i : imap([] (const int x) { return x*x; }, iter::range(10))) { - std::cout << i << '\n'; - } - - for (auto i : imap([] (const int x) { return x*x; }, - std::vector{1,2,3,4,5})){ - std::cout << i << '\n'; - } - return 0; -} diff --git a/tests/testpermutations.cpp b/tests/testpermutations.cpp deleted file mode 100644 index a73a2a3b..00000000 --- a/tests/testpermutations.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "samples.hpp" - -#include -#include - -#include -#include -#include - -int main() { - using iter::permutations; - std::vector v = {1,2,3}; - for (auto vec : permutations(v)) { - for (auto i : vec) { - std::cout << i << " "; - } - std::cout << std::endl; - } - //try with string - std::string s = "aba"; - for (auto vec : permutations(s)) { - for (auto c : vec) { - std::cout << c << " "; - } - std::cout << std::endl; - } - s = "abc"; - for (auto vec : permutations(s)) { - for (auto c : vec) { - std::cout << c << " "; - } - std::cout << std::endl; - } - - std::cout << "init list\n"; - //std::next_permutation doesn't work on initializer_lists - for (auto vec : permutations({1,2,3,4})) { - for (auto c : vec) { - std::cout << c << " "; - } - std::cout << std::endl; - } - - std::cout << "with container of move-only objects\n"; - std::vector mv; - for (auto i : iter::range(3)) { - mv.emplace_back(i); - } - for (auto v : permutations(mv)) { - for (auto i : v) std::cout << i << " "; - std::cout << std::endl; - } - - std::cout << "with deref-by-value iterator\n"; - itertest::DerefByValue dbv; - for (auto v : permutations(dbv)) { - for (auto i : v) std::cout << i << " "; - std::cout << std::endl; - } -} diff --git a/tests/testpowerset.cpp b/tests/testpowerset.cpp deleted file mode 100644 index 20ca0098..00000000 --- a/tests/testpowerset.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "samples.hpp" -#include -#include -#include -#include - -using iter::powerset; - -int main() { - std::vector vec {1,2,3,4,5,6,7,8,9}; - for (auto v : powerset(vec)) { - for (auto i : v) std::cout << i << " "; - std::cout << std::endl; - } - std::cout << "with temporary\n"; - for (auto v : powerset(std::vector{1,2,3})) { - for (auto i : v) std::cout << i << " "; - std::cout << std::endl; - } - std::cout << "with initializer_list\n"; - for (auto v : powerset({1,2,3})) { - for (auto i : v) std::cout << i << " "; - std::cout << std::endl; - } - - std::cout << "with container of move-only objects\n"; - std::vector mv; - for (auto i : iter::range(3)) { - mv.emplace_back(i); - } - for (auto v : powerset(mv)) { - for (auto i : v) std::cout << i << " "; - std::cout << std::endl; - } - - std::cout << "with deref-by-value iterator\n"; - itertest::DerefByValue dbv; - for (auto v : powerset(dbv)) { - for (auto i : v) std::cout << i << " "; - std::cout << std::endl; - } - - return 0; -} diff --git a/tests/testproduct.cpp b/tests/testproduct.cpp deleted file mode 100644 index 22d132ec..00000000 --- a/tests/testproduct.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "samples.hpp" - -#include -#include - -#include -#include -#include - -using iter::product; -int main() { - - std::vector mv; - for (auto i : iter::range(10)) { - mv.emplace_back(i); - } - std::vector empty{}; - std::vector v1{1,2,3}; - std::vector v2{7,8}; - std::vector v3{"the","cat"}; - std::vector v4{"hi","what","up","dude"}; - - for (auto t : product(v1, mv)) { - std::cout << std::get<0>(t) << ", " - << std::get<1>(t) << std::endl; - } - for (auto t : product(empty,v1)) { - std::cout << std::get<0>(t) << ", " - << std::get<1>(t) << std::endl; - } - for (auto t : product(v1,empty)) { - std::cout << std::get<0>(t) << ", " - << std::get<1>(t) << std::endl; - } - std::cout<(t) << ", " - << std::get<1>(t) << std::endl; - } - std::cout<(t) << ", " - << std::get<1>(t) << ", " - << std::get<2>(t) << ", " - << std::get<3>(t) << std::endl; - } - std::cout<(t) << std::endl; - } - std::cout<(t) << ", " - << std::get<1>(t) << std::endl; - } - std::cout << '\n'; - - for (auto t : product()) { t=t; } - - for (auto t : product(std::string{"hi"}, v1)) { - std::cout << std::get<0>(t) << ", " - << std::get<1>(t) << std::endl; - } - std::cout << '\n'; - - int arr[] = {1,2}; - for (auto t : product(std::string{"hi"}, arr)) { - std::cout << std::get<0>(t) << ", " - << std::get<1>(t) << std::endl; - } - std::cout << '\n'; - for (auto&& ij: iter::product(iter::range(10), iter::range(5))) { - std::cout << std::get<0>(ij) << "," << std::get<1>(ij) << std::endl; - } - - return 0; -} diff --git a/tests/testrange.cpp b/tests/testrange.cpp deleted file mode 100644 index 9404ae57..00000000 --- a/tests/testrange.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include - -#include - -using iter::range; - -int main() -{ - for (auto i : range(10)) { - std::cout << i << std::endl; - } - for (auto i : range(20, 30)) { - std::cout << i << std::endl; - } - for (auto i : range(50, 60, 2)) { - std::cout << i << std::endl; - } - - std::cout << "Negative Tests\n"; - for (auto i: range(-10, 0)) { - std::cout << i << std::endl; - } - - for (auto i : range(-10, 10, 2)) { - std::cout << i << std::endl; - } - - std::cout << "Tests where (stop - start)%step != 0" << std::endl; - for (auto i : range(1, 10, 2)) { - std::cout << i << std::endl; - } - - for (auto i : range(-1, -10, -2)) { - std::cout << i << std::endl; - } - - std::cout << "Tests with different types" << std::endl; - for(auto i : range(5.0, 10.0, 0.5)) { - std::cout << i << std::endl; - } - std::cout << "test unsigned" << std::endl; - std::cout << "empty range: " << std::endl; - size_t len = 0; - for(auto i : range(len)){ - std::cout << i << std::endl; - } - std::cout << "stop only" << std::endl; - len = 3; - for(auto i : range(len)){ - std::cout << i << std::endl; - } - std::cout << "start stop" << std::endl; - size_t start = 1; - for(auto i : range(start, len)){ - std::cout << i << std::endl; - } - - std::cout << "start stop skip" << std::endl; - len = 10; - size_t skip = 3; - for(auto i : range(start, len, skip)){ - std::cout << i << std::endl; - } - - - - // invalid ranges: - std::cout << "Should not print anything after this line until exception\n"; - for (auto i : range(-10, 0, -1)) { - std::cout << i << std::endl; - } - - for (auto i : range(0, 1, -1)) { - std::cout << i << std::endl; - } - - std::cout << "Should see exception now\n"; - for (auto i : range(0, 10, 0) ) { - std::cout << i << std::endl; - } - - return 0; -} diff --git a/tests/testrepeat.cpp b/tests/testrepeat.cpp deleted file mode 100644 index b91fba03..00000000 --- a/tests/testrepeat.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "repeat.hpp" -#include -#include -#include -#include -#include - -int main () { - int a = 10; - int i = 0; - for (auto num : iter::repeat(a)) {//goes infintely - std::cout << num << std::endl; - ++i; - if (i > 20) break; - } - std::cout<{new int{2}}, 2)) { - std::cout << *p << '\n'; - } - -} diff --git a/tests/testreversed.cpp b/tests/testreversed.cpp deleted file mode 100644 index c6d0ab46..00000000 --- a/tests/testreversed.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include - -#include -#include -#include -#include - -int main () { - std::vector a{1,2,3,4,5,6,7}; - std::vector b{"hey","how","are","you","doing"}; - std::cout << std::endl << "reversed range test" << std::endl << std::endl; - for (auto i : iter::reversed(a)) { - std::cout << i << std::endl; - } - std::cout<{1, 2, 3, 4, 5, 6, 7})) { - std::cout << i << '\n'; - } - - std::cout << "statically sized array\n"; - int arr[] = {1, 2, 3, 4, 5, 6, 7}; - for (auto i : iter::reversed(arr)) { - std::cout << i << '\n'; - } - - -} diff --git a/tests/testslice.cpp b/tests/testslice.cpp deleted file mode 100644 index eaf8e1ce..00000000 --- a/tests/testslice.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include - -#include -#include - -#include -#include - -int main() { - std::cout << std::endl << "Slice range test" << std::endl << std::endl; - std::vector a{0,1,2,3,4,5,6,7,8,9,10,11,12,13}; - std::vector b{"hey","how","are","you","doing"}; - - std::cout << "step out of slice\n"; - for (auto i : iter::slice(a, 1, 4, 5)) { - std::cout << i << '\n'; - } - std::cout << "end step out\n"; - - for (auto i : iter::slice(a,2)) { - std::cout << i << std::endl; - } - std::cout<{1, 2, 4, 8, 16, 32, 64, 128}, 2, 6)) { - std::cout << i << '\n'; - } - -} diff --git a/tests/testsliding_window.cpp b/tests/testsliding_window.cpp deleted file mode 100644 index 16708db7..00000000 --- a/tests/testsliding_window.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "sliding_window.hpp" - -#include -#include - -using iter::sliding_window; - -int main() { - std::vector v = {1,2,3,4,5,6,7,8,9}; - for (auto sec : sliding_window(v,4)) { - for (auto i : sec) { - std::cout << i << " "; - i.get() = 90; - } - std::cout << std::endl; - } - - std::cout << "with temporary\n"; - for (auto sec : sliding_window(std::vector{1,2,3,4,5,6,7,8,9}, 4)) { - for (auto i : sec) { - std::cout << i << " "; - i.get() = 90; - } - std::cout << std::endl; - } - - std::cout << "with init list\n"; - for (auto sec : sliding_window({1,2,3,4,5,6,7,8,9}, 4)) { - for (auto i : sec) { - std::cout << i << " "; - } - std::cout << std::endl; - } - - std::cout << "with window_size > length\n"; - for (auto sec : sliding_window({1,2,3}, 10)) { - for (auto i : sec) { - std::cout << i << " "; - } - std::cout << std::endl; - } - - std::cout << "with static array\n"; - int arr[] = {1,2,3,4,5,6,7,8,9}; - for (auto sec : sliding_window(arr, 4)) { - for (auto i : sec) { - std::cout << i << " "; - } - std::cout << std::endl; - } - - return 0; -} diff --git a/tests/testsorted.cpp b/tests/testsorted.cpp deleted file mode 100644 index aed57d32..00000000 --- a/tests/testsorted.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include - -#include -#include -#include - -using iter::sorted; - -int main() -{ - std::vector vec = {19, 45, 32, 10, 0, 90, 15, 1, 7, 5, 6, 69}; - for (auto i : sorted(vec)) { - std::cout << i << '\n'; - } - - const std::vector cvec(vec); - for (auto i : sorted(cvec)) { - std::cout << i << '\n'; - } - - std::cout << "Sort by first character only\n"; - std::vector svec = {"hello", "everyone", "thanks", "for", - "having", "me", "here", "today"}; - for (auto s : sorted(svec, - [] (const std::string & s1, const std::string & s2) { - return s1[0] < s2[0]; })) { - std::cout << s << '\n'; - } - - - for (auto i : sorted( - std::vector{19, 45, 32, 10, 0, 90, 15, 1, 7, 5, 6, 69})) { - std::cout << i << '\n'; - } - return 0; -} diff --git a/tests/teststarmap.cpp b/tests/teststarmap.cpp deleted file mode 100644 index f85bd40d..00000000 --- a/tests/teststarmap.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -using iter::starmap; - -double f(double d, int i) { - return d * i; -} - -std::string g(const std::string& s, int i, double d) { - std::stringstream ss; - ss << s << ' ' << i << ' ' << d; - return ss.str(); -} - -void test_normal() { - std::cout << "vector>\n"; - std::vector> v1 = {{1.0, 2}, {3.2, 42}, {6.9, 7}}; - for (auto&& i : starmap(f, v1)) { - std::cout << i << '\n'; - } - std::cout << '\n'; - - std::cout << "list\n"; - { - using T = std::tuple; - std::list li = - {T{"hey", 42, 6.9}, T{"there", 3, 4.0}, T{"yall", 5, 3.1}}; - for (auto&& s : starmap(g, li)) { - std::cout << s << '\n'; - } - } - std::cout << '\n'; -} - -struct Callable { - int operator()(int a, int b, int c) { - return a + b + c; - } - - int operator()(int a) { - return a; - } -}; - -void test_tuple_of_tuples() { - auto tup = std::make_tuple(std::make_tuple(10, 19, 60),std::make_tuple(7)); - Callable c; - std::cout << "tuple, tuple>\n"; - for (auto&& i : starmap(c, tup)) { - std::cout << i << '\n'; - } - - auto tup2 = std::make_tuple(std::array{{15, 100, 2000}}, - std::make_tuple(16)); - std::cout << "tuple, tuple>\n"; - for (auto&& i : starmap(c, tup2)) { - std::cout << i << '\n'; - } - std::cout << '\n'; - - std::cout << "pair, tuple>\n"; - auto p = std::make_pair(std::array{{15, 100, 2000}}, - std::make_tuple(16)); - for (auto&& i : starmap(c, p)) { - std::cout << i << '\n'; - } - std::cout << '\n'; -} - -int main() { - test_normal(); - test_tuple_of_tuples(); - -} diff --git a/tests/testtakewhile.cpp b/tests/testtakewhile.cpp deleted file mode 100644 index bec3aeae..00000000 --- a/tests/testtakewhile.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -#include -#include - -using iter::takewhile; -using iter::range; - -int main() { - std::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)) { - std::cout << i << '\n'; - } - - for (auto i : takewhile([] (int i) {return i < 5;}, range(10))) { - std::cout << i << '\n'; - } - - for (auto i : takewhile([] (int i) {return i < 5;}, - {1, 2, 3, 4, 5, 6, 7, 8, 9})) { - std::cout << i << '\n'; - } - - std::cout << "with temporary\n"; - for (auto i : takewhile([] (int i) {return i < 5;}, - std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9})) { - std::cout << i << '\n'; - } - - return 0; -} diff --git a/tests/testunique_everseen.cpp b/tests/testunique_everseen.cpp deleted file mode 100644 index 015adb7d..00000000 --- a/tests/testunique_everseen.cpp +++ /dev/null @@ -1,41 +0,0 @@ - -#include -#include - -#include -using iter::unique_everseen; - -int main() { - { - //should work same as justseen here - std::vector v {1,1,1,2,2,3,4,4,5,6,7,8,8,8,8,9,9}; - for (auto i : unique_everseen(v)) { - std::cout << i << " "; - }std::cout << std::endl; - } - { - std::vector v {1,2,3,4,3,2,1,5,6,7,7,8,9,8,9,6}; - for (auto i : unique_everseen(v)) { - std::cout << i << " "; - }std::cout << std::endl; - } - - for (auto i : unique_everseen( - std::vector{1,2,1,3,4,3,2,1,5,6,7,7,8,9,8,9,6})) { - std::cout << i << " "; - } - std::cout << std::endl; - - int arr[] = {1,2,1,3,4,3,2,1,5,6,7,7,8,9,8,9,6}; - for (auto i : unique_everseen(arr)) { - std::cout << i << ' '; - } - std::cout << '\n'; - - for (auto i : unique_everseen({1,2,1,3,4,3,2,1,5,6,7,7,8,9,8,9,6})) { - std::cout << i << ' '; - } - std::cout << '\n'; - - return 0; -} diff --git a/tests/testunique_justseen.cpp b/tests/testunique_justseen.cpp deleted file mode 100644 index 8f454b6d..00000000 --- a/tests/testunique_justseen.cpp +++ /dev/null @@ -1,35 +0,0 @@ - -#include -#include - -#include -using iter::unique_justseen; - -int main() { - std::vector v {1,1,1,2,2,4,4,5,6,7,8,8,8,8,9,9}; - for (auto i : unique_justseen(v)) { - std::cout << i << " "; - } - std::cout << '\n'; - - std::cout << "with temporary\n"; - for (auto i : unique_justseen(std::vector{1,1,1,2,3,3})) { - std::cout << i << " "; - } - std::cout << '\n'; - - std::cout << "with init list\n"; - for (auto i : unique_justseen({1,1,1,2,3,3})) { - std::cout << i << " "; - } - std::cout << '\n'; - - std::cout << "with static array\n"; - int arr[] = {1, 1, 2, 3, 3, 3, 4}; - for (auto i : unique_justseen(arr)) { - std::cout << i << " "; - } - std::cout << '\n'; - - return 0; -} diff --git a/tests/testzip.cpp b/tests/testzip.cpp deleted file mode 100644 index 76a95fd7..00000000 --- a/tests/testzip.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include - -using iter::zip; - -int main() { - //Ryan's test - { - for (auto t : zip()) { t=t; } - - std::vector ivec{1, 4, 9, 16, 25, 36}; - std::vector svec{"hello", "good day", "goodbye"}; - - constexpr int magic_value = 69; - for (auto e : zip(ivec, svec)) { - auto &i = std::get<0>(e); - std::cout << i << std::endl; - i = magic_value; - std::cout << std::get<1>(e) << std::endl; - } - assert(ivec.at(0) == magic_value); - for (auto e : zip(ivec, svec)) { - std::cout << std::get<0>(e) << std::endl; - std::cout << std::get<1>(e) << std::endl; - } - - for (auto e : zip(std::vector{5,6,7})) { - std::cout << std::get<0>(e) << std::endl; - } - for (auto e : zip(std::vector{5,6,7}, std::array{{1,2}})){ - std::cout << std::get<0>(e) << std::endl; - std::cout << std::get<1>(e) << std::endl; - } - - for (auto e : zip(iter::range(10), iter::range(10, 20))) { - std::cout << std::get<0>(e) << '\n'; - std::cout << std::get<1>(e) << '\n'; - } - - int arr[] = {1,2,3,3,4}; - for (auto e : zip(iter::range(10), arr)) { - std::cout << std::get<0>(e) << '\n'; - std::cout << std::get<1>(e) << '\n'; - } - - } - //Aaron's test - { - std::array i{{1,2,3,4}}; - std::vector f{1.2,1.4,12.3,4.5,9.9}; - std::vector s{"i","like","apples","alot","dude"}; - std::array d{{1.2,1.2,1.2,1.2,1.2}}; - std::cout << std::endl << "Variadic template zip iterator" << std::endl; - for (auto e : iter::zip(i,f,s,d)) { - std::cout << std::get<0>(e) << " " - << std::get<1>(e) << " " - << std::get<2>(e) << " " - << std::get<3>(e) << std::endl; - std::get<1>(e)=2.2f; //modify the float array - } - std::cout<(e) << " " - << std::get<1>(e) << " " - << std::get<2>(e) << " " - << std::get<3>(e) << std::endl; - } - std::cout << std::endl << "Try some weird range differences" << std::endl; - std::vector empty{}; - for (auto e : iter::zip(empty,f,s,d)) { - std::cout << std::get<0>(e) << " " - << std::get<1>(e) << " " - << std::get<2>(e) << " " - << std::get<3>(e) << std::endl; - } - std::cout<(e) << " " - << std::get<1>(e) << " " - << std::get<2>(e) << " " - << std::get<3>(e) << std::endl; - }//both should print nothing - std::cout<(e) << " " - << std::get<1>(e) << " " - << std::get<2>(e) << " " - << std::get<3>(e) << std::endl; - } - std::cout< constvector{1.1,2.2,3.3,4.4}; - for (auto e : zip( - iter::chain(std::vector{5,6}, - std::array{{1,2}}), - std::initializer_list{ - "asdfas","aaron","ryan","apple","juice"}, - std::initializer_list{1, 2, 3, 4}, - constvector)) - { - - std::cout << std::get<0>(e) << " " - << std::get<1>(e) << " " - << std::get<2>(e) - << '\n'; - } - } - - - return 0; -} - diff --git a/tests/testzip_longest.cpp b/tests/testzip_longest.cpp deleted file mode 100644 index 63dc8fd0..00000000 --- a/tests/testzip_longest.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include - -#include -#include -#include -#include -#include - -using iter::zip_longest; - -template -std::ostream & operator<<(std::ostream & out, const boost::optional& opt) { - if (opt) { - out << "Just " << *opt; - } else { - out << "Nothing"; - } - return out; -} - -int main() { - //Ryan's test - { - std::vector ivec{1, 4, 9, 16, 25, 36}; - std::vector svec{"hello", "good day", "goodbye"}; - - for (auto e : zip_longest(ivec, svec)) { - std::cout << std::get<0>(e) << std::endl; - std::cout << std::get<1>(e) << std::endl; - } - - for (auto e : zip_longest("helloworld", - std::vector{1,2,3})) { - std::cout << std::get<0>(e) << std::endl; - std::cout << std::get<1>(e) << std::endl; - } - } - //Aaron's test - { - std::array i{{1,2,3,4}}; - std::vector f{1.2,1.4,12.3,4.5,9.9}; - std::vector s{"i","like","apples","alot","dude"}; - std::array d{{1.2,1.2,1.2,1.2,1.2}}; - std::cout << std::endl << "Variadic template zip_longest" << std::endl; - for (auto e : iter::zip_longest(i,f,s,d)) { - std::cout << std::get<0>(e) << ' ' - << std::get<1>(e) << ' ' - << std::get<2>(e) << ' ' - << std::get<3>(e) << std::endl; - *std::get<1>(e)=2.2f; //modify the float array - } - std::cout<<"modified array" <(e) << ' ' - << std::get<1>(e) << ' ' - << std::get<2>(e) << ' ' - << std::get<3>(e) << std::endl; - } - std::cout << std::endl << "Try some weird range differences" << std::endl; - std::vector empty{}; - for (auto e : iter::zip_longest(empty,f,s,d)) { - std::cout << std::get<0>(e) << ' ' - << std::get<1>(e) << ' ' - << std::get<2>(e) << ' ' - << std::get<3>(e) << std::endl; - } - std::cout<(e) << ' ' - << std::get<1>(e) << ' ' - << std::get<2>(e) << ' ' - << std::get<3>(e) << std::endl; - } - std::cout<(e) << ' ' - << std::get<1>(e) << ' ' - << std::get<2>(e) << ' ' - << std::get<3>(e) << std::endl; - } - std::cout<{1,2,3,4,5,6}, - std::initializer_list{1.1,2.2,3.3,4.4}, - std::initializer_list{1.1,2.2,3.3,4.4}, - std::array{{1,2,3}})) { - std::cout << std::get<0>(e) << ' ' - << std::get<1>(e) << ' ' - << std::get<2>(e) << ' ' - << std::get<3>(e) << std::endl; - } - std::cout< Date: Wed, 20 May 2015 00:52:44 -0700 Subject: [PATCH 73/90] moves test_starmap into test/ --- {catchtest => test}/test_starmap.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {catchtest => test}/test_starmap.cpp (100%) diff --git a/catchtest/test_starmap.cpp b/test/test_starmap.cpp similarity index 100% rename from catchtest/test_starmap.cpp rename to test/test_starmap.cpp From d6a0b4911987db540942ee79fbf7daf15c211907 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 20 May 2015 01:17:06 -0700 Subject: [PATCH 74/90] adds starmap_examples.cpp file --- examples/starmap_examples.cpp | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 examples/starmap_examples.cpp diff --git a/examples/starmap_examples.cpp b/examples/starmap_examples.cpp new file mode 100644 index 00000000..9797756c --- /dev/null +++ b/examples/starmap_examples.cpp @@ -0,0 +1,40 @@ +#include + +#include +#include +#include +#include + +// Since this is an example file I'm dumping a bunch of using declarations +// here, in real code I use using declarations very sparingly +using std::pair; +using std::tuple; +using std::vector; +using std::make_pair; +using std::make_tuple; + +struct Callable { + int operator()(int i) const { return i; } + int operator()(int i, char c) const { return i + c; } + int operator()(unsigned int u, int i, char c) const { return i + c + u; } +}; + +int main() { + // the function will be called with the tuple-like object unpacked + // using std::get. This means an iterable of tuples, arrays, pairs, or + // whatever works with std::get + vector> v = {{2, 3}, {5, 2}, {3, 4}}; // {base, exponent} + for (auto&& i : iter::starmap([](int b, int e){ return b * e; }, v)) { + std::cout << i << '\n'; + } + + // Alternatively if an object has multiple call operators, a tuple-like + // object of tuple-like objects + auto t = make_tuple( + make_tuple(5), // first form + make_pair(3, 'c'), // second form + make_tuple(1u, 1, '1')); // third form + for (auto&& i : iter::starmap(Callable{}, t)) { + std::cout << i << '\n'; + } +} From e4e2d21bcad1d561d602af5612f6228ed89161f8 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 20 May 2015 01:17:58 -0700 Subject: [PATCH 75/90] builds starmap_examples --- examples/SConstruct | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/SConstruct b/examples/SConstruct index 41acb956..3a9bfbb4 100644 --- a/examples/SConstruct +++ b/examples/SConstruct @@ -4,7 +4,7 @@ env = Environment( ENV = {'PATH' : os.environ['PATH']}, CXX='c++', CXXFLAGS= ['-g', '-Wall', '-Wextra', - '-pedantic', '-std=c++11', + '-pedantic', '-std=c++14', '-fdiagnostics-color=always', '-I/usr/local/include'], CPPPATH='..', @@ -34,6 +34,7 @@ progs = Split( slice sliding_window sorted + starmap takewhile unique_justseen unique_everseen From 8fa94f7452cd28adc0007886630b3eae8174dec4 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 20 May 2015 10:55:54 -0700 Subject: [PATCH 76/90] adds reverse iter aliases --- iterbase.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/iterbase.hpp b/iterbase.hpp index 9f6177e4..5e66cd7f 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -44,7 +44,7 @@ namespace iter { // iterator_type is the type of C's iterator template using reverse_iterator_type = - decltype(std::declval().rbegin()); + decltype(std::rbegin(std::declval())); // iterator_deref is the type obtained by dereferencing an iterator // to an object of type C @@ -52,6 +52,10 @@ namespace iter { using reverse_iterator_deref = decltype(*std::declval&>()); + template + using reverse_iterator_traits_deref = + std::remove_reference_t>; + template struct is_random_access_iter : std::false_type { }; From 128806ee5a5d26ca94a5f0538afbaaded59bee65 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 20 May 2015 10:56:06 -0700 Subject: [PATCH 77/90] uses std::rbegin and rend, removes specialization Instead of using .rbegin() and .rend(), uses non-member std::rbegin() and std::rend() to get the iterators. This also means (like replacing .begin() with std::begin() forever ago) that Reverser can handle arrays. This commit removes the array specialization. --- reversed.hpp | 83 +++++----------------------------------------------- 1 file changed, 7 insertions(+), 76 deletions(-) diff --git a/reversed.hpp b/reversed.hpp index 0e03b6c1..8fdaa96e 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -13,13 +13,12 @@ namespace iter { template Reverser reversed(Container&&); - template class Reverser { private: Container container; friend Reverser reversed(Container&&); - + Reverser(Container&& in_container) : container(std::forward(in_container)) { } @@ -27,20 +26,20 @@ namespace iter { public: class Iterator : public std::iterator< std::input_iterator_tag, - iterator_traits_deref> + reverse_iterator_traits_deref> { private: reverse_iterator_type sub_iter; public: - Iterator (reverse_iterator_type&& iter) + Iterator(reverse_iterator_type&& iter) : sub_iter{std::move(iter)} - { } + { } reverse_iterator_deref operator*() { return *this->sub_iter; } - Iterator& operator++() { + Iterator& operator++() { ++this->sub_iter; return *this; } @@ -61,11 +60,11 @@ namespace iter { }; Iterator begin() { - return {this->container.rbegin()}; + return {std::rbegin(this->container)}; } Iterator end() { - return {this->container.rend()}; + return {std::rend(this->container)}; } }; @@ -74,74 +73,6 @@ namespace iter { Reverser reversed(Container&& container) { return {std::forward(container)}; } - - // - // specialization for statically allocated arrays - // - template - Reverser reversed(T (&)[N]); - - template - class Reverser { - private: - T *array; - friend Reverser reversed(T (&)[N]); - - // Value constructor for use only in the reversed function - Reverser(T *in_array) - : array{in_array} - { } - - public: - Reverser(const Reverser&) = default; - class Iterator : public std::iterator - { - private: - T *sub_iter; - public: - Iterator (T *iter) - : sub_iter{iter} - { } - - iterator_deref operator*() { - return *(this->sub_iter - 1); - } - - Iterator& operator++() { - --this->sub_iter; - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - return this->sub_iter != other.sub_iter; - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - }; - - Iterator begin() { - return {this->array + N}; - } - - Iterator end() { - return {this->array}; - } - - }; - - template - Reverser reversed(T (&array)[N]) { - return {array}; - } - } #endif From 684dcf6c4c5fe9e3f8ab4ea7b626c256693f07c9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 20 May 2015 11:10:42 -0700 Subject: [PATCH 78/90] moves reverse_iterator aliases into reversed.hpp They're only used in reversed, they don't need to be in iterbase --- iterbase.hpp | 16 ---------------- reversed.hpp | 17 +++++++++++++---- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 5e66cd7f..7bf65d69 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -36,26 +36,10 @@ namespace iter { using const_iterator_deref = decltype(*std::declval&>()); - template using iterator_traits_deref = std::remove_reference_t>; - // iterator_type is the type of C's iterator - template - using reverse_iterator_type = - decltype(std::rbegin(std::declval())); - - // iterator_deref is the type obtained by dereferencing an iterator - // to an object of type C - template - using reverse_iterator_deref = - decltype(*std::declval&>()); - - template - using reverse_iterator_traits_deref = - std::remove_reference_t>; - template struct is_random_access_iter : std::false_type { }; diff --git a/reversed.hpp b/reversed.hpp index 8fdaa96e..e270c971 100644 --- a/reversed.hpp +++ b/reversed.hpp @@ -23,19 +23,28 @@ namespace iter { : container(std::forward(in_container)) { } + using reverse_iterator_type = + decltype(std::rbegin(std::declval())); + + using reverse_iterator_deref = + decltype(*std::declval()); + + using reverse_iterator_traits_deref = + std::remove_reference_t; + public: class Iterator : public std::iterator< std::input_iterator_tag, - reverse_iterator_traits_deref> + reverse_iterator_traits_deref> { private: - reverse_iterator_type sub_iter; + reverse_iterator_type sub_iter; public: - Iterator(reverse_iterator_type&& iter) + Iterator(reverse_iterator_type&& iter) : sub_iter{std::move(iter)} { } - reverse_iterator_deref operator*() { + reverse_iterator_deref operator*() { return *this->sub_iter; } From b4cec8441bb74fe6aaad93db8d2a68a8a87244e3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Wed, 20 May 2015 11:19:06 -0700 Subject: [PATCH 79/90] conditionally declares BasicIterable::rbegin --- test/helpers.hpp | 18 +++++------------- test/test_reversed.cpp | 5 ++++- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/test/helpers.hpp b/test/helpers.hpp index 7c36ca89..c0db7fe7 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -110,19 +110,6 @@ class BasicIterable { BasicIterable& operator=(const BasicIterable&) = delete; 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; - } - } -#endif - BasicIterable(BasicIterable&& other) : data{other.data}, @@ -170,6 +157,11 @@ class BasicIterable { Iterator end() { return {this->data + this->size}; } + +#ifdef DECLARE_REVERSE_ITERATOR + Iterator rbegin(); + Iterator rend(); +#endif // ifdef DECLARE_REVERSE_ITERATOR }; using iter::void_t; diff --git a/test/test_reversed.cpp b/test/test_reversed.cpp index 389badd0..6736b1a7 100644 --- a/test/test_reversed.cpp +++ b/test/test_reversed.cpp @@ -5,9 +5,12 @@ #include #include -#include "helpers.hpp" #include "catch.hpp" +#define DECLARE_REVERSE_ITERATOR +#include "helpers.hpp" +#undef DECLARE_REVERSE_ITERATOR + using iter::reversed; using Vec = const std::vector; From 91201db3b6901ed75b1dc576cb05d4f7613615ed Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 21 May 2015 15:27:05 -0700 Subject: [PATCH 80/90] removes trailing space --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0bb7e56a..48d9dcfc 100644 --- a/README.md +++ b/README.md @@ -368,7 +368,7 @@ 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 -tuple of the elements the iterators were holding. +tuple of the elements the iterators were holding. Example usage: ```c++ From 1209101060265fc848fab3a3fa681584e4d8b5a9 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 26 May 2015 12:24:39 -0700 Subject: [PATCH 81/90] replaces "naked new" in chain with make_unique --- chain.hpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/chain.hpp b/chain.hpp index 5b0a1086..bc4fd097 100644 --- a/chain.hpp +++ b/chain.hpp @@ -60,7 +60,7 @@ class Chained { constexpr static std::array derefers{{ get_and_deref...}}; - + constexpr static std::array incrementers{{ get_and_increment...}}; @@ -68,7 +68,7 @@ class Chained { get_and_check_not_equal...}}; - using TraitsValue = + using TraitsValue = iterator_traits_deref>; private: TupType tup; @@ -188,8 +188,8 @@ constexpr std::array< static std::unique_ptr clone_sub_pointer( const SubIter* sub_iter) { - return std::unique_ptr{ sub_iter ? - new SubIter{*sub_iter} : nullptr}; + return sub_iter ? + std::make_unique(*sub_iter) : nullptr; } bool sub_iters_differ(const Iterator& other) const { @@ -211,9 +211,11 @@ constexpr std::array< : top_level_iter{std::move(top_iter)}, top_level_end{std::move(top_end)}, sub_iter_p{!(top_iter != top_end) ? // iter == end ? - nullptr : new SubIter{std::begin(*top_iter)}}, + nullptr : + std::make_unique(std::begin(*top_iter))}, sub_end_p{!(top_iter != top_end) ? // iter == end ? - nullptr : new SubIter{std::end(*top_iter)}} + nullptr : + std::make_unique(std::end(*top_iter))} { } Iterator(const Iterator& other) @@ -245,13 +247,15 @@ constexpr std::array< 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.reset( - new SubIter{std::begin(*this->top_level_iter)}); - sub_end_p.reset( - new SubIter{std::end(*this->top_level_iter)}); + sub_iter_p = + std::make_unique( + std::begin(*this->top_level_iter)); + sub_end_p = + std::make_unique( + std::end(*this->top_level_iter)); } else { - sub_iter_p.reset(nullptr); - sub_end_p.reset(nullptr); + sub_iter_p.reset(); + sub_end_p.reset(); } } return *this; From 1d458f3aabca03224d3d1fae7acd8e8e2b26190b Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 26 May 2015 12:29:54 -0700 Subject: [PATCH 82/90] removes "naked new"s in powerset using make_shared --- powerset.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/powerset.hpp b/powerset.hpp index 555be582..d3743cc4 100644 --- a/powerset.hpp +++ b/powerset.hpp @@ -39,7 +39,8 @@ namespace iter { Iterator(Container& in_container, std::size_t sz) : container_p{&in_container}, set_size{sz}, - comb{new CombinatorType(combinations(in_container, sz))}, + comb{std::make_shared( + combinations(in_container, sz))}, comb_iter{std::begin(*comb)}, comb_end{std::end(*comb)} { } @@ -48,8 +49,9 @@ namespace iter { ++this->comb_iter; if (this->comb_iter == this->comb_end) { ++this->set_size; - this->comb.reset(new CombinatorType(combinations( - *this->container_p, 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); } From 7413ddb05d7105f8f4290c492c83df0d8905e688 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Tue, 26 May 2015 13:44:56 -0700 Subject: [PATCH 83/90] replaces "naked new"s in iterbase with make_unique --- iterbase.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iterbase.hpp b/iterbase.hpp index 7bf65d69..16679a4f 100644 --- a/iterbase.hpp +++ b/iterbase.hpp @@ -200,12 +200,13 @@ namespace iter { DerefHolder() = default; DerefHolder(const DerefHolder& other) - : item_p{other.item_p ? new TPlain(*other.item_p) : nullptr} + : item_p{other.item_p ? + std::make_unique(*other.item_p) : nullptr} { } DerefHolder& operator=(const DerefHolder& other) { - this->item_p.reset(other.item_p - ? new TPlain(*other.item_p) : nullptr); + this->item_p = other.item_p ? + std::make_unique(*other.item_p) : nullptr; return *this; } @@ -224,7 +225,7 @@ namespace iter { } void reset(T&& item) { - item_p.reset(new TPlain(std::move(item))); + item_p = std::make_unique(std::move(item)); } explicit operator bool() const { @@ -236,8 +237,7 @@ namespace iter { // Specialization for when T is an lvalue ref. Keep this in mind // wherever a T appears. template - class DerefHolder::value>::type> + class DerefHolder::value>> { private: static_assert(std::is_lvalue_reference::value, From 93177acc9bd7b32b779601106eb394534d09b0c5 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 27 Aug 2015 22:42:37 -0700 Subject: [PATCH 84/90] tests chain.from_iterable arrow --- test/test_chain.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/test_chain.cpp b/test/test_chain.cpp index 46319d33..b4cf0836 100644 --- a/test/test_chain.cpp +++ b/test/test_chain.cpp @@ -186,6 +186,12 @@ TEST_CASE("chain.from_iterable: postfix ++", "[chain.from_iterable]") { REQUIRE( *it == 'n' ); } +TEST_CASE("chain.from_iterable: operator->","[chain.from_iterable]") { + std::vector> sv{{"a", "ab"}, {"abc"}}; + auto ch = chain.from_iterable(sv); + auto it = std::begin(ch); + REQUIRE( it->size() == 1 ); +} TEST_CASE("chain.from_iterable: moves rvalues and binds ref to lvalues", "[chain.from_iterable]") { From 4eb45a6f8c36ee6b082ac9aa02fd9b476c7b042f Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 27 Aug 2015 22:42:48 -0700 Subject: [PATCH 85/90] implements chain.from_iterable arrow --- chain.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/chain.hpp b/chain.hpp index 2556fecc..3fb097a5 100644 --- a/chain.hpp +++ b/chain.hpp @@ -255,6 +255,10 @@ class iter::impl::ChainedFromIterable { iterator_deref> operator*() { return **this->sub_iter_p; } + + iterator_arrow> operator->() { + return apply_arrow(*this->sub_iter_p); + } }; Iterator begin() { From afbe4ffccc2bb08c31f1597e0c70984e320f04c6 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 27 Aug 2015 22:48:30 -0700 Subject: [PATCH 86/90] puts back in chain operator-> --- chain.hpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/chain.hpp b/chain.hpp index 3fb097a5..b50e520f 100644 --- a/chain.hpp +++ b/chain.hpp @@ -41,12 +41,18 @@ class iter::impl::Chained { 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 + static ArrowType get_and_arrow(IterTupType& iters) { + return apply_arrow(std::get(iters)); + } + template static void get_and_increment(IterTupType& iters) { ++std::get(iters); @@ -59,12 +65,16 @@ class iter::impl::Chained { } 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...}}; + constexpr static std::array arrowers{ + {get_and_arrow...}}; + constexpr static std::array incrementers{ {get_and_increment...}}; @@ -77,7 +87,6 @@ class iter::impl::Chained { TupType tup; public: - Chained(Chained&&) = default; Chained(TupType&& t) : tup(std::move(t)) {} class Iterator : public std::iterator { @@ -103,6 +112,10 @@ class iter::impl::Chained { return derefers[this->index](this->iters); } + decltype(auto) operator -> () { + return arrowers[this->index](this->iters); + } + Iterator& operator++() { incrementers[this->index](this->iters); this->check_for_end_and_adjust(); @@ -141,6 +154,10 @@ template constexpr std::array::DerefFunc, sizeof...(Is)> iter::impl::Chained::derefers; +template +constexpr std::array::ArrowFunc, + sizeof...(Is)> iter::impl::Chained::arrowers; + template constexpr std::array::IncFunc, sizeof...(Is)> iter::impl::Chained::incrementers; From 3fc699523184273335b94801330bf21c7fbe91fd Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 27 Aug 2015 22:50:15 -0700 Subject: [PATCH 87/90] adds back zip and zip_longest iter-> --- zip.hpp | 5 ++ zip_longest.hpp | 201 ++++++++++++++++++++++++------------------------ 2 files changed, 104 insertions(+), 102 deletions(-) diff --git a/zip.hpp b/zip.hpp index 1771ed32..569ea6ee 100644 --- a/zip.hpp +++ b/zip.hpp @@ -33,6 +33,7 @@ class iter::impl::Zipped { Zipped(TupleType&& in_containers) : containers(std::move(in_containers)) {} public: + Zipped(Zipped&&) = default; class Iterator : public std::iterator { private: iterator_tuple_type iters; @@ -67,6 +68,10 @@ class iter::impl::Zipped { ZipIterDeref operator*() { return ZipIterDeref{(*std::get(this->iters))...}; } + + auto operator -> () -> ArrowProxy { + return {**this}; + } }; Iterator begin() { diff --git a/zip_longest.hpp b/zip_longest.hpp index 98b20ec4..800261b7 100644 --- a/zip_longest.hpp +++ b/zip_longest.hpp @@ -1,124 +1,121 @@ #ifndef ITER_ZIP_LONGEST_HPP_ #define ITER_ZIP_LONGEST_HPP_ -#include "iterbase.hpp" +#include "internal/iterbase.hpp" #include #include #include #include - namespace iter { - + namespace impl { template class ZippedLongest; template - ZippedLongest - zip_longest_impl(TupleType&&, std::index_sequence); + ZippedLongest zip_longest_impl( + TupleType&&, std::index_sequence); + } - template - class ZippedLongest { - private: - TupleType containers; - friend ZippedLongest zip_longest_impl( - TupleType&&, std::index_sequence); - - template - using OptType = boost::optional>>; - - using ZipIterDeref = std::tuple...>; - - ZippedLongest(TupleType&& in_containers) - : containers(std::move(in_containers)) - { } - public: - class Iterator - : public std::iterator - { - private: - 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& 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) : 0)...); - return *this; - } - - Iterator operator++(int) { - auto ret = *this; - ++*this; - return ret; - } - - bool operator!=(const Iterator& other) const { - if (sizeof...(Is) == 0) return false; - - bool results[] = { false, - (std::get(this->iters) != - std::get(other.iters))... - }; - return std::any_of( - std::begin(results), std::end(results), - [](bool b){ return b; } ); - } - - bool operator==(const Iterator& other) const { - return !(*this != other); - } - - ZipIterDeref operator*() { - return ZipIterDeref{ - ((std::get(this->iters) != - std::get(this->ends)) - ? OptType{*std::get(this->iters)} - : OptType{})...}; - } - }; - - Iterator begin() { - return { - iterator_tuple_type{ - std::begin(std::get(this->containers))...}, - iterator_tuple_type{ - std::end(std::get(this->containers))...}}; - } - - Iterator end() { - return { - iterator_tuple_type{ - std::end(std::get(this->containers))...}, - iterator_tuple_type{ - std::end(std::get(this->containers))...}}; - } -}; + template + auto zip_longest(Containers&&... containers); +} - template - ZippedLongest zip_longest_impl( - TupleType&& in_containers, std::index_sequence) { - return {std::move(in_containers)}; +template +class iter::impl::ZippedLongest { + private: + TupleType containers; + friend ZippedLongest zip_longest_impl( + TupleType&&, std::index_sequence); + + template + using OptType = + boost::optional>>; + + using ZipIterDeref = std::tuple...>; + + ZippedLongest(TupleType&& in_containers) + : containers(std::move(in_containers)) {} + + public: + ZippedLongest(ZippedLongest&&) = default; + class Iterator : public std::iterator { + private: + 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& 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) + : 0)...); + return *this; } - template - auto zip_longest(Containers&&... containers) { - return zip_longest_impl(std::tuple{ - std::forward(containers)...}, - std::index_sequence_for{}); + Iterator operator++(int) { + auto ret = *this; + ++*this; + return ret; + } + + bool operator!=(const Iterator& other) const { + if (sizeof...(Is) == 0) return false; + + bool results[] = { + false, (std::get(this->iters) != std::get(other.iters))...}; + return std::any_of( + std::begin(results), std::end(results), [](bool b) { return b; }); } + + bool operator==(const Iterator& other) const { + return !(*this != other); + } + + ZipIterDeref operator*() { + return ZipIterDeref{ + ((std::get(this->iters) != std::get(this->ends)) + ? OptType{*std::get(this->iters)} + : OptType{})...}; + } + + auto operator -> () -> ArrowProxy { + return {**this}; + } + }; + + Iterator begin() { + return {iterator_tuple_type{ + std::begin(std::get(this->containers))...}, + iterator_tuple_type{ + std::end(std::get(this->containers))...}}; + } + + Iterator end() { + return {iterator_tuple_type{ + std::end(std::get(this->containers))...}, + iterator_tuple_type{ + std::end(std::get(this->containers))...}}; + } +}; + +template +iter::impl::ZippedLongest iter::impl::zip_longest_impl( + TupleType&& in_containers, std::index_sequence) { + return {std::move(in_containers)}; +} + +template +auto iter::zip_longest(Containers&&... containers) { + return impl::zip_longest_impl( + std::tuple{std::forward(containers)...}, + std::index_sequence_for{}); } #endif From 7fbb8b5cde31079d6c242f74af0a24d2265a4958 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 27 Aug 2015 22:51:03 -0700 Subject: [PATCH 88/90] make Chained ctor private --- chain.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain.hpp b/chain.hpp index b50e520f..cc7c4d5c 100644 --- a/chain.hpp +++ b/chain.hpp @@ -84,10 +84,10 @@ class iter::impl::Chained { using TraitsValue = iterator_traits_deref>; private: + Chained(TupType&& t) : tup(std::move(t)) {} TupType tup; public: - Chained(TupType&& t) : tup(std::move(t)) {} class Iterator : public std::iterator { private: From af2a8b1922216886373f6f57de1261faed20986a Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Thu, 27 Aug 2015 22:52:00 -0700 Subject: [PATCH 89/90] makes Chained move-only --- chain.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/chain.hpp b/chain.hpp index cc7c4d5c..59369982 100644 --- a/chain.hpp +++ b/chain.hpp @@ -88,6 +88,7 @@ class iter::impl::Chained { TupType tup; public: + Chained(Chained&&) = default; class Iterator : public std::iterator { private: From 93c032eeaeda416d43e5b5b396200e9ff7c014a3 Mon Sep 17 00:00:00 2001 From: Ryan Haining Date: Mon, 7 Sep 2015 12:01:48 -0700 Subject: [PATCH 90/90] adds dummy operator()() to ArrowHelper --- internal/iterbase.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/iterbase.hpp b/internal/iterbase.hpp index f9295170..c215d003 100644 --- a/internal/iterbase.hpp +++ b/internal/iterbase.hpp @@ -54,6 +54,7 @@ namespace iter { template struct ArrowHelper { using type = void; + void operator()(T&) const noexcept { } }; template